]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/commitdiff
Add support for TorServices. https://redmine.stoutner.com/issues/1324 master
authorSoren Stoutner <soren@stoutner.com>
Thu, 7 May 2026 21:23:43 +0000 (14:23 -0700)
committerSoren Stoutner <soren@stoutner.com>
Thu, 7 May 2026 21:23:43 +0000 (14:23 -0700)
14 files changed:
app/src/main/AndroidManifest.xml
app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt
app/src/main/java/com/stoutner/privacybrowser/dialogs/ProxyNotInstalledDialog.kt
app/src/main/java/com/stoutner/privacybrowser/fragments/AboutVersionFragment.kt
app/src/main/res/layout/about_version_scrollview.xml
app/src/main/res/values-de/strings.xml
app/src/main/res/values-es/strings.xml
app/src/main/res/values-fr/strings.xml
app/src/main/res/values-it/strings.xml
app/src/main/res/values-pt-rBR/strings.xml
app/src/main/res/values-ru/strings.xml
app/src/main/res/values-tr/strings.xml
app/src/main/res/values-zh-rCN/strings.xml
app/src/main/res/values/strings.xml

index 82ea7e29ae48c6b6f38745f8fec190b98b2f0851..f2e3cffca754bb9ff9894a280e6d539b182ea2a0 100644 (file)
@@ -40,8 +40,9 @@
         <package android:name="net.i2p.android" />  <!-- Google Play flavor. -->
         <package android:name="net.i2p.android.router" />  <!-- F-Droid flavor. -->
 
-        <!-- Orbot. -->
-        <package android:name="org.torproject.android" />
+        <!-- Tor. -->
+        <package android:name="org.torproject.android" />  <!-- Orbot. -->
+        <package android:name="org.torproject.torservices" />  <!-- TorServices. -->
 
         <!-- OpenKeyChain. -->
         <package android:name="org.sufficientlysecure.keychain" />
index c70b2c15e6899f17bd527432c36269f384eb4649..846aef5e81a5021a43e9ebe8a1060c5733accfad 100644 (file)
@@ -3602,23 +3602,28 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 if (Build.VERSION.SDK_INT < 35)
                     window.statusBarColor = getColor(R.color.blue_background)
 
-                // Check to see if Orbot is installed.
+                // Check to see if Orbot or TorServices is installed.
                 try {
-                    // Check to see if Orbot is in the list.  This will throw an error and drop to the catch section if it isn't installed.
+                    // Check to see if Orbot is installed.  This will throw an error and drop to the catch section if it isn't installed.
                     packageManager.getPackageInfo("org.torproject.android", 0)
                 } catch (_: PackageManager.NameNotFoundException) {  // Orbot is not installed.
-                    // Show the Orbot not installed dialog if it is not already displayed.
-                    if (supportFragmentManager.findFragmentByTag(getString(R.string.proxy_not_installed_dialog)) == null) {
-                        // Get a handle for the Orbot not installed alert dialog.
-                        val orbotNotInstalledDialogFragment = ProxyNotInstalledDialog.displayDialog(proxyMode)
+                    try {
+                        // Check to see if TorServices is installed.  This will throw an error and drop to the catch section if it isn't installed.
+                        packageManager.getPackageInfo("org.torproject.torservices", 0)
+                    } catch (_: PackageManager.NameNotFoundException) {  // TorServices is not installed.
+                        // Show the Orbot not installed dialog if it is not already displayed.
+                        if (supportFragmentManager.findFragmentByTag(getString(R.string.proxy_not_installed_dialog)) == null) {
+                            // Get a handle for the Orbot or Tor Services not installed alert dialog.
+                            val orbotOrTorServicesNotInstalledDialogFragment = ProxyNotInstalledDialog.displayDialog(proxyMode)
 
-                        // Try to show the dialog.  Sometimes the window is not yet active if returning from Settings.
-                        try {
-                            // Display the Orbot not installed alert dialog.
-                            orbotNotInstalledDialogFragment.show(supportFragmentManager, getString(R.string.proxy_not_installed_dialog))
-                        } catch (_: Exception) {
-                            // Add the dialog to the pending dialog array list.  It will be displayed in `onStart()`.
-                            pendingDialogsArrayList.add(PendingDialogDataClass(orbotNotInstalledDialogFragment, getString(R.string.proxy_not_installed_dialog)))
+                            // Try to show the dialog.  Sometimes the window is not yet active if returning from Settings.
+                            try {
+                                // Display the Orbot not installed alert dialog.
+                                orbotOrTorServicesNotInstalledDialogFragment.show(supportFragmentManager, getString(R.string.proxy_not_installed_dialog))
+                            } catch (_: Exception) {
+                                // Add the dialog to the pending dialog array list.  It will be displayed in `onStart()`.
+                                pendingDialogsArrayList.add(PendingDialogDataClass(orbotOrTorServicesNotInstalledDialogFragment, getString(R.string.proxy_not_installed_dialog)))
+                            }
                         }
                     }
                 }
index 0d9df13302e2595294a2910401a501653c30dcbd..f19e8b70dd745bb806a18b2942a68ace14319ba8 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-3.0-or-later
- * SPDX-FileCopyrightText: 2019-2023 Soren Stoutner <soren@stoutner.com>
+ * SPDX-FileCopyrightText: 2019-2023, 2026 Soren Stoutner <soren@stoutner.com>
  *
  * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
  *
@@ -67,10 +67,10 @@ class ProxyNotInstalledDialog : DialogFragment() {
         when (proxyMode) {
             ProxyHelper.TOR -> {
                 // Set the title.
-                dialogBuilder.setTitle(R.string.orbot_not_installed_title)
+                dialogBuilder.setTitle(R.string.orbot_or_tor_services_not_installed_title)
 
                 // Set the message.
-                dialogBuilder.setMessage(R.string.orbot_not_installed_message)
+                dialogBuilder.setMessage(R.string.orbot_or_tor_services_not_installed_message)
             }
 
             ProxyHelper.I2P -> {
index cc3dcf5fde51a1e2e8d5a0e29fd21d19c17879b7..43d6c342b83dc3dcb018ad1a5502b1430ec7590a 100644 (file)
@@ -138,6 +138,7 @@ class AboutVersionFragment : Fragment() {
     private lateinit var systemAvailableMemoryTextView: TextView
     private lateinit var systemConsumedMemoryTextView: TextView
     private lateinit var systemTotalMemoryTextView: TextView
+    private lateinit var torServicesTextView: TextView
     private lateinit var versionTextView: TextView
     private lateinit var ultraListTextView: TextView
     private lateinit var ultraPrivacyTextView: TextView
@@ -295,6 +296,7 @@ class AboutVersionFragment : Fragment() {
         webViewProviderTextView = aboutVersionLayout.findViewById(R.id.webview_provider)
         webViewVersionTextView = aboutVersionLayout.findViewById(R.id.webview_version)
         orbotTextView = aboutVersionLayout.findViewById(R.id.orbot)
+        torServicesTextView = aboutVersionLayout.findViewById(R.id.tor_services)
         i2pTextView = aboutVersionLayout.findViewById(R.id.i2p)
         openKeychainTextView = aboutVersionLayout.findViewById(R.id.open_keychain)
         memoryUsageTextView = aboutVersionLayout.findViewById(R.id.memory_usage)
@@ -372,13 +374,22 @@ class AboutVersionFragment : Fragment() {
 
         // Get the Orbot version name if Orbot is installed.
         val orbot: String = try {
-            // If the safe call (`?.`) is null, the Elvis operator (`?"`) returns the following value instead, which is an empty string.
+            // If the safe call is null, the Elvis operator (`?:`) returns the following value instead, which is an empty string.
             requireContext().packageManager.getPackageInfo("org.torproject.android", 0).versionName ?: ""
         } catch (_: PackageManager.NameNotFoundException) {
             // Store an empty string.
             ""
         }
 
+        // Get the TorServices version name if TorServices is installed.
+        val torServices: String = try {
+            // If the safe call is null, the Elvis operator (`?:`) returns the following value instead, which is an empty string.
+            requireContext().packageManager.getPackageInfo("org.torproject.torservices", 0).versionName ?: ""
+        } catch (_: PackageManager.NameNotFoundException) {
+            // Store an empty string.
+            ""
+        }
+
         // Get the I2P version name if I2P is installed.
         val i2p: String = try {
             // Check to see if the F-Droid flavor is installed.
@@ -497,6 +508,24 @@ class AboutVersionFragment : Fragment() {
             orbotTextView.visibility = View.GONE
         }
 
+        // Only populate the TorServices text view if it is installed.
+        if (torServices.isNotEmpty()) {
+            // Set up the label.
+            val torServicesLabel = getString(R.string.tor_services)
+
+            // Create a spannable string builder.
+            val torServicesStringBuilder = SpannableStringBuilder(torServicesLabel + torServices)
+
+            // Set the span to display the TorServices version.
+            torServicesStringBuilder.setSpan(blueColorSpan, torServicesLabel.length, torServicesStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
+
+            // Display the string in the text view.
+            torServicesTextView.text = torServicesStringBuilder
+        } else {  // TorServices is not installed.
+            // Hide the TorServices text view.
+            torServicesTextView.visibility = View.GONE
+        }
+
         // Only populate the I2P text view if it is installed.
         if (i2p.isNotEmpty()) {
             // Set up the label.
@@ -774,6 +803,10 @@ class AboutVersionFragment : Fragment() {
             aboutVersionStringBuilder.append(orbotTextView.text)
             aboutVersionStringBuilder.append("\n")
         }
+        if (torServicesTextView.isVisible) {
+            aboutVersionStringBuilder.append(torServicesTextView.text)
+            aboutVersionStringBuilder.append("\n")
+        }
         if (i2pTextView.isVisible) {
             aboutVersionStringBuilder.append(i2pTextView.text)
             aboutVersionStringBuilder.append("\n")
index 3bde58b26a49218e3cae3244296fdfe1ba9eb953..6504831ba625c4edda0b3bc4447f024b1120bd92 100644 (file)
@@ -2,7 +2,7 @@
 
 <!--
   SPDX-License-Identifier: GPL-3.0-or-later
-  SPDX-FileCopyrightText: 2016-2018, 2020, 2022-2023, 2025 Soren Stoutner <soren@stoutner.com>
+  SPDX-FileCopyrightText: 2016-2018, 2020, 2022-2023, 2025-2026 Soren Stoutner <soren@stoutner.com>
 
   This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
 
                 android:layout_width="wrap_content"
                 android:textIsSelectable="true" />
 
+            <TextView
+                android:id="@+id/tor_services"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:textIsSelectable="true" />
+
             <TextView
                 android:id="@+id/i2p"
                 android:layout_height="wrap_content"
index 9bcc3c5aed2a668e359535d1e18d4a9b0f3d753a..d8c190b551427140cdbbf2cccdaee70165cfc543 100644 (file)
     <string name="gui">Benutzer-Oberfläche</string>
 
     <!-- Proxy. -->
-    <string name="orbot_not_installed_title">Orbot ist nicht installiert</string>
-    <string name="orbot_not_installed_message">Der Orbot-Proxy kann erst nach Installation der Orbot-App genutzt werden.</string>
     <string name="i2p_not_installed_title">I2P ist nicht installiert</string>
     <string name="i2p_not_installed_message">Der I2P-Proxy kann erst nach Installation der I2P-App genutzt werden.</string>
     <string name="custom_proxy_invalid">Die benutzerdefinierte Proxy-URL ist ungültig.</string>
             <string name="webview_provider">WebView-Anbieter: \u0020</string>
             <string name="webview_version">WebView-Version: \u0020</string>
             <string name="orbot">Orbot: \u0020</string>
+            <string name="tor_services">TorServices: \u0020</string>
             <string name="i2p">I2P: \u0020</string>
                 <string name="fdroid_flavor">%1$s (F-Droid-Version)</string>
                 <string name="google_play_flavor">%1$s (Google-Play-Version)</string>
index 9067174dbeb4b00ea505948b3449dc07d19743a3..7967a23c3d462b8a8cc26a18aba3312a3369f086 100644 (file)
     <string name="gui">Interfaz</string>
 
     <!-- Proxy. -->
-    <string name="orbot_not_installed_title">Orbot No Instalado</string>
-    <string name="orbot_not_installed_message">El proxy a través de Orbot no funcionará a menos que la aplicación Orbot esté instalada.</string>
     <string name="i2p_not_installed_title">I2P No Instalado</string>
     <string name="i2p_not_installed_message">El proxy a través de I2P no funcionará a menos que la aplicación I2P esté instalada.</string>
     <string name="custom_proxy_invalid">La URL del proxy personalizado no es válida.</string>
             <string name="webview_provider">Proveedor de WebView: \u0020</string>
             <string name="webview_version">Versión de WebView: \u0020</string>
             <string name="orbot">Orbot: \u0020</string>
+            <string name="tor_services">TorServices: \u0020</string>
             <string name="i2p">I2P: \u0020</string>
                 <string name="fdroid_flavor">%1$s (variante de F-Droid)</string>
                 <string name="google_play_flavor">%1$s (variante de Google Play)</string>
index 37fc2a7ff644593e2470ea8231f6cbd5d9426bb6..1c54d7503c450b4361fd305073e435e21f0118c3 100644 (file)
     <string name="gui">Interface</string>
 
     <!-- Proxy. -->
-    <string name="orbot_not_installed_title">Orbot non installé</string>
-    <string name="orbot_not_installed_message">Le proxy via Orbot ne fonctionnera que si l\'application Orbot est installée.</string>
     <string name="i2p_not_installed_title">I2P non installé</string>
     <string name="i2p_not_installed_message">Le proxy via I2P ne fonctionnera que si l\'application I2P est installée.</string>
     <string name="custom_proxy_invalid">L\'URL du proxy personnalisé n\'est pas valide.</string>
             <string name="webview_provider">Fournisseur WebView :\u0020</string>
             <string name="webview_version">Version WebView :\u0020</string>
             <string name="orbot">Orbot :\u0020</string>
+            <string name="tor_services">TorServices :\u0020</string>
             <string name="i2p">I2P :\u0020</string>
                 <string name="fdroid_flavor">%1$s (Version F-Droid)</string>
                 <string name="google_play_flavor">%1$s (Version Google Play)</string>
index 279f2a79f561056680c4292aa440bb0796afbbef..09e33bcf1c1bd25a90d152215b569c2e47cb4581 100644 (file)
     <string name="gui">Interfaccia</string>
 
     <!-- Proxy. -->
-    <string name="orbot_not_installed_title">Orbot Non Installato</string>
-    <string name="orbot_not_installed_message">Il Proxy con Orbot non funziona se non è installata la app Orbot.</string>
     <string name="i2p_not_installed_title">I2P Non Installato</string>
     <string name="i2p_not_installed_message">Il Proxy con I2P non funziona se non è installata la app I2P.</string>
     <string name="custom_proxy_invalid">La URL del proxy personalizzato non è valida.</string>
             <string name="webview_provider">Provider di WebView: \u0020</string>
             <string name="webview_version">Versione di WebView: \u0020</string>
             <string name="orbot">Orbot: \u0020</string>
+            <string name="tor_services">TorServices: \u0020</string>
             <string name="i2p">I2P: \u0020</string>
                 <string name="fdroid_flavor">%1$s (Versione F-Droid)</string>
                 <string name="google_play_flavor">%1$s (Versione Google Play)</string>
index d69e9cf509e469a1810abe4c69925f3db3d97eb7..b5f864f5c54c2ded1c63ddab89fc89f0f5afbf34 100644 (file)
     <string name="gui">Interface</string>
 
     <!-- Proxy. -->
-    <string name="orbot_not_installed_title">Orbot Não  Instalado</string>
-    <string name="orbot_not_installed_message">O proxy através do Orbot não funcionará a menos que o aplicativo Orbot esteja instalado.</string>
-    <string name="i2p_not_installed_title">I2P Não  Instalado</string>
+    <string name="i2p_not_installed_title">I2P Não Instalado</string>
     <string name="i2p_not_installed_message">O proxy através do I2P não funcionará a menos que o aplicativo I2P esteja instalado.</string>
     <string name="custom_proxy_invalid">O URL do proxy personalizado é inválido.</string>
 
             <string name="webview_provider">Fornecedor WebView: \u0020</string>
             <string name="webview_version">Versão do WebView: \u0020</string>
             <string name="orbot">Orbot: \u0020</string>
+            <string name="tor_services">TorServices: \u0020</string>
             <string name="i2p">I2P: \u0020</string>
                 <string name="fdroid_flavor">%1$s (Derivação do F-Droid)</string>
                 <string name="google_play_flavor">%1$s (Derivação do Google Play)</string>
index 384bf562eacb55e12958acc5e08a0d0f3ede4620..4baf0c5c90883113e74aa2f8cb7839430dcc50f7 100644 (file)
     <string name="gui">Интерфейс</string>
 
     <!-- Proxy. -->
-    <string name="orbot_not_installed_title">Orbot не установлен</string>
-    <string name="orbot_not_installed_message">Прокси через Orbot работать не будет, если приложение Orbot не установлено.</string>
     <string name="i2p_not_installed_title">I2P не установлен</string>
     <string name="i2p_not_installed_message">Прокси через I2P работать не будет, если приложение I2P не установлено.</string>
     <string name="custom_proxy_invalid">URL пользовательского прокси недействителен.</string>
             <string name="webview_provider">Провайдер WebView: \u0020</string>
             <string name="webview_version">Версия WebView: \u0020</string>
             <string name="orbot">Orbot: \u0020</string>
+            <string name="tor_services">TorServices: \u0020</string>
             <string name="i2p">I2P: \u0020</string>
                 <string name="fdroid_flavor">%1$s (F-Droid-версия)</string>
                 <string name="google_play_flavor">%1$s (Google Play-версия)</string>
index d07e2962ff7588052e469f9f5df7a196a0f63a36..ed25d925003a51f8d6ab59111f6210f84cccbe4f 100644 (file)
             <string name="build">Derleme: \u0020</string>
             <string name="webview_provider">WebView Sağlayıcısı: \u0020</string>
             <string name="webview_version">WebView Versiyonu: \u0020</string>
-            <string name="orbot">Orbot:</string>
+            <string name="orbot">Orbot: \u0020</string>
+            <string name="tor_services">TorServices: \u0020</string>
             <string name="openkeychain">OpenKeychain: \u0020</string>
             <string name="ultraprivacy_label">UltraPrivacy: \u0020</string>
             <string name="ultralist_label">UltraList: \u0020</string>
index d7eed555a68cd1df4cc8b1c9e985b11d188a8ee3..85fa4a59364866563e890f8df0a5d668ece23097 100644 (file)
     <string name="gui">界面</string>
 
     <!-- Proxy. -->
-    <string name="orbot_not_installed_title">Orbot 未下载</string>
-    <string name="orbot_not_installed_message">Orbot应用被安装Orbot才会工作.</string>
     <string name="i2p_not_installed_title">I2P 未下载</string>
     <string name="i2p_not_installed_message">I2P应用被安装I2P才会工作.</string>
     <string name="custom_proxy_invalid">自定义代理无效.</string>
             <string name="webview_provider">WebView Provider: \u0020</string>
             <string name="webview_version">WebView Version: \u0020</string>
             <string name="orbot">Orbot: \u0020</string>
+            <string name="tor_services">TorServices: \u0020</string>
             <string name="i2p">I2P: \u0020</string>
                 <string name="fdroid_flavor">%1$s (F-Droid flavor)</string>
                 <string name="google_play_flavor">%1$s (Google Play flavor)</string>
index 0b76134f0f8a2781c389280850a46f395b87209b..3b07303c6d2d9ea32e57c8930d5cf88a20bd8819 100644 (file)
 
     <!-- Proxy. -->
     <string name="proxy_not_installed_dialog" translatable="false">Proxy not installed dialog</string>  <!-- This string is used to tag the proxy not installed dialog.  It is never displayed to the user. -->
-    <string name="orbot_not_installed_title">Orbot Not Installed</string>
-    <string name="orbot_not_installed_message">Proxying through Orbot will not work unless the Orbot app is installed.</string>
+    <string name="orbot_or_tor_services_not_installed_title">Orbot or TorServices Not Installed</string>
+    <string name="orbot_or_tor_services_not_installed_message">Proxying through Tor will not work unless either the Orbot or TorServices app is installed.</string>
     <string name="i2p_not_installed_title">I2P Not Installed</string>
     <string name="i2p_not_installed_message">Proxying through I2P will not work unless the I2P app is installed.</string>
     <string name="custom_proxy_invalid">The custom proxy URL is invalid.</string>
             <string name="webview_provider">WebView Provider: \u0020</string>
             <string name="webview_version">WebView Version: \u0020</string>
             <string name="orbot">Orbot: \u0020</string>
+            <string name="tor_services">TorServices: \u0020</string>
             <string name="i2p">I2P: \u0020</string>
                 <string name="fdroid_flavor">%1$s (F-Droid flavor)</string>
                 <string name="google_play_flavor">%1$s (Google Play flavor)</string>