[tor-commits] [Git][tpo/applications/firefox-android][firefox-android-115.2.1-13.5-1] Enable the connect assist experiments on alpha

Pier Angelo Vendrame (@pierov) git at gitlab.torproject.org
Thu Dec 21 21:57:42 UTC 2023



Pier Angelo Vendrame pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android


Commits:
48593938 by clairehurst at 2023-12-21T14:48:46-07:00
Enable the connect assist experiments on alpha

- - - - -


13 changed files:

- android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngine.kt
- android-components/components/concept/engine/src/main/java/mozilla/components/concept/engine/Settings.kt
- fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
- fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt
- fenix/app/src/main/java/org/mozilla/fenix/components/Core.kt
- fenix/app/src/main/java/org/mozilla/fenix/settings/TorNetworkSettingsFragment.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/TorBetaConnectionFeaturesFragment.kt
- fenix/app/src/main/java/org/mozilla/fenix/tor/TorBootstrapFragment.kt
- fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt
- + fenix/app/src/main/res/layout/tor_network_settings_beta_connection_features.xml
- fenix/app/src/main/res/navigation/nav_graph.xml
- fenix/app/src/main/res/values/preference_keys.xml
- fenix/app/src/main/res/xml/tor_network_settings_preferences.xml


Changes:

=====================================
android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngine.kt
=====================================
@@ -799,6 +799,11 @@ class GeckoEngine(
         override var prioritizeOnions: Boolean
             get() = runtime.settings.prioritizeOnions
             set(value) { runtime.settings.prioritizeOnions = value }
+        override var useNewBootstrap: Boolean
+            get() = runtime.settings.useNewBootstrap
+            set(value) {
+                runtime.settings.useNewBootstrap = value
+            }
     }.apply {
         defaultSettings?.let {
             this.javascriptEnabled = it.javascriptEnabled
@@ -824,6 +829,7 @@ class GeckoEngine(
             this.torSecurityLevel = it.torSecurityLevel
             this.spoofEnglish = it.spoofEnglish
             this.prioritizeOnions = it.prioritizeOnions
+            this.useNewBootstrap = it.useNewBootstrap
         }
     }
 
@@ -929,6 +935,8 @@ class GeckoEngine(
             unBlockedBySmartBlock = this.blockingData.any { it.unBlockedBySmartBlock() },
         )
     }
+
+    fun getTorIntegrationController() = runtime.getTorIntegrationController()
 }
 
 internal fun ContentBlockingController.LogEntry.BlockingData.hasBlockedCookies(): Boolean {


=====================================
android-components/components/concept/engine/src/main/java/mozilla/components/concept/engine/Settings.kt
=====================================
@@ -214,6 +214,8 @@ abstract class Settings {
     open var spoofEnglish: Boolean by UnsupportedSetting()
 
     open var prioritizeOnions: Boolean by UnsupportedSetting()
+
+    open var useNewBootstrap: Boolean by UnsupportedSetting()
 }
 
 /**
@@ -259,6 +261,7 @@ data class DefaultSettings(
     override var torSecurityLevel: Int = 4,
     override var spoofEnglish: Boolean = false,
     override var prioritizeOnions: Boolean = false,
+    override var useNewBootstrap: Boolean = false,
 ) : Settings()
 
 class UnsupportedSetting<T> {


=====================================
fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
=====================================
@@ -164,6 +164,11 @@ import org.mozilla.fenix.utils.Settings
 import java.lang.ref.WeakReference
 import java.util.Locale
 
+import androidx.navigation.fragment.findNavController
+import mozilla.components.browser.engine.gecko.GeckoEngine
+import mozilla.components.browser.state.selector.findCustomTab
+import org.mozilla.geckoview.TorIntegrationAndroid
+
 /**
  * The main activity of the application. The application is primarily a single Activity (this one)
  * with fragments switching out to display different views. The most important views shown here are the:
@@ -171,7 +176,7 @@ import java.util.Locale
  * - browser screen
  */
 @SuppressWarnings("TooManyFunctions", "LargeClass", "LongParameterList", "LongMethod")
-open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
+open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorIntegrationAndroid.BootstrapStateChangeListener {
     // DO NOT MOVE ANYTHING ABOVE THIS, GETTING INIT TIME IS CRITICAL
     // we need to store startup timestamp for warm startup. we cant directly store
     // inside AppStartupTelemetry since that class lives inside components and
@@ -201,7 +206,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
 
     private var inflater: LayoutInflater? = null
 
-    private val navHost by lazy {
+    val navHost by lazy {
         supportFragmentManager.findFragmentById(R.id.container) as NavHostFragment
     }
 
@@ -396,6 +401,12 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
 
         components.notificationsDelegate.bindToActivity(this)
 
+        val engine = components.core.engine
+        if (engine is GeckoEngine) {
+            val torIntegration = engine.getTorIntegrationController()
+            torIntegration.registerBootstrapStateChangeListener(this)
+        }
+
         StartupTimeline.onActivityCreateEndHome(this) // DO NOT MOVE ANYTHING BELOW HERE.
     }
 
@@ -609,6 +620,12 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
             // underlying Application, as well.
             (application as FenixApplication).terminate()
         }
+
+        val engine = components.core.engine
+        if (engine is GeckoEngine) {
+            val torIntegration = engine.getTorIntegrationController()
+            torIntegration.unregisterBootstrapStateChangeListener(this)
+        }
     }
 
     override fun onConfigurationChanged(newConfig: Configuration) {
@@ -1163,7 +1180,20 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
     }
 
     open fun navigateToHome() {
-        navHost.navController.navigate(NavGraphDirections.actionStartupTorbootstrap())
+        if (settings().useNewBootstrap) {
+            if (settings().useNewBootstrapNativeUi) {
+                navHost.navController.navigate(NavGraphDirections.actionStartupTorConnectionAssist())
+            } else {
+                navHost.navController.navigate(NavGraphDirections.actionStartupHome())
+                openToBrowserAndLoad(
+                    searchTermOrURL = "about:torconnect",
+                    newTab = true,
+                    from = BrowserDirection.FromHome,
+                )
+            }
+        } else {
+            navHost.navController.navigate(NavGraphDirections.actionStartupTorbootstrap())
+        }
     }
 
     override fun attachBaseContext(base: Context) {
@@ -1341,4 +1371,15 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
         // telemetry purposes.
         const val PWA_RECENTLY_USED_THRESHOLD = DateUtils.DAY_IN_MILLIS * 30L
     }
+
+    override fun onBootstrapStateChange(state: String) = Unit
+    override fun onBootstrapProgress(progress: Double, status: String, hasWarnings: Boolean) = Unit
+    override fun onBootstrapComplete() {
+        components.useCases.tabsUseCases.removeAllTabs()
+        navHost.navController.navigate(NavGraphDirections.actionStartupHome())
+    }
+    override fun onBootstrapError(message: String, details: String) = Unit
+    override fun onSettingsRequested() {
+        navHost.navController.navigate(NavGraphDirections.actionGlobalSettingsFragment())
+    }
 }


=====================================
fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt
=====================================
@@ -1189,6 +1189,9 @@ abstract class BaseBrowserFragment :
                 val context = requireContext()
                 resumeDownloadDialogState(selectedTab.id, context.components.core.store, context, toolbarHeight)
                 it.announceForAccessibility(selectedTab.toDisplayTitle())
+                if (getCurrentTab()?.content?.url == "about:torconnect") {
+                    browserToolbarView.view.visibility = View.GONE
+                }
             }
         } else {
             view?.let { view -> initializeUI(view) }
@@ -1206,6 +1209,24 @@ abstract class BaseBrowserFragment :
             components.useCases.sessionUseCases.reload()
         }
         hideToolbar()
+        handleBetaHtmlTorConnect()
+    }
+
+    private fun handleBetaHtmlTorConnect() {
+        if (getCurrentTab()?.content?.url == "about:torconnect") {
+            if (!requireActivity().settings().useNewBootstrap) {
+                requireContext().components.useCases.tabsUseCases.removeAllTabs()
+                (requireActivity() as HomeActivity).navHost.navController.navigate(
+                    NavGraphDirections.actionStartupTorbootstrap(),
+                )
+            } else if (!requireActivity().settings().useNewBootstrapHtmlUi) {
+                requireContext().components.useCases.tabsUseCases.removeAllTabs()
+                (requireActivity() as HomeActivity).navigateToHome()
+            } else {
+                // This just makes it not flash (be visible for a split second) before handleTabSelected() hides it again
+                browserToolbarView.view.visibility = View.GONE
+            }
+        }
     }
 
     @CallSuper


=====================================
fenix/app/src/main/java/org/mozilla/fenix/components/Core.kt
=====================================
@@ -146,6 +146,7 @@ class Core(
             torSecurityLevel = context.settings().torSecurityLevel().intRepresentation,
             spoofEnglish = context.settings().spoofEnglish,
             prioritizeOnions = context.settings().prioritizeOnions,
+            useNewBootstrap = context.settings().useNewBootstrap,
         )
 
         GeckoEngine(


=====================================
fenix/app/src/main/java/org/mozilla/fenix/settings/TorNetworkSettingsFragment.kt
=====================================
@@ -76,6 +76,15 @@ class TorNetworkSettingsFragment : PreferenceFragmentCompat(), TorEvents {
             }
         }
 
+        requirePreference<Preference>(R.string.pref_key_use_new_bootstrap).apply {
+            setOnPreferenceClickListener {
+                val directions =
+                    TorNetworkSettingsFragmentDirections.actionTorNetworkSettingsFragmentToBetaConnectionFeaturesFragment()
+                requireView().findNavController().navigate(directions)
+                true
+            }
+        }
+
         setStatus()
     }
 


=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorBetaConnectionFeaturesFragment.kt
=====================================
@@ -0,0 +1,69 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.tor
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.children
+import androidx.fragment.app.Fragment
+import org.mozilla.fenix.databinding.TorNetworkSettingsBetaConnectionFeaturesBinding
+import org.mozilla.fenix.ext.components
+import org.mozilla.fenix.ext.settings
+
+/**
+ * Lets the user customize beta connection features mode.
+ */
+class TorBetaConnectionFeaturesFragment : Fragment() {
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?,
+    ): View {
+        val binding = TorNetworkSettingsBetaConnectionFeaturesBinding.inflate(inflater)
+
+        binding.enableBetaConnectionFeaturesSwitch.run {
+            isChecked = context.settings().useNewBootstrap
+            setConnectionAssistUI(binding, isChecked)
+
+            setOnCheckedChangeListener { _, isConnectionAssistEnabled ->
+                context.settings().useNewBootstrap = isConnectionAssistEnabled
+                setConnectionAssistUI(binding, isConnectionAssistEnabled)
+                updateEngineConnectionAssistMode()
+            }
+        }
+
+        // Since the beta connection features modes are in a RadioGroup we only need one listener to know of all their changes.
+        binding.useNewBootstrapWithNativeUiRadioButton.setOnCheckedChangeListener { _, _ ->
+            updateEngineConnectionAssistMode()
+        }
+
+        return binding.root
+    }
+
+    private fun setConnectionAssistUI(
+        binding: TorNetworkSettingsBetaConnectionFeaturesBinding,
+        isBetaConnectionAssistEnabled: Boolean,
+    ) {
+        if (!isBetaConnectionAssistEnabled) {
+            binding.enableBetaConnectionFeaturesModes.apply {
+                clearCheck()
+                children.forEach { it.isEnabled = false }
+            }
+        } else {
+            // Do not enable the native UI until it is actually available.
+            // binding.enableBetaConnectionFeaturesModes.children.forEach { it.isEnabled = true }
+            binding.useNewBootstrapWithHtmlUiRadioButton.isEnabled = true
+            binding.useNewBootstrapWithNativeUiRadioButton.isEnabled = false
+        }
+    }
+
+    private fun updateEngineConnectionAssistMode() {
+        requireContext().components.core.engine.settings.useNewBootstrap =
+            requireContext().settings().useNewBootstrap
+    }
+
+}


=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorBootstrapFragment.kt
=====================================
@@ -20,8 +20,10 @@ import org.mozilla.fenix.tor.interactor.DefaultTorBootstrapInteractor
 import org.mozilla.fenix.tor.interactor.TorBootstrapInteractor
 import androidx.navigation.fragment.findNavController
 import com.google.android.material.appbar.AppBarLayout
+import org.mozilla.fenix.HomeActivity
 import org.mozilla.fenix.ext.components
 import org.mozilla.fenix.ext.hideToolbar
+import org.mozilla.fenix.ext.settings
 import org.mozilla.fenix.tor.controller.DefaultTorBootstrapController
 import org.mozilla.fenix.tor.view.TorBootstrapView
 
@@ -169,6 +171,9 @@ class TorBootstrapFragment : Fragment() {
         // triggered to cause an automatic update on warm start (no tab selection occurs). So we
         // update it manually here.
         requireComponents.useCases.sessionUseCases.updateLastAccess()
+        if (requireContext().settings().useNewBootstrap){
+            (requireActivity() as HomeActivity).navigateToHome()
+        }
     }
 
     private fun handleTorBootstrapConnect() {


=====================================
fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt
=====================================
@@ -1859,4 +1859,19 @@ class Settings(private val appContext: Context) : PreferencesHolder {
      * Indicates if the new Search settings UI is enabled.
      */
     var enableUnifiedSearchSettingsUI: Boolean = showUnifiedSearchFeature && FeatureFlags.unifiedSearchSettings
+
+    var useNewBootstrap by booleanPreference(
+        appContext.getPreferenceKey(R.string.pref_key_use_new_bootstrap),
+        default = false,
+    )
+
+    var useNewBootstrapNativeUi by booleanPreference(
+        appContext.getPreferenceKey(R.string.pref_key_use_new_bootstrap_with_android_native),
+        default = false,
+    )
+
+    var useNewBootstrapHtmlUi by booleanPreference(
+        appContext.getPreferenceKey(R.string.pref_key_use_new_bootstrap_with_html),
+        default = true
+    )
 }


=====================================
fenix/app/src/main/res/layout/tor_network_settings_beta_connection_features.xml
=====================================
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?><!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <TextView
+        android:id="@+id/enable_beta_connection_features_title"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="16dp"
+        android:layout_marginBottom="2dp"
+        android:clickable="false"
+        android:text="Enable beta connection features"
+        android:textAppearance="@style/ListItemTextStyle"
+        android:textSize="16sp"
+        app:layout_constraintBottom_toTopOf="@id/enable_beta_connection_features_summary"
+        app:layout_constraintEnd_toStartOf="@id/enable_beta_connection_features_switch"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:lineHeight="24.sp" />
+
+    <TextView
+        android:id="@+id/enable_beta_connection_features_summary"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:text="Help us test our new connection assist features which focuses on a streamlined connection with better integration with bridges"
+        android:textColor="?attr/textSecondary"
+        android:textColorLink="?attr/textSecondary"
+        android:textSize="12sp"
+        app:layout_constraintBottom_toTopOf="@id/enable_beta_connection_features_modes"
+        app:layout_constraintEnd_toEndOf="@id/enable_beta_connection_features_title"
+        app:layout_constraintStart_toStartOf="@id/enable_beta_connection_features_title"
+        app:layout_constraintTop_toBottomOf="@id/enable_beta_connection_features_title"
+        app:lineHeight="16.sp" />
+
+    <androidx.appcompat.widget.SwitchCompat
+        android:id="@+id/enable_beta_connection_features_switch"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minHeight="48dp"
+        android:paddingStart="18dp"
+        android:paddingEnd="18dp"
+        android:textColor="@color/state_list_text_color"
+        android:textOff="@string/studies_off"
+        android:textOn="@string/studies_on"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="@id/enable_beta_connection_features_title" />
+
+    <RadioGroup
+        android:id="@+id/enable_beta_connection_features_modes"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/enable_beta_connection_features_summary">
+
+        <org.mozilla.fenix.settings.PreferenceBackedRadioButton
+            android:id="@+id/use_new_bootstrap_with_html_ui_radio_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:background="?android:attr/selectableItemBackground"
+            android:button="@null"
+            android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
+            android:paddingStart="@dimen/radio_button_preference_horizontal"
+            android:paddingTop="@dimen/radio_button_preference_vertical"
+            android:paddingEnd="@dimen/radio_button_preference_horizontal"
+            android:paddingBottom="@dimen/radio_button_preference_vertical"
+            android:text="HTML UI"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:textSize="16sp"
+            app:drawableStartCompat="?android:attr/listChoiceIndicatorSingle"
+            app:preferenceKey="@string/pref_key_use_new_bootstrap_with_html"
+            app:preferenceKeyDefaultValue="true" />
+
+        <org.mozilla.fenix.settings.PreferenceBackedRadioButton
+            android:id="@+id/use_new_bootstrap_with_native_ui_radio_button"
+            android:layout_width="match_parent"
+            android:layout_height="48dp"
+            android:background="?android:attr/selectableItemBackground"
+            android:button="@null"
+            android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
+            android:enabled="false"
+            android:paddingStart="@dimen/radio_button_preference_horizontal"
+            android:paddingTop="@dimen/radio_button_preference_vertical"
+            android:paddingEnd="@dimen/radio_button_preference_horizontal"
+            android:paddingBottom="@dimen/radio_button_preference_vertical"
+            android:text="Native Android UI"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:textSize="16sp"
+            app:drawableStartCompat="?android:attr/listChoiceIndicatorSingle"
+            app:preferenceKey="@string/pref_key_use_new_bootstrap_with_android_native"
+            app:preferenceKeyDefaultValue="false" />
+    </RadioGroup>
+
+</androidx.constraintlayout.widget.ConstraintLayout>


=====================================
fenix/app/src/main/res/navigation/nav_graph.xml
=====================================
@@ -27,6 +27,12 @@
         app:popUpTo="@id/startupFragment"
         app:popUpToInclusive="true" />
 
+    <action
+        android:id="@+id/action_startup_tor_connection_assist"
+        app:destination="@+id/torConnectionAssistFragment"
+        app:popUpTo="@id/startupFragment"
+        app:popUpToInclusive="true" />
+
     <action
         android:id="@+id/action_global_home"
         app:destination="@id/homeFragment"
@@ -941,12 +947,25 @@
             app:exitAnim="@anim/slide_out_left"
             app:popEnterAnim="@anim/slide_in_left"
             app:popExitAnim="@anim/slide_out_right" />
+        <action
+            android:id="@+id/action_torNetworkSettingsFragment_to_BetaConnectionFeaturesFragment"
+            app:destination="@+id/torBetaConnectionFeaturesFragment"
+            app:enterAnim="@anim/slide_in_right"
+            app:exitAnim="@anim/slide_out_left"
+            app:popEnterAnim="@anim/slide_in_left"
+            app:popExitAnim="@anim/slide_out_right" />
     </fragment>
     <fragment
         android:id="@+id/torBridgeConfigFragment"
         android:name="org.mozilla.fenix.settings.TorBridgeConfigFragment"
         android:label="@string/preferences_tor_network_settings_bridge_config"
         tools:layout="@layout/fragment_tor_bridge_config" />
+    <fragment
+        android:id="@+id/torBetaConnectionFeaturesFragment"
+        android:name="org.mozilla.fenix.tor.TorBetaConnectionFeaturesFragment"
+        android:label="Enable beta connection features"
+        tools:layout="@layout/tor_network_settings_beta_connection_features" />
+
     <fragment
         android:id="@+id/trackingProtectionFragment"
         android:name="org.mozilla.fenix.settings.TrackingProtectionFragment">


=====================================
fenix/app/src/main/res/values/preference_keys.xml
=====================================
@@ -376,6 +376,9 @@
     <string name="pref_key_tor_network_settings" translatable="false">pref_key_tor_network_settings</string>
     <string name="pref_key_tor_network_settings_explanation" translatable="false">pref_key_tor_network_settings_explanation</string>
     <string name="pref_key_tor_network_settings_bridge_config" translatable="false">pref_key_tor_network_settings_bridge_config</string>
+    <string name="pref_key_use_new_bootstrap" translatable="false">pref_key_use_new_bootstrap</string>
+    <string name="pref_key_use_new_bootstrap_with_android_native" translatable="false">pref_key_use_new_bootstrap_with_android_native</string>
+    <string name="pref_key_use_new_bootstrap_with_html" translatable="false">pref_key_use_new_bootstrap_with_html</string>
     <string name="pref_key_tor_network_settings_bridge_config_explanation" translatable="false">pref_key_tor_network_settings_bridge_config_explanation</string>
     <string name="pref_key_tor_network_settings_bridge_config_toggle" translatable="false">pref_key_tor_network_settings_bridge_config_toggle</string>
     <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>


=====================================
fenix/app/src/main/res/xml/tor_network_settings_preferences.xml
=====================================
@@ -27,4 +27,9 @@
         android:title="@string/preferences_tor_network_settings_bridge_config"
         android:summary="@string/preferences_tor_network_settings_bridge_config_description"
         app:allowDividerAbove="true" />
+    <Preference
+        android:key="@string/pref_key_use_new_bootstrap"
+        android:title="Enable beta connection features"
+        app:allowDividerAbove="true" />
+
 </androidx.preference.PreferenceScreen>



View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/48593938fafff1345fc8e131caa59c48a892b171

-- 
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/48593938fafff1345fc8e131caa59c48a892b171
You're receiving this email because of your account on gitlab.torproject.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tor-commits/attachments/20231221/11353a72/attachment-0001.htm>


More information about the tor-commits mailing list