Dan Ballard pushed to branch tor-browser-140.1.0esr-15.0-1 at The Tor Project / Applications / Tor Browser

Commits:

13 changed files:

Changes:

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
    ... ... @@ -101,7 +101,6 @@ import org.mozilla.fenix.browser.browsingmode.BrowsingMode
    101 101
     import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
    
    102 102
     import org.mozilla.fenix.browser.browsingmode.DefaultBrowsingModeManager
    
    103 103
     import org.mozilla.fenix.components.appstate.AppAction
    
    104
    -import org.mozilla.fenix.components.appstate.AppAction.ShareAction
    
    105 104
     import org.mozilla.fenix.components.appstate.OrientationMode
    
    106 105
     import org.mozilla.fenix.components.metrics.BreadcrumbsRecorder
    
    107 106
     import org.mozilla.fenix.components.metrics.GrowthDataWorker
    
    ... ... @@ -137,7 +136,6 @@ import org.mozilla.fenix.home.intent.OpenBrowserIntentProcessor
    137 136
     import org.mozilla.fenix.home.intent.OpenPasswordManagerIntentProcessor
    
    138 137
     import org.mozilla.fenix.home.intent.OpenRecentlyClosedIntentProcessor
    
    139 138
     import org.mozilla.fenix.home.intent.OpenSpecificTabIntentProcessor
    
    140
    -import org.mozilla.fenix.home.intent.ReEngagementIntentProcessor
    
    141 139
     import org.mozilla.fenix.home.intent.SpeechProcessingIntentProcessor
    
    142 140
     import org.mozilla.fenix.home.intent.StartSearchIntentProcessor
    
    143 141
     import org.mozilla.fenix.library.bookmarks.DesktopFolders
    
    ... ... @@ -167,19 +165,18 @@ import org.mozilla.fenix.theme.DefaultThemeManager
    167 165
     import org.mozilla.fenix.theme.StatusBarColorManager
    
    168 166
     import org.mozilla.fenix.theme.ThemeManager
    
    169 167
     import org.mozilla.fenix.tor.TorConnectionAssistFragmentDirections
    
    170
    -import org.mozilla.fenix.tor.TorEvents
    
    171 168
     import org.mozilla.fenix.utils.Settings
    
    172 169
     import org.mozilla.fenix.utils.changeAppLauncherIcon
    
    173 170
     import java.lang.ref.WeakReference
    
    174 171
     import java.util.Locale
    
    175 172
     
    
    176
    -import androidx.compose.material.SnackbarDuration
    
    177 173
     import mozilla.components.browser.engine.gecko.GeckoEngine
    
    178 174
     import org.mozilla.fenix.compose.core.Action
    
    179 175
     import org.mozilla.fenix.compose.snackbar.SnackbarState
    
    180 176
     import org.mozilla.fenix.compose.snackbar.Snackbar
    
    181 177
     import org.mozilla.fenix.tor.UrlQuickLoadViewModel
    
    182 178
     import org.mozilla.geckoview.TorAndroidIntegration
    
    179
    +import org.mozilla.geckoview.TorAndroidIntegration.BootstrapStateChangeListener
    
    183 180
     import org.mozilla.geckoview.TorConnectStage
    
    184 181
     import kotlin.system.exitProcess
    
    185 182
     
    
    ... ... @@ -915,19 +912,25 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorAn
    915 912
          */
    
    916 913
         @SuppressLint("MissingSuperCall") // super.onNewIntent is called in [onNewIntentInternal(intent)]
    
    917 914
         final override fun onNewIntent(intent: Intent) {
    
    918
    -        if (intent.action == ACTION_MAIN || components.torController.isConnected) {
    
    915
    +        if (intent.action == ACTION_MAIN || components.torController.isBootstrapped) {
    
    919 916
                 onNewIntentInternal(intent)
    
    920 917
             } else {
    
    921 918
                 // Wait until Tor is connected to handle intents from external apps for links, search, etc.
    
    922
    -            components.torController.registerTorListener(object : TorEvents {
    
    923
    -                override fun onTorConnected() {
    
    924
    -                    components.torController.unregisterTorListener(this)
    
    925
    -                    onNewIntentInternal(intent)
    
    919
    +            val torIntegration = (components.core.engine as GeckoEngine).getTorIntegrationController()
    
    920
    +            torIntegration.registerBootstrapStateChangeListener(
    
    921
    +                object : BootstrapStateChangeListener {
    
    922
    +
    
    923
    +                    override fun onBootstrapStageChange(stage: TorConnectStage) {
    
    924
    +                        if (stage.isBootstrapped) {
    
    925
    +                            torIntegration.unregisterBootstrapStateChangeListener(this)
    
    926
    +                            onNewIntentInternal(intent)
    
    927
    +                        }
    
    928
    +                    }
    
    929
    +
    
    930
    +                    override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) {}
    
    926 931
                     }
    
    927
    -                override fun onTorConnecting() { /* no-op */ }
    
    928
    -                override fun onTorStopped() { /* no-op */ }
    
    929
    -                override fun onTorStatusUpdate(entry: String?, status: String?, progress: Double?) { /* no-op */ }
    
    930
    -            })
    
    932
    +            )
    
    933
    +
    
    931 934
                 return
    
    932 935
             }
    
    933 936
         }
    
    ... ... @@ -1516,7 +1519,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorAn
    1516 1519
                 // we want to ignore other cases when the app gets open by users clicking on links,
    
    1517 1520
                 // unless Tor is not yet connected.
    
    1518 1521
                 getSettings().shouldStartOnHome() && (intent?.action == ACTION_MAIN ||
    
    1519
    -                    !components.torController.isConnected)
    
    1522
    +                    !components.torController.isBootstrapped)
    
    1520 1523
             }
    
    1521 1524
         }
    
    1522 1525
     
    
    ... ... @@ -1606,14 +1609,13 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorAn
    1606 1609
             exitProcess(0)
    
    1607 1610
         }
    
    1608 1611
     
    
    1609
    -    override fun onBootstrapStateChange(state: String) = Unit
    
    1610
    -    override fun onBootstrapStageChange(stage: TorConnectStage) = Unit
    
    1611
    -    override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) = Unit
    
    1612
    -    override fun onBootstrapComplete() {
    
    1613
    -        if (settings().useHtmlConnectionUi) {
    
    1614
    -            components.useCases.tabsUseCases.removeAllTabs()
    
    1615
    -            navHost.navController.navigate(NavGraphDirections.actionStartupHome())
    
    1612
    +    override fun onBootstrapStageChange(stage: TorConnectStage)  {
    
    1613
    +        if (stage.isBootstrapped) {
    
    1614
    +            if (settings().useHtmlConnectionUi) {
    
    1615
    +                components.useCases.tabsUseCases.removeAllTabs()
    
    1616
    +                navHost.navController.navigate(NavGraphDirections.actionStartupHome())
    
    1617
    +            }
    
    1616 1618
             }
    
    1617 1619
         }
    
    1618
    -    override fun onBootstrapError(code: String?, message: String?, phase: String?, reason: String?) = Unit
    
    1620
    +    override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) = Unit
    
    1619 1621
     }

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/IntentReceiverActivity.kt
    ... ... @@ -13,6 +13,7 @@ import android.os.Build
    13 13
     import android.os.Bundle
    
    14 14
     import android.os.StrictMode
    
    15 15
     import androidx.annotation.VisibleForTesting
    
    16
    +import mozilla.components.browser.engine.gecko.GeckoEngine
    
    16 17
     import mozilla.components.feature.intent.ext.sanitize
    
    17 18
     import mozilla.components.feature.intent.processing.IntentProcessor
    
    18 19
     import mozilla.components.support.base.log.logger.Logger
    
    ... ... @@ -31,7 +32,8 @@ import org.mozilla.fenix.ext.settings
    31 32
     import org.mozilla.fenix.perf.MarkersActivityLifecycleCallbacks
    
    32 33
     import org.mozilla.fenix.perf.StartupTimeline
    
    33 34
     import org.mozilla.fenix.shortcut.NewTabShortcutIntentProcessor
    
    34
    -import org.mozilla.fenix.tor.TorEvents
    
    35
    +import org.mozilla.geckoview.TorAndroidIntegration.BootstrapStateChangeListener
    
    36
    +import org.mozilla.geckoview.TorConnectStage
    
    35 37
     
    
    36 38
     /**
    
    37 39
      * Processes incoming intents and sends them to the corresponding activity.
    
    ... ... @@ -55,19 +57,24 @@ class IntentReceiverActivity : Activity() {
    55 57
             // the HomeActivity.
    
    56 58
             val intent = intent?.let { Intent(it) } ?: Intent()
    
    57 59
             intent.sanitize().stripUnwantedFlags()
    
    58
    -        if (intent.action == ACTION_MAIN || components.torController.isConnected) {
    
    60
    +        if (intent.action == ACTION_MAIN || components.torController.isBootstrapped) {
    
    59 61
                 processIntent(intent)
    
    60 62
             } else {
    
    61 63
                 // Wait until Tor is connected to handle intents from external apps for links, search, etc.
    
    62
    -            components.torController.registerTorListener(object : TorEvents {
    
    63
    -                override fun onTorConnected() {
    
    64
    -                    components.torController.unregisterTorListener(this)
    
    65
    -                    processIntent(intent)
    
    66
    -                }
    
    67
    -                override fun onTorConnecting() { /* no-op */ }
    
    68
    -                override fun onTorStopped() { /* no-op */ }
    
    69
    -                override fun onTorStatusUpdate(entry: String?, status: String?, progress: Double?) { /* no-op */ }
    
    70
    -            })
    
    64
    +            val engine = components.core.engine as GeckoEngine
    
    65
    +            engine.getTorIntegrationController().registerBootstrapStateChangeListener(
    
    66
    +                object : BootstrapStateChangeListener {
    
    67
    +
    
    68
    +                    override fun onBootstrapStageChange(stage: TorConnectStage) {
    
    69
    +                        if (stage.isBootstrapped) {
    
    70
    +                            engine.getTorIntegrationController().unregisterBootstrapStateChangeListener(this)
    
    71
    +                            processIntent(intent)
    
    72
    +                        }
    
    73
    +                    }
    
    74
    +
    
    75
    +                    override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) {}
    
    76
    +                })
    
    77
    +
    
    71 78
     
    
    72 79
                 // In the meantime, open the HomeActivity so the user can get connected.
    
    73 80
                 processIntent(Intent())
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/TorBrowserFeatures.kt
    ... ... @@ -20,7 +20,7 @@ import mozilla.components.support.webextensions.WebExtensionSupport
    20 20
     import mozilla.components.support.base.log.logger.Logger
    
    21 21
     import org.mozilla.fenix.ext.components
    
    22 22
     import org.mozilla.fenix.ext.settings
    
    23
    -import org.mozilla.fenix.tor.TorEvents
    
    23
    +import org.mozilla.fenix.tor.RunOnceBootstrapped
    
    24 24
     
    
    25 25
     object TorBrowserFeatures {
    
    26 26
         private val logger = Logger("torbrowser-features")
    
    ... ... @@ -142,9 +142,8 @@ object TorBrowserFeatures {
    142 142
              *  causing automatic update checks failures (components.addonUpdater being a lazy prop).
    
    143 143
              *  The extension, from then on, should behave as if the user had installed it manually.
    
    144 144
              */
    
    145
    -        context.components.torController.registerTorListener(object : TorEvents {
    
    146
    -            override fun onTorConnected() {
    
    147
    -                context.components.torController.unregisterTorListener(this)
    
    145
    +        context.components.torController.registerRunOnceBootstrapped(object : RunOnceBootstrapped {
    
    146
    +            override fun onBootstrapped() {
    
    148 147
                     // Enable automatic updates. This must be done on every startup (tor-browser#42353)
    
    149 148
                     context.components.addonUpdater.registerForFutureUpdates(NOSCRIPT_ID)
    
    150 149
                     // Force a one-time immediate update check for older installations
    
    ... ... @@ -153,18 +152,6 @@ object TorBrowserFeatures {
    153 152
                         settings.noscriptUpdated = 2
    
    154 153
                     }
    
    155 154
                 }
    
    156
    -
    
    157
    -            @SuppressWarnings("EmptyFunctionBlock")
    
    158
    -            override fun onTorConnecting() {
    
    159
    -            }
    
    160
    -
    
    161
    -            @SuppressWarnings("EmptyFunctionBlock")
    
    162
    -            override fun onTorStopped() {
    
    163
    -            }
    
    164
    -
    
    165
    -            @SuppressWarnings("EmptyFunctionBlock")
    
    166
    -            override fun onTorStatusUpdate(entry: String?, status: String?, progress: Double?) {
    
    167
    -            }
    
    168 155
             })
    
    169 156
         }
    
    170 157
     
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/TorBridgeConfigFragment.kt
    ... ... @@ -56,7 +56,6 @@ class TorBridgeConfigFragment : PreferenceFragmentCompat() {
    56 56
                 setOnPreferenceChangeListener<Boolean> { preference, enabled ->
    
    57 57
                     preference.context.components.torController.bridgesEnabled = enabled
    
    58 58
                     updateCurrentConfiguredBridgePref(preference)
    
    59
    -                preference.context.components.torController.restartTor()
    
    60 59
                     true
    
    61 60
                 }
    
    62 61
             }
    
    ... ... @@ -71,7 +70,6 @@ class TorBridgeConfigFragment : PreferenceFragmentCompat() {
    71 70
                     preference.context.components.torController.bridgeTransport = TorBridgeTransportConfig.USER_PROVIDED
    
    72 71
                     preference.context.components.torController.userProvidedBridges = userProvidedBridge
    
    73 72
                     updateCurrentConfiguredBridgePref(preference)
    
    74
    -                preference.context.components.torController.restartTor()
    
    75 73
                     true
    
    76 74
                 }
    
    77 75
                 val userProvidedBridge: String? = context.components.torController.userProvidedBridges
    
    ... ... @@ -103,7 +101,6 @@ class TorBridgeConfigFragment : PreferenceFragmentCompat() {
    103 101
                         preference.context.components.torController.bridgeTransport = bridge
    
    104 102
                         previousTransportConfig = bridge
    
    105 103
                         updateCurrentConfiguredBridgePref(preference)
    
    106
    -                    preference.context.components.torController.restartTor()
    
    107 104
                     }
    
    108 105
                     true
    
    109 106
                 }
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorBootstrapProgressViewModel.kt
    ... ... @@ -27,20 +27,9 @@ class TorBootstrapProgressViewModel(
    27 27
             super.onCleared()
    
    28 28
         }
    
    29 29
     
    
    30
    -    override fun onBootstrapStateChange(state: String?) {}
    
    31 30
         override fun onBootstrapStageChange(stage: TorConnectStage) = Unit
    
    32 31
     
    
    33 32
         override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) {
    
    34 33
             this.progress.value = progress.toInt()
    
    35 34
         }
    
    36
    -
    
    37
    -    override fun onBootstrapComplete() {}
    
    38
    -
    
    39
    -    override fun onBootstrapError(
    
    40
    -        code: String?,
    
    41
    -        message: String?,
    
    42
    -        phase: String?,
    
    43
    -        reason: String?,
    
    44
    -    ) {
    
    45
    -    }
    
    46 35
     }

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistViewModel.kt
    ... ... @@ -154,23 +154,12 @@ class TorConnectionAssistViewModel(
    154 154
             }
    
    155 155
         }
    
    156 156
     
    
    157
    -    override fun onBootstrapStateChange(state: String?) {}
    
    158
    -
    
    159
    -    override fun onBootstrapStageChange(stage: TorConnectStage?) {
    
    157
    +    override fun onBootstrapStageChange(stage: TorConnectStage) {
    
    160 158
             torConnectStage.value = stage
    
    161 159
         }
    
    162 160
     
    
    163 161
         override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) {}
    
    164 162
     
    
    165
    -    override fun onBootstrapComplete() {}
    
    166
    -
    
    167
    -    override fun onBootstrapError(
    
    168
    -        code: String?,
    
    169
    -        message: String?,
    
    170
    -        phase: String?,
    
    171
    -        reason: String?,
    
    172
    -    ) {}
    
    173
    -
    
    174 163
         fun button1ShouldBeDisabled(screen: ConnectAssistUiState): Boolean {
    
    175 164
             return selectedCountryCode.value == "automatic" && screen.regionDropDownDefaultItem == R.string.connection_assist_select_country_or_region
    
    176 165
         }
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorController.kt
    ... ... @@ -6,37 +6,14 @@ package org.mozilla.fenix.tor
    6 6
     
    
    7 7
     import androidx.lifecycle.LifecycleCoroutineScope
    
    8 8
     
    
    9
    -interface TorEvents {
    
    10
    -    fun onTorConnecting()
    
    11
    -    fun onTorConnected()
    
    12
    -    fun onTorStatusUpdate(entry: String?, status: String?, progress: Double? = 0.0)
    
    13
    -    fun onTorStopped()
    
    9
    +// Callback for function to be run one time when the system is bootstrapped and then disregarded
    
    10
    +interface RunOnceBootstrapped {
    
    11
    +    fun onBootstrapped()
    
    14 12
     }
    
    15
    -class TorError(
    
    16
    -    var message: String,
    
    17
    -    var details: String,
    
    18
    -    var phase: String,
    
    19
    -    var reason: String,
    
    20
    -) { }
    
    21 13
     
    
    22
    -interface TorLogs {
    
    23
    -    fun onLog(type: String?, message: String?, timestamp: String?)
    
    24
    -}
    
    25
    -
    
    26
    -internal enum class TorStatus(val status: String) {
    
    27
    -    OFF("OFF"),
    
    28
    -    STARTING("STARTING"),
    
    29
    -    ON("ON"),
    
    30
    -    STOPPING("STOPPING"),
    
    31
    -    UNKNOWN("UNKNOWN");
    
    32
    -}
    
    33
    -
    
    34
    -interface TorController: TorEvents {
    
    14
    +interface TorController {
    
    35 15
         val logEntries: MutableList<TorLog>
    
    36
    -    val isStarting: Boolean
    
    37
    -    val isRestarting: Boolean
    
    38 16
         val isBootstrapped: Boolean
    
    39
    -    val isConnected: Boolean
    
    40 17
         var bridgesEnabled: Boolean
    
    41 18
         var bridgeTransport: TorBridgeTransportConfig
    
    42 19
         var userProvidedBridges: String?
    
    ... ... @@ -44,21 +21,21 @@ interface TorController: TorEvents {
    44 21
         fun start()
    
    45 22
         fun stop()
    
    46 23
     
    
    47
    -    override fun onTorConnecting()
    
    48
    -    override fun onTorConnected()
    
    49
    -    override fun onTorStatusUpdate(entry: String?, status: String?, progress: Double?)
    
    50
    -    override fun onTorStopped()
    
    51
    -
    
    52
    -    fun getLastErrorState() : TorError?
    
    53
    -
    
    54
    -    fun registerTorListener(l: TorEvents)
    
    55
    -    fun unregisterTorListener(l: TorEvents)
    
    56
    -
    
    57
    -    fun registerTorLogListener(l: TorLogs)
    
    58
    -    fun unregisterTorLogListener(l: TorLogs)
    
    24
    +    // TorBrowserFeatures.install wants to register a callback for when tor bootstraps the first time
    
    25
    +    // so it can then check for noscript updates.
    
    26
    +    // Currently it needs to register it before TorAndroidIntegration is fully loaded, so this way
    
    27
    +    // they can register with TorController which will start streaming events from TAS when available
    
    28
    +    // and call them one time when the system is bootstrapped
    
    29
    +    // TODO: rewire the noscript update call in TorBrowserFeatures.install
    
    30
    +    //   a) call TorBrowserFeatures.install from somewhere else (ex: move from Core.GeckoEngine.also
    
    31
    +    //      to maybe FenixApplication.setupInMainProcessOnly
    
    32
    +    //      dan: had trouble with this first time:
    
    33
    +    //      https://gitlab.torproject.org/tpo/applications/tor-browser/-/merge_requests/1423#note_3191590
    
    34
    +    //   b) just move the call to `context.components.addonUpdater.update(NOSCRIPT_ID)` somewhere else
    
    35
    +    //      that can use TorAndroidIntegration.BootstrapListener
    
    36
    +    fun registerRunOnceBootstrapped(rob: RunOnceBootstrapped)
    
    37
    +    fun unregisterRunOnceBootstrapped(rob: RunOnceBootstrapped)
    
    59 38
     
    
    60 39
         fun initiateTorBootstrap(lifecycleScope: LifecycleCoroutineScope? = null, withDebugLogging: Boolean = false)
    
    61 40
         fun stopTor()
    
    62
    -    fun setTorStopped()
    
    63
    -    fun restartTor()
    
    64 41
     }

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerGV.kt
    ... ... @@ -4,75 +4,30 @@ package org.mozilla.fenix.tor
    4 4
     import android.content.Context
    
    5 5
     import android.util.Log
    
    6 6
     import androidx.lifecycle.LifecycleCoroutineScope
    
    7
    -import kotlinx.coroutines.flow.MutableStateFlow
    
    8
    -import kotlinx.coroutines.flow.StateFlow
    
    9 7
     import mozilla.components.browser.engine.gecko.GeckoEngine
    
    10 8
     import org.mozilla.fenix.ext.components
    
    11 9
     import org.mozilla.geckoview.TorAndroidIntegration
    
    12 10
     import org.mozilla.geckoview.TorAndroidIntegration.BootstrapStateChangeListener
    
    13 11
     import org.mozilla.geckoview.TorAndroidIntegration.TorLogListener
    
    14 12
     import org.mozilla.geckoview.TorConnectStage
    
    13
    +import org.mozilla.geckoview.TorConnectStageName
    
    15 14
     import org.mozilla.geckoview.TorSettings
    
    16 15
     import org.mozilla.geckoview.TorSettings.BridgeBuiltinType
    
    17 16
     import org.mozilla.geckoview.TorSettings.BridgeSource
    
    18 17
     
    
    19
    -// Enum matching TorConnectState from TorConnect.sys.mjs that we get from onBootstrapStateChange
    
    20
    -internal enum class TorConnectState(val state: String) {
    
    21
    -    Initial("Initial"),
    
    22
    -    Configuring("Configuring"),
    
    23
    -    AutoBootstrapping("AutoBootstrapping"),
    
    24
    -    Bootstrapping("Bootstrapping"),
    
    25
    -    Error("Error"),
    
    26
    -    Bootstrapped("Bootstrapped"),
    
    27
    -    Disabled("Disabled");
    
    28
    -
    
    29
    -    fun isStarting() = this == Bootstrapping || this == AutoBootstrapping
    
    30
    -    fun isError() = this == Error
    
    31
    -
    
    32
    -    fun isStarted() = this == Bootstrapped
    
    33
    -
    
    34
    -    fun isOff() = this == Initial || this == Configuring || this == Disabled || this == Error
    
    35
    -
    
    36
    -
    
    37
    -    // Convert to TorStatus that firefox-android uses based on tor-android-service
    
    38
    -    fun toTorStatus(): TorStatus {
    
    39
    -        return when (this) {
    
    40
    -            Initial -> TorStatus.OFF
    
    41
    -            Configuring -> TorStatus.OFF
    
    42
    -            AutoBootstrapping -> TorStatus.STARTING
    
    43
    -            Bootstrapping -> TorStatus.STARTING
    
    44
    -            Error -> TorStatus.UNKNOWN
    
    45
    -            Bootstrapped -> TorStatus.ON
    
    46
    -            Disabled -> TorStatus.OFF
    
    47
    -        }
    
    48
    -    }
    
    49
    -}
    
    50
    -
    
    51 18
     class TorControllerGV(
    
    52 19
         private val context: Context,
    
    53
    -) : TorController, TorEvents, BootstrapStateChangeListener, TorLogListener {
    
    20
    +) : TorController, BootstrapStateChangeListener, TorLogListener {
    
    54 21
     
    
    55 22
         private val TAG = "TorControllerGV"
    
    56 23
     
    
    57
    -    private var torListeners = mutableListOf<TorEvents>()
    
    58
    -    private var torLogListeners = mutableListOf<TorLogs>()
    
    59
    -
    
    60
    -    private val _lastKnownStatus = MutableStateFlow(TorConnectState.Initial)
    
    61
    -    internal val lastKnownStatus: StateFlow<TorConnectState> = _lastKnownStatus
    
    24
    +    private var runOnceBootstrappedHandlers = mutableListOf<RunOnceBootstrapped>()
    
    62 25
     
    
    63
    -    internal var lastKnownError: TorError? = null
    
    64
    -    private var wasTorBootstrapped = false
    
    65
    -    private var isTorRestarting = false
    
    66
    -
    
    67
    -    private var isTorBootstrapped = false
    
    68
    -        get() = ((_lastKnownStatus.value.isStarted()) && wasTorBootstrapped)
    
    26
    +    override val isBootstrapped get() =
    
    27
    +        getTorIntegration().lastKnowStage.value?.name?.isBootstrapped ?: false
    
    69 28
     
    
    70 29
         private val entries = mutableListOf<TorLog>()
    
    71 30
         override val logEntries get() = entries
    
    72
    -    override val isStarting get() = _lastKnownStatus.value.isStarting()
    
    73
    -    override val isRestarting get() = isTorRestarting
    
    74
    -    override val isBootstrapped get() = isTorBootstrapped
    
    75
    -    override val isConnected get() = (_lastKnownStatus.value.isStarted() && !isTorRestarting)
    
    76 31
     
    
    77 32
         private fun getTorIntegration(): TorAndroidIntegration {
    
    78 33
             return (context.components.core.engine as GeckoEngine).getTorIntegrationController()
    
    ... ... @@ -82,8 +37,7 @@ class TorControllerGV(
    82 37
             return getTorIntegration().getSettings()
    
    83 38
         }
    
    84 39
     
    
    85
    -
    
    86
    -    // On a fresh install bridgeEnagled can be set to true without a valid bridgeSource
    
    40
    +    // On a fresh install bridgeEnabled can be set to true without a valid bridgeSource
    
    87 41
         // having been selected. After first use this will not happen because last selected bridge
    
    88 42
         // will be remembered and reused.
    
    89 43
         // However, on first use, submitting this to TorSettings is an invalid state.
    
    ... ... @@ -105,7 +59,6 @@ class TorControllerGV(
    105 59
                 }
    
    106 60
             }
    
    107 61
     
    
    108
    -
    
    109 62
         override var bridgeTransport: TorBridgeTransportConfig
    
    110 63
             get() {
    
    111 64
                 return when (getTorSettings()?.bridgesSource) {
    
    ... ... @@ -144,7 +97,6 @@ class TorControllerGV(
    144 97
                 }
    
    145 98
             }
    
    146 99
     
    
    147
    -
    
    148 100
         // Currently the UI takes a user provided string and sets this in one step so there is where we
    
    149 101
         // actually set it.bridgesSource = BridgeSource.UserProvided, not above,
    
    150 102
         // as TorSettings.sys.mjs #cleanupSettings could reject BridgeSource.UserProvided
    
    ... ... @@ -179,73 +131,37 @@ class TorControllerGV(
    179 131
             getTorIntegration().unregisterLogListener(this)
    
    180 132
         }
    
    181 133
     
    
    182
    -    // TorEvents
    
    183
    -    override fun onTorConnecting() {
    
    184
    -        synchronized(torListeners) {
    
    185
    -            torListeners.toList().forEach { it.onTorConnecting() }
    
    186
    -        }
    
    187
    -    }
    
    188
    -
    
    189
    -    // TorEvents
    
    190
    -    override fun onTorConnected() {
    
    191
    -        synchronized(torListeners) {
    
    192
    -            torListeners.toList().forEach { it.onTorConnected() }
    
    193
    -        }
    
    194
    -    }
    
    195
    -
    
    196
    -    // TorEvents
    
    197
    -    override fun onTorStatusUpdate(entry: String?, status: String?, progress: Double?) {
    
    198
    -        synchronized(torListeners) {
    
    199
    -            torListeners.toList().forEach { it.onTorStatusUpdate(entry, status, progress) }
    
    200
    -        }
    
    201
    -    }
    
    202
    -
    
    203
    -    // TorEvents
    
    204
    -    override fun onTorStopped() {
    
    205
    -        synchronized(torListeners) {
    
    206
    -            torListeners.toList().forEach { it.onTorStopped() }
    
    207
    -        }
    
    208
    -    }
    
    209
    -
    
    210 134
         override fun onLog(type: String?, message: String?, timestamp: String?) {
    
    211
    -        synchronized(torLogListeners) {
    
    135
    +        synchronized(entries) {
    
    212 136
                 entries.add(TorLog(type ?: "null", message ?: "null", timestamp ?: "null"))
    
    213
    -            torLogListeners.toList().forEach { it.onLog(type ?: "null", message ?: "null", timestamp) }
    
    214
    -        }
    
    215
    -    }
    
    216
    -
    
    217
    -    override fun registerTorListener(l: TorEvents) {
    
    218
    -        synchronized(torListeners) {
    
    219
    -            if (torListeners.contains(l)) {
    
    220
    -                return
    
    221
    -            }
    
    222
    -            torListeners.add(l)
    
    223 137
             }
    
    224 138
         }
    
    225 139
     
    
    226
    -    override fun unregisterTorListener(l: TorEvents) {
    
    227
    -        synchronized(torListeners) {
    
    228
    -            if (!torListeners.contains(l)) {
    
    140
    +    override fun registerRunOnceBootstrapped(rob: RunOnceBootstrapped) {
    
    141
    +        // TODO Remove need for this with tb-44002
    
    142
    +        // it would be nice to have a short circuit run and don't add if already bootstrapped
    
    143
    +        // however this calls context.components.core.engine which tries to lazy load engine
    
    144
    +        // which causes a recursive loop. instead we should do the work in tb-44002
    
    145
    +        // this is currently fine as there is a single use case for this called in
    
    146
    +        // TorBrowserFeatures that is at startup
    
    147
    +        //if (isBootstrapped) {
    
    148
    +        //    rob.onBootstrapped()
    
    149
    +        //    return
    
    150
    +        //}
    
    151
    +        synchronized(runOnceBootstrappedHandlers) {
    
    152
    +            if (runOnceBootstrappedHandlers.contains(rob)) {
    
    229 153
                     return
    
    230 154
                 }
    
    231
    -            torListeners.remove(l)
    
    155
    +            runOnceBootstrappedHandlers.add(rob)
    
    232 156
             }
    
    233 157
         }
    
    234 158
     
    
    235
    -    override fun registerTorLogListener(l: TorLogs) {
    
    236
    -        synchronized(torLogListeners) {
    
    237
    -            if (torLogListeners.contains(l)) {
    
    238
    -                return
    
    239
    -            }
    
    240
    -            torLogListeners.add(l)
    
    241
    -        }
    
    242
    -    }
    
    243
    -    override fun unregisterTorLogListener(l: TorLogs) {
    
    244
    -        synchronized(torLogListeners) {
    
    245
    -            if (!torLogListeners.contains(l)) {
    
    159
    +    override fun unregisterRunOnceBootstrapped(rob: RunOnceBootstrapped) {
    
    160
    +        synchronized(runOnceBootstrappedHandlers) {
    
    161
    +            if (!runOnceBootstrappedHandlers.contains(rob)) {
    
    246 162
                     return
    
    247 163
                 }
    
    248
    -            torLogListeners.remove(l)
    
    164
    +            runOnceBootstrappedHandlers.remove(rob)
    
    249 165
             }
    
    250 166
         }
    
    251 167
     
    
    ... ... @@ -260,82 +176,22 @@ class TorControllerGV(
    260 176
             getTorIntegration().cancelBootstrap()
    
    261 177
         }
    
    262 178
     
    
    263
    -    override fun setTorStopped() {
    
    264
    -        _lastKnownStatus.value = TorConnectState.Configuring
    
    265
    -        onTorStatusUpdate(null, lastKnownStatus.toString(), 0.0)
    
    266
    -        onTorStopped()
    
    267
    -    }
    
    268
    -
    
    269
    -    override fun restartTor() {
    
    270
    -        if (!_lastKnownStatus.value.isStarted() && wasTorBootstrapped) {
    
    271
    -            // If we aren't started, but we were previously bootstrapped,
    
    272
    -            // then we handle a "restart" request as a "start" restart
    
    273
    -            initiateTorBootstrap()
    
    274
    -        } else {
    
    275
    -            // |isTorRestarting| tracks the state of restart. When we receive an |OFF| state
    
    276
    -            // from TorService in persistentBroadcastReceiver::onReceive we restart the Tor
    
    277
    -            // service.
    
    278
    -            isTorRestarting = true
    
    279
    -            stopTor()
    
    280
    -        }
    
    281
    -    }
    
    282
    -
    
    283
    -    override fun getLastErrorState() : TorError? {
    
    284
    -        return lastKnownError
    
    285
    -    }
    
    286
    -
    
    287
    -    // TorEventsBootstrapStateChangeListener -> (lastKnowStatus, TorEvents)
    
    288
    -    // Handle events from GeckoView TorAndroidIntegration and map to TorEvents based events
    
    289
    -    // and state for firefox-android (designed for tor-android-service)
    
    290
    -    //   fun onTorConnecting()
    
    291
    -    //   fun onTorConnected()
    
    292
    -    //   fun onTorStatusUpdate(entry: String?, status: String?, progress: Double?)
    
    293
    -    //   fun onTorStopped()
    
    294
    -
    
    295 179
         // TorEventsBootstrapStateChangeListener
    
    296
    -    override fun onBootstrapStateChange(newStateVal: String?) {
    
    297
    -        Log.d(TAG, "onBootstrapStateChange(newStateVal = $newStateVal)")
    
    298
    -        val newState: TorConnectState = TorConnectState.valueOf(newStateVal ?: "Error")
    
    299
    -
    
    300
    -        if (newState.isError() && wasTorBootstrapped) {
    
    301
    -            stopTor()
    
    302
    -        }
    
    303
    -
    
    304
    -        if (newState.isStarted()) {
    
    305
    -            wasTorBootstrapped = true
    
    306
    -            onTorConnected()
    
    307
    -        }
    
    308
    -
    
    309
    -        if (wasTorBootstrapped && newState == TorConnectState.Configuring) {
    
    310
    -            wasTorBootstrapped = false
    
    311
    -            if (isTorRestarting) {
    
    312
    -                initiateTorBootstrap()
    
    313
    -            } else {
    
    314
    -                setTorStopped()
    
    180
    +    override fun onBootstrapStageChange(stage: TorConnectStage) {
    
    181
    +        Log.d(TAG, "onBootstrapStageChange(stage = $stage)")
    
    182
    +
    
    183
    +        if (stage.name == TorConnectStageName.Bootstrapped) {
    
    184
    +            synchronized(runOnceBootstrappedHandlers) {
    
    185
    +                runOnceBootstrappedHandlers.toList().forEach {
    
    186
    +                    it.onBootstrapped()
    
    187
    +                    runOnceBootstrappedHandlers.remove(it)
    
    188
    +                }
    
    315 189
                 }
    
    316 190
             }
    
    317
    -
    
    318
    -        if (_lastKnownStatus.value.isOff() && newState.isStarting()) {
    
    319
    -            isTorRestarting = false
    
    320
    -        }
    
    321
    -
    
    322
    -        _lastKnownStatus.value = newState
    
    323
    -        onTorStatusUpdate(null, newStateVal, null)
    
    324 191
         }
    
    325 192
     
    
    326
    -    override fun onBootstrapStageChange(stage: TorConnectStage) = Unit
    
    327
    -
    
    328 193
         // TorEventsBootstrapStateChangeListener
    
    329 194
         override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) {
    
    330 195
             Log.d(TAG, "onBootstrapProgress(progress = $progress, hasWarnings = $hasWarnings)")
    
    331
    -        onTorStatusUpdate("", _lastKnownStatus.value.toTorStatus().status, progress)
    
    332
    -    }
    
    333
    -
    
    334
    -    // TorEventsBootstrapStateChangeListener
    
    335
    -    override fun onBootstrapComplete() = Unit
    
    336
    -
    
    337
    -    // TorEventsBootstrapStateChangeListener
    
    338
    -    override fun onBootstrapError(code: String?, message: String?, phase: String?, reason: String?) {
    
    339
    -        lastKnownError = TorError(code ?: "", message ?: "", phase ?: "", reason ?: "")
    
    340 196
         }
    
    341 197
     }

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsViewModel.kt
    ... ... @@ -13,11 +13,15 @@ import android.widget.Toast
    13 13
     import androidx.lifecycle.AndroidViewModel
    
    14 14
     import androidx.lifecycle.LiveData
    
    15 15
     import androidx.lifecycle.MutableLiveData
    
    16
    +import mozilla.components.browser.engine.gecko.GeckoEngine
    
    16 17
     import org.mozilla.fenix.R
    
    17 18
     import org.mozilla.fenix.ext.components
    
    19
    +import org.mozilla.geckoview.TorAndroidIntegration.TorLogListener
    
    18 20
     
    
    19
    -class TorLogsViewModel(application: Application) : AndroidViewModel(application), TorLogs {
    
    21
    +class TorLogsViewModel(application: Application) : AndroidViewModel(application), TorLogListener {
    
    20 22
         private val torController = application.components.torController
    
    23
    +    private val engine = application.components.core.engine as GeckoEngine
    
    24
    +    private val torAndroidIntegration = engine.getTorIntegrationController()
    
    21 25
         private val clipboardManager =
    
    22 26
             application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    
    23 27
     
    
    ... ... @@ -33,7 +37,7 @@ class TorLogsViewModel(application: Application) : AndroidViewModel(application)
    33 37
     
    
    34 38
         init {
    
    35 39
             setupClipboardListener()
    
    36
    -        torController.registerTorLogListener(this)
    
    40
    +        torAndroidIntegration.registerLogListener(this)
    
    37 41
             val currentEntries = torController.logEntries
    
    38 42
             for (log in currentEntries) {
    
    39 43
                 addLog(log)
    
    ... ... @@ -46,7 +50,7 @@ class TorLogsViewModel(application: Application) : AndroidViewModel(application)
    46 50
     
    
    47 51
         override fun onCleared() {
    
    48 52
             super.onCleared()
    
    49
    -        torController.unregisterTorLogListener(this)
    
    53
    +        torAndroidIntegration.unregisterLogListener(this)
    
    50 54
         }
    
    51 55
     
    
    52 56
         private fun setupClipboardListener() {
    

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorAndroidIntegration.java
    ... ... @@ -39,11 +39,8 @@ public class TorAndroidIntegration implements BundleEventListener {
    39 39
       private static final String EVENT_TOR_STOP = "GeckoView:Tor:StopTor";
    
    40 40
       private static final String EVENT_MEEK_START = "GeckoView:Tor:StartMeek";
    
    41 41
       private static final String EVENT_MEEK_STOP = "GeckoView:Tor:StopMeek";
    
    42
    -  private static final String EVENT_CONNECT_STATE_CHANGED = "GeckoView:Tor:ConnectStateChanged"; // deprecation path
    
    43
    -  private static final String EVENT_CONNECT_STAGE_CHANGED = "GeckoView:Tor:ConnectStageChanged"; // replacement path
    
    44
    -  private static final String EVENT_CONNECT_ERROR = "GeckoView:Tor:ConnectError";
    
    42
    +  private static final String EVENT_CONNECT_STAGE_CHANGED = "GeckoView:Tor:ConnectStageChanged";
    
    45 43
       private static final String EVENT_BOOTSTRAP_PROGRESS = "GeckoView:Tor:BootstrapProgress";
    
    46
    -  private static final String EVENT_BOOTSTRAP_COMPLETE = "GeckoView:Tor:BootstrapComplete";
    
    47 44
       private static final String EVENT_TOR_LOGS = "GeckoView:Tor:Logs";
    
    48 45
       private static final String EVENT_SETTINGS_READY = "GeckoView:Tor:SettingsReady";
    
    49 46
       private static final String EVENT_SETTINGS_CHANGED = "GeckoView:Tor:SettingsChanged";
    
    ... ... @@ -62,6 +59,7 @@ public class TorAndroidIntegration implements BundleEventListener {
    62 59
       private static final String EVENT_QUICKSTART_GET = "GeckoView:Tor:QuickstartGet";
    
    63 60
       private static final String EVENT_QUICKSTART_SET = "GeckoView:Tor:QuickstartSet";
    
    64 61
       private static final String EVENT_REGION_NAMES_GET = "GeckoView:Tor:RegionNamesGet";
    
    62
    +  private static final String EVENT_SHOULD_SHOW_TOR_CONNECT = "GeckoView:Tor:ShouldShowTorConnect";
    
    65 63
     
    
    66 64
       private static final String CONTROL_PORT_FILE = "/control-ipc";
    
    67 65
       private static final String SOCKS_FILE = "/socks-ipc";
    
    ... ... @@ -124,11 +122,8 @@ public class TorAndroidIntegration implements BundleEventListener {
    124 122
                 EVENT_MEEK_STOP,
    
    125 123
                 EVENT_SETTINGS_READY,
    
    126 124
                 EVENT_SETTINGS_CHANGED,
    
    127
    -            EVENT_CONNECT_STATE_CHANGED,
    
    128 125
                 EVENT_CONNECT_STAGE_CHANGED,
    
    129
    -            EVENT_CONNECT_ERROR,
    
    130 126
                 EVENT_BOOTSTRAP_PROGRESS,
    
    131
    -            EVENT_BOOTSTRAP_COMPLETE,
    
    132 127
                 EVENT_TOR_LOGS);
    
    133 128
       }
    
    134 129
     
    
    ... ... @@ -157,35 +152,18 @@ public class TorAndroidIntegration implements BundleEventListener {
    157 152
           } else {
    
    158 153
             Log.w(TAG, "Ignoring a settings changed event that did not have the new settings.");
    
    159 154
           }
    
    160
    -    } else if (EVENT_CONNECT_STATE_CHANGED.equals(event)) {
    
    161
    -      String state = message.getString("state");
    
    162
    -      for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
    
    163
    -        listener.onBootstrapStateChange(state);
    
    164
    -      }
    
    165 155
         } else if (EVENT_CONNECT_STAGE_CHANGED.equals(event)) {
    
    166 156
           TorConnectStage stage = new TorConnectStage(message.getBundle("stage"));
    
    167 157
           _lastKnownStage.setValue(stage);
    
    168 158
           for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
    
    169 159
             listener.onBootstrapStageChange(stage);
    
    170 160
           }
    
    171
    -    } else if (EVENT_CONNECT_ERROR.equals(event)) {
    
    172
    -      String code = message.getString("code");
    
    173
    -      String msg = message.getString("message");
    
    174
    -      String phase = message.getString("phase");
    
    175
    -      String reason = message.getString("reason");
    
    176
    -      for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
    
    177
    -        listener.onBootstrapError(code, msg, phase, reason);
    
    178
    -      }
    
    179 161
         } else if (EVENT_BOOTSTRAP_PROGRESS.equals(event)) {
    
    180 162
           double progress = message.getDouble("progress");
    
    181 163
           boolean hasWarnings = message.getBoolean("hasWarnings");
    
    182 164
           for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
    
    183 165
             listener.onBootstrapProgress(progress, hasWarnings);
    
    184 166
           }
    
    185
    -    } else if (EVENT_BOOTSTRAP_COMPLETE.equals(event)) {
    
    186
    -      for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
    
    187
    -        listener.onBootstrapComplete();
    
    188
    -      }
    
    189 167
         } else if (EVENT_TOR_LOGS.equals(event)) {
    
    190 168
           String msg = message.getString("message");
    
    191 169
           String type = message.getString("logType");
    
    ... ... @@ -647,15 +625,9 @@ public class TorAndroidIntegration implements BundleEventListener {
    647 625
       }
    
    648 626
     
    
    649 627
       public interface BootstrapStateChangeListener {
    
    650
    -    void onBootstrapStateChange(String state); // depreaction path
    
    651
    -
    
    652
    -    void onBootstrapStageChange(TorConnectStage stage); // new upgrade
    
    628
    +    void onBootstrapStageChange(@NonNull TorConnectStage stage); // new upgrade
    
    653 629
     
    
    654 630
         void onBootstrapProgress(double progress, boolean hasWarnings);
    
    655
    -
    
    656
    -    void onBootstrapComplete();
    
    657
    -
    
    658
    -    void onBootstrapError(String code, String message, String phase, String reason);
    
    659 631
       }
    
    660 632
     
    
    661 633
       public interface TorLogListener {
    
    ... ... @@ -736,6 +708,17 @@ public class TorAndroidIntegration implements BundleEventListener {
    736 708
         });
    
    737 709
       }
    
    738 710
     
    
    711
    +  public interface ShouldShowTorConnectGetter {
    
    712
    +    void onValue(Boolean shouldShowTorConnect);
    
    713
    +  }
    
    714
    +
    
    715
    +  public void shouldShowTorConnectGet(ShouldShowTorConnectGetter shouldShowTorConnectGetter) {
    
    716
    +    EventDispatcher.getInstance().queryBoolean(EVENT_SHOULD_SHOW_TOR_CONNECT).then(shouldShowTorConnect -> {
    
    717
    +      shouldShowTorConnectGetter.onValue(shouldShowTorConnect);
    
    718
    +      return new GeckoResult<Void>();
    
    719
    +    });
    
    720
    +  }
    
    721
    +
    
    739 722
       public @NonNull GeckoResult<Void> beginBootstrap() {
    
    740 723
         return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_BEGIN);
    
    741 724
       }
    
    ... ... @@ -754,21 +737,21 @@ public class TorAndroidIntegration implements BundleEventListener {
    754 737
         return EventDispatcher.getInstance().queryVoid(EVENT_BOOTSTRAP_CANCEL);
    
    755 738
       }
    
    756 739
     
    
    757
    -  public void registerBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
    
    740
    +  public synchronized void registerBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
    
    758 741
         mBootstrapStateListeners.add(listener);
    
    759 742
       }
    
    760 743
     
    
    761
    -  public void unregisterBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
    
    744
    +  public synchronized void unregisterBootstrapStateChangeListener(BootstrapStateChangeListener listener) {
    
    762 745
         mBootstrapStateListeners.remove(listener);
    
    763 746
       }
    
    764 747
     
    
    765 748
       private final HashSet<BootstrapStateChangeListener> mBootstrapStateListeners = new HashSet<>();
    
    766 749
     
    
    767
    -  public void registerLogListener(TorLogListener listener) {
    
    750
    +  public synchronized void registerLogListener(TorLogListener listener) {
    
    768 751
         mLogListeners.add(listener);
    
    769 752
       }
    
    770 753
     
    
    771
    -  public void unregisterLogListener(TorLogListener listener) {
    
    754
    +  public synchronized void unregisterLogListener(TorLogListener listener) {
    
    772 755
         mLogListeners.remove(listener);
    
    773 756
       }
    
    774 757
     
    

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorConnectError.java
    1
    +package org.mozilla.geckoview;
    
    2
    +
    
    3
    +import org.mozilla.gecko.util.GeckoBundle;
    
    4
    +
    
    5
    +public class TorConnectError {
    
    6
    +    public String code;
    
    7
    +    public String message;
    
    8
    +    public String phase;
    
    9
    +    public String reason;
    
    10
    +
    
    11
    +    public TorConnectError(GeckoBundle bundle) {
    
    12
    +        code = bundle.getString("code");
    
    13
    +        message = bundle.getString("message");
    
    14
    +        phase = bundle.getString("phase");
    
    15
    +        reason = bundle.getString("reason");
    
    16
    +    }
    
    17
    +
    
    18
    +    public TorConnectError(String code, String message, String phase, String reason) {
    
    19
    +        this.code = code;
    
    20
    +        this.message = message;
    
    21
    +        this.phase = phase;
    
    22
    +        this.reason = reason;
    
    23
    +    }
    
    24
    +}

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorConnectStage.java
    ... ... @@ -5,24 +5,10 @@ import org.mozilla.gecko.util.GeckoBundle;
    5 5
     // Class to receive ConnectStage object from TorConnect.sys.mjs ~ln677
    
    6 6
     public class TorConnectStage {
    
    7 7
     
    
    8
    -    public class Error {
    
    9
    -        public String code;
    
    10
    -        public String message;
    
    11
    -        public String phase;
    
    12
    -        public String reason;
    
    13
    -
    
    14
    -        public Error(GeckoBundle bundle) {
    
    15
    -            code = bundle.getString("code");
    
    16
    -            message = bundle.getString("message");
    
    17
    -            phase = bundle.getString("phase");
    
    18
    -            reason = bundle.getString("reason");
    
    19
    -        }
    
    20
    -    }
    
    21
    -
    
    22 8
         public TorConnectStageName name;
    
    23 9
         // The TorConnectStage prior to this bootstrap attempt. Only set during the "Bootstrapping" stage.
    
    24 10
         public TorConnectStageName bootstrapTrigger;
    
    25
    -    public Error error;
    
    11
    +    public TorConnectError error;
    
    26 12
         public String defaultRegion;
    
    27 13
         public Boolean potentiallyBlocked;
    
    28 14
         public Boolean tryAgain;
    
    ... ... @@ -37,7 +23,7 @@ public class TorConnectStage {
    37 23
             potentiallyBlocked = bundle.getBoolean("potentiallyBlocked");
    
    38 24
             tryAgain = bundle.getBoolean("tryAgain");
    
    39 25
             if (bundle.getBundle("error") != null) {
    
    40
    -            error = new Error(bundle.getBundle("error"));
    
    26
    +            error = new TorConnectError(bundle.getBundle("error"));
    
    41 27
             }
    
    42 28
             bootstrappingStatus = new TorBootstrappingStatus(bundle.getBundle("bootstrappingStatus"));
    
    43 29
         }
    

  • toolkit/modules/TorAndroidIntegration.sys.mjs
    ... ... @@ -28,7 +28,6 @@ const EmittedEvents = Object.freeze({
    28 28
       settingsChanged: "GeckoView:Tor:SettingsChanged",
    
    29 29
       connectStateChanged: "GeckoView:Tor:ConnectStateChanged", // deprecation path
    
    30 30
       connectStageChanged: "GeckoView:Tor:ConnectStageChanged", // new replacement path
    
    31
    -  connectError: "GeckoView:Tor:ConnectError",
    
    32 31
       bootstrapProgress: "GeckoView:Tor:BootstrapProgress",
    
    33 32
       bootstrapComplete: "GeckoView:Tor:BootstrapComplete",
    
    34 33
       torLogs: "GeckoView:Tor:Logs",
    
    ... ... @@ -49,6 +48,7 @@ const ListenedEvents = Object.freeze({
    49 48
       quickstartGet: "GeckoView:Tor:QuickstartGet",
    
    50 49
       quickstartSet: "GeckoView:Tor:QuickstartSet",
    
    51 50
       regionNamesGet: "GeckoView:Tor:RegionNamesGet",
    
    51
    +  shouldShowTorConnectGet: "GeckoView:Tor:ShouldShowTorConnect",
    
    52 52
     });
    
    53 53
     
    
    54 54
     class TorAndroidIntegrationImpl {
    
    ... ... @@ -134,16 +134,6 @@ class TorAndroidIntegrationImpl {
    134 134
               type: EmittedEvents.bootstrapComplete,
    
    135 135
             });
    
    136 136
             break;
    
    137
    -      // TODO: Replace with StageChange stage.error.
    
    138
    -      case lazy.TorConnectTopics.Error:
    
    139
    -        lazy.EventDispatcher.instance.sendRequest({
    
    140
    -          type: EmittedEvents.connectError,
    
    141
    -          code: subj.wrappedJSObject.code ?? "",
    
    142
    -          message: subj.wrappedJSObject.message ?? "",
    
    143
    -          phase: subj.wrappedJSObject.cause?.phase ?? "",
    
    144
    -          reason: subj.wrappedJSObject.cause?.reason ?? "",
    
    145
    -        });
    
    146
    -        break;
    
    147 137
           case lazy.TorProviderTopics.TorLog:
    
    148 138
             lazy.EventDispatcher.instance.sendRequest({
    
    149 139
               type: EmittedEvents.torLogs,
    
    ... ... @@ -225,6 +215,9 @@ class TorAndroidIntegrationImpl {
    225 215
             case ListenedEvents.regionNamesGet:
    
    226 216
               callback?.onSuccess(lazy.TorConnect.getRegionNames());
    
    227 217
               return;
    
    218
    +        case ListenedEvents.shouldShowTorConnectGet:
    
    219
    +          callback?.onSuccess(lazy.TorConnect.shouldShowTorConnect());
    
    220
    +          return;
    
    228 221
           }
    
    229 222
           callback?.onSuccess();
    
    230 223
         } catch (e) {