Commits:
14 changed files:
Changes:
mobile/android/fenix/app/src/beta/res/drawable/tor_browser_app_icon.png
No preview for this file type
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/biometricauthentication/UnlockPrivateTabsFragment.kt
| ... |
... |
@@ -56,8 +56,7 @@ class UnlockPrivateTabsFragment : Fragment(), UserInteractionHandler { |
|
56
|
56
|
UnlockPrivateTabsScreen(
|
|
57
|
57
|
onUnlockClicked = { requestPrompt() },
|
|
58
|
58
|
onLeaveClicked = {
|
|
59
|
|
- PrivateBrowsingLocked.seeOtherTabsClicked.record()
|
|
60
|
|
- closeFragment()
|
|
|
59
|
+ requireActivity().moveTaskToBack(true)
|
|
61
|
60
|
},
|
|
62
|
61
|
)
|
|
63
|
62
|
|
| ... |
... |
@@ -67,13 +66,14 @@ class UnlockPrivateTabsFragment : Fragment(), UserInteractionHandler { |
|
67
|
66
|
}
|
|
68
|
67
|
|
|
69
|
68
|
override fun onBackPressed(): Boolean {
|
|
70
|
|
- closeFragment()
|
|
|
69
|
+ requireActivity().moveTaskToBack(true)
|
|
71
|
70
|
return true
|
|
72
|
71
|
}
|
|
73
|
72
|
|
|
74
|
73
|
private fun requestPrompt() {
|
|
75
|
74
|
DefaultBiometricUtils.bindBiometricsCredentialsPromptOrShowWarning(
|
|
76
|
|
- titleRes = R.string.pbm_authentication_unlock_private_tabs,
|
|
|
75
|
+ titleRes = R.string.tor_authentication_unlock_private_tabs,
|
|
|
76
|
+ titleRes2 = R.string.app_name,
|
|
77
|
77
|
view = requireView(),
|
|
78
|
78
|
onShowPinVerification = { intent -> startForResult.launch(intent) },
|
|
79
|
79
|
onAuthSuccess = ::onAuthSuccess,
|
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/biometricauthentication/UnlockPrivateTabsScreen.kt
| ... |
... |
@@ -31,6 +31,14 @@ import org.mozilla.fenix.ext.isLargeWindow |
|
31
|
31
|
import org.mozilla.fenix.theme.FirefoxTheme
|
|
32
|
32
|
import org.mozilla.fenix.theme.Theme
|
|
33
|
33
|
|
|
|
34
|
+import androidx.compose.foundation.layout.Row
|
|
|
35
|
+import androidx.compose.foundation.layout.size
|
|
|
36
|
+import androidx.compose.ui.text.AnnotatedString
|
|
|
37
|
+import androidx.compose.ui.text.SpanStyle
|
|
|
38
|
+import androidx.compose.ui.text.font.FontWeight
|
|
|
39
|
+import androidx.compose.ui.unit.sp
|
|
|
40
|
+import org.mozilla.fenix.compose.parseHtml
|
|
|
41
|
+
|
|
34
|
42
|
private const val FILL_WIDTH_LARGE_WINDOW = 0.5f
|
|
35
|
43
|
private const val FILL_WIDTH_DEFAULT = 1.0f
|
|
36
|
44
|
|
| ... |
... |
@@ -72,16 +80,30 @@ private fun Header() { |
|
72
|
80
|
modifier = Modifier.padding(horizontal = 16.dp),
|
|
73
|
81
|
horizontalAlignment = Alignment.CenterHorizontally,
|
|
74
|
82
|
) {
|
|
75
|
|
- Image(
|
|
76
|
|
- painter = painterResource(id = R.drawable.ic_pbm_firefox_logo),
|
|
77
|
|
- contentDescription = null, // decorative only.
|
|
78
|
|
- modifier = Modifier.padding(32.dp),
|
|
79
|
|
- )
|
|
|
83
|
+ Row (
|
|
|
84
|
+ verticalAlignment = Alignment.CenterVertically
|
|
|
85
|
+ ) {
|
|
|
86
|
+ Image(
|
|
|
87
|
+ painter = painterResource(id = R.drawable.tor_browser_app_icon),
|
|
|
88
|
+ contentDescription = null, // decorative only.
|
|
|
89
|
+ Modifier
|
|
|
90
|
+ .size(62.dp)
|
|
|
91
|
+ .padding(end = 10.dp),
|
|
|
92
|
+ )
|
|
|
93
|
+ Text(
|
|
|
94
|
+ text = stringResource(R.string.app_name),
|
|
|
95
|
+ color = FirefoxTheme.colors.textPrimary,
|
|
|
96
|
+ fontWeight = FontWeight.Bold,
|
|
|
97
|
+ fontSize = 29.sp,
|
|
|
98
|
+ letterSpacing = 0.18.sp,
|
|
|
99
|
+ lineHeight = 52.sp,
|
|
|
100
|
+ )
|
|
|
101
|
+ }
|
|
80
|
102
|
|
|
81
|
103
|
Spacer(modifier = Modifier.height(24.dp))
|
|
82
|
104
|
|
|
83
|
105
|
Text(
|
|
84
|
|
- text = stringResource(id = R.string.pbm_authentication_unlock_private_tabs),
|
|
|
106
|
+ text = stringResource(id = R.string.tor_authentication_unlock_private_tabs, stringResource(R.string.app_name)),
|
|
85
|
107
|
color = FirefoxTheme.colors.textPrimary,
|
|
86
|
108
|
textAlign = TextAlign.Center,
|
|
87
|
109
|
style = FirefoxTheme.typography.headline6,
|
| ... |
... |
@@ -109,15 +131,6 @@ private fun Footer(onUnlockClicked: () -> Unit, onLeaveClicked: () -> Unit) { |
|
109
|
131
|
modifier = Modifier.fillMaxWidth(),
|
|
110
|
132
|
onClick = onUnlockClicked,
|
|
111
|
133
|
)
|
|
112
|
|
-
|
|
113
|
|
- Spacer(modifier = Modifier.height(8.dp))
|
|
114
|
|
-
|
|
115
|
|
- TextButton(
|
|
116
|
|
- text = stringResource(R.string.pbm_authentication_leave_private_tabs),
|
|
117
|
|
- onClick = onLeaveClicked,
|
|
118
|
|
- textColor = FirefoxTheme.colors.textActionPrimary,
|
|
119
|
|
- upperCaseText = false,
|
|
120
|
|
- )
|
|
121
|
134
|
}
|
|
122
|
135
|
}
|
|
123
|
136
|
|
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/lifecycle/PrivateBrowsingLockFeature.kt
| ... |
... |
@@ -312,7 +312,8 @@ fun Fragment.verifyUser( |
|
312
|
312
|
onVerified: (() -> Unit)? = null,
|
|
313
|
313
|
) {
|
|
314
|
314
|
biometricUtils.bindBiometricsCredentialsPromptOrShowWarning(
|
|
315
|
|
- titleRes = R.string.pbm_authentication_unlock_private_tabs,
|
|
|
315
|
+ titleRes = R.string.tor_authentication_unlock_private_tabs,
|
|
|
316
|
+ titleRes2 = R.string.app_name,
|
|
316
|
317
|
view = requireView(),
|
|
317
|
318
|
onShowPinVerification = { intent -> fallbackVerification.launch(intent) },
|
|
318
|
319
|
onAuthSuccess = { handleVerificationSuccess(requireContext(), onVerified) },
|
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/TabsSettingsFragment.kt
| ... |
... |
@@ -17,6 +17,16 @@ import org.mozilla.fenix.ext.settings |
|
17
|
17
|
import org.mozilla.fenix.ext.showToolbar
|
|
18
|
18
|
import org.mozilla.fenix.utils.view.addToRadioGroup
|
|
19
|
19
|
|
|
|
20
|
+import android.content.Intent
|
|
|
21
|
+import android.provider.Settings
|
|
|
22
|
+import androidx.activity.result.ActivityResultLauncher
|
|
|
23
|
+import androidx.biometric.BiometricManager
|
|
|
24
|
+import androidx.preference.Preference
|
|
|
25
|
+import org.mozilla.fenix.ext.registerForActivityResult
|
|
|
26
|
+import org.mozilla.fenix.settings.biometric.DefaultBiometricUtils
|
|
|
27
|
+import org.mozilla.fenix.settings.biometric.ext.isAuthenticatorAvailable
|
|
|
28
|
+import org.mozilla.fenix.settings.biometric.ext.isHardwareAvailable
|
|
|
29
|
+
|
|
20
|
30
|
/**
|
|
21
|
31
|
* Lets the user customize auto closing tabs.
|
|
22
|
32
|
*/
|
| ... |
... |
@@ -40,6 +50,31 @@ class TabsSettingsFragment : PreferenceFragmentCompat() { |
|
40
|
50
|
findPreference<PreferenceCategory>(getString(R.string.pref_key_inactive_tabs_category))?.apply {
|
|
41
|
51
|
isVisible = !context.settings().shouldDisableNormalMode
|
|
42
|
52
|
}
|
|
|
53
|
+
|
|
|
54
|
+ startForResult = registerForActivityResult(
|
|
|
55
|
+ onFailure = { },
|
|
|
56
|
+ onSuccess = { onSuccessfulAuthenticationUsingFallbackPrompt() },
|
|
|
57
|
+ )
|
|
|
58
|
+ }
|
|
|
59
|
+
|
|
|
60
|
+ private lateinit var startForResult: ActivityResultLauncher<Intent>
|
|
|
61
|
+
|
|
|
62
|
+ private fun onSuccessfulAuthenticationUsingFallbackPrompt() {
|
|
|
63
|
+ val newValue = !requireContext().settings().privateBrowsingLockedEnabled
|
|
|
64
|
+ requireContext().settings().privateBrowsingLockedEnabled = newValue
|
|
|
65
|
+ // Update switch state manually
|
|
|
66
|
+ requirePreference<SwitchPreference>(R.string.pref_key_private_browsing_locked_enabled).apply {
|
|
|
67
|
+ isChecked = !isChecked
|
|
|
68
|
+ }
|
|
|
69
|
+ }
|
|
|
70
|
+
|
|
|
71
|
+ private fun onSuccessfulAuthenticationUsingPrimaryPrompt(
|
|
|
72
|
+ pbmLockEnabled: Boolean,
|
|
|
73
|
+ preference: Preference,
|
|
|
74
|
+ ) {
|
|
|
75
|
+ requireContext().settings().privateBrowsingLockedEnabled = pbmLockEnabled
|
|
|
76
|
+ // Update switch state manually
|
|
|
77
|
+ (preference as? SwitchPreference)?.isChecked = pbmLockEnabled
|
|
43
|
78
|
}
|
|
44
|
79
|
|
|
45
|
80
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
| ... |
... |
@@ -86,6 +121,67 @@ class TabsSettingsFragment : PreferenceFragmentCompat() { |
|
86
|
121
|
radioOneMonth.onClickListener(::enableInactiveTabsSetting)
|
|
87
|
122
|
|
|
88
|
123
|
setupRadioGroups()
|
|
|
124
|
+ /**
|
|
|
125
|
+ * Changes in this file for "tor-browser#44027 Update PBM lockscreen" were copied from
|
|
|
126
|
+ * [PrivateBrowsingFragment] and changed to make sense and work for TBA such as removing
|
|
|
127
|
+ * any use of nimbus/glean that was being used for business logic which was making the
|
|
|
128
|
+ * release build variant not work. We should check [PrivateBrowsingFragment] for updates
|
|
|
129
|
+ * when we rebase
|
|
|
130
|
+ * */
|
|
|
131
|
+ setUpHideBrowsingSessionPreference()
|
|
|
132
|
+ }
|
|
|
133
|
+
|
|
|
134
|
+ private fun setUpHideBrowsingSessionPreference() {
|
|
|
135
|
+ val biometricManager = BiometricManager.from(requireContext())
|
|
|
136
|
+ val deviceCapable = biometricManager.isHardwareAvailable()
|
|
|
137
|
+ val userHasEnabledCapability = biometricManager.isAuthenticatorAvailable()
|
|
|
138
|
+
|
|
|
139
|
+ requirePreference<SwitchPreference>(R.string.pref_key_private_browsing_locked_enabled).apply {
|
|
|
140
|
+ title = getString(R.string.preferences_tor_lock_screen_title, getString(R.string.app_name))
|
|
|
141
|
+ summary = getString(R.string.preferences_tor_lock_screen_summary, getString(R.string.app_name))
|
|
|
142
|
+ isChecked = context.settings().privateBrowsingLockedEnabled &&
|
|
|
143
|
+ biometricManager.isAuthenticatorAvailable()
|
|
|
144
|
+ isVisible = deviceCapable
|
|
|
145
|
+ isEnabled = userHasEnabledCapability
|
|
|
146
|
+
|
|
|
147
|
+ setOnPreferenceChangeListener { preference, newValue ->
|
|
|
148
|
+ val pbmLockEnabled = newValue as? Boolean
|
|
|
149
|
+ ?: return@setOnPreferenceChangeListener false
|
|
|
150
|
+
|
|
|
151
|
+ val titleRes = if (pbmLockEnabled) {
|
|
|
152
|
+ R.string.tor_authentication_enable_lock
|
|
|
153
|
+ } else {
|
|
|
154
|
+ R.string.tor_authentication_disable_lock
|
|
|
155
|
+ }
|
|
|
156
|
+
|
|
|
157
|
+ DefaultBiometricUtils.bindBiometricsCredentialsPromptOrShowWarning(
|
|
|
158
|
+ titleRes = titleRes,
|
|
|
159
|
+ titleRes2 = R.string.app_name,
|
|
|
160
|
+ view = requireView(),
|
|
|
161
|
+ onShowPinVerification = { intent -> startForResult.launch(intent) },
|
|
|
162
|
+ onAuthSuccess = {
|
|
|
163
|
+ onSuccessfulAuthenticationUsingPrimaryPrompt(
|
|
|
164
|
+ pbmLockEnabled = pbmLockEnabled,
|
|
|
165
|
+ preference = preference,
|
|
|
166
|
+ )
|
|
|
167
|
+ },
|
|
|
168
|
+ onAuthFailure = { },
|
|
|
169
|
+ )
|
|
|
170
|
+
|
|
|
171
|
+ // Cancel toggle change until biometric is successful
|
|
|
172
|
+ false
|
|
|
173
|
+ }
|
|
|
174
|
+ }
|
|
|
175
|
+
|
|
|
176
|
+ requirePreference<Preference>(R.string.pref_key_private_browsing_lock_device_feature_enabled).apply {
|
|
|
177
|
+ title = getString(R.string.tor_authentication_lock_device_feature_disabled, getString(R.string.app_name))
|
|
|
178
|
+ isVisible = deviceCapable && !userHasEnabledCapability
|
|
|
179
|
+
|
|
|
180
|
+ setOnPreferenceClickListener {
|
|
|
181
|
+ context.startActivity(Intent(Settings.ACTION_SECURITY_SETTINGS))
|
|
|
182
|
+ true
|
|
|
183
|
+ }
|
|
|
184
|
+ }
|
|
89
|
185
|
}
|
|
90
|
186
|
|
|
91
|
187
|
private fun setupRadioGroups() {
|
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/biometric/BiometricUtils.kt
| ... |
... |
@@ -42,6 +42,7 @@ interface BiometricUtils { |
|
42
|
42
|
*/
|
|
43
|
43
|
fun bindBiometricsCredentialsPromptOrShowWarning(
|
|
44
|
44
|
@StringRes titleRes: Int = R.string.logins_biometric_prompt_message_2,
|
|
|
45
|
+ @StringRes titleRes2: Int = R.string.empty_string,
|
|
45
|
46
|
view: View,
|
|
46
|
47
|
onShowPinVerification: (Intent) -> Unit,
|
|
47
|
48
|
onAuthSuccess: () -> Unit,
|
| ... |
... |
@@ -56,6 +57,7 @@ object DefaultBiometricUtils : BiometricUtils { |
|
56
|
57
|
@Suppress("Deprecation")
|
|
57
|
58
|
override fun bindBiometricsCredentialsPromptOrShowWarning(
|
|
58
|
59
|
@StringRes titleRes: Int,
|
|
|
60
|
+ @StringRes titleRes2: Int,
|
|
59
|
61
|
view: View,
|
|
60
|
62
|
onShowPinVerification: (Intent) -> Unit,
|
|
61
|
63
|
onAuthSuccess: () -> Unit,
|
| ... |
... |
@@ -90,7 +92,7 @@ object DefaultBiometricUtils : BiometricUtils { |
|
90
|
92
|
// Use the BiometricPrompt first
|
|
91
|
93
|
if (BiometricPromptFeature.canUseFeature(BiometricManager.from(context))) {
|
|
92
|
94
|
biometricPromptFeature.get()
|
|
93
|
|
- ?.requestAuthentication(context.resources.getString(titleRes))
|
|
|
95
|
+ ?.requestAuthentication(context.resources.getString(titleRes, context.resources.getString(titleRes2)))
|
|
94
|
96
|
return
|
|
95
|
97
|
}
|
|
96
|
98
|
|
| ... |
... |
@@ -99,7 +101,7 @@ object DefaultBiometricUtils : BiometricUtils { |
|
99
|
101
|
if (manager?.isKeyguardSecure == true) {
|
|
100
|
102
|
val confirmDeviceCredentialIntent = manager.createConfirmDeviceCredentialIntent(
|
|
101
|
103
|
context.resources.getString(R.string.logins_biometric_prompt_message_pin),
|
|
102
|
|
- context.resources.getString(titleRes),
|
|
|
104
|
+ context.resources.getString(titleRes, context.resources.getString(titleRes2)),
|
|
103
|
105
|
)
|
|
104
|
106
|
onShowPinVerification(confirmDeviceCredentialIntent)
|
|
105
|
107
|
} else {
|
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayBanner.kt
| ... |
... |
@@ -205,7 +205,7 @@ fun TabsTrayBanner( |
|
205
|
205
|
// After this bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1965545
|
|
206
|
206
|
// is resolved, we should swap the button 1 and button 2 click actions.
|
|
207
|
207
|
Banner(
|
|
208
|
|
- message = stringResource(id = R.string.private_tab_cfr_title),
|
|
|
208
|
+ message = stringResource(id = R.string.tor_tab_cfr_title, stringResource(R.string.app_name)),
|
|
209
|
209
|
button1Text = stringResource(id = R.string.private_tab_cfr_negative),
|
|
210
|
210
|
button2Text = stringResource(id = R.string.private_tab_cfr_positive),
|
|
211
|
211
|
onButton1Click = {
|
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt
| ... |
... |
@@ -265,7 +265,7 @@ class TabsTrayFragment : AppCompatDialogFragment() { |
|
265
|
265
|
shouldShowTabAutoCloseBanner = requireContext().settings().shouldShowAutoCloseTabsBanner &&
|
|
266
|
266
|
requireContext().settings().canShowCfr,
|
|
267
|
267
|
shouldShowLockPbmBanner =
|
|
268
|
|
- if (FxNimbus.features.privateBrowsingLock.value().enabled) {
|
|
|
268
|
+ if (true) {
|
|
269
|
269
|
shouldShowLockPbmBanner(
|
|
270
|
270
|
isPrivateMode = (activity as HomeActivity).browsingModeManager.mode.isPrivate,
|
|
271
|
271
|
hasPrivateTabs = requireComponents.core.store.state.privateTabs.isNotEmpty(),
|
| ... |
... |
@@ -775,10 +775,11 @@ class TabsTrayFragment : AppCompatDialogFragment() { |
|
775
|
775
|
val isAuthenticatorAvailable =
|
|
776
|
776
|
BiometricManager.from(requireContext()).isAuthenticatorAvailable()
|
|
777
|
777
|
if (!isAuthenticatorAvailable) {
|
|
778
|
|
- findNavController().navigate(TabsTrayFragmentDirections.actionGlobalPrivateBrowsingFragment())
|
|
|
778
|
+ findNavController().navigate(TabsTrayFragmentDirections.actionGlobalTabSettingsFragment())
|
|
779
|
779
|
} else {
|
|
780
|
780
|
DefaultBiometricUtils.bindBiometricsCredentialsPromptOrShowWarning(
|
|
781
|
|
- titleRes = R.string.pbm_authentication_enable_lock,
|
|
|
781
|
+ titleRes = R.string.tor_authentication_enable_lock,
|
|
|
782
|
+ titleRes2 = R.string.app_name,
|
|
782
|
783
|
view = requireView(),
|
|
783
|
784
|
onShowPinVerification = { intent -> enablePbmPinLauncher.launch(intent) },
|
|
784
|
785
|
onAuthSuccess = {
|
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt
| ... |
... |
@@ -334,10 +334,9 @@ class Settings(private val appContext: Context) : PreferencesHolder { |
|
334
|
334
|
default = false,
|
|
335
|
335
|
)
|
|
336
|
336
|
|
|
337
|
|
- var privateBrowsingLockedEnabled by lazyFeatureFlagPreference(
|
|
|
337
|
+ var privateBrowsingLockedEnabled by booleanPreference(
|
|
338
|
338
|
appContext.getPreferenceKey(R.string.pref_key_private_browsing_locked_enabled),
|
|
339
|
|
- featureFlag = FxNimbus.features.privateBrowsingLock.value().enabled,
|
|
340
|
|
- default = { false },
|
|
|
339
|
+ default = false,
|
|
341
|
340
|
)
|
|
342
|
341
|
|
|
343
|
342
|
var shouldReturnToBrowser by booleanPreference(
|
mobile/android/fenix/app/src/main/res/drawable/tor_browser_app_icon.png
No preview for this file type
mobile/android/fenix/app/src/main/res/values/torbrowser_strings.xml
| ... |
... |
@@ -142,4 +142,21 @@ |
|
142
|
142
|
<!-- Notification body for closing browser tabs. "%s" will be replaced with the localised application name, such as "Tor Browser". -->
|
|
143
|
143
|
<string name="notification_close_tor_browser_tabs_long">Tap or swipe this notification to close %s’s tabs</string>
|
|
144
|
144
|
|
|
|
145
|
+ <!-- Hide Tor Browser tabs authentication screen -->
|
|
|
146
|
+ <!-- Label for the primary action button to unlock private tabs. "%s" will be replaced with the localised application name, such as "Tor Browser" -->
|
|
|
147
|
+ <string name="tor_authentication_unlock_private_tabs">Unlock %s tabs</string>
|
|
|
148
|
+ <!-- Authentication prompt title to enable the private tabs mode. "%s" will be replaced with the localised application name, such as "Tor Browser" -->
|
|
|
149
|
+ <string name="tor_authentication_enable_lock">Enable %s tabs screen lock</string>
|
|
|
150
|
+ <!-- Authentication prompt title to disable the private tabs mode. "%s" will be replaced with the localised application name, such as "Tor Browser" -->
|
|
|
151
|
+ <string name="tor_authentication_disable_lock">Disable %s tabs screen lock</string>
|
|
|
152
|
+ <!-- Label for a preference shown when the device supports screen lock (e.g., PIN, pattern, or password) but the user has not set one up. "%s" will be replaced with the localised application name, such as "Tor Browser" -->
|
|
|
153
|
+ <string name="tor_authentication_lock_device_feature_disabled">Set up screen lock to hide %s tabs</string>
|
|
|
154
|
+ <!-- Title text for the contextual feature recommendation (CFR) suggesting the user enable a screen lock to protect Tor Browser tabs. "%s" will be replaced with the localised application name, such as "Tor Browser" -->
|
|
|
155
|
+ <string name="tor_tab_cfr_title">Use screen lock to hide %s tabs?</string>
|
|
|
156
|
+
|
|
|
157
|
+ <!-- Preference title for using the screen lock to hide Tor Browser tabs. "%s" will be replaced with the localised application name, such as "Tor Browser" -->
|
|
|
158
|
+ <string name="preferences_tor_lock_screen_title">Use screen lock to hide %s tabs</string>
|
|
|
159
|
+ <!-- Informs the user how to access the tabs when "Use screen lock to hide Tor Browser tabs" is enabled. "%s" will be replaced with the localised application name, such as "Tor Browser" -->
|
|
|
160
|
+ <string name="preferences_tor_lock_screen_summary">View %s tabs with your fingerprint, PIN, or face unlock.</string>
|
|
|
161
|
+
|
|
145
|
162
|
</resources> |
mobile/android/fenix/app/src/main/res/xml/tabs_preferences.xml
| ... |
... |
@@ -57,4 +57,14 @@ |
|
57
|
57
|
android:key="@string/pref_key_inactive_tabs"
|
|
58
|
58
|
android:title="@string/preferences_inactive_tabs_title"/>
|
|
59
|
59
|
</androidx.preference.PreferenceCategory>
|
|
|
60
|
+
|
|
|
61
|
+ <PreferenceCategory
|
|
|
62
|
+ android:key="@string/pref_key_pbm_lock_category_divider"
|
|
|
63
|
+ android:layout="@xml/preference_category_divider"
|
|
|
64
|
+ android:selectable="false" />
|
|
|
65
|
+ <SwitchPreference
|
|
|
66
|
+ android:defaultValue="false"
|
|
|
67
|
+ android:key="pref_key_private_browsing_locked_enabled" />
|
|
|
68
|
+ <Preference
|
|
|
69
|
+ android:key="@string/pref_key_private_browsing_lock_device_feature_enabled" />
|
|
60
|
70
|
</androidx.preference.PreferenceScreen> |
mobile/android/fenix/app/src/nightly/res/drawable/tor_browser_app_icon.png
No preview for this file type
mobile/android/fenix/app/src/release/res/drawable/tor_browser_app_icon.png
No preview for this file type
|