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

Commits:

21 changed files:

Changes:

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
    ... ... @@ -7,6 +7,7 @@ package org.mozilla.fenix
    7 7
     import android.annotation.SuppressLint
    
    8 8
     import android.app.assist.AssistContent
    
    9 9
     import android.app.PendingIntent
    
    10
    +import android.content.ActivityNotFoundException
    
    10 11
     import android.content.ComponentName
    
    11 12
     import android.content.Context
    
    12 13
     import android.content.Intent
    
    ... ... @@ -19,6 +20,7 @@ import android.os.Bundle
    19 20
     import android.os.StrictMode
    
    20 21
     import android.text.format.DateUtils
    
    21 22
     import android.util.AttributeSet
    
    23
    +import android.util.Log
    
    22 24
     import android.view.ActionMode
    
    23 25
     import android.view.KeyEvent
    
    24 26
     import android.view.LayoutInflater
    
    ... ... @@ -40,7 +42,9 @@ import androidx.core.net.toUri
    40 42
     import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
    
    41 43
     import androidx.core.text.layoutDirection
    
    42 44
     import androidx.core.view.doOnLayout
    
    45
    +import androidx.lifecycle.Lifecycle
    
    43 46
     import androidx.lifecycle.lifecycleScope
    
    47
    +import androidx.lifecycle.repeatOnLifecycle
    
    44 48
     import androidx.navigation.NavController
    
    45 49
     import androidx.navigation.NavDirections
    
    46 50
     import androidx.navigation.fragment.NavHostFragment
    
    ... ... @@ -203,6 +207,7 @@ import org.mozilla.fenix.compose.snackbar.SnackbarState
    203 207
     import org.mozilla.fenix.compose.snackbar.Snackbar
    
    204 208
     import org.mozilla.fenix.tor.CustomSecurityLevelViewModel
    
    205 209
     import org.mozilla.fenix.tor.TorController
    
    210
    +import org.mozilla.fenix.tor.ProviderStoppedViewModel
    
    206 211
     import org.mozilla.fenix.tor.UrlQuickLoadViewModel
    
    207 212
     import org.mozilla.geckoview.TorAndroidIntegration.BootstrapStateChangeListener
    
    208 213
     import org.mozilla.geckoview.TorConnectStage
    
    ... ... @@ -436,6 +441,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash
    436 441
     
    
    437 442
         private var dialog: RedirectDialogFragment? = null
    
    438 443
     
    
    444
    +    private val providerStoppedViewModel: ProviderStoppedViewModel by viewModels()
    
    445
    +
    
    439 446
         private val urlQuickLoadViewModel: UrlQuickLoadViewModel by viewModels()
    
    440 447
     
    
    441 448
         private val customSecurityLevelViewModel: CustomSecurityLevelViewModel by viewModels()
    
    ... ... @@ -445,6 +452,18 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash
    445 452
             // DO NOT MOVE ANYTHING ABOVE THIS getProfilerTime CALL.
    
    446 453
             val startTimeProfiler = components.core.engine.profiler?.getProfilerTime()
    
    447 454
     
    
    455
    +        lifecycleScope.launch {
    
    456
    +            repeatOnLifecycle(Lifecycle.State.STARTED) {
    
    457
    +                providerStoppedViewModel.providerStoppedStateFlow.collect { isStopped ->
    
    458
    +                    Log.d("providerStoppedViewModel", "isStopped = $isStopped")
    
    459
    +                    if (isStopped) {
    
    460
    +                        navHost.navController.navigate(NavGraphDirections.actionNavigateToConnectionAssistFromAnywhere())
    
    461
    +                        providerStoppedViewModel.providerStoppedStateFlow.value = false
    
    462
    +                    }
    
    463
    +                }
    
    464
    +            }
    
    465
    +        }
    
    466
    +
    
    448 467
             // Setup nimbus-cli tooling. This is a NOOP when launching normally.
    
    449 468
             components.nimbus.sdk.initializeTooling(applicationContext, intent)
    
    450 469
             components.strictMode.attachListenerToDisablePenaltyDeath(supportFragmentManager)
    
    ... ... @@ -1788,4 +1807,14 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash
    1788 1807
             components.torController.shutdown()
    
    1789 1808
             exitProcess(0)
    
    1790 1809
         }
    
    1810
    +
    
    1811
    +    fun openBatterySaverSettings() {
    
    1812
    +        try {
    
    1813
    +            startActivity(
    
    1814
    +                Intent(android.provider.Settings.ACTION_BATTERY_SAVER_SETTINGS)
    
    1815
    +            )
    
    1816
    +        } catch (e: ActivityNotFoundException) {
    
    1817
    +            e.printStackTrace()
    
    1818
    +        }
    
    1819
    +    }
    
    1791 1820
     }

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsFragment.kt
    ... ... @@ -265,6 +265,13 @@ class SecretSettingsFragment : PreferenceFragmentCompat(), SystemInsetsPaddedFra
    265 265
                 }
    
    266 266
             }
    
    267 267
     
    
    268
    +        requirePreference<Preference>(R.string.pref_key_test_kill_tor).apply {
    
    269
    +            setOnPreferenceClickListener {
    
    270
    +                requireContext().components.core.geckoRuntime.torIntegrationController.shutdown()
    
    271
    +                true
    
    272
    +            }
    
    273
    +        }
    
    274
    +
    
    268 275
             requirePreference<SwitchPreferenceCompat>(R.string.pref_key_enable_fxsuggest).apply {
    
    269 276
                 isVisible = FeatureFlags.FX_SUGGEST
    
    270 277
                 isChecked = settings.enableFxSuggest
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/ConnectAssistUiState.kt
    ... ... @@ -3,8 +3,8 @@ package org.mozilla.fenix.tor
    3 3
     import androidx.annotation.ColorRes
    
    4 4
     import androidx.annotation.DrawableRes
    
    5 5
     import androidx.annotation.StringRes
    
    6
    -import mozilla.components.lib.crash.R as crashR
    
    7 6
     import org.mozilla.fenix.R
    
    7
    +import mozilla.components.lib.crash.R as crashR
    
    8 8
     
    
    9 9
     enum class ConnectAssistUiState(
    
    10 10
         val progressBarVisible: Boolean,
    
    ... ... @@ -33,6 +33,7 @@ enum class ConnectAssistUiState(
    33 33
         val torBootstrapButton2ShouldOpenSettings: Boolean = true,
    
    34 34
         val wordmarkLogoVisible: Boolean = false,
    
    35 35
         val torBootstrapButton2ShouldRestartApp: Boolean = false,
    
    36
    +    val torBootstrapButton1ShouldRestartTor: Boolean = false,
    
    36 37
     ) {
    
    37 38
         Loading(
    
    38 39
             progressBarVisible = false,
    
    ... ... @@ -298,5 +299,30 @@ enum class ConnectAssistUiState(
    298 299
             torBootstrapButton2TextStringResource = crashR.string.mozac_lib_crash_dialog_button_restart,
    
    299 300
             torBootstrapButton2ShouldOpenSettings = false,
    
    300 301
             torBootstrapButton2ShouldRestartApp = true,
    
    301
    -    )
    
    302
    +    ),
    
    303
    +    ProviderStopped(
    
    304
    +        progressBarVisible = false,
    
    305
    +        backButtonVisible = false,
    
    306
    +        settingsButtonVisible = true,
    
    307
    +        torConnectImageVisible = true,
    
    308
    +        torConnectImageResource = R.drawable.onion_broken,
    
    309
    +        titleLargeTextViewVisible = true,
    
    310
    +        titleLargeTextViewTextStringResource = R.string.connection_assist_provider_stopped_title,
    
    311
    +        titleDescriptionVisible = true,
    
    312
    +        learnMoreStringResource = R.string.connection_assist_final_error_learn_more_link,
    
    313
    +        internetErrorDescription = R.string.connection_assist_provider_stopped_description1,
    
    314
    +        internetErrorDescription1 = R.string.connection_assist_provider_stopped_description2,
    
    315
    +        internetErrorDescription2 = R.string.connection_assist_provider_stopped_description3,
    
    316
    +        titleDescriptionTextStringResource = null,
    
    317
    +        quickstartSwitchVisible = false,
    
    318
    +        regionDropDownVisible = false,
    
    319
    +        torBootstrapButton1Visible = true,
    
    320
    +        torBootstrapButton1TextStringResource = R.string.connection_assist_restart_connection_button,
    
    321
    +        torBootstrapButton1ShouldOpenSettings = false,
    
    322
    +        torBootstrapButton1ShouldRestartTor = true,
    
    323
    +        torBootstrapButton2Visible = false,
    
    324
    +        torBootstrapButton2TextStringResource = null,
    
    325
    +        torBootstrapButton2ShouldOpenSettings = false,
    
    326
    +        torBootstrapButton2ShouldRestartApp = false,
    
    327
    +    ),
    
    302 328
     }

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/ProviderStoppedViewModel.kt
    1
    +package org.mozilla.fenix.tor
    
    2
    +
    
    3
    +import android.app.Application
    
    4
    +import android.util.Log
    
    5
    +import androidx.lifecycle.AndroidViewModel
    
    6
    +import kotlinx.coroutines.flow.MutableStateFlow
    
    7
    +import kotlinx.coroutines.flow.StateFlow
    
    8
    +import org.mozilla.fenix.ext.components
    
    9
    +import org.mozilla.geckoview.TorAndroidIntegration
    
    10
    +import org.mozilla.geckoview.TorConnectStage
    
    11
    +import org.mozilla.geckoview.TorConnectStageName
    
    12
    +
    
    13
    +class ProviderStoppedViewModel(
    
    14
    +    application: Application,
    
    15
    +) : AndroidViewModel(application), TorAndroidIntegration.BootstrapStateChangeListener {
    
    16
    +
    
    17
    +    private val TAG = "ProviderStoppedViewModel"
    
    18
    +
    
    19
    +    internal val providerStoppedStateFlow: MutableStateFlow<Boolean> by lazy { MutableStateFlow(false) }
    
    20
    +
    
    21
    +    private val _maybeConfigIssue = MutableStateFlow(false)
    
    22
    +    internal val maybeConfigIssue: StateFlow<Boolean> = _maybeConfigIssue
    
    23
    +
    
    24
    +    override fun onBootstrapStageChange(stage: TorConnectStage) {
    
    25
    +        when (stage.name) {
    
    26
    +            TorConnectStageName.ProviderStopped -> {
    
    27
    +                Log.d(TAG, "ProviderStopped detected")
    
    28
    +                providerStoppedStateFlow.value = true
    
    29
    +            }
    
    30
    +
    
    31
    +            else -> {
    
    32
    +                providerStoppedStateFlow.value = false
    
    33
    +            }
    
    34
    +        }
    
    35
    +
    
    36
    +        _maybeConfigIssue.value = stage.providerStatus.maybeConfigIssue
    
    37
    +    }
    
    38
    +
    
    39
    +    init {
    
    40
    +        getApplication<Application>().components.core.geckoRuntime.torIntegrationController.registerBootstrapStateChangeListener(this)
    
    41
    +    }
    
    42
    +
    
    43
    +    override fun onCleared() {
    
    44
    +        getApplication<Application>().components.core.geckoRuntime.torIntegrationController.unregisterBootstrapStateChangeListener(this)
    
    45
    +    }
    
    46
    +
    
    47
    +    override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) {}
    
    48
    +
    
    49
    +}

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistFragment.kt
    ... ... @@ -8,6 +8,7 @@ import android.graphics.Color
    8 8
     import android.graphics.Typeface
    
    9 9
     import android.os.Build
    
    10 10
     import android.os.Bundle
    
    11
    +import android.os.PowerManager
    
    11 12
     import android.text.SpannableString
    
    12 13
     import android.text.Spanned
    
    13 14
     import android.text.TextPaint
    
    ... ... @@ -17,9 +18,11 @@ import android.util.Log
    17 18
     import android.view.LayoutInflater
    
    18 19
     import android.view.View
    
    19 20
     import android.view.ViewGroup
    
    21
    +import androidx.annotation.StringRes
    
    20 22
     import androidx.appcompat.content.res.AppCompatResources
    
    21 23
     import androidx.compose.foundation.Image
    
    22 24
     import androidx.compose.foundation.background
    
    25
    +import androidx.compose.foundation.layout.Arrangement
    
    23 26
     import androidx.compose.foundation.layout.Box
    
    24 27
     import androidx.compose.foundation.layout.Column
    
    25 28
     import androidx.compose.foundation.layout.Row
    
    ... ... @@ -43,14 +46,22 @@ import androidx.compose.runtime.getValue
    43 46
     import androidx.compose.runtime.mutableStateOf
    
    44 47
     import androidx.compose.runtime.saveable.rememberSaveable
    
    45 48
     import androidx.compose.runtime.setValue
    
    49
    +import androidx.compose.ui.Alignment
    
    46 50
     import androidx.compose.ui.Modifier
    
    47 51
     import androidx.compose.ui.platform.ViewCompositionStrategy
    
    48 52
     import androidx.compose.ui.res.painterResource
    
    53
    +import androidx.compose.ui.res.stringResource
    
    54
    +import androidx.compose.ui.text.LinkAnnotation
    
    55
    +import androidx.compose.ui.text.TextLinkStyles
    
    49 56
     import androidx.compose.ui.text.TextStyle
    
    57
    +import androidx.compose.ui.text.buildAnnotatedString
    
    50 58
     import androidx.compose.ui.text.font.FontWeight
    
    59
    +import androidx.compose.ui.text.style.TextDecoration
    
    60
    +import androidx.compose.ui.tooling.preview.Preview
    
    51 61
     import androidx.compose.ui.unit.DpOffset
    
    52 62
     import androidx.compose.ui.unit.dp
    
    53 63
     import androidx.compose.ui.unit.sp
    
    64
    +import androidx.core.content.getSystemService
    
    54 65
     import androidx.core.view.isEmpty
    
    55 66
     import androidx.fragment.app.Fragment
    
    56 67
     import androidx.fragment.app.activityViewModels
    
    ... ... @@ -68,6 +79,7 @@ import org.mozilla.fenix.HomeActivity
    68 79
     import org.mozilla.fenix.R
    
    69 80
     import org.mozilla.fenix.databinding.FragmentTorConnectionAssistBinding
    
    70 81
     import org.mozilla.fenix.e2e.SystemInsetsPaddedFragment
    
    82
    +import org.mozilla.fenix.ext.components
    
    71 83
     import org.mozilla.fenix.ext.hideToolbar
    
    72 84
     
    
    73 85
     class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemInsetsPaddedFragment {
    
    ... ... @@ -76,6 +88,7 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemIn
    76 88
         private val progressViewModel: TorBootstrapProgressViewModel by viewModels()
    
    77 89
         private val quickstartViewModel: QuickstartViewModel by activityViewModels()
    
    78 90
         private val torConnectionAssistViewModel : TorConnectionAssistViewModel by viewModels()
    
    91
    +    private val providerStoppedViewModel : ProviderStoppedViewModel by activityViewModels()
    
    79 92
     
    
    80 93
         private var _binding: FragmentTorConnectionAssistBinding? = null
    
    81 94
         private val binding get() = _binding!!
    
    ... ... @@ -103,6 +116,7 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemIn
    103 116
                 Log.d(TAG, "shouldOpenHome = $it")
    
    104 117
                 if (it) {
    
    105 118
                     openHome()
    
    119
    +                torConnectionAssistViewModel.shouldOpenHome.value = false
    
    106 120
                 }
    
    107 121
             }
    
    108 122
     
    
    ... ... @@ -200,13 +214,142 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemIn
    200 214
             binding.torConnectImage.setImageResource(screen.torConnectImageResource)
    
    201 215
         }
    
    202 216
     
    
    217
    +    @Composable
    
    218
    +    fun TextWithClickable(
    
    219
    +        @StringRes mainTextRes: Int,
    
    220
    +        @StringRes clickableTextRes: Int,
    
    221
    +        onClick: () -> Unit,
    
    222
    +        style: TextStyle,
    
    223
    +        tag: String,
    
    224
    +    ) {
    
    225
    +        Text(
    
    226
    +            text = buildAnnotatedString {
    
    227
    +                val clickableText = stringResource(clickableTextRes)
    
    228
    +                val plainText = stringResource(mainTextRes, clickableText)
    
    229
    +                append(plainText)
    
    230
    +                addLink(
    
    231
    +                    clickable = LinkAnnotation.Clickable(
    
    232
    +                        tag = tag,
    
    233
    +                        styles = TextLinkStyles(
    
    234
    +                            style = style.toSpanStyle().copy(textDecoration = TextDecoration.Underline),
    
    235
    +                            pressedStyle = style.toSpanStyle(),
    
    236
    +                        ),
    
    237
    +                        linkInteractionListener = { onClick() }
    
    238
    +                    ),
    
    239
    +                    start = plainText.indexOf(clickableText),
    
    240
    +                    end = plainText.indexOf(clickableText) + clickableText.length,
    
    241
    +                )
    
    242
    +            },
    
    243
    +            style = style,
    
    244
    +        )
    
    245
    +    }
    
    246
    +
    
    247
    +    @Preview
    
    248
    +    @Composable
    
    249
    +    fun DaemonFailedScreen(
    
    250
    +        isDeviceInPowerSaveMode: Boolean = false,
    
    251
    +        maybeConfigIssue: Boolean = false,
    
    252
    +        style: TextStyle = TextStyle(
    
    253
    +            fontSize = 16.sp,
    
    254
    +            lineHeight = 24.sp,
    
    255
    +            fontWeight = FontWeight(400),
    
    256
    +            color = PhotonColors.LightGrey05,
    
    257
    +            letterSpacing = 0.5.sp,
    
    258
    +        )
    
    259
    +    ) {
    
    260
    +        Column(
    
    261
    +            verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterVertically),
    
    262
    +        ) {
    
    263
    +            Text(
    
    264
    +                text = stringResource(R.string.connection_assist_provider_stopped_description1),
    
    265
    +                style = style,
    
    266
    +            )
    
    267
    +            Text(
    
    268
    +                text = stringResource(R.string.connection_assist_provider_stopped_description2),
    
    269
    +                style = style.copy(fontWeight = FontWeight.Bold),
    
    270
    +            )
    
    271
    +            if (isDeviceInPowerSaveMode && !maybeConfigIssue) {
    
    272
    +                Row {
    
    273
    +                    Image(
    
    274
    +                        painter = painterResource(R.drawable.bullet_point),
    
    275
    +                        contentDescription = null,
    
    276
    +                        modifier = Modifier.padding(6.dp)
    
    277
    +                    )
    
    278
    +                    Text(
    
    279
    +                        style = style,
    
    280
    +                        text = stringResource(R.string.connection_assist_provider_stopped_description_battery1),
    
    281
    +                    )
    
    282
    +                }
    
    283
    +            }
    
    284
    +            Row {
    
    285
    +                Image(
    
    286
    +                    painter = painterResource(R.drawable.bullet_point),
    
    287
    +                    contentDescription = null,
    
    288
    +                    modifier = Modifier.padding(6.dp)
    
    289
    +                )
    
    290
    +                Text(
    
    291
    +                    style = style,
    
    292
    +                    text = stringResource(R.string.connection_assist_provider_stopped_description3),
    
    293
    +                )
    
    294
    +            }
    
    295
    +            Text(
    
    296
    +                text = stringResource(R.string.connection_assist_provider_stopped_description4),
    
    297
    +                style = style.copy(fontWeight = FontWeight.Bold),
    
    298
    +            )
    
    299
    +            if (isDeviceInPowerSaveMode && !maybeConfigIssue) {
    
    300
    +                Row {
    
    301
    +                    Image(
    
    302
    +                        painter = painterResource(R.drawable.bullet_point),
    
    303
    +                        contentDescription = null,
    
    304
    +                        modifier = Modifier.padding(6.dp),
    
    305
    +                    )
    
    306
    +                    TextWithClickable(
    
    307
    +                        mainTextRes = R.string.connection_assist_provider_stopped_description_turn_off_battery_saver2,
    
    308
    +                        clickableTextRes = R.string.connection_assist_provider_stopped_description_turn_off_battery_saver_clickable,
    
    309
    +                        onClick = { (requireActivity() as HomeActivity).openBatterySaverSettings() },
    
    310
    +                        style = style,
    
    311
    +                        tag = BATTERY_SETTINGS_TAG,
    
    312
    +                    )
    
    313
    +                }
    
    314
    +            } else {
    
    315
    +                Row {
    
    316
    +                    Image(
    
    317
    +                        painter = painterResource(R.drawable.bullet_point),
    
    318
    +                        contentDescription = null,
    
    319
    +                        modifier = Modifier.padding(6.dp),
    
    320
    +                    )
    
    321
    +                    Text(
    
    322
    +                        text = stringResource(R.string.connection_assist_provider_stopped_description5),
    
    323
    +                        style = style,
    
    324
    +                    )
    
    325
    +                }
    
    326
    +            }
    
    327
    +            Text(
    
    328
    +                text = stringResource(R.string.connection_assist_provider_stopped_description6,
    
    329
    +                    stringResource(R.string.connection_assist_provider_stopped_description7)
    
    330
    +                ),
    
    331
    +                style = style,
    
    332
    +            )
    
    333
    +        }
    
    334
    +    }
    
    335
    +
    
    203 336
         private fun setTitle(screen: ConnectAssistUiState) {
    
    204 337
             binding.titleLargeTextView.visibility =
    
    205 338
                 if (screen.titleLargeTextViewVisible) View.VISIBLE else View.GONE
    
    206 339
             binding.titleLargeTextView.text = getString(screen.titleLargeTextViewTextStringResource)
    
    207 340
             binding.titleDescription.visibility =
    
    208 341
                 if (screen.titleDescriptionVisible) View.VISIBLE else View.GONE
    
    209
    -        if (screen.learnMoreStringResource != null && screen.internetErrorDescription != null) {
    
    342
    +        binding.daemonFailedDescription.visibility = View.GONE
    
    343
    +        if (screen == ConnectAssistUiState.ProviderStopped) {
    
    344
    +            binding.titleDescription.visibility = View.GONE
    
    345
    +            binding.daemonFailedDescription.setContent {
    
    346
    +                DaemonFailedScreen(
    
    347
    +                    isDeviceInPowerSaveMode = requireContext().getSystemService<PowerManager>()?.isPowerSaveMode ?: false,
    
    348
    +                    maybeConfigIssue = providerStoppedViewModel.maybeConfigIssue.collectAsState().value,
    
    349
    +                    )
    
    350
    +            }
    
    351
    +            binding.daemonFailedDescription.visibility = View.VISIBLE
    
    352
    +        } else if (screen.learnMoreStringResource != null && screen.internetErrorDescription != null) {
    
    210 353
                 val learnMore: String = "" // getString(screen.learnMoreStringResource) tor-browser#43198 uncomment and add back once we have the "Learn more" screens for relevant pages
    
    211 354
                 val internetErrorDescription: String =
    
    212 355
                     if (screen.internetErrorDescription1 == null) {
    
    ... ... @@ -434,6 +577,13 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemIn
    434 577
                 setOnClickListener {
    
    435 578
                     if (screen.torBootstrapButton1ShouldOpenSettings) {
    
    436 579
                         openTorConnectionSettings()
    
    580
    +                } else if (screen.torBootstrapButton1ShouldRestartTor) {
    
    581
    +                    requireContext().components.core.geckoRuntime.torIntegrationController.restartProvider()
    
    582
    +                    backgroundTintList = AppCompatResources.getColorStateList(
    
    583
    +                        requireContext(),
    
    584
    +                        R.color.disabled_connect_button_purple,
    
    585
    +                    )
    
    586
    +                    text = getString(R.string.connection_assist_restarting_connection_button)
    
    437 587
                     } else {
    
    438 588
                         torConnectionAssistViewModel.handleConnect(screen)
    
    439 589
                     }
    
    ... ... @@ -561,8 +711,11 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemIn
    561 711
         }
    
    562 712
     
    
    563 713
         override fun onBackPressed(): Boolean {
    
    564
    -        torConnectionAssistViewModel.handleBackButtonPressed(requireActivity() as HomeActivity)
    
    565
    -        return true
    
    714
    +        return torConnectionAssistViewModel.handleBackButtonPressed(requireActivity() as HomeActivity)
    
    715
    +    }
    
    716
    +
    
    717
    +    companion object {
    
    718
    +        const val BATTERY_SETTINGS_TAG = "BATTERY_SETTINGS_TAG"
    
    566 719
         }
    
    567 720
     
    
    568 721
     }

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistViewModel.kt
    ... ... @@ -138,17 +138,18 @@ class TorConnectionAssistViewModel(
    138 138
             torConnectStage.collect {
    
    139 139
                 Log.d(TAG, "torConnectStageName: ${it?.name}")
    
    140 140
                 when (it?.name) {
    
    141
    -                TorConnectStageName.Disabled       -> shouldOpenHome.value = true // TODO use TorConnect.enabled instead to determine this
    
    142
    -                TorConnectStageName.Loading        -> _torConnectScreen.value = ConnectAssistUiState.Loading
    
    143
    -                TorConnectStageName.Start          -> _torConnectScreen.value = ConnectAssistUiState.Start
    
    144
    -                TorConnectStageName.Bootstrapping  -> _torConnectScreen.value = handleBootstrapTrigger(it.bootstrapTrigger)
    
    145
    -                TorConnectStageName.Offline        -> _torConnectScreen.value = ConnectAssistUiState.Offline
    
    146
    -                TorConnectStageName.ChooseRegion   -> _torConnectScreen.value = ConnectAssistUiState.ChooseRegion
    
    147
    -                TorConnectStageName.RegionNotFound -> _torConnectScreen.value = ConnectAssistUiState.RegionNotFound
    
    148
    -                TorConnectStageName.ConfirmRegion  -> _torConnectScreen.value = ConnectAssistUiState.ConfirmRegion
    
    149
    -                TorConnectStageName.FinalError     -> _torConnectScreen.value = ConnectAssistUiState.FinalError
    
    150
    -                TorConnectStageName.Bootstrapped   -> shouldOpenHome.value = true
    
    151
    -                null                               -> {}
    
    141
    +                TorConnectStageName.Disabled        -> shouldOpenHome.value = true // TODO use TorConnect.enabled instead to determine this
    
    142
    +                TorConnectStageName.Loading         -> _torConnectScreen.value = ConnectAssistUiState.Loading
    
    143
    +                TorConnectStageName.ProviderStopped -> _torConnectScreen.value = ConnectAssistUiState.ProviderStopped
    
    144
    +                TorConnectStageName.Start           -> _torConnectScreen.value = ConnectAssistUiState.Start
    
    145
    +                TorConnectStageName.Bootstrapping   -> _torConnectScreen.value = handleBootstrapTrigger(it.bootstrapTrigger)
    
    146
    +                TorConnectStageName.Offline         -> _torConnectScreen.value = ConnectAssistUiState.Offline
    
    147
    +                TorConnectStageName.ChooseRegion    -> _torConnectScreen.value = ConnectAssistUiState.ChooseRegion
    
    148
    +                TorConnectStageName.RegionNotFound  -> _torConnectScreen.value = ConnectAssistUiState.RegionNotFound
    
    149
    +                TorConnectStageName.ConfirmRegion   -> _torConnectScreen.value = ConnectAssistUiState.ConfirmRegion
    
    150
    +                TorConnectStageName.FinalError      -> _torConnectScreen.value = ConnectAssistUiState.FinalError
    
    151
    +                TorConnectStageName.Bootstrapped    -> shouldOpenHome.value = true
    
    152
    +                null                                -> {}
    
    152 153
                 }
    
    153 154
             }
    
    154 155
         }
    
    ... ... @@ -168,11 +169,12 @@ class TorConnectionAssistViewModel(
    168 169
             }
    
    169 170
         }
    
    170 171
     
    
    171
    -    fun handleBackButtonPressed(homeActivity: HomeActivity) {
    
    172
    -        when (torConnectScreen.value) {
    
    173
    -            ConnectAssistUiState.Loading -> homeActivity.shutDown()
    
    174
    -            ConnectAssistUiState.Start   -> homeActivity.shutDown()
    
    175
    -            else                         -> torAndroidIntegration.startAgain()
    
    172
    +    fun handleBackButtonPressed(homeActivity: HomeActivity): Boolean {
    
    173
    +        return when (torConnectScreen.value) {
    
    174
    +            ConnectAssistUiState.Loading         -> homeActivity.shutDown()
    
    175
    +            ConnectAssistUiState.Start           -> homeActivity.shutDown()
    
    176
    +            ConnectAssistUiState.ProviderStopped -> false
    
    177
    +            else                                 -> torAndroidIntegration.startAgain().let { true }
    
    176 178
             }
    
    177 179
         }
    
    178 180
     
    

  • mobile/android/fenix/app/src/main/res/drawable/bullet_point.xml
    1
    +<vector xmlns:android="http://schemas.android.com/apk/res/android"
    
    2
    +  android:autoMirrored="true"
    
    3
    +  android:height="6dp"
    
    4
    +  android:viewportHeight="6"
    
    5
    +  android:viewportWidth="6"
    
    6
    +  android:width="6dp">
    
    7
    +  <path
    
    8
    +    android:fillColor="#FBFBFE"
    
    9
    +    android:pathData="M3,3m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0" />
    
    10
    +</vector>

  • mobile/android/fenix/app/src/main/res/drawable/loading_wheel.xml
    1
    +<vector xmlns:android="http://schemas.android.com/apk/res/android"
    
    2
    +  android:autoMirrored="true"
    
    3
    +  android:height="16dp"
    
    4
    +  android:viewportHeight="16"
    
    5
    +  android:viewportWidth="16"
    
    6
    +  android:width="16dp">
    
    7
    +  <path
    
    8
    +    android:fillAlpha="0.4"
    
    9
    +    android:fillColor="#FBFBFE"
    
    10
    +    android:fillType="evenOdd"
    
    11
    +    android:pathData="M8,15C8,14.448 7.549,14.009 7.004,13.918C4.164,13.443 2,10.974 2,8C2,4.686 4.686,2 8,2C10.974,2 13.443,4.164 13.918,7.004C14.009,7.549 14.448,8 15,8C15.552,8 16.007,7.55 15.938,7.002C15.447,3.055 12.08,0 8,0C3.582,0 0,3.582 0,8C0,12.08 3.055,15.447 7.002,15.938C7.55,16.007 8,15.552 8,15Z" />
    
    12
    +</vector>

  • mobile/android/fenix/app/src/main/res/drawable/onion_broken.xml
    1
    +<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="40dp" android:viewportHeight="40" android:viewportWidth="40" android:width="40dp">
    
    2
    +      
    
    3
    +    <path android:fillColor="#FBFBFE" android:pathData="M33.259,33.258C29.865,36.651 25.178,38.75 20,38.75C9.645,38.75 1.25,30.355 1.25,20C1.25,14.823 3.348,10.135 6.741,6.742L8.813,8.814C5.95,11.677 4.18,15.632 4.18,20C4.18,28.737 11.263,35.82 20,35.82C24.369,35.82 28.324,34.049 31.187,31.186L33.259,33.258Z"/>
    
    4
    +      
    
    5
    +    <path android:fillColor="#FBFBFE" android:pathData="M35.284,30.863C37.466,27.798 38.75,24.049 38.75,20C38.75,9.645 30.355,1.25 20,1.25C15.951,1.25 12.202,2.533 9.137,4.716L11.243,6.822C13.751,5.153 16.762,4.18 20,4.18C28.737,4.18 35.82,11.263 35.82,20C35.82,23.238 34.847,26.249 33.178,28.757L35.284,30.863Z"/>
    
    6
    +      
    
    7
    +    <path android:fillColor="#FBFBFE" android:pathData="M31.226,26.805C32.431,24.82 33.125,22.491 33.125,20C33.125,12.751 27.249,6.875 20,6.875C17.509,6.875 15.18,7.569 13.195,8.774L15.347,10.926C16.742,10.209 18.324,9.805 20,9.805C25.631,9.805 30.195,14.369 30.195,20C30.195,21.676 29.791,23.258 29.074,24.653L31.226,26.805Z"/>
    
    8
    +      
    
    9
    +    <path android:fillColor="#FBFBFE" android:pathData="M29.281,29.281L27.209,27.209C25.364,29.054 22.815,30.195 20,30.195C14.369,30.195 9.805,25.631 9.805,20C9.805,17.185 10.946,14.636 12.79,12.791L10.719,10.72C8.344,13.095 6.875,16.376 6.875,20C6.875,27.249 12.751,33.125 20,33.125C23.625,33.125 26.906,31.656 29.281,29.281Z"/>
    
    10
    +      
    
    11
    +    <path android:fillColor="#FBFBFE" android:pathData="M14.696,14.697C13.339,16.054 12.5,17.929 12.5,20C12.5,24.142 15.858,27.5 20,27.5C22.071,27.5 23.946,26.66 25.303,25.303L23.232,23.232C22.405,24.059 21.262,24.57 20,24.57C17.476,24.57 15.43,22.524 15.43,20C15.43,18.738 15.941,17.596 16.768,16.769L14.696,14.697Z"/>
    
    12
    +      
    
    13
    +    <path android:fillColor="#FBFBFE" android:pathData="M24.568,20.147C24.569,20.098 24.57,20.049 24.57,20C24.57,17.476 22.524,15.43 20,15.43C19.951,15.43 19.902,15.431 19.853,15.432L17.388,12.967C18.202,12.665 19.081,12.5 20,12.5C24.142,12.5 27.5,15.858 27.5,20C27.5,20.919 27.335,21.799 27.033,22.612L24.568,20.147Z"/>
    
    14
    +      
    
    15
    +    <path android:fillColor="#FBFBFE" android:pathData="M20,38.75C9.645,38.75 1.25,30.355 1.25,20C1.25,14.823 3.348,10.135 6.741,6.742L20,20V38.75Z"/>
    
    16
    +      
    
    17
    +    <path android:fillColor="#FBFBFE" android:pathData="M20,15.579V1.25C15.951,1.25 12.202,2.533 9.137,4.716L20,15.579Z"/>
    
    18
    +      
    
    19
    +    <path android:fillColor="#FF9AA2" android:pathData="M35.291,39.061C35.085,39.062 34.882,39.021 34.692,38.943C34.503,38.864 34.33,38.749 34.186,38.604L2.31,6.731C2.037,6.434 1.889,6.043 1.898,5.64C1.906,5.236 2.07,4.851 2.355,4.566C2.64,4.28 3.025,4.116 3.428,4.107C3.832,4.099 4.223,4.246 4.52,4.519L36.396,36.394C36.688,36.688 36.851,37.085 36.851,37.5C36.851,37.915 36.688,38.312 36.396,38.606C36.25,38.751 36.078,38.866 35.888,38.944C35.699,39.022 35.496,39.062 35.291,39.061Z"/>
    
    20
    +    
    
    21
    +</vector>

  • mobile/android/fenix/app/src/main/res/layout/fragment_tor_connection_assist.xml
    ... ... @@ -99,6 +99,19 @@
    99 99
             android:textSize="14sp"
    
    100 100
             app:layout_constraintTop_toBottomOf="@id/title_large_text_view" />
    
    101 101
     
    
    102
    +    <androidx.compose.ui.platform.ComposeView
    
    103
    +        android:id="@+id/daemon_failed_description"
    
    104
    +        android:layout_width="match_parent"
    
    105
    +        android:layout_height="wrap_content"
    
    106
    +        android:visibility="gone"
    
    107
    +        android:paddingHorizontal="24dp"
    
    108
    +        android:paddingVertical="16dp"
    
    109
    +        app:layout_constraintBottom_toTopOf="@id/tor_bootstrap_button_1"
    
    110
    +        app:layout_constraintEnd_toEndOf="parent"
    
    111
    +        app:layout_constraintStart_toStartOf="parent"
    
    112
    +        app:layout_constraintTop_toBottomOf="@id/title_large_text_view"
    
    113
    +        app:layout_constraintVertical_bias="0" />
    
    114
    +
    
    102 115
         <androidx.appcompat.widget.SwitchCompat
    
    103 116
             android:id="@+id/quickstart_switch"
    
    104 117
             android:layout_width="match_parent"
    

  • mobile/android/fenix/app/src/main/res/navigation/nav_graph.xml
    ... ... @@ -27,6 +27,10 @@
    27 27
             app:popUpTo="@id/torConnectionAssistFragment"
    
    28 28
             app:popUpToInclusive="true"/>
    
    29 29
     
    
    30
    +    <action
    
    31
    +        android:id="@+id/action_navigate_to_connection_assist_from_anywhere"
    
    32
    +        app:destination="@id/torConnectionAssistFragment" />
    
    33
    +
    
    30 34
         <action
    
    31 35
             android:id="@+id/action_global_home"
    
    32 36
             app:destination="@id/homeFragment"
    

  • mobile/android/fenix/app/src/main/res/values/preference_keys.xml
    ... ... @@ -652,6 +652,7 @@
    652 652
         <string name="pref_key_tor_network_settings_bridge_config" translatable="false">pref_key_tor_network_settings_bridge_config</string>
    
    653 653
         <string name="pref_key_tor_logs" translatable="false">pref_key_tor_logs</string>
    
    654 654
         <string name="pref_key_about_config_shortcut" translatable="false">pref_key_about_config_shortcut</string>
    
    655
    +    <string name="pref_key_test_kill_tor" translatable="false">pref_key_test_kill_tor</string>
    
    655 656
         <string name="pref_key_tor_network_settings_bridge_config_explanation" translatable="false">pref_key_tor_network_settings_bridge_config_explanation</string>
    
    656 657
         <string name="pref_key_tor_network_settings_bridge_config_toggle" translatable="false">pref_key_tor_network_settings_bridge_config_toggle</string>
    
    657 658
         <string name="pref_key_tor_network_settings_bridge_config_builtin_bridge_obfs4" translatable="false">pref_key_tor_network_settings_bridge_config_builtin_bridge_obfs4</string>
    

  • mobile/android/fenix/app/src/main/res/values/torbrowser_strings.xml
    ... ... @@ -135,6 +135,32 @@
    135 135
         <string name="connection_assist_back_button_content_description_start_again">Start again</string>
    
    136 136
         <!-- Connection assist. This message is shown briefly after the connection to the Tor network completes. -->
    
    137 137
         <string name="connection_assist_bootstrap_succeeded_toast_message">Connected to Tor</string>
    
    138
    +    <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
    
    139
    +    <string name="connection_assist_provider_stopped_title">The Tor process has stopped working</string>
    
    140
    +    <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. -->
    
    141
    +    <string name="connection_assist_provider_stopped_description1">The underlying process that controls your connection to the Tor network has stopped working.</string>
    
    142
    +    <!-- Connection assist. -->
    
    143
    +    <string name="connection_assist_provider_stopped_description2">What could be causing this?</string>
    
    144
    +    <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. -->
    
    145
    +    <string name="connection_assist_provider_stopped_description_battery1">Your device has quit the process to save battery.</string>
    
    146
    +    <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
    
    147
    +    <string name="connection_assist_provider_stopped_description3">The Tor process has stopped working due to a technical issue.</string>
    
    148
    +    <!-- Connection assist. -->
    
    149
    +    <string name="connection_assist_provider_stopped_description4">What can you do about it?</string>
    
    150
    +    <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
    
    151
    +    <string name="connection_assist_provider_stopped_description5">Try restarting the Tor process (this won’t close your browser tabs).</string>
    
    152
    +    <!-- Connection assist.-->
    
    153
    +    <string name="connection_assist_provider_stopped_description_turn_off_battery_saver_clickable">Turn off Battery Saver on your device</string>
    
    154
    +    <!-- Connection assist. "%1$s" will be replaced with connection_assist_provider_stopped_description_turn_off_battery_saver_clickable. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
    
    155
    +    <string name="connection_assist_provider_stopped_description_turn_off_battery_saver2">%1$s and try restarting the Tor process (this won’t close your browser tabs).</string>
    
    156
    +    <!-- Connection assist. "%1$s" will be replaced with connection_assist_provider_stopped_description7. -->
    
    157
    +    <string name="connection_assist_provider_stopped_description6">If the problem remains, get in contact with us through one of our %1$s.</string>
    
    158
    +    <!-- Connection assist. -->
    
    159
    +    <string name="connection_assist_provider_stopped_description7">support channels</string>
    
    160
    +    <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
    
    161
    +    <string name="connection_assist_restart_connection_button">Restart Tor process</string>
    
    162
    +    <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
    
    163
    +    <string name="connection_assist_restarting_connection_button">Restarting Tor process…</string>
    
    138 164
     
    
    139 165
         <!-- Notification title for closing browser tabs. "%s" will be replaced with the localised application name, such as "Tor Browser". -->
    
    140 166
         <string name="notification_close_tor_browser_tabs">Close %s’s tabs?</string>
    

  • mobile/android/fenix/app/src/main/res/xml/secret_settings_preferences.xml
    ... ... @@ -135,6 +135,10 @@
    135 135
           android:key="@string/pref_key_enable_lna_tracker_blocking_enabled"
    
    136 136
           android:title="@string/preferences_debug_settings_enable_lna_tracker_blocking"
    
    137 137
           app:iconSpaceReserved="false" />
    
    138
    +    <Preference
    
    139
    +      android:key="@string/pref_key_test_kill_tor"
    
    140
    +      android:title="TEST kill tor daemon"
    
    141
    +      app:iconSpaceReserved="false" />
    
    138 142
       </PreferenceCategory>
    
    139 143
     
    
    140 144
       <PreferenceCategory
    

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ProviderStatus.java
    1
    +package org.mozilla.geckoview;
    
    2
    +
    
    3
    +import org.mozilla.gecko.util.GeckoBundle;
    
    4
    +
    
    5
    +public class ProviderStatus {
    
    6
    +  public Boolean maybeConfigIssue;
    
    7
    +
    
    8
    +  public ProviderStatus(GeckoBundle bundle) {
    
    9
    +    maybeConfigIssue = bundle.getBoolean("maybeConfigIssue");
    
    10
    +  }
    
    11
    +}

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorAndroidIntegration.java
    ... ... @@ -57,6 +57,7 @@ public class TorAndroidIntegration implements BundleEventListener {
    57 57
       private static final String EVENT_BOOTSTRAP_BEGIN_AUTO = "GeckoView:Tor:BootstrapBeginAuto";
    
    58 58
       private static final String EVENT_BOOTSTRAP_CANCEL = "GeckoView:Tor:BootstrapCancel";
    
    59 59
       private static final String EVENT_START_AGAIN = "GeckoView:Tor:StartAgain";
    
    60
    +  private static final String EVENT_RESTART_PROVIDER = "GeckoView:Tor:RestartProvider";
    
    60 61
       private static final String EVENT_QUICKSTART_GET = "GeckoView:Tor:QuickstartGet";
    
    61 62
       private static final String EVENT_QUICKSTART_SET = "GeckoView:Tor:QuickstartSet";
    
    62 63
       private static final String EVENT_REGION_NAMES_GET = "GeckoView:Tor:RegionNamesGet";
    
    ... ... @@ -706,6 +707,10 @@ public class TorAndroidIntegration implements BundleEventListener {
    706 707
         return EventDispatcher.getInstance().queryVoid(EVENT_START_AGAIN);
    
    707 708
       }
    
    708 709
     
    
    710
    +  public @NonNull GeckoResult<Void> restartProvider() {
    
    711
    +    return EventDispatcher.getInstance().queryVoid(EVENT_RESTART_PROVIDER);
    
    712
    +  }
    
    713
    +
    
    709 714
       public interface QuickstartGetter {
    
    710 715
         void onValue(boolean enabled);
    
    711 716
       }
    

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorConnectStage.java
    ... ... @@ -13,6 +13,7 @@ public class TorConnectStage {
    13 13
         public Boolean potentiallyBlocked;
    
    14 14
         public Boolean tryAgain;
    
    15 15
         public TorBootstrappingStatus bootstrappingStatus;
    
    16
    +    public ProviderStatus providerStatus;
    
    16 17
     
    
    17 18
         public TorConnectStage(GeckoBundle bundle) {
    
    18 19
             name = TorConnectStageName.fromString(bundle.getString("name"));
    
    ... ... @@ -26,6 +27,7 @@ public class TorConnectStage {
    26 27
                 error = new TorConnectError(bundle.getBundle("error"));
    
    27 28
             }
    
    28 29
             bootstrappingStatus = new TorBootstrappingStatus(bundle.getBundle("bootstrappingStatus"));
    
    30
    +        providerStatus = new ProviderStatus(bundle.getBundle("providerStatus"));
    
    29 31
         }
    
    30 32
     
    
    31 33
         public Boolean isBootstrapped() {
    

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorConnectStageName.java
    ... ... @@ -3,9 +3,10 @@ package org.mozilla.geckoview;
    3 3
     import java.security.InvalidParameterException;
    
    4 4
     
    
    5 5
     public enum TorConnectStageName {
    
    6
    -    // These names should match entries from TorConnectStage in TorConnect.sys.mjs at ~ln163.
    
    6
    +    // These names should match entries from TorConnectStage in TorConnect.sys.mjs at ~ln674.
    
    7 7
         Disabled("Disabled"),
    
    8 8
         Loading("Loading"),
    
    9
    +    ProviderStopped("ProviderStopped"),
    
    9 10
         Start("Start"),
    
    10 11
         Bootstrapping("Bootstrapping"),
    
    11 12
         Offline("Offline"),
    

  • toolkit/components/tor-launcher/TorProcessAndroid.sys.mjs
    ... ... @@ -51,6 +51,11 @@ export class TorProcessAndroid {
    51 51
        * it failed to start tor.
    
    52 52
        */
    
    53 53
       #startReject = null;
    
    54
    +  /**
    
    55
    +   * Tells whether we ever registered ourself as the listener to the various
    
    56
    +   * process events.
    
    57
    +   */
    
    58
    +  #registeredListeners = false;
    
    54 59
     
    
    55 60
       onExit = () => {};
    
    56 61
     
    
    ... ... @@ -74,6 +79,7 @@ export class TorProcessAndroid {
    74 79
           this,
    
    75 80
           Object.values(TorIncomingEvents)
    
    76 81
         );
    
    82
    +    this.#registeredListeners = true;
    
    77 83
         let config;
    
    78 84
         try {
    
    79 85
           config = await lazy.EventDispatcher.instance.sendRequestForResult(
    
    ... ... @@ -103,10 +109,13 @@ export class TorProcessAndroid {
    103 109
         });
    
    104 110
         logger.debug("Sent the stop event.");
    
    105 111
         this.#processHandle = null;
    
    106
    -    lazy.EventDispatcher.instance.unregisterListener(
    
    107
    -      this,
    
    108
    -      Object.values(TorIncomingEvents)
    
    109
    -    );
    
    112
    +    if (this.#registeredListeners) {
    
    113
    +      lazy.EventDispatcher.instance.unregisterListener(
    
    114
    +        this,
    
    115
    +        Object.values(TorIncomingEvents)
    
    116
    +      );
    
    117
    +      this.#registeredListeners = false;
    
    118
    +    }
    
    110 119
       }
    
    111 120
     
    
    112 121
       onEvent(event, data, _callback) {
    

  • toolkit/modules/TorAndroidIntegration.sys.mjs
    ... ... @@ -48,6 +48,7 @@ const ListenedEvents = Object.freeze({
    48 48
       bootstrapBeginAuto: "GeckoView:Tor:BootstrapBeginAuto",
    
    49 49
       bootstrapCancel: "GeckoView:Tor:BootstrapCancel",
    
    50 50
       startAgain: "GeckoView:Tor:StartAgain",
    
    51
    +  restartProvider: "GeckoView:Tor:RestartProvider",
    
    51 52
       quickstartGet: "GeckoView:Tor:QuickstartGet",
    
    52 53
       quickstartSet: "GeckoView:Tor:QuickstartSet",
    
    53 54
       regionNamesGet: "GeckoView:Tor:RegionNamesGet",
    
    ... ... @@ -98,11 +99,6 @@ class TorAndroidIntegrationImpl {
    98 99
         lazy.TorConnect.init();
    
    99 100
     
    
    100 101
         lazy.TorDomainIsolator.init();
    
    101
    -
    
    102
    -    // On Android immediately call firstWindowLoaded. This should be safe to
    
    103
    -    // call since it will await the initialisation of the TorProvider set up
    
    104
    -    // by TorProviderBuilder.init.
    
    105
    -    lazy.TorProviderBuilder.firstWindowLoaded();
    
    106 102
       }
    
    107 103
     
    
    108 104
       observe(subj, topic) {
    
    ... ... @@ -203,6 +199,9 @@ class TorAndroidIntegrationImpl {
    203 199
             case ListenedEvents.startAgain:
    
    204 200
               lazy.TorConnect.startAgain();
    
    205 201
               break;
    
    202
    +        case ListenedEvents.restartProvider:
    
    203
    +          lazy.TorConnect.restartProvider();
    
    204
    +          break;
    
    206 205
             case ListenedEvents.quickstartGet:
    
    207 206
               callback?.onSuccess(lazy.TorConnect.quickstart);
    
    208 207
               return;
    

  • toolkit/modules/TorConnect.sys.mjs
    ... ... @@ -1109,12 +1109,9 @@ export const TorConnect = {
    1109 1109
           throw new Error(`Trying to set the stage to ${name} during a bootstrap`);
    
    1110 1110
         }
    
    1111 1111
         if (!this._providerRunning && name !== TorConnectStage.ProviderStopped) {
    
    1112
    -      if (!lazy.TorLauncherUtil.isAndroid) {
    
    1113
    -        // TODO: Remove Android exception.
    
    1114
    -        throw new Error(
    
    1115
    -          `Trying to set the stage to ${name} when provider is not running`
    
    1116
    -        );
    
    1117
    -      }
    
    1112
    +      throw new Error(
    
    1113
    +        `Trying to set the stage to ${name} when provider is not running`
    
    1114
    +      );
    
    1118 1115
         }
    
    1119 1116
     
    
    1120 1117
         lazy.logger.info(`Entering stage ${name}`);
    
    ... ... @@ -1596,13 +1593,8 @@ export const TorConnect = {
    1596 1593
           return;
    
    1597 1594
         }
    
    1598 1595
         if (!this._providerRunning && stage !== TorConnectStage.ProviderStopped) {
    
    1599
    -      if (!lazy.TorLauncherUtil.isAndroid) {
    
    1600
    -        // TODO: Remove Android exception.
    
    1601
    -        lazy.logger.warn(
    
    1602
    -          `Cannot move to ${stage} when provider is not running`
    
    1603
    -        );
    
    1604
    -        return;
    
    1605
    -      }
    
    1596
    +      lazy.logger.warn(`Cannot move to ${stage} when provider is not running`);
    
    1597
    +      return;
    
    1606 1598
         }
    
    1607 1599
         if (this._stageName === TorConnectStage.Loading) {
    
    1608 1600
           if (stage === TorConnectStage.ProviderStopped) {
    
    ... ... @@ -1709,13 +1701,7 @@ export const TorConnect = {
    1709 1701
             // But other methods should take into account that _providerRunning is now
    
    1710 1702
             // `false` to early return and guarantee that we enter this
    
    1711 1703
             // ProviderStopped stage.
    
    1712
    -        if (lazy.TorLauncherUtil.isAndroid) {
    
    1713
    -          // TODO: Remove this Android path when android supports the
    
    1714
    -          // `ProviderStopped` stage.
    
    1715
    -          this._makeStageRequest(TorConnectStage.Start, true);
    
    1716
    -        } else {
    
    1717
    -          this._makeStageRequest(TorConnectStage.ProviderStopped, true);
    
    1718
    -        }
    
    1704
    +        this._makeStageRequest(TorConnectStage.ProviderStopped, true);
    
    1719 1705
           }
    
    1720 1706
         }
    
    1721 1707