
Dan Ballard pushed to branch tor-browser-128.11.0esr-14.5-1 at The Tor Project / Applications / Tor Browser Commits: 1f3d54f3 by clairehurst at 2025-06-04T12:43:41+02:00 fixup! TB 40026 [android]: Implement Security Level settings on Android. TB 43786: Add new UX flow for changing security level (Android) - - - - - 4c264ede by clairehurst at 2025-06-04T12:43:41+02:00 fixup! [android] Implement Android-native Connection Assist UI TB 43786: Add new UX flow for changing security level (Android) - - - - - 80613d52 by clairehurst at 2025-06-04T12:43:42+02:00 fixup! [android] TBA strings TB 43786: Add new UX flow for changing security level (Android) - - - - - 18 changed files: - mobile/android/android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngine.kt - mobile/android/android-components/components/concept/engine/src/main/java/mozilla/components/concept/engine/Settings.kt - mobile/android/android-components/components/feature/search/src/main/java/mozilla/components/feature/search/SearchUseCases.kt - mobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt - mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/Core.kt - mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt - − mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/TorSecurityLevelFragment.kt - − mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/SecurityLevel.kt - mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistFragment.kt - + mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorSecurityLevel.kt - + mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorSecurityLevelFragment.kt - mobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt - + mobile/android/fenix/app/src/main/res/layout/fragment_tor_security_level_preferences.xml - mobile/android/fenix/app/src/main/res/navigation/nav_graph.xml - mobile/android/fenix/app/src/main/res/values/preference_keys.xml - mobile/android/fenix/app/src/main/res/values/torbrowser_strings.xml - mobile/android/fenix/app/src/main/res/xml/preferences.xml - − mobile/android/fenix/app/src/main/res/xml/tor_security_level_preferences.xml Changes: ===================================== mobile/android/android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngine.kt ===================================== @@ -1335,9 +1335,7 @@ class GeckoEngine( override var torSecurityLevel: Int get() = runtime.settings.torSecurityLevel set(value) { - value.let { - runtime.settings.torSecurityLevel = it - } + runtime.settings.torSecurityLevel = value } override var spoofEnglish: Boolean ===================================== mobile/android/android-components/components/concept/engine/src/main/java/mozilla/components/concept/engine/Settings.kt ===================================== @@ -254,6 +254,12 @@ abstract class Settings { /** * Setting to control the current security level + * + * 4 -> STANDARD + * + * 2 -> SAFER + * + * 1 -> SAFEST */ open var torSecurityLevel: Int by UnsupportedSetting() ===================================== mobile/android/android-components/components/feature/search/src/main/java/mozilla/components/feature/search/SearchUseCases.kt ===================================== @@ -76,12 +76,7 @@ class SearchUseCases( flags: EngineSession.LoadUrlFlags = EngineSession.LoadUrlFlags.none(), additionalHeaders: Map<String, String>? = null, ) { - var securityLevel: Int - try { - securityLevel = settings?.torSecurityLevel ?: 0 - } catch (e: UnsupportedSettingException) { - securityLevel = 0 - } + val securityLevel : Int = settings!!.torSecurityLevel val searchUrl = searchEngine?.let { searchEngine.buildSearchUrl(searchTerms, securityLevel) } ?: store.state.search.selectedOrDefaultSearchEngine?.buildSearchUrl(searchTerms, securityLevel) @@ -172,12 +167,7 @@ class SearchUseCases( flags: EngineSession.LoadUrlFlags = EngineSession.LoadUrlFlags.none(), additionalHeaders: Map<String, String>? = null, ) { - var securityLevel: Int - try { - securityLevel = settings?.torSecurityLevel ?: 0 - } catch (e: UnsupportedSettingException) { - securityLevel = 0 - } + val securityLevel : Int = settings!!.torSecurityLevel val searchUrl = searchEngine?.let { searchEngine.buildSearchUrl(searchTerms, securityLevel) } ?: store.state.search.selectedOrDefaultSearchEngine?.buildSearchUrl(searchTerms, securityLevel) ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt ===================================== @@ -1439,6 +1439,15 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorAn private const val PWA_RECENTLY_USED_THRESHOLD = DateUtils.DAY_IN_MILLIS * 30L } + fun restartApplication() { + startActivity( + Intent(applicationContext, HomeActivity::class.java).addFlags( + Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK, + ), + ) + shutDown() + } + fun shutDown() : Nothing { finishAndRemoveTask() exitProcess(0) ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/Core.kt ===================================== @@ -157,7 +157,7 @@ class Core( cookieBannerHandlingGlobalRules = context.settings().shouldEnableCookieBannerGlobalRules, cookieBannerHandlingGlobalRulesSubFrames = context.settings().shouldEnableCookieBannerGlobalRulesSubFrame, emailTrackerBlockingPrivateBrowsing = false, - torSecurityLevel = context.settings().torSecurityLevel().intRepresentation, + torSecurityLevel = context.settings().torSecurityLevel, spoofEnglish = context.settings().spoofEnglish, ) ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt ===================================== @@ -13,6 +13,7 @@ import android.os.Build import android.os.Bundle import android.os.Handler import android.os.Looper +import android.util.Log import android.view.LayoutInflater import android.view.WindowManager import android.widget.Toast @@ -67,7 +68,7 @@ import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.nimbus.FxNimbus import org.mozilla.fenix.perf.ProfilerViewModel import org.mozilla.fenix.settings.account.AccountUiView -import org.mozilla.fenix.tor.SecurityLevel +import org.mozilla.fenix.tor.TorSecurityLevel import org.mozilla.fenix.tor.QuickstartViewModel import org.mozilla.fenix.utils.Settings import kotlin.system.exitProcess @@ -353,7 +354,7 @@ class SettingsFragment : PreferenceFragmentCompat(), UserInteractionHandler { SettingsFragmentDirections.actionSettingsFragmentToPrivateBrowsingFragment() } - resources.getString(R.string.pref_key_tor_security_level_settings) -> { + resources.getString(R.string.pref_key_tor_security_level) -> { SettingsFragmentDirections.actionSettingsFragmentToTorSecurityLevelFragment() } @@ -852,14 +853,14 @@ class SettingsFragment : PreferenceFragmentCompat(), UserInteractionHandler { @VisibleForTesting internal fun setupSecurityLevelPreference() { val securityLevelPreference = - requirePreference<Preference>(R.string.pref_key_tor_security_level_settings) - securityLevelPreference.summary = context?.settings()?.torSecurityLevel()?.let { - when (it) { - SecurityLevel.STANDARD -> getString(R.string.tor_security_level_standard_option) - SecurityLevel.SAFER -> getString(R.string.tor_security_level_safer_option) - SecurityLevel.SAFEST -> getString(R.string.tor_security_level_safest_option) + requirePreference<Preference>(R.string.pref_key_tor_security_level) + securityLevelPreference.summary = + when (requireContext().settings().torSecurityLevel) { + TorSecurityLevel.STANDARD.level -> getString(R.string.tor_security_level_standard) + TorSecurityLevel.SAFER.level -> getString(R.string.tor_security_level_safer) + TorSecurityLevel.SAFEST.level -> getString(R.string.tor_security_level_safest) + else -> throw Exception("Unexpected TorSecurityLevel of ${requireContext().settings().torSecurityLevel}") } - } } @VisibleForTesting ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/TorSecurityLevelFragment.kt deleted ===================================== @@ -1,81 +0,0 @@ -/* 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.settings - -import android.os.Bundle -import androidx.preference.PreferenceFragmentCompat -import org.mozilla.fenix.R -import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.settings -import org.mozilla.fenix.ext.showToolbar -import org.mozilla.fenix.tor.SecurityLevel -import org.mozilla.fenix.tor.SecurityLevelUtil -import org.mozilla.fenix.utils.view.GroupableRadioButton -import org.mozilla.fenix.utils.view.addToRadioGroup -import org.mozilla.fenix.utils.view.uncheckAll - -/** - * Lets the user choose their security level - */ -@Suppress("SpreadOperator") -class TorSecurityLevelFragment : PreferenceFragmentCompat() { - private val securityLevelRadioGroups = mutableListOf<GroupableRadioButton>() - private var previousSecurityLevel: SecurityLevel? = null - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.tor_security_level_preferences, rootKey) - - val currentLevel: SecurityLevel? = context?.components?.let { - try { - SecurityLevelUtil.getSecurityLevelFromInt( - it.core.engine.settings.torSecurityLevel - ) - } catch (e: IllegalStateException) { - // The default state is 0. If we get an invalid state then - // default to Standard (4). - SecurityLevel.STANDARD - } - } - - if (currentLevel == null) { - throw IllegalStateException("context or Components is null.") - } - - val radioSafer = bindSecurityLevelRadio(SecurityLevel.SAFER) - val radioSafest = bindSecurityLevelRadio(SecurityLevel.SAFEST) - val radioStandard = bindSecurityLevelRadio(SecurityLevel.STANDARD) - - securityLevelRadioGroups.addAll(mutableListOf(radioSafer, radioSafest, radioStandard)) - // `*` is Kotlin's "spread" operator, for expanding an Array as a vararg. - addToRadioGroup(*securityLevelRadioGroups.toTypedArray()) - - securityLevelRadioGroups.uncheckAll() - val securityLevelRadioButton = requirePreference<RadioButtonPreference>(currentLevel.preferenceKey) - // Cache this for later comparison in the OnPreferenceChangeListener - previousSecurityLevel = currentLevel - securityLevelRadioButton.setCheckedWithoutClickListener(true) - } - - private fun bindSecurityLevelRadio( - level: SecurityLevel - ): RadioButtonPreference { - val radio = requirePreference<RadioButtonPreference>(level.preferenceKey) - - radio.summary = getString(level.contentDescriptionRes) - - radio.apply { - setOnPreferenceChangeListener<Boolean> { preference, isChecked -> - if (isChecked && (previousSecurityLevel!! != level)) { - preference.context.components.core.engine.settings.torSecurityLevel = - level.intRepresentation - previousSecurityLevel = level - } - true - } - } - - return radio - } -} ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/SecurityLevel.kt deleted ===================================== @@ -1,53 +0,0 @@ -/* 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.Parcelable -import androidx.annotation.StringRes -import kotlinx.parcelize.Parcelize -import org.mozilla.fenix.R - - -const val SECURITY_LEVEL_STANDARD = 4 -const val SECURITY_LEVEL_SAFER = 2 -const val SECURITY_LEVEL_SAFEST = 1 - -@Parcelize -enum class SecurityLevel( - @StringRes val preferenceKey: Int, - @StringRes val contentDescriptionRes: Int, - val intRepresentation: Int -) : Parcelable { - - STANDARD( - preferenceKey = R.string.pref_key_tor_security_level_standard_option, - contentDescriptionRes = R.string.tor_security_level_standard_description, - intRepresentation = SECURITY_LEVEL_STANDARD - ), - SAFER( - preferenceKey = R.string.pref_key_tor_security_level_safer_option, - contentDescriptionRes = R.string.tor_security_level_safer_description, - intRepresentation = SECURITY_LEVEL_SAFER - ), - SAFEST( - preferenceKey = R.string.pref_key_tor_security_level_safest_option, - contentDescriptionRes = R.string.tor_security_level_safest_description, - intRepresentation = SECURITY_LEVEL_SAFEST - ); - - - -} - -object SecurityLevelUtil { - fun getSecurityLevelFromInt(level: Int): SecurityLevel { - return when (level) { - SECURITY_LEVEL_STANDARD -> SecurityLevel.STANDARD - SECURITY_LEVEL_SAFER -> SecurityLevel.SAFER - SECURITY_LEVEL_SAFEST -> SecurityLevel.SAFEST - else -> throw IllegalStateException("Security Level $level is not valid") - } - } -} ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistFragment.kt ===================================== @@ -343,7 +343,7 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler { if (screen.torBootstrapButton2ShouldOpenSettings) { openTorConnectionSettings() } else if (screen.torBootstrapButton2ShouldRestartApp) { - restartApplication() + (requireActivity() as HomeActivity).restartApplication() } else { torConnectionAssistViewModel.cancelTorBootstrap() } @@ -404,15 +404,6 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler { openSettings(requireContext().getString(R.string.pref_key_connection)) } - private fun restartApplication() { - startActivity( - Intent(requireContext(), HomeActivity::class.java).addFlags( - Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK, - ), - ) - Runtime.getRuntime().exit(0) - } - override fun onBackPressed(): Boolean { torConnectionAssistViewModel.handleBackButtonPressed(requireActivity() as HomeActivity) return true ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorSecurityLevel.kt ===================================== @@ -0,0 +1,13 @@ +/* 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.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +enum class TorSecurityLevel(val level: Int) : Parcelable { + STANDARD(4), SAFER(2), SAFEST(1) +} ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorSecurityLevelFragment.kt ===================================== @@ -0,0 +1,144 @@ +/* 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.content.Context +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.appcompat.content.res.AppCompatResources +import androidx.fragment.app.Fragment +import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.R +import org.mozilla.fenix.ext.components +import org.mozilla.fenix.databinding.FragmentTorSecurityLevelPreferencesBinding +import androidx.core.content.edit + +class TorSecurityLevelFragment : Fragment() { + private var _binding: FragmentTorSecurityLevelPreferencesBinding? = null + private val binding get() = _binding!! + + private val tag = "TorSecurityLevelFrag" + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + _binding = FragmentTorSecurityLevelPreferencesBinding.inflate( + inflater, container, false, + ) + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.description.text = getString(R.string.tor_security_level_warning, getString(R.string.app_name)) + + updateSaveAndRestartButtonUI() + + val currentLevel: Int = requireContext().components.core.engine.settings.torSecurityLevel + + when (currentLevel) { + TorSecurityLevel.STANDARD.level -> { + binding.standardPreference.text = + getString(R.string.tor_security_level_standard_current_level) + binding.securityLevelRadioGroup.check(binding.standardPreference.id) + } + + TorSecurityLevel.SAFER.level -> { + binding.saferPreference.text = + getString(R.string.tor_security_level_safer_current_level) + binding.securityLevelRadioGroup.check(binding.saferPreference.id) + } + + TorSecurityLevel.SAFEST.level -> { + binding.safestPreference.text = + getString(R.string.tor_security_level_safest_current_level) + binding.securityLevelRadioGroup.check(binding.safestPreference.id) + } + } + + binding.securityLevelRadioGroup.setOnCheckedChangeListener { _, checkedId -> + binding.saveAndRestartButton.isEnabled = when (checkedId) { + binding.standardPreference.id -> currentLevel != TorSecurityLevel.STANDARD.level + binding.saferPreference.id -> currentLevel != TorSecurityLevel.SAFER.level + binding.safestPreference.id -> currentLevel != TorSecurityLevel.SAFEST.level + else -> throw Exception("unexpected checkedID of $checkedId") + } + + updateSaveAndRestartButtonUI() + } + + binding.saveAndRestartButton.setOnClickListener { + + Toast.makeText( + requireContext(), + R.string.tor_security_level_restarting, + Toast.LENGTH_SHORT, + ).show() + + val selectedSecurityLevel: Int = + when (binding.securityLevelRadioGroup.checkedRadioButtonId) { + binding.standardPreference.id -> TorSecurityLevel.STANDARD.level + binding.saferPreference.id -> TorSecurityLevel.SAFER.level + binding.safestPreference.id -> TorSecurityLevel.SAFEST.level + else -> throw Exception("Unexpected checkedRadioButtonId of ${binding.securityLevelRadioGroup.checkedRadioButtonId}") + } + + requireContext().components.core.geckoRuntime.settings.torSecurityLevel = selectedSecurityLevel + + requireActivity().getSharedPreferences("fenix_preferences", Context.MODE_PRIVATE).edit( + commit = true, + ) { + putInt( + requireContext().getString(R.string.pref_key_tor_security_level), + selectedSecurityLevel, + ) + } + + Thread.sleep(1000) + + (requireActivity() as HomeActivity).restartApplication() + } + + binding.cancelButton.setOnClickListener { + requireActivity().onBackPressed() + } + } + + private fun updateSaveAndRestartButtonUI() { + binding.saveAndRestartButton.apply { + if (binding.saveAndRestartButton.isEnabled) { + backgroundTintList = AppCompatResources.getColorStateList( + requireContext(), + R.color.connect_button_purple, + ) + setTextColor( + AppCompatResources.getColorStateList( + requireContext(), + R.color.photonLightGrey05, + ), + ) + } else { + backgroundTintList = AppCompatResources.getColorStateList( + requireContext(), + R.color.disabled_connect_button_purple, + ) + setTextColor( + AppCompatResources.getColorStateList( + requireContext(), + R.color.disabled_text_gray_purple, + ), + ) + } + } + } +} ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt ===================================== @@ -52,7 +52,8 @@ import org.mozilla.fenix.settings.registerOnSharedPreferenceChangeListener import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_BLOCK_ALL import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_BLOCK_AUDIBLE import org.mozilla.fenix.wallpapers.Wallpaper -import org.mozilla.fenix.tor.SecurityLevel +import org.mozilla.fenix.settings.SettingsFragment +import org.mozilla.fenix.tor.TorSecurityLevel import java.security.InvalidParameterException import java.util.UUID @@ -299,31 +300,55 @@ class Settings(private val appContext: Context) : PreferencesHolder { false, ) - var standardSecurityLevel by booleanPreference( - appContext.getPreferenceKey(SecurityLevel.STANDARD.preferenceKey), - default = true + private var oldStandardSecurityLevel by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_tor_security_level_standard_option), + default = false ) - var saferSecurityLevel by booleanPreference( - appContext.getPreferenceKey(SecurityLevel.SAFER.preferenceKey), + private var oldSaferSecurityLevel by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_tor_security_level_safer_option), default = false ) - var safestSecurityLevel by booleanPreference( - appContext.getPreferenceKey(SecurityLevel.SAFEST.preferenceKey), + private var oldSafestSecurityLevel by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_tor_security_level_safest_option), default = false ) - // torSecurityLevel is defined as the first |true| preference, - // beginning at the safest level. - // If multiple preferences are true, then that is a bug and the - // highest |true| security level is chosen. - // Standard is the default level. - fun torSecurityLevel(): SecurityLevel = when { - safestSecurityLevel -> SecurityLevel.SAFEST - saferSecurityLevel -> SecurityLevel.SAFER - standardSecurityLevel -> SecurityLevel.STANDARD - else -> SecurityLevel.STANDARD + /** + * Backing property that should used only for the [SettingsFragment] UI + * + * 4 -> STANDARD + * + * 2 -> SAFER + * + * 1 -> SAFEST + */ + var torSecurityLevel by intPreference( + appContext.getPreferenceKey(R.string.pref_key_tor_security_level), + migrateTorSecurityLevel() ?: 4, + ) + + /** + * Remove in 15.0 release. + */ + private fun migrateTorSecurityLevel(): Int? { + return when { + oldSafestSecurityLevel -> { + TorSecurityLevel.SAFEST.level + } + oldSaferSecurityLevel -> { + TorSecurityLevel.SAFER.level + } + oldStandardSecurityLevel -> { + TorSecurityLevel.STANDARD.level + } + else -> null + }.also { + oldSafestSecurityLevel = false + oldSaferSecurityLevel = false + oldStandardSecurityLevel = false + } } var spoofEnglish by booleanPreference( ===================================== mobile/android/fenix/app/src/main/res/layout/fragment_tor_security_level_preferences.xml ===================================== @@ -0,0 +1,117 @@ +<?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="match_parent"> + + <TextView + android:id="@+id/description" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:lineSpacingExtra="6dp" + android:paddingHorizontal="24dp" + android:paddingVertical="16dp" + android:text="@string/tor_security_level_warning" + android:textColor="@color/photonLightGrey40" + android:textSize="14sp" + app:layout_constraintTop_toTopOf="parent" /> + + <RadioGroup + android:id="@+id/security_level_radio_group" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginHorizontal="16dp" + app:layout_constraintTop_toBottomOf="@+id/description"> + + <RadioButton + android:id="@+id/standard_preference" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/tor_security_level_standard" + android:textColor="@color/photonLightGrey05" + android:textSize="16sp" /> + + <TextView + android:id="@+id/standard_preference_description" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="32dp" + android:text="@string/tor_security_level_standard_description" + android:textColor="@color/photonLightGrey40" /> + + <RadioButton + android:id="@+id/safer_preference" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/tor_security_level_safer" + android:textColor="@color/photonLightGrey05" + android:textSize="16sp" /> + + <TextView + android:id="@+id/safer_preference_description" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="32dp" + android:text="@string/tor_security_level_safer_description" + android:textColor="@color/photonLightGrey40" /> + + <RadioButton + android:id="@+id/safest_preference" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/tor_security_level_safest" + android:textColor="@color/photonLightGrey05" + android:textSize="16sp" /> + + <TextView + android:id="@+id/safest_preference_description" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="32dp" + android:text="@string/tor_security_level_safest_description" + android:textColor="@color/photonLightGrey40" /> + </RadioGroup> + + <Button + android:id="@+id/save_and_restart_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginEnd="24dp" + android:layout_marginBottom="8dp" + android:background="@drawable/rounded_corners" + android:backgroundTint="@color/connect_button_purple" + android:enabled="false" + android:minWidth="360dp" + android:text="@string/tor_security_level_save_and_restart_tor_browser" + android:textAlignment="center" + android:textAllCaps="false" + android:textColor="@color/photonLightGrey05" + android:textSize="14sp" + android:textStyle="bold" + app:layout_constraintBottom_toTopOf="@id/cancel_button" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + + <Button + android:id="@+id/cancel_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginEnd="24dp" + android:layout_marginBottom="8dp" + android:background="@drawable/rounded_corners" + android:backgroundTint="@color/configure_connection_button_white" + android:minWidth="360dp" + android:text="@string/btn_cancel" + android:textAlignment="center" + android:textAllCaps="false" + android:textColor="@color/photonDarkGrey90" + android:textSize="14sp" + android:textStyle="bold" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> +</androidx.constraintlayout.widget.ConstraintLayout> ===================================== mobile/android/fenix/app/src/main/res/navigation/nav_graph.xml ===================================== @@ -907,7 +907,7 @@ android:label="@string/preferences_customize" /> <fragment android:id="@+id/torSecurityLevelFragment" - android:name="org.mozilla.fenix.settings.TorSecurityLevelFragment" + android:name="org.mozilla.fenix.tor.TorSecurityLevelFragment" android:label="@string/preferences_tor_security_level_options" /> <fragment android:id="@+id/privateBrowsingFragment" ===================================== mobile/android/fenix/app/src/main/res/values/preference_keys.xml ===================================== @@ -406,6 +406,9 @@ <string name="pref_key_https_everywhere_removed" translatable="false">pref_key_https_everywhere_removed</string> <!-- Security Level Settings --> + <string name="pref_key_tor_security_level" translatable="false">pref_key_tor_security_level</string> + + <!-- Deprecated Security Level Settings --> <string name="pref_key_tor_security_level_settings" translatable="false">pref_key_tor_security_level_settings</string> <string name="pref_key_tor_security_level_standard_option" translatable="false">pref_key_tor_security_level_standard_option</string> <string name="pref_key_tor_security_level_safer_option" translatable="false">pref_key_tor_security_level_safer_option</string> ===================================== mobile/android/fenix/app/src/main/res/values/torbrowser_strings.xml ===================================== @@ -36,12 +36,19 @@ <string name="preferences_tor_security_level_options">Security Level</string> <!-- Description of security levels --> - <string name="tor_security_level_standard_option">Standard</string> + <!-- %s will be replaced with the localised application name, such as "Tor Browser". --> + <string name="tor_security_level_warning">You will need to restart %s to apply any changes. This will close all tabs.</string> + <string name="tor_security_level_standard">Standard</string> + <string name="tor_security_level_standard_current_level">Standard (current level)</string> <string name="tor_security_level_standard_description">All Tor Browser and website features are enabled.</string> - <string name="tor_security_level_safer_option">Safer</string> + <string name="tor_security_level_safer">Safer</string> + <string name="tor_security_level_safer_current_level">Safer (current level)</string> <string name="tor_security_level_safer_description">Disable website features that are often dangerous, causing some sites to lose functionality.</string> - <string name="tor_security_level_safest_option">Safest</string> + <string name="tor_security_level_safest">Safest</string> + <string name="tor_security_level_safest_current_level">Safest (current level)</string> <string name="tor_security_level_safest_description">Only allow website features required for static sites and basic services. These changes affect images, media, and scripts.</string> + <string name="tor_security_level_save_and_restart_tor_browser">Save and restart</string> + <string name="tor_security_level_restarting">Restarting</string> <string name="btn_cancel">Cancel</string> ===================================== mobile/android/fenix/app/src/main/res/xml/preferences.xml ===================================== @@ -103,7 +103,7 @@ android:layout="@layout/preference_category_no_icon_style"> <androidx.preference.Preference - android:key="@string/pref_key_tor_security_level_settings" + android:key="@string/pref_key_tor_security_level" app:iconSpaceReserved="false" android:title="@string/preferences_tor_security_level_options" /> ===================================== mobile/android/fenix/app/src/main/res/xml/tor_security_level_preferences.xml deleted ===================================== @@ -1,21 +0,0 @@ -<?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.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> - <org.mozilla.fenix.settings.RadioButtonPreference - android:defaultValue="true" - android:key="@string/pref_key_tor_security_level_standard_option" - android:summary="@string/tor_security_level_standard_description" - android:title="@string/tor_security_level_standard_option" /> - <org.mozilla.fenix.settings.RadioButtonPreference - android:defaultValue="false" - android:key="@string/pref_key_tor_security_level_safer_option" - android:summary="@string/tor_security_level_safer_description" - android:title="@string/tor_security_level_safer_option" /> - <org.mozilla.fenix.settings.RadioButtonPreference - android:defaultValue="false" - android:key="@string/pref_key_tor_security_level_safest_option" - android:summary="@string/tor_security_level_safest_description" - android:title="@string/tor_security_level_safest_option" /> -</androidx.preference.PreferenceScreen> View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/298a041... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/298a041... You're receiving this email because of your account on gitlab.torproject.org.