morgan pushed to branch tor-browser-128.5.0esr-14.5-1 at The Tor Project / Applications / Tor Browser

Commits:

9 changed files:

Changes:

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
    ... ... @@ -25,6 +25,7 @@ import android.view.MotionEvent
    25 25
     import android.view.View
    
    26 26
     import android.view.ViewConfiguration
    
    27 27
     import android.view.WindowManager.LayoutParams.FLAG_SECURE
    
    28
    +import androidx.activity.viewModels
    
    28 29
     import androidx.annotation.CallSuper
    
    29 30
     import androidx.annotation.IdRes
    
    30 31
     import androidx.annotation.RequiresApi
    
    ... ... @@ -32,7 +33,6 @@ import androidx.annotation.VisibleForTesting
    32 33
     import androidx.appcompat.app.ActionBar
    
    33 34
     import androidx.appcompat.widget.Toolbar
    
    34 35
     import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
    
    35
    -import androidx.core.content.ContentProviderCompat.requireContext
    
    36 36
     import androidx.lifecycle.lifecycleScope
    
    37 37
     import androidx.navigation.NavController
    
    38 38
     import androidx.navigation.fragment.NavHostFragment
    
    ... ... @@ -151,10 +151,10 @@ import org.mozilla.fenix.utils.Settings
    151 151
     import java.lang.ref.WeakReference
    
    152 152
     import java.util.Locale
    
    153 153
     
    
    154
    -import androidx.navigation.fragment.findNavController
    
    155 154
     import mozilla.components.browser.engine.gecko.GeckoEngine
    
    156
    -import mozilla.components.browser.state.selector.findCustomTab
    
    155
    +import org.mozilla.fenix.components.FenixSnackbar
    
    157 156
     import org.mozilla.fenix.home.HomeFragment
    
    157
    +import org.mozilla.fenix.tor.TorConnectionAssistViewModel
    
    158 158
     import org.mozilla.geckoview.TorIntegrationAndroid
    
    159 159
     
    
    160 160
     /**
    
    ... ... @@ -238,6 +238,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorIn
    238 238
     
    
    239 239
         private var dialog: RedirectDialogFragment? = null
    
    240 240
     
    
    241
    +    private val torConnectionAssistViewModel: TorConnectionAssistViewModel by viewModels()
    
    242
    +
    
    241 243
         @Suppress("ComplexMethod")
    
    242 244
         final override fun onCreate(savedInstanceState: Bundle?) {
    
    243 245
             // DO NOT MOVE ANYTHING ABOVE THIS getProfilerTime CALL.
    
    ... ... @@ -1115,6 +1117,25 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorIn
    1115 1117
             historyMetadata: HistoryMetadataKey? = null,
    
    1116 1118
             additionalHeaders: Map<String, String>? = null,
    
    1117 1119
         ) {
    
    1120
    +        if (!components.torController.isBootstrapped && !searchTermOrURL.startsWith("about:")) {
    
    1121
    +            FenixSnackbar.make(
    
    1122
    +                view = binding.root,
    
    1123
    +                isDisplayedWithBrowserToolbar = true,
    
    1124
    +            )
    
    1125
    +                .setText(getString(R.string.connection_assist_connect_to_tor_before_opening_links))
    
    1126
    +                .setAction(getString(R.string.connection_assist_connect_to_tor_before_opening_links_confirmation)) {
    
    1127
    +                    torConnectionAssistViewModel.handleConnect(searchTermOrURL)
    
    1128
    +                    if (navHost.navController.previousBackStackEntry?.destination?.id == R.id.torConnectionAssistFragment) {
    
    1129
    +                        supportFragmentManager.popBackStack()
    
    1130
    +                    } else {
    
    1131
    +                        navHost.navController.navigate(
    
    1132
    +                            TorConnectionAssistFragmentDirections.actionConnectToTorBeforeOpeningLinks()
    
    1133
    +                        )
    
    1134
    +                    }
    
    1135
    +                }
    
    1136
    +                .show()
    
    1137
    +            return
    
    1138
    +        }
    
    1118 1139
             openToBrowser(from, customTabSessionId)
    
    1119 1140
             load(
    
    1120 1141
                 searchTermOrURL = searchTermOrURL,
    
    ... ... @@ -1434,8 +1455,10 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorIn
    1434 1455
         override fun onBootstrapStateChange(state: String) = Unit
    
    1435 1456
         override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) = Unit
    
    1436 1457
         override fun onBootstrapComplete() {
    
    1437
    -        components.useCases.tabsUseCases.removeAllTabs()
    
    1438
    -        navHost.navController.navigate(NavGraphDirections.actionStartupHome())
    
    1458
    +        if (settings().useHtmlConnectionUi) {
    
    1459
    +            components.useCases.tabsUseCases.removeAllTabs()
    
    1460
    +            navHost.navController.navigate(NavGraphDirections.actionStartupHome())
    
    1461
    +        }
    
    1439 1462
         }
    
    1440 1463
         override fun onBootstrapError(code: String?, message: String?, phase: String?, reason: String?) = Unit
    
    1441 1464
     }

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt
    ... ... @@ -160,6 +160,7 @@ import org.mozilla.fenix.tabstray.TabsTrayAccessPoint
    160 160
     import org.mozilla.fenix.theme.FirefoxTheme
    
    161 161
     import org.mozilla.fenix.tor.TorBootstrapFragmentDirections
    
    162 162
     import org.mozilla.fenix.tor.TorBootstrapStatus
    
    163
    +import org.mozilla.fenix.tor.TorConnectionAssistViewModel
    
    163 164
     import org.mozilla.fenix.utils.Settings.Companion.TOP_SITES_PROVIDER_MAX_THRESHOLD
    
    164 165
     import org.mozilla.fenix.utils.allowUndo
    
    165 166
     import org.mozilla.fenix.wallpapers.Wallpaper
    
    ... ... @@ -179,6 +180,7 @@ class HomeFragment : Fragment(), UserInteractionHandler {
    179 180
         private val binding get() = _binding!!
    
    180 181
     
    
    181 182
         private val homeViewModel: HomeScreenViewModel by activityViewModels()
    
    183
    +    private val torConnectionAssistViewModel: TorConnectionAssistViewModel by activityViewModels()
    
    182 184
     
    
    183 185
         private val snackbarAnchorView: View?
    
    184 186
             get() = when (requireContext().settings().toolbarPosition) {
    
    ... ... @@ -899,6 +901,17 @@ class HomeFragment : Fragment(), UserInteractionHandler {
    899 901
                 view = view,
    
    900 902
             )
    
    901 903
     
    
    904
    +        torConnectionAssistViewModel.urlToLoadAfterConnecting.also {
    
    905
    +            if(!it.isNullOrBlank()){
    
    906
    +                (requireActivity() as HomeActivity).openToBrowserAndLoad(
    
    907
    +                    searchTermOrURL = it,
    
    908
    +                    newTab = true,
    
    909
    +                    from = BrowserDirection.FromHome,
    
    910
    +                )
    
    911
    +                torConnectionAssistViewModel.urlToLoadAfterConnecting = null // Only load this url once
    
    912
    +            }
    
    913
    +        }
    
    914
    +
    
    902 915
             // DO NOT MOVE ANYTHING BELOW THIS addMarker CALL!
    
    903 916
             requireComponents.core.engine.profiler?.addMarker(
    
    904 917
                 MarkersFragmentLifecycleCallbacks.MARKER_NAME,
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt
    ... ... @@ -25,6 +25,7 @@ import androidx.lifecycle.Observer
    25 25
     import androidx.lifecycle.lifecycleScope
    
    26 26
     import androidx.navigation.NavDirections
    
    27 27
     import androidx.navigation.findNavController
    
    28
    +import androidx.navigation.fragment.findNavController
    
    28 29
     import androidx.navigation.fragment.navArgs
    
    29 30
     import androidx.preference.Preference
    
    30 31
     import androidx.preference.PreferenceFragmentCompat
    
    ... ... @@ -40,6 +41,7 @@ import mozilla.components.concept.sync.OAuthAccount
    40 41
     import mozilla.components.concept.sync.Profile
    
    41 42
     import mozilla.components.feature.addons.ui.AddonFilePicker
    
    42 43
     import mozilla.components.service.glean.private.NoExtras
    
    44
    +import mozilla.components.support.base.feature.UserInteractionHandler
    
    43 45
     import mozilla.components.support.ktx.android.view.showKeyboard
    
    44 46
     import mozilla.components.ui.widgets.withCenterAlignedButtons
    
    45 47
     import org.mozilla.fenix.BrowserDirection
    
    ... ... @@ -77,7 +79,7 @@ import kotlin.system.exitProcess
    77 79
     import org.mozilla.fenix.GleanMetrics.Settings as SettingsMetrics
    
    78 80
     
    
    79 81
     @Suppress("LargeClass", "TooManyFunctions")
    
    80
    -class SettingsFragment : PreferenceFragmentCompat() {
    
    82
    +class SettingsFragment : PreferenceFragmentCompat(), UserInteractionHandler {
    
    81 83
     
    
    82 84
         private val args by navArgs<SettingsFragmentArgs>()
    
    83 85
         private lateinit var accountUiView: AccountUiView
    
    ... ... @@ -883,4 +885,18 @@ class SettingsFragment : PreferenceFragmentCompat() {
    883 885
             private const val FXA_SYNC_OVERRIDE_EXIT_DELAY = 2000L
    
    884 886
             private const val AMO_COLLECTION_OVERRIDE_EXIT_DELAY = 3000L
    
    885 887
         }
    
    888
    +
    
    889
    +    override fun onBackPressed(): Boolean {
    
    890
    +        // If tor is already bootstrapped, skip going back to [TorConnectionAssistFragment] and instead go directly to [HomeFragment]
    
    891
    +        if (requireComponents.torController.isBootstrapped) {
    
    892
    +            val navController = findNavController()
    
    893
    +            if (navController.previousBackStackEntry?.destination?.id == R.id.torConnectionAssistFragment) {
    
    894
    +                navController.navigate(
    
    895
    +                    SettingsFragmentDirections.actionGlobalHomeFragment(),
    
    896
    +                )
    
    897
    +                return true
    
    898
    +            }
    
    899
    +        }
    
    900
    +        return false
    
    901
    +    }
    
    886 902
     }

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistFragment.kt
    ... ... @@ -19,7 +19,7 @@ import android.view.View
    19 19
     import android.view.ViewGroup
    
    20 20
     import androidx.appcompat.content.res.AppCompatResources
    
    21 21
     import androidx.fragment.app.Fragment
    
    22
    -import androidx.fragment.app.viewModels
    
    22
    +import androidx.fragment.app.activityViewModels
    
    23 23
     import androidx.lifecycle.Lifecycle
    
    24 24
     import androidx.lifecycle.lifecycleScope
    
    25 25
     import androidx.lifecycle.repeatOnLifecycle
    
    ... ... @@ -34,7 +34,7 @@ import org.mozilla.fenix.ext.hideToolbar
    34 34
     class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
    
    35 35
     
    
    36 36
         private val TAG = "TorConnectionAssistFrag"
    
    37
    -    private val viewModel: TorConnectionAssistViewModel by viewModels()
    
    37
    +    private val viewModel: TorConnectionAssistViewModel by activityViewModels()
    
    38 38
         private var _binding: FragmentTorConnectionAssistBinding? = null
    
    39 39
         private val binding get() = _binding!!
    
    40 40
     
    
    ... ... @@ -46,6 +46,11 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
    46 46
             _binding = FragmentTorConnectionAssistBinding.inflate(
    
    47 47
                 inflater, container, false,
    
    48 48
             )
    
    49
    +        viewLifecycleOwner.lifecycleScope.launch {
    
    50
    +            repeatOnLifecycle(Lifecycle.State.STARTED) {
    
    51
    +                viewModel.collectLastKnownStatus()
    
    52
    +            }
    
    53
    +        }
    
    49 54
     
    
    50 55
             viewLifecycleOwner.lifecycleScope.launch {
    
    51 56
                 repeatOnLifecycle(Lifecycle.State.STARTED) {
    
    ... ... @@ -62,7 +67,6 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
    62 67
         override fun onResume() {
    
    63 68
             super.onResume()
    
    64 69
             hideToolbar()
    
    65
    -        viewModel.handleTorConnectStateToScreen() // Covers the case where the app is backgrounded when the bootstrap finishes
    
    66 70
         }
    
    67 71
     
    
    68 72
         override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    
    ... ... @@ -71,11 +75,7 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
    71 75
             viewModel.progress().observe(
    
    72 76
                 viewLifecycleOwner,
    
    73 77
             ) { progress ->
    
    74
    -            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    
    75
    -                binding.torBootstrapProgressBar.setProgress(progress, true)
    
    76
    -            } else {
    
    77
    -                binding.torBootstrapProgressBar.progress = progress
    
    78
    -            }
    
    78
    +            setProgressBarCompat(progress)
    
    79 79
             }
    
    80 80
     
    
    81 81
             viewModel.quickstartToggle().observe(
    
    ... ... @@ -95,6 +95,14 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
    95 95
     
    
    96 96
         }
    
    97 97
     
    
    98
    +    private fun setProgressBarCompat(progress: Int) {
    
    99
    +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    
    100
    +            binding.torBootstrapProgressBar.setProgress(progress, true)
    
    101
    +        } else {
    
    102
    +            binding.torBootstrapProgressBar.progress = progress
    
    103
    +        }
    
    104
    +    }
    
    105
    +
    
    98 106
         private fun showScreen(screen: ConnectAssistUiState) {
    
    99 107
             setProgressBar(screen)
    
    100 108
             setSettingsButton(screen)
    
    ... ... @@ -269,7 +277,7 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
    269 277
     
    
    270 278
         private fun openHome() {
    
    271 279
             Log.d(TAG, "openHome()")
    
    272
    -        findNavController().navigate(TorConnectionAssistFragmentDirections.actionStartupHome())
    
    280
    +        viewModel.openHome(findNavController())
    
    273 281
         }
    
    274 282
     
    
    275 283
         private fun openSettings(preferenceToScrollTo: String? = null) {
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistViewModel.kt
    ... ... @@ -10,6 +10,7 @@ import androidx.lifecycle.AndroidViewModel
    10 10
     import androidx.lifecycle.LifecycleCoroutineScope
    
    11 11
     import androidx.lifecycle.LiveData
    
    12 12
     import androidx.lifecycle.MutableLiveData
    
    13
    +import androidx.navigation.NavController
    
    13 14
     import kotlinx.coroutines.flow.MutableStateFlow
    
    14 15
     import kotlinx.coroutines.flow.StateFlow
    
    15 16
     import org.mozilla.fenix.ext.components
    
    ... ... @@ -44,20 +45,25 @@ class TorConnectionAssistViewModel(
    44 45
         }
    
    45 46
     
    
    46 47
         init {
    
    47
    -        Log.d(TAG, "initiating TorConnectionAssistViewModel")
    
    48
    +        Log.d(TAG, "initiating TorConnectionAssistViewModel $this")
    
    48 49
             _torController.registerTorListener(this)
    
    49
    -        handleTorConnectStateToScreen() // should cover the case of when we have an onBootStrapStateChange() event before this is initialized, which lead to being stuck on the splash screen
    
    50 50
         }
    
    51 51
     
    
    52
    -    private fun handleConnect(
    
    52
    +    var urlToLoadAfterConnecting: String? = null
    
    53
    +
    
    54
    +    fun handleConnect(
    
    55
    +        urlToLoadAfterConnecting: String? = null,
    
    53 56
             withDebugLogging: Boolean = false,
    
    54 57
             lifecycleScope: LifecycleCoroutineScope? = null,
    
    55 58
         ) {
    
    56
    -        Log.d(TAG, "handleConnect initiatingTorBootstrap with lifecycleScope = $lifecycleScope")
    
    57
    -        _torController.initiateTorBootstrap(
    
    58
    -            withDebugLogging = withDebugLogging,
    
    59
    -            lifecycleScope = lifecycleScope,
    
    60
    -        )
    
    59
    +        this.urlToLoadAfterConnecting = urlToLoadAfterConnecting
    
    60
    +        if (_torController.lastKnownStatus.value.isOff()) {
    
    61
    +            Log.d(TAG, "handleConnect() triggered, initiatingTorBootstrap")
    
    62
    +            _torController.initiateTorBootstrap(
    
    63
    +                withDebugLogging = withDebugLogging,
    
    64
    +                lifecycleScope = lifecycleScope,
    
    65
    +            )
    
    66
    +        }
    
    61 67
         }
    
    62 68
     
    
    63 69
         fun handleQuickstartChecked(checked: Boolean) {
    
    ... ... @@ -96,18 +102,19 @@ class TorConnectionAssistViewModel(
    96 102
                 _progress.value = progress.toInt()
    
    97 103
             }
    
    98 104
     
    
    99
    -        handleTorConnectStateToScreen()
    
    100 105
         }
    
    101 106
     
    
    102
    -    fun handleTorConnectStateToScreen() {
    
    103
    -        when (_torController.lastKnownStatus) {
    
    104
    -            TorConnectState.Initial -> _torConnectScreen.value = ConnectAssistUiState.Splash
    
    105
    -            TorConnectState.Configuring -> handleConfiguring()
    
    106
    -            TorConnectState.AutoBootstrapping -> handleBootstrap()
    
    107
    -            TorConnectState.Bootstrapping -> handleBootstrap()
    
    108
    -            TorConnectState.Bootstrapped -> _shouldOpenHome.value = true
    
    109
    -            TorConnectState.Disabled -> _shouldOpenHome.value = true
    
    110
    -            TorConnectState.Error -> handleError()
    
    107
    +    suspend fun collectLastKnownStatus() {
    
    108
    +        _torController.lastKnownStatus.collect {
    
    109
    +            when (it) {
    
    110
    +                TorConnectState.Initial -> _torConnectScreen.value = ConnectAssistUiState.Splash
    
    111
    +                TorConnectState.Configuring -> handleConfiguring()
    
    112
    +                TorConnectState.AutoBootstrapping -> handleBootstrap()
    
    113
    +                TorConnectState.Bootstrapping -> handleBootstrap()
    
    114
    +                TorConnectState.Bootstrapped -> _shouldOpenHome.value = true
    
    115
    +                TorConnectState.Disabled -> _shouldOpenHome.value = true
    
    116
    +                TorConnectState.Error -> handleError()
    
    117
    +            }
    
    111 118
             }
    
    112 119
         }
    
    113 120
     
    
    ... ... @@ -254,4 +261,10 @@ class TorConnectionAssistViewModel(
    254 261
             }
    
    255 262
             return true
    
    256 263
         }
    
    264
    +
    
    265
    +    fun openHome(navController: NavController) {
    
    266
    +        navController.navigate(
    
    267
    +            TorConnectionAssistFragmentDirections.actionHome(),
    
    268
    +        )
    
    269
    +    }
    
    257 270
     }

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerGV.kt
    ... ... @@ -4,6 +4,8 @@ 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
    
    7 9
     import mozilla.components.browser.engine.gecko.GeckoEngine
    
    8 10
     import org.mozilla.fenix.ext.components
    
    9 11
     import org.mozilla.geckoview.TorIntegrationAndroid
    
    ... ... @@ -54,20 +56,22 @@ class TorControllerGV(
    54 56
         private var torListeners = mutableListOf<TorEvents>()
    
    55 57
         private var torLogListeners = mutableListOf<TorLogs>()
    
    56 58
     
    
    57
    -    internal var lastKnownStatus = TorConnectState.Initial
    
    59
    +    private val _lastKnownStatus = MutableStateFlow(TorConnectState.Initial)
    
    60
    +    internal val lastKnownStatus: StateFlow<TorConnectState> = _lastKnownStatus
    
    61
    +
    
    58 62
         internal var lastKnownError: TorError? = null
    
    59 63
         private var wasTorBootstrapped = false
    
    60 64
         private var isTorRestarting = false
    
    61 65
     
    
    62 66
         private var isTorBootstrapped = false
    
    63
    -        get() = ((lastKnownStatus.isStarted()) && wasTorBootstrapped)
    
    67
    +        get() = ((_lastKnownStatus.value.isStarted()) && wasTorBootstrapped)
    
    64 68
     
    
    65 69
         private val entries = mutableListOf<Pair<String?, String?>>()
    
    66 70
         override val logEntries get() = entries
    
    67
    -    override val isStarting get() = lastKnownStatus.isStarting()
    
    71
    +    override val isStarting get() = _lastKnownStatus.value.isStarting()
    
    68 72
         override val isRestarting get() = isTorRestarting
    
    69 73
         override val isBootstrapped get() = isTorBootstrapped
    
    70
    -    override val isConnected get() = (lastKnownStatus.isStarted() && !isTorRestarting)
    
    74
    +    override val isConnected get() = (_lastKnownStatus.value.isStarted() && !isTorRestarting)
    
    71 75
     
    
    72 76
         override var quickstart: Boolean
    
    73 77
             get() {
    
    ... ... @@ -267,13 +271,13 @@ class TorControllerGV(
    267 271
         }
    
    268 272
     
    
    269 273
         override fun setTorStopped() {
    
    270
    -        lastKnownStatus = TorConnectState.Configuring
    
    274
    +        _lastKnownStatus.value = TorConnectState.Configuring
    
    271 275
             onTorStatusUpdate(null, lastKnownStatus.toString(), 0.0)
    
    272 276
             onTorStopped()
    
    273 277
         }
    
    274 278
     
    
    275 279
         override fun restartTor() {
    
    276
    -        if (!lastKnownStatus.isStarted() && wasTorBootstrapped) {
    
    280
    +        if (!_lastKnownStatus.value.isStarted() && wasTorBootstrapped) {
    
    277 281
                 // If we aren't started, but we were previously bootstrapped,
    
    278 282
                 // then we handle a "restart" request as a "start" restart
    
    279 283
                 initiateTorBootstrap()
    
    ... ... @@ -321,42 +325,22 @@ class TorControllerGV(
    321 325
                 }
    
    322 326
             }
    
    323 327
     
    
    324
    -        if (lastKnownStatus.isOff() && newState.isStarting()) {
    
    328
    +        if (_lastKnownStatus.value.isOff() && newState.isStarting()) {
    
    325 329
                 isTorRestarting = false
    
    326 330
             }
    
    327 331
     
    
    328
    -        lastKnownStatus = newState
    
    332
    +        _lastKnownStatus.value = newState
    
    329 333
             onTorStatusUpdate(null, newStateVal, null)
    
    330 334
         }
    
    331 335
     
    
    332 336
         // TorEventsBootstrapStateChangeListener
    
    333 337
         override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) {
    
    334
    -        Log.d(TAG, "onBootstrapProgress($progress, $hasWarnings)")
    
    335
    -	// TODO: onBootstrapProgress should only be used to change the shown
    
    336
    -	// bootstrap percentage or a Tor log option during a "Bootstrapping"
    
    337
    -	// stage.
    
    338
    -	// The progress value should not be used to change the `lastKnownStatus`
    
    339
    -	// value or determine if a bootstrap has started or completed. The
    
    340
    -	// TorConnectStage should be used instead.
    
    341
    -        if (progress == 100.0) {
    
    342
    -            lastKnownStatus = TorConnectState.Bootstrapped
    
    343
    -            wasTorBootstrapped = true
    
    344
    -            onTorConnected()
    
    345
    -        } else if (lastKnownStatus == TorConnectState.Bootstrapping) {
    
    346
    -            onTorConnecting()
    
    347
    -        }
    
    348
    -        onTorStatusUpdate("", lastKnownStatus.toTorStatus().status, progress)
    
    338
    +        Log.d(TAG, "onBootstrapProgress(progress = $progress, hasWarnings = $hasWarnings)")
    
    339
    +        onTorStatusUpdate("", _lastKnownStatus.value.toTorStatus().status, progress)
    
    349 340
         }
    
    350 341
     
    
    351 342
         // TorEventsBootstrapStateChangeListener
    
    352
    -    override fun onBootstrapComplete() {
    
    353
    -	// TODO: There should be no need to respond to the BootstrapComplete
    
    354
    -	// event if we are already handling TorConnectStage.Bootstrapped.
    
    355
    -	// In particular, `lastKnownStatus` and onTorConnected should be set in
    
    356
    -	// response to a change in TorConnectStage instead.
    
    357
    -        lastKnownStatus = TorConnectState.Bootstrapped
    
    358
    -        this.onTorConnected()
    
    359
    -    }
    
    343
    +    override fun onBootstrapComplete() = Unit
    
    360 344
     
    
    361 345
         // TorEventsBootstrapStateChangeListener
    
    362 346
         override fun onBootstrapError(code: String?, message: String?, phase: String?, reason: String?) {
    

  • mobile/android/fenix/app/src/main/res/layout/fenix_snackbar.xml
    ... ... @@ -21,6 +21,12 @@
    21 21
             android:paddingStart="16dp"
    
    22 22
             android:paddingEnd="16dp">
    
    23 23
     
    
    24
    +        <!--
    
    25
    +        TextView below changed as part of tor-browser#43229 to match the designs
    
    26
    +        https://www.figma.com/design/vXrWeiV2IlKx5IIZVLtxBX/Android-Components?node-id=1807-3117&t=8Gc1mpPYPQCLMYH2-1 screenshot shown here
    
    27
    +        Line spacing eyeballed from screenshot here
    
    28
    +        https://gitlab.torproject.org/tpo/applications/tor-browser/-/merge_requests/1275#note_3125666
    
    29
    +        -->
    
    24 30
             <TextView
    
    25 31
                 android:id="@+id/snackbar_text"
    
    26 32
                 android:layout_width="0dp"
    
    ... ... @@ -29,8 +35,9 @@
    29 35
                 android:letterSpacing="0.05"
    
    30 36
                 android:minHeight="46dp"
    
    31 37
                 android:maxLines="2"
    
    32
    -            android:paddingTop="8dp"
    
    33
    -            android:paddingBottom="8dp"
    
    38
    +            android:paddingTop="12dp"
    
    39
    +            android:paddingBottom="12dp"
    
    40
    +            android:lineSpacingExtra="8sp"
    
    34 41
                 android:textAlignment="textStart"
    
    35 42
                 android:textColor="@color/photonWhite"
    
    36 43
                 android:textSize="18sp"
    

  • mobile/android/fenix/app/src/main/res/navigation/nav_graph.xml
    ... ... @@ -27,6 +27,12 @@
    27 27
             app:popUpTo="@id/startupFragment"
    
    28 28
             app:popUpToInclusive="true" />
    
    29 29
     
    
    30
    +    <action
    
    31
    +        android:id="@+id/action_connect_to_tor_before_opening_links"
    
    32
    +        app:destination="@+id/torConnectionAssistFragment"
    
    33
    +        app:popUpTo="@id/torConnectionAssistFragment"
    
    34
    +        app:popUpToInclusive="true"/>
    
    35
    +
    
    30 36
         <action
    
    31 37
             android:id="@+id/action_global_home"
    
    32 38
             app:destination="@id/homeFragment"
    
    ... ... @@ -264,7 +270,7 @@
    264 270
         <fragment
    
    265 271
             android:id="@+id/torConnectionAssistFragment"
    
    266 272
             android:name="org.mozilla.fenix.tor.TorConnectionAssistFragment"
    
    267
    -        tools:layout="@layout/fragment_home">
    
    273
    +        tools:layout="@layout/fragment_tor_connection_assist">
    
    268 274
             <action
    
    269 275
                 android:id="@+id/action_home"
    
    270 276
                 app:destination="@id/homeFragment"
    

  • mobile/android/fenix/app/src/main/res/values/torbrowser_strings.xml
    ... ... @@ -149,4 +149,31 @@
    149 149
         <string name="connection_assist_final_error_troubleshoot_connection_link">troubleshooting your connection</string>
    
    150 150
         <!-- Connection assist. -->
    
    151 151
         <string name="connection_assist_final_error_learn_more_link">Learn more</string>
    
    152
    +
    
    153
    +    <!-- Connection assist. Description for a shown "Snackbar" (special popup notification) with an action to connect -->
    
    154
    +    <string name="connection_assist_connect_to_tor_before_opening_links">Connect to Tor before opening links</string>
    
    155
    +    <!-- Connection assist. Confirmation button for a shown "Snackbar" (special popup notification) that has a previously mentioned description. Automatically shown in ALL CAPS if available, regardless of the localized string -->
    
    156
    +    <string name="connection_assist_connect_to_tor_before_opening_links_confirmation">CONNECT</string>
    
    157
    +
    
    158
    +    <!-- 2024 YEC. -->
    
    159
    +    <string name="YEC_2024_right_to_speak">You have a right to SPEAK without uninvited listeners.</string>
    
    160
    +    <!-- 2024 YEC. -->
    
    161
    +    <string name="YEC_2024_right_to_BROWSE">You have a right to BROWSE without being watched.</string>
    
    162
    +    <!-- 2024 YEC. -->
    
    163
    +    <string name="YEC_2024_right_to_SEARCH">You have a right to SEARCH without being followed.</string>
    
    164
    +
    
    165
    +    <!-- 2024 YEC. -->
    
    166
    +    <string name="YEC_2024_donation_encouragement">Join the thousands of Tor supporters building an internet powered by privacy. Make a donation today.</string>
    
    167
    +
    
    168
    +    <!-- 2024 YEC. -->
    
    169
    +    <string name="YEC_2024_donation_match_text">Through December 31, your gift will be matched, up to $300,000!</string>
    
    170
    +
    
    171
    +    <!-- 2024 YEC. %1$s is the app name "Tor Browser". Since this will only ever show on release, it will always be "Tor Browser" (and not "Tor Browser Alpha" for instance) -->
    
    172
    +    <string name="YEC_2024_tor_browser_for_android_will_always_be_free_no_donation_required">%1$s for Android will always be free to use—no donation is required to use this app.</string>
    
    173
    +
    
    174
    +    <!-- 2024 YEC. Accessible name for the "X" button. -->
    
    175
    +    <string name="YEC_2024_close">Close</string>
    
    176
    +
    
    177
    +    <!-- 2024 YEC. -->
    
    178
    +    <string name="YEC_2024_donate_now">Donate now</string>
    
    152 179
     </resources>