Skip to content
Snippets Groups Projects
Commit 2d4837e7 authored by Matthew Finkel's avatar Matthew Finkel Committed by Beatriz Rizental
Browse files

TB 40041 [android]: Implement Tor Network Settings

Originally, fenix#40041.
parent f8824a51
Branches
Tags
1 merge request!1527Bug 43808: Rebase 128.10.1 onto 128.11
Showing
with 658 additions and 39 deletions
......@@ -50,6 +50,7 @@ import org.mozilla.fenix.GleanMetrics.TrackingProtection
import org.mozilla.fenix.GleanMetrics.Translations
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.ReleaseChannel
import org.mozilla.fenix.components.accounts.FenixFxAEntryPoint
import org.mozilla.fenix.databinding.AmoCollectionOverrideDialogBinding
import org.mozilla.fenix.ext.application
......@@ -64,6 +65,7 @@ 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.QuickstartViewModel
import org.mozilla.fenix.utils.Settings
import kotlin.system.exitProcess
import org.mozilla.fenix.GleanMetrics.Settings as SettingsMetrics
......@@ -76,6 +78,8 @@ class SettingsFragment : PreferenceFragmentCompat() {
private lateinit var addonFilePicker: AddonFilePicker
private val profilerViewModel: ProfilerViewModel by activityViewModels()
private val quickstartViewModel: QuickstartViewModel by activityViewModels()
@VisibleForTesting
internal val accountObserver = object : AccountObserver {
private fun updateAccountUi(profile: Profile? = null) {
......@@ -167,6 +171,8 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
//setPreferencesFromResource(R.xml.tor_network_settings_preferences, rootKey)
//setupConnectionPreferences()
setPreferencesFromResource(R.xml.preferences, rootKey)
}
......@@ -190,7 +196,11 @@ class SettingsFragment : PreferenceFragmentCompat() {
update(shouldUpdateAccountUIState = !creatingFragment)
requireView().findViewById<RecyclerView>(R.id.recycler_view)
?.hideInitialScrollBar(viewLifecycleOwner.lifecycleScope)
.also {
it?.hideInitialScrollBar(viewLifecycleOwner.lifecycleScope)
// Prevent disabled settings from having a collapsing animation on open
it?.disableHidingAnimation()
}
args.preferenceToScrollTo?.let {
scrollToPreference(it)
......@@ -250,9 +260,9 @@ class SettingsFragment : PreferenceFragmentCompat() {
// getString(R.string.preferences_credit_cards_2)
// }
val openLinksInAppsSettingsPreference =
requirePreference<Preference>(R.string.pref_key_open_links_in_apps)
openLinksInAppsSettingsPreference.summary = context?.settings()?.getOpenLinksInAppsString()
// val openLinksInAppsSettingsPreference =
// requirePreference<Preference>(R.string.pref_key_open_links_in_apps)
// openLinksInAppsSettingsPreference.summary = context?.settings()?.getOpenLinksInAppsString()
// Hide "Delete browsing data on quit" when in Private Browsing-only mode
deleteBrowsingDataPreference.isVisible =
......@@ -429,9 +439,9 @@ class SettingsFragment : PreferenceFragmentCompat() {
null
}
resources.getString(R.string.pref_key_open_links_in_apps) -> {
SettingsFragmentDirections.actionSettingsFragmentToOpenLinksInAppsFragment()
}
// resources.getString(R.string.pref_key_open_links_in_apps) -> {
// SettingsFragmentDirections.actionSettingsFragmentToOpenLinksInAppsFragment()
// }
resources.getString(R.string.pref_key_sync_debug) -> {
SettingsFragmentDirections.actionSettingsFragmentToSyncDebugFragment()
......@@ -560,6 +570,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
setupSearchPreference()
setupHomepagePreference()
setupTrackingProtectionPreference()
setupConnectionPreferences()
}
/**
......@@ -594,6 +605,10 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
}
private fun RecyclerView.disableHidingAnimation() {
this.setItemAnimator(null)
this.setLayoutAnimation(null)
}
private fun updateFxAAllowDomesticChinaServerMenu() {
val settings = requireContext().settings()
val preferenceAllowDomesticChinaServer =
......@@ -732,6 +747,56 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
}
internal fun setupConnectionPreferences() {
// will be needed for phase2
//val torController = requireContext().components.torController
requirePreference<Preference>(R.string.pref_key_tor_network_settings_bridge_config).apply {
setOnPreferenceClickListener {
val directions =
SettingsFragmentDirections
.actionSettingsFragmentToTorBridgeConfigFragment()
requireView().findNavController().navigate(directions)
true
}
}
requirePreference<SwitchPreference>(R.string.pref_key_quick_start).apply {
isChecked = quickstartViewModel.quickstart().value == true
setOnPreferenceClickListener {
quickstartViewModel.quickstartSet(
isChecked,
)
true
}
}
requirePreference<Preference>(R.string.pref_key_use_html_connection_ui).apply {
onPreferenceChangeListener = object : SharedPreferenceUpdater() {}
isVisible = Config.channel != ReleaseChannel.Release
}
requirePreference<Preference>(R.string.pref_key_tor_logs).apply {
setOnPreferenceClickListener {
val directions =
SettingsFragmentDirections.actionSettingsFragmentToTorLogsFragment()
requireView().findNavController().navigate(directions)
true
}
}
requirePreference<Preference>(R.string.pref_key_about_config_shortcut).apply {
isVisible = requireContext().settings().showSecretDebugMenuThisSession || Config.channel == ReleaseChannel.Debug
setOnPreferenceClickListener {
(requireActivity() as HomeActivity).openToBrowserAndLoad(
searchTermOrURL = "about:config",
from = BrowserDirection.FromSettings,
newTab = true,
)
true
}
}
}
@VisibleForTesting
internal fun setupCookieBannerPreference() {
// FxNimbus.features.cookieBanners.recordExposure()
......
/* 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.EditTextPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import org.mozilla.fenix.Config
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.TorBridgeTransportConfig
import org.mozilla.fenix.utils.view.addToRadioGroup
import org.mozilla.fenix.utils.view.GroupableRadioButton
import org.mozilla.fenix.utils.view.uncheckAll
/**
* Displays the toggle for enabling bridges, options for built-in pluggable transports, and an additional
* preference for configuring a user-provided bridge.
*/
@Suppress("SpreadOperator")
class TorBridgeConfigFragment : PreferenceFragmentCompat() {
private val builtinBridgeRadioGroups = mutableListOf<GroupableRadioButton>()
private var previousTransportConfig: TorBridgeTransportConfig? = null
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.tor_bridge_config_preferences, rootKey)
// Initialize radio button group for built-in bridge transport types
val radioObfs4 = bindBridgeTransportRadio(TorBridgeTransportConfig.BUILTIN_OBFS4)
val radioMeekAzure = bindBridgeTransportRadio(TorBridgeTransportConfig.BUILTIN_MEEK_AZURE)
val radioSnowflake = bindBridgeTransportRadio(TorBridgeTransportConfig.BUILTIN_SNOWFLAKE)
builtinBridgeRadioGroups.addAll(mutableListOf(radioObfs4, radioMeekAzure, radioSnowflake))
// `*` is Kotlin's "spread" operator, for expanding an Array as a vararg.
addToRadioGroup(*builtinBridgeRadioGroups.toTypedArray())
}
override fun onResume() {
super.onResume()
showToolbar(getString(R.string.preferences_tor_network_settings_bridge_config))
val bridgesEnabled = requireContext().components.torController.bridgesEnabled
val prefBridgeConfig =
requirePreference<SwitchPreference>(R.string.pref_key_tor_network_settings_bridge_config_toggle)
prefBridgeConfig.apply {
isChecked = bridgesEnabled
setOnPreferenceChangeListener<Boolean> { preference, enabled ->
preference.context.components.torController.bridgesEnabled = enabled
updateCurrentConfiguredBridgePref(preference)
preference.context.components.torController.restartTor()
true
}
}
val userProvidedBridges = requirePreference<EditTextPreference>(
R.string.pref_key_tor_network_settings_bridge_config_user_provided_bridge
)
userProvidedBridges.apply {
setOnPreferenceChangeListener<String> { preference, userProvidedBridge ->
builtinBridgeRadioGroups.uncheckAll()
preference.context.components.torController.bridgeTransport = TorBridgeTransportConfig.USER_PROVIDED
preference.context.components.torController.userProvidedBridges = userProvidedBridge
updateCurrentConfiguredBridgePref(preference)
preference.context.components.torController.restartTor()
true
}
val userProvidedBridge: String? = context.components.torController.userProvidedBridges
if (userProvidedBridge != null) {
setText(userProvidedBridge)
}
}
val currentBridgeType = prefBridgeConfig.context.components.torController.bridgeTransport
// Cache the current configured transport type
previousTransportConfig = currentBridgeType
builtinBridgeRadioGroups.uncheckAll()
if (currentBridgeType != TorBridgeTransportConfig.USER_PROVIDED) {
val bridgeRadioButton = requirePreference<RadioButtonPreference>(currentBridgeType.preferenceKey)
bridgeRadioButton.setCheckedWithoutClickListener(true)
}
updateCurrentConfiguredBridgePref(prefBridgeConfig)
}
private fun bindBridgeTransportRadio(
bridge: TorBridgeTransportConfig
): RadioButtonPreference {
val radio = requirePreference<RadioButtonPreference>(bridge.preferenceKey)
radio.apply {
setOnPreferenceChangeListener<Boolean> { preference, isChecked ->
if (isChecked && (previousTransportConfig!! != bridge)) {
preference.context.components.torController.bridgeTransport = bridge
previousTransportConfig = bridge
updateCurrentConfiguredBridgePref(preference)
preference.context.components.torController.restartTor()
}
true
}
}
return radio
}
private fun setCurrentBridgeLabel(currentBridgePref: Preference?, bridge: String) {
currentBridgePref?.apply {
title = getString(
R
.string
.preferences_tor_network_settings_bridge_config_current_bridge,
bridge
)
}
}
private fun updateCurrentConfiguredBridgePref(preference: Preference) {
val currentBridge: Preference? =
findPreference(
getString(
R.string.pref_key_tor_network_settings_bridge_config_current_bridge
)
)
val enabled = requireContext().components.torController.bridgesEnabled
if (enabled) {
val configuredBridge = preference.context.components.torController.bridgeTransport
var bridges = when (configuredBridge) {
TorBridgeTransportConfig.USER_PROVIDED ->
preference.context.components.torController.userProvidedBridges
else -> configuredBridge.transportName
}
if (bridges == null) {
bridges = "not known"
}
setCurrentBridgeLabel(currentBridge, bridges)
} else {
setCurrentBridgeLabel(
currentBridge,
getString(R.string.tor_network_settings_bridge_not_configured)
)
}
}
}
/* 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.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.selection.DisableSelection
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import mozilla.components.ui.colors.PhotonColors
import org.mozilla.fenix.R
class TorLogsComposeFragment : Fragment() {
private val viewModel: TorLogsViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
return ComposeView(requireContext()).apply {
setContent {
Scaffold(
floatingActionButton = { CopyLogsButton() },
content = { TorLogs(paddingValues = it) },
)
}
}
}
@Composable
private fun TorLogs(paddingValues: PaddingValues) {
val torLogsState = remember { mutableStateOf<List<TorLog>>(emptyList()) }
val lifecycleOwner = LocalLifecycleOwner.current
val scrollState = rememberScrollState()
DisposableEffect(viewModel.torLogs(), lifecycleOwner) {
val observer = Observer<List<TorLog>> { logs ->
torLogsState.value = logs
}
viewModel.torLogs().observe(lifecycleOwner, observer)
onDispose {
viewModel.torLogs().removeObserver(observer)
}
}
val torLogs = torLogsState.value
LaunchedEffect(torLogs) {
scrollState.animateScrollTo(scrollState.maxValue)
}
SelectionContainer {
Column(
// Column instead of LazyColumn so that you can select all the logs, and not just one "screen" at a time
// The logs won't be too big so loading them all instead of just whats visible shouldn't be a big deal
modifier = Modifier
.fillMaxSize()
.verticalScroll(scrollState)
.padding(paddingValues)
.background(PhotonColors.Ink50), // Standard background color
) {
for (log in torLogs) {
LogRow(log = log)
}
}
}
}
@Composable
@Stable
private fun LogRow(log: TorLog, modifier: Modifier = Modifier) {
Column(
modifier
.fillMaxWidth()
.padding(
start = 16.dp,
end = 16.dp,
bottom = 16.dp,
),
) {
Text(
text = log.timestamp,
color = PhotonColors.LightGrey40,
modifier = modifier
.padding(bottom = 4.dp),
)
Text(
text = "[${log.type}] " + log.text,
color = PhotonColors.LightGrey05,
)
}
}
@Composable
private fun CopyLogsButton() {
FloatingActionButton(
onClick = { viewModel.copyAllLogsToClipboard() },
content = {
Icon(
painter = painterResource(id = R.drawable.ic_copy),
contentDescription = getString(R.string.share_copy_link_to_clipboard),
)
},
backgroundColor = PhotonColors.Violet50, // Same color as connect button
contentColor = PhotonColors.LightGrey05,
)
}
}
/* 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.app.Application
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Build
import android.widget.Toast
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
class TorLogsViewModel(application: Application) : AndroidViewModel(application), TorLogs {
private val torController = application.components.torController
private val clipboardManager =
application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
private val _torLogs: MutableLiveData<List<TorLog>> = MutableLiveData(mutableListOf())
fun torLogs(): LiveData<List<TorLog>> {
return _torLogs
}
private fun addLog(log: TorLog) {
_torLogs.value = _torLogs.value?.plus(log) ?: return
}
init {
setupClipboardListener()
torController.registerTorLogListener(this)
val currentEntries = torController.logEntries
for (log in currentEntries) {
addLog(log)
}
}
override fun onLog(type: String?, message: String?, timestamp: String?) {
addLog(TorLog(type ?: "null", message ?: "null", timestamp ?: "null"))
}
override fun onCleared() {
super.onCleared()
torController.unregisterTorLogListener(this)
}
private fun setupClipboardListener() {
clipboardManager.addPrimaryClipChangedListener {
// Only show a toast for Android 12 and lower.
// https://developer.android.com/develop/ui/views/touch-and-input/copy-paste#duplicate-notifications
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
Toast.makeText(
getApplication<Application>().applicationContext,
getApplication<Application>().getString(R.string.toast_copy_link_to_clipboard), // "Copied to clipboard" already translated
Toast.LENGTH_SHORT,
).show()
}
}
}
fun copyAllLogsToClipboard() {
clipboardManager.setPrimaryClip(
ClipData.newPlainText(
getApplication<Application>().getString(R.string.preferences_tor_logs),
getAllTorLogs(),
),
)
}
private fun getAllTorLogs(): String {
var ret = ""
for (log in torLogs().value
?: return getApplication<Application>().getString(R.string.default_error_msg)) {
ret += "${log.timestamp} [${log.type}] ${log.text}\n"
}
return ret
}
}
......@@ -624,6 +624,7 @@ class Settings(private val appContext: Context) : PreferencesHolder {
/**
* Get the display string for the current open links in apps setting
*/
/*
fun getOpenLinksInAppsString(): String =
when (openLinksInExternalApp) {
appContext.getString(R.string.pref_key_open_links_in_apps_always) -> {
......@@ -640,6 +641,7 @@ class Settings(private val appContext: Context) : PreferencesHolder {
appContext.getString(R.string.preferences_open_links_in_apps_never)
}
}
*/
var shouldUseDarkTheme by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_dark_theme),
......@@ -1361,26 +1363,31 @@ class Settings(private val appContext: Context) : PreferencesHolder {
/**
* Check to see if we should open the link in an external app
*/
@Suppress("UNUSED_PARAMETER")
fun shouldOpenLinksInApp(isCustomTab: Boolean = false): Boolean {
return when (openLinksInExternalApp) {
appContext.getString(R.string.pref_key_open_links_in_apps_always) -> true
appContext.getString(R.string.pref_key_open_links_in_apps_ask) -> true
return false
//return when (openLinksInExternalApp) {
// appContext.getString(R.string.pref_key_open_links_in_apps_always) -> true
// appContext.getString(R.string.pref_key_open_links_in_apps_ask) -> true
/* Some applications will not work if custom tab never open links in apps, return true if it's custom tab */
appContext.getString(R.string.pref_key_open_links_in_apps_never) -> isCustomTab
else -> false
}
// appContext.getString(R.string.pref_key_open_links_in_apps_never) -> isCustomTab
//else -> false
//}
}
/**
* Check to see if we need to prompt the user if the link can be opened in an external app
*/
fun shouldPromptOpenLinksInApp(): Boolean {
return true
/*
return when (openLinksInExternalApp) {
appContext.getString(R.string.pref_key_open_links_in_apps_always) -> false
appContext.getString(R.string.pref_key_open_links_in_apps_ask) -> true
appContext.getString(R.string.pref_key_open_links_in_apps_never) -> true
else -> true
}
*/
}
var openLinksInExternalApp by stringPreference(
......@@ -2099,4 +2106,9 @@ class Settings(private val appContext: Context) : PreferencesHolder {
default = { false },
featureFlag = FxNimbus.features.toolbarRedesign.value().enabled,
)
var useHtmlConnectionUi by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_use_html_connection_ui),
default = false,
)
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="18dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M22.7,19l-9.1,-9.1c0.9,-2.3 0.4,-5 -1.5,-6.9 -2,-2 -5,-2.4 -7.4,-1.3L9,6 6,9 1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1,0.4 1.4,0l2.3,-2.3c0.5,-0.4 0.5,-1.1 0.1,-1.4z"
android:fillColor="#ffffff"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,0.75C18.2132,0.75 23.25,5.7865 23.25,11.9997C23.25,18.2132 18.2132,23.25 12,23.25C5.7865,23.25 0.75,18.2132 0.75,11.9997C0.75,5.7865 5.7865,0.75 12,0.75ZM12.0231,2.7958L12.0231,4.1596C16.3429,4.172 19.8408,7.677 19.8408,11.9997C19.8408,16.3227 16.3429,19.8277 12.0231,19.8401L12.0231,19.8401L12.0231,21.2039C17.0961,21.1914 21.2042,17.0758 21.2042,11.9997C21.2042,6.9239 17.0961,2.8086 12.0231,2.7958L12.0231,2.7958ZM12.0231,6.2057L12.0231,7.5691C14.4596,7.5819 16.4318,9.56 16.4318,11.9997C16.4318,14.4397 14.4596,16.4178 12.0231,16.4306L12.0231,16.4306L12.0231,17.794C15.2131,17.7816 17.7956,15.1928 17.7956,11.9997C17.7956,8.8069 15.2131,6.2181 12.0231,6.2057L12.0231,6.2057ZM12.0231,9.6146L12.0231,14.3851C13.3301,14.3726 14.3863,13.3101 14.3863,11.9997C14.3863,10.6896 13.3301,9.6271 12.0231,9.6146L12.0231,9.6146Z"
android:strokeAlpha="0.8"
android:strokeWidth="1"
android:fillColor="?attr/textPrimary"
android:fillType="evenOdd"
android:strokeColor="#00000000"
android:fillAlpha="0.8"/>
</vector>
<?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/. -->
<com.google.android.material.switchmaterial.SwitchMaterial xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/switch_widget"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:clickable="false"
android:focusable="false"
android:gravity="center_vertical"
android:orientation="vertical" />
......@@ -610,6 +610,20 @@
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
<action
android:id="@+id/action_settingsFragment_to_torBridgeConfigFragment"
app:destination="@id/torBridgeConfigFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
<action
android:id="@+id/action_settingsFragment_to_torLogsFragment"
app:destination="@+id/torLogsFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
<action
android:id="@+id/action_settingsFragment_to_trackingProtectionFragment"
app:destination="@id/trackingProtectionFragment"
......@@ -659,6 +673,7 @@
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
<!--
<action
android:id="@+id/action_settingsFragment_to_openLinksInAppsFragment"
app:destination="@id/openLinksInAppsFragment"
......@@ -666,6 +681,7 @@
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
-->
<action
android:id="@+id/action_settingsFragment_to_tabsSettingsFragment"
app:destination="@id/tabsSettingsFragment"
......@@ -864,8 +880,11 @@
<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" />
android:label="@string/preferences_tor_network_settings_bridge_config" />
<fragment
android:id="@+id/torLogsFragment"
android:name="org.mozilla.fenix.tor.TorLogsComposeFragment"
android:label="@string/preferences_tor_logs" />
<fragment
android:id="@+id/trackingProtectionFragment"
android:name="org.mozilla.fenix.settings.TrackingProtectionFragment">
......@@ -884,9 +903,11 @@
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
</fragment>
<!--
<fragment
android:id="@+id/openLinksInAppsFragment"
android:name="org.mozilla.fenix.settings.OpenLinksInAppsFragment" />
-->
<fragment
android:id="@+id/deleteBrowsingDataFragment"
android:name="org.mozilla.fenix.settings.deletebrowsingdata.DeleteBrowsingDataFragment"
......
......@@ -14,6 +14,9 @@
<string name="pref_key_accessibility" translatable="false">pref_key_accessibility</string>
<string name="pref_key_accessibility_auto_size" translatable="false">pref_key_accessibility_auto_size</string>
<string name="pref_key_accessibility_font_scale" translatable="false">pref_key_accessibility_font_scale</string>
<string name="pref_key_privacy" translatable="false">pref_key_privacy</string>
<string name="pref_key_connection" translatable="false">pref_key_connection</string>
<string name="pref_key_quick_start" translatable="false">pref_key_quick_start</string>
<string name="pref_key_accessibility_force_enable_zoom" translatable="false">pref_key_accessibility_force_enable_zoom</string>
<string name="pref_key_advanced" translatable="false">pref_key_advanced</string>
<string name="pref_key_language" translatable="false">pref_key_language</string>
......@@ -408,5 +411,23 @@
<string name="pref_key_tor_security_level_safer_option" translatable="false">pref_key_tor_security_level_safer_option</string>
<string name="pref_key_tor_security_level_safest_option" translatable="false">pref_key_tor_security_level_safest_option</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_tor_logs" translatable="false">pref_key_tor_logs</string>
<string name="pref_key_use_html_connection_ui" translatable="false">pref_key_use_html_connection_ui</string> <!-- Changing the pref_key should reset it to off for users that had it enabled -->
<string name="pref_key_about_config_shortcut" translatable="false">pref_key_about_config_shortcut</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>
<string name="pref_key_tor_network_settings_bridge_config_builtin_bridge_meek_azure" translatable="false">pref_key_tor_network_settings_bridge_config_builtin_bridge_meek_azure</string>
<string name="pref_key_tor_network_settings_bridge_config_builtin_bridge_snowflake" translatable="false">pref_key_tor_network_settings_bridge_config_builtin_bridge_snowflake</string>
<string name="pref_key_tor_network_settings_bridge_config_user_provided_bridge" translatable="false">pref_key_tor_network_settings_bridge_config_user_provided_bridge</string>
<string name="pref_key_tor_network_settings_bridge_config_user_provided_bridge_preference" translatable="false">pref_key_tor_network_settings_bridge_config_user_provided_bridge_preference</string>
<string name="pref_key_tor_network_settings_bridge_config_current_bridge" translatable="false">pref_key_tor_network_settings_bridge_config_current_bridge</string>
<string name="pref_key_tor_network_settings_status">pref_key_tor_network_settings_status</string>
<string name="pref_key_tor_network_settings_tor_ready">pref_key_tor_network_settings_tor_ready</string>
<string name="pref_key_tor_network_settings_state">pref_key_tor_network_settings_state</string>
<string name="pref_key_tor_network_settings_bridges_enabled">pref_key_tor_network_settings_bridges_enabled</string>
<string name="pref_key_spoof_english" translatable="false">pref_key_spoof_english</string>
</resources>
......@@ -99,6 +99,7 @@
<androidx.preference.PreferenceCategory
android:title="@string/preferences_category_privacy_security"
android:key="@string/pref_key_privacy"
android:layout="@layout/preference_category_no_icon_style">
<androidx.preference.Preference
......@@ -157,6 +158,54 @@
</androidx.preference.PreferenceCategory>
<!-- title="@string/preferences_category_advanced"
key="@string/pref_key_advanced"-->
<PreferenceCategory
android:title="@string/preferences_tor_connection_settings_title"
android:key="@string/pref_key_connection"
android:layout="@layout/preference_category_no_icon_style">
<Preference
android:key="@string/pref_key_tor_network_settings_explanation"
app:iconSpaceReserved="false"
android:title="@string/preferences_tor_network_settings_explanation" />
<Preference
android:key="@string/pref_key_tor_network_settings_bridge_config"
app:iconSpaceReserved="false"
android:title="@string/preferences_tor_network_settings_bridge_config"
android:summary="@string/preferences_tor_network_settings_bridge_config_description" />
<SwitchPreference
android:key="@string/pref_key_quick_start"
android:title="@string/tor_connect_automatically_label"
app:iconSpaceReserved="false" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/pref_key_use_html_connection_ui"
android:summary="Recommended only for debugging"
android:title="Enable HTML connection UI"
app:iconSpaceReserved="false" />
<Preference
android:key="@string/pref_key_tor_logs"
app:iconSpaceReserved="false"
android:title="@string/preferences_tor_logs"
android:summary="@string/preferences_tor_logs_description" />
<Preference
android:key="@string/pref_key_about_config_shortcut"
app:iconSpaceReserved="false"
android:title="about:config"/>
<!-- Auto connect -->
<!-- Tor Logs -->
</PreferenceCategory>
<PreferenceCategory
android:title="@string/preferences_category_advanced"
android:key="@string/pref_key_advanced"
......@@ -182,12 +231,12 @@
android:key="@string/pref_key_override_amo_collection"
app:iconSpaceReserved="false"
android:title="@string/preferences_customize_extension_collection" />
<!--
<androidx.preference.Preference
android:key="@string/pref_key_open_links_in_apps"
android:title="@string/preferences_open_links_in_apps"
app:iconSpaceReserved="false" />
-->
<androidx.preference.SwitchPreference
android:defaultValue="false"
android:key="@string/pref_key_external_download_manager"
......
<?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">
<androidx.preference.Preference
android:key="@string/pref_key_tor_network_settings_bridge_config_explanation"
android:summary="@string/preferences_tor_network_settings_bridge_config_explanation"
app:allowDividerBelow="false" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/pref_key_tor_network_settings_bridge_config_toggle"
android:title="@string/preferences_tor_network_settings_bridge_config_toggle"
android:summary="@string/preferences_tor_network_settings_bridge_config_toggle_description" />
<org.mozilla.fenix.settings.RadioButtonPreference
android:defaultValue="false"
android:dependency="@string/pref_key_tor_network_settings_bridge_config_toggle"
android:key="@string/pref_key_tor_network_settings_bridge_config_builtin_bridge_obfs4"
android:title="@string/preferences_tor_network_settings_bridge_config_builtin_bridge_obfs4" />
<org.mozilla.fenix.settings.RadioButtonPreference
android:defaultValue="false"
android:dependency="@string/pref_key_tor_network_settings_bridge_config_toggle"
android:key="@string/pref_key_tor_network_settings_bridge_config_builtin_bridge_meek_azure"
android:title="@string/preferences_tor_network_settings_bridge_config_builtin_bridge_meek_azure" />
<org.mozilla.fenix.settings.RadioButtonPreference
android:defaultValue="false"
android:dependency="@string/pref_key_tor_network_settings_bridge_config_toggle"
android:key="@string/pref_key_tor_network_settings_bridge_config_builtin_bridge_snowflake"
android:title="@string/preferences_tor_network_settings_bridge_config_builtin_bridge_snowflake" />
<EditTextPreference
android:dependency="@string/pref_key_tor_network_settings_bridge_config_toggle"
android:key="@string/pref_key_tor_network_settings_bridge_config_user_provided_bridge"
android:title="@string/preferences_tor_network_settings_bridge_config_user_provided_bridge"
android:summary="@string/preferences_tor_network_settings_bridge_config_user_provided_bridge_description" />
<Preference
android:dependency="@string/pref_key_tor_network_settings_bridge_config_toggle"
android:key="@string/pref_key_tor_network_settings_bridge_config_current_bridge"
android:title="@string/preferences_tor_network_settings_bridge_config_current_bridge" />
</androidx.preference.PreferenceScreen>
......@@ -934,28 +934,28 @@ class SettingsTest {
assertFalse(settings.shouldUseHttpsOnlyInPrivateTabsOnly)
}
@Test
fun `GIVEN open links in apps setting THEN return the correct display string`() {
settings.openLinksInExternalApp = "pref_key_open_links_in_apps_always"
settings.lastKnownMode = BrowsingMode.Normal
assertEquals(settings.getOpenLinksInAppsString(), "Always")
settings.openLinksInExternalApp = "pref_key_open_links_in_apps_ask"
assertEquals(settings.getOpenLinksInAppsString(), "Ask before opening")
settings.openLinksInExternalApp = "pref_key_open_links_in_apps_never"
assertEquals(settings.getOpenLinksInAppsString(), "Never")
settings.openLinksInExternalApp = "pref_key_open_links_in_apps_always"
settings.lastKnownMode = BrowsingMode.Private
assertEquals(settings.getOpenLinksInAppsString(), "Ask before opening")
settings.openLinksInExternalApp = "pref_key_open_links_in_apps_ask"
assertEquals(settings.getOpenLinksInAppsString(), "Ask before opening")
settings.openLinksInExternalApp = "pref_key_open_links_in_apps_never"
assertEquals(settings.getOpenLinksInAppsString(), "Never")
}
// @Test
// fun `GIVEN open links in apps setting THEN return the correct display string`() {
// settings.openLinksInExternalApp = "pref_key_open_links_in_apps_always"
// settings.lastKnownMode = BrowsingMode.Normal
// assertEquals(settings.getOpenLinksInAppsString(), "Always")
//
// settings.openLinksInExternalApp = "pref_key_open_links_in_apps_ask"
// assertEquals(settings.getOpenLinksInAppsString(), "Ask before opening")
//
// settings.openLinksInExternalApp = "pref_key_open_links_in_apps_never"
// assertEquals(settings.getOpenLinksInAppsString(), "Never")
//
// settings.openLinksInExternalApp = "pref_key_open_links_in_apps_always"
// settings.lastKnownMode = BrowsingMode.Private
// assertEquals(settings.getOpenLinksInAppsString(), "Ask before opening")
//
// settings.openLinksInExternalApp = "pref_key_open_links_in_apps_ask"
// assertEquals(settings.getOpenLinksInAppsString(), "Ask before opening")
//
// settings.openLinksInExternalApp = "pref_key_open_links_in_apps_never"
// assertEquals(settings.getOpenLinksInAppsString(), "Never")
// }
@Test
fun `GIVEN a written integer value for pref_key_search_widget_installed WHEN reading searchWidgetInstalled THEN do not throw a ClassCastException`() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment