Commits:
-
fe45b5e3
by Henry Wilkes at 2026-08-05T12:12:42-06:00
fixup! TB 40597: Implement TorSettings module
TB 43571: Allow android to enter ProviderStopped.
-
80e2704f
by Henry Wilkes at 2026-08-05T12:12:43-06:00
fixup! TB 42247: Android helpers for the TorProvider
TB 43571: Drop `TorProviderBuilder.firstWindowLoaded`, which is covered
by `TorConnect.init` now.
-
48c8f5a9
by clairehurst at 2026-08-05T12:12:43-06:00
fixup! [android] Implement Android-native Connection Assist UI
Bug 43570: Add tor exit prompt
-
ec776e7f
by clairehurst at 2026-08-05T12:12:43-06:00
fixup! TB 42247: Android helpers for the TorProvider
Bug 43570: Add tor exit prompt
-
45aace81
by clairehurst at 2026-08-05T12:12:44-06:00
fixup! [android] TBA strings
Bug 43570: Add tor exit prompt
-
1efdc3dc
by clairehurst at 2026-08-05T12:12:44-06:00
fixup! [android] Implement Android-native Connection Assist UI
Bug 43570: Add tor exit prompt
# Conflicts:
# mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/ProviderStoppedViewModel.kt
-
5b194faf
by clairehurst at 2026-08-05T12:13:48-06:00
fixup! TB 40933: Add tor-launcher functionality
Bug 43571: [Android] Add tor exit prompt
Specifically, this commit is a patch provided from
https://gitlab.torproject.org/tpo/applications/tor-browser/-/merge_requests/2054#note_3446133
21 changed files:
Changes:
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
| ... |
... |
@@ -7,6 +7,7 @@ package org.mozilla.fenix |
|
7
|
7
|
import android.annotation.SuppressLint
|
|
8
|
8
|
import android.app.assist.AssistContent
|
|
9
|
9
|
import android.app.PendingIntent
|
|
|
10
|
+import android.content.ActivityNotFoundException
|
|
10
|
11
|
import android.content.ComponentName
|
|
11
|
12
|
import android.content.Context
|
|
12
|
13
|
import android.content.Intent
|
| ... |
... |
@@ -19,6 +20,7 @@ import android.os.Bundle |
|
19
|
20
|
import android.os.StrictMode
|
|
20
|
21
|
import android.text.format.DateUtils
|
|
21
|
22
|
import android.util.AttributeSet
|
|
|
23
|
+import android.util.Log
|
|
22
|
24
|
import android.view.ActionMode
|
|
23
|
25
|
import android.view.KeyEvent
|
|
24
|
26
|
import android.view.LayoutInflater
|
| ... |
... |
@@ -40,7 +42,9 @@ import androidx.core.net.toUri |
|
40
|
42
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|
41
|
43
|
import androidx.core.text.layoutDirection
|
|
42
|
44
|
import androidx.core.view.doOnLayout
|
|
|
45
|
+import androidx.lifecycle.Lifecycle
|
|
43
|
46
|
import androidx.lifecycle.lifecycleScope
|
|
|
47
|
+import androidx.lifecycle.repeatOnLifecycle
|
|
44
|
48
|
import androidx.navigation.NavController
|
|
45
|
49
|
import androidx.navigation.NavDirections
|
|
46
|
50
|
import androidx.navigation.fragment.NavHostFragment
|
| ... |
... |
@@ -203,6 +207,7 @@ import org.mozilla.fenix.compose.snackbar.SnackbarState |
|
203
|
207
|
import org.mozilla.fenix.compose.snackbar.Snackbar
|
|
204
|
208
|
import org.mozilla.fenix.tor.CustomSecurityLevelViewModel
|
|
205
|
209
|
import org.mozilla.fenix.tor.TorController
|
|
|
210
|
+import org.mozilla.fenix.tor.ProviderStoppedViewModel
|
|
206
|
211
|
import org.mozilla.fenix.tor.UrlQuickLoadViewModel
|
|
207
|
212
|
import org.mozilla.geckoview.TorAndroidIntegration.BootstrapStateChangeListener
|
|
208
|
213
|
import org.mozilla.geckoview.TorConnectStage
|
| ... |
... |
@@ -436,6 +441,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash |
|
436
|
441
|
|
|
437
|
442
|
private var dialog: RedirectDialogFragment? = null
|
|
438
|
443
|
|
|
|
444
|
+ private val providerStoppedViewModel: ProviderStoppedViewModel by viewModels()
|
|
|
445
|
+
|
|
439
|
446
|
private val urlQuickLoadViewModel: UrlQuickLoadViewModel by viewModels()
|
|
440
|
447
|
|
|
441
|
448
|
private val customSecurityLevelViewModel: CustomSecurityLevelViewModel by viewModels()
|
| ... |
... |
@@ -445,6 +452,18 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash |
|
445
|
452
|
// DO NOT MOVE ANYTHING ABOVE THIS getProfilerTime CALL.
|
|
446
|
453
|
val startTimeProfiler = components.core.engine.profiler?.getProfilerTime()
|
|
447
|
454
|
|
|
|
455
|
+ lifecycleScope.launch {
|
|
|
456
|
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
|
|
|
457
|
+ providerStoppedViewModel.providerStoppedStateFlow.collect { isStopped ->
|
|
|
458
|
+ Log.d("providerStoppedViewModel", "isStopped = $isStopped")
|
|
|
459
|
+ if (isStopped) {
|
|
|
460
|
+ navHost.navController.navigate(NavGraphDirections.actionNavigateToConnectionAssistFromAnywhere())
|
|
|
461
|
+ providerStoppedViewModel.providerStoppedStateFlow.value = false
|
|
|
462
|
+ }
|
|
|
463
|
+ }
|
|
|
464
|
+ }
|
|
|
465
|
+ }
|
|
|
466
|
+
|
|
448
|
467
|
// Setup nimbus-cli tooling. This is a NOOP when launching normally.
|
|
449
|
468
|
components.nimbus.sdk.initializeTooling(applicationContext, intent)
|
|
450
|
469
|
components.strictMode.attachListenerToDisablePenaltyDeath(supportFragmentManager)
|
| ... |
... |
@@ -1788,4 +1807,14 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash |
|
1788
|
1807
|
components.torController.shutdown()
|
|
1789
|
1808
|
exitProcess(0)
|
|
1790
|
1809
|
}
|
|
|
1810
|
+
|
|
|
1811
|
+ fun openBatterySaverSettings() {
|
|
|
1812
|
+ try {
|
|
|
1813
|
+ startActivity(
|
|
|
1814
|
+ Intent(android.provider.Settings.ACTION_BATTERY_SAVER_SETTINGS)
|
|
|
1815
|
+ )
|
|
|
1816
|
+ } catch (e: ActivityNotFoundException) {
|
|
|
1817
|
+ e.printStackTrace()
|
|
|
1818
|
+ }
|
|
|
1819
|
+ }
|
|
1791
|
1820
|
} |
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsFragment.kt
| ... |
... |
@@ -265,6 +265,13 @@ class SecretSettingsFragment : PreferenceFragmentCompat(), SystemInsetsPaddedFra |
|
265
|
265
|
}
|
|
266
|
266
|
}
|
|
267
|
267
|
|
|
|
268
|
+ requirePreference<Preference>(R.string.pref_key_test_kill_tor).apply {
|
|
|
269
|
+ setOnPreferenceClickListener {
|
|
|
270
|
+ requireContext().components.core.geckoRuntime.torIntegrationController.shutdown()
|
|
|
271
|
+ true
|
|
|
272
|
+ }
|
|
|
273
|
+ }
|
|
|
274
|
+
|
|
268
|
275
|
requirePreference<SwitchPreferenceCompat>(R.string.pref_key_enable_fxsuggest).apply {
|
|
269
|
276
|
isVisible = FeatureFlags.FX_SUGGEST
|
|
270
|
277
|
isChecked = settings.enableFxSuggest
|
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/ConnectAssistUiState.kt
| ... |
... |
@@ -3,8 +3,8 @@ package org.mozilla.fenix.tor |
|
3
|
3
|
import androidx.annotation.ColorRes
|
|
4
|
4
|
import androidx.annotation.DrawableRes
|
|
5
|
5
|
import androidx.annotation.StringRes
|
|
6
|
|
-import mozilla.components.lib.crash.R as crashR
|
|
7
|
6
|
import org.mozilla.fenix.R
|
|
|
7
|
+import mozilla.components.lib.crash.R as crashR
|
|
8
|
8
|
|
|
9
|
9
|
enum class ConnectAssistUiState(
|
|
10
|
10
|
val progressBarVisible: Boolean,
|
| ... |
... |
@@ -33,6 +33,7 @@ enum class ConnectAssistUiState( |
|
33
|
33
|
val torBootstrapButton2ShouldOpenSettings: Boolean = true,
|
|
34
|
34
|
val wordmarkLogoVisible: Boolean = false,
|
|
35
|
35
|
val torBootstrapButton2ShouldRestartApp: Boolean = false,
|
|
|
36
|
+ val torBootstrapButton1ShouldRestartTor: Boolean = false,
|
|
36
|
37
|
) {
|
|
37
|
38
|
Loading(
|
|
38
|
39
|
progressBarVisible = false,
|
| ... |
... |
@@ -298,5 +299,30 @@ enum class ConnectAssistUiState( |
|
298
|
299
|
torBootstrapButton2TextStringResource = crashR.string.mozac_lib_crash_dialog_button_restart,
|
|
299
|
300
|
torBootstrapButton2ShouldOpenSettings = false,
|
|
300
|
301
|
torBootstrapButton2ShouldRestartApp = true,
|
|
301
|
|
- )
|
|
|
302
|
+ ),
|
|
|
303
|
+ ProviderStopped(
|
|
|
304
|
+ progressBarVisible = false,
|
|
|
305
|
+ backButtonVisible = false,
|
|
|
306
|
+ settingsButtonVisible = true,
|
|
|
307
|
+ torConnectImageVisible = true,
|
|
|
308
|
+ torConnectImageResource = R.drawable.onion_broken,
|
|
|
309
|
+ titleLargeTextViewVisible = true,
|
|
|
310
|
+ titleLargeTextViewTextStringResource = R.string.connection_assist_provider_stopped_title,
|
|
|
311
|
+ titleDescriptionVisible = true,
|
|
|
312
|
+ learnMoreStringResource = R.string.connection_assist_final_error_learn_more_link,
|
|
|
313
|
+ internetErrorDescription = R.string.connection_assist_provider_stopped_description1,
|
|
|
314
|
+ internetErrorDescription1 = R.string.connection_assist_provider_stopped_description2,
|
|
|
315
|
+ internetErrorDescription2 = R.string.connection_assist_provider_stopped_description3,
|
|
|
316
|
+ titleDescriptionTextStringResource = null,
|
|
|
317
|
+ quickstartSwitchVisible = false,
|
|
|
318
|
+ regionDropDownVisible = false,
|
|
|
319
|
+ torBootstrapButton1Visible = true,
|
|
|
320
|
+ torBootstrapButton1TextStringResource = R.string.connection_assist_restart_connection_button,
|
|
|
321
|
+ torBootstrapButton1ShouldOpenSettings = false,
|
|
|
322
|
+ torBootstrapButton1ShouldRestartTor = true,
|
|
|
323
|
+ torBootstrapButton2Visible = false,
|
|
|
324
|
+ torBootstrapButton2TextStringResource = null,
|
|
|
325
|
+ torBootstrapButton2ShouldOpenSettings = false,
|
|
|
326
|
+ torBootstrapButton2ShouldRestartApp = false,
|
|
|
327
|
+ ),
|
|
302
|
328
|
} |
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/ProviderStoppedViewModel.kt
|
|
1
|
+package org.mozilla.fenix.tor
|
|
|
2
|
+
|
|
|
3
|
+import android.app.Application
|
|
|
4
|
+import android.util.Log
|
|
|
5
|
+import androidx.lifecycle.AndroidViewModel
|
|
|
6
|
+import kotlinx.coroutines.flow.MutableStateFlow
|
|
|
7
|
+import kotlinx.coroutines.flow.StateFlow
|
|
|
8
|
+import org.mozilla.fenix.ext.components
|
|
|
9
|
+import org.mozilla.geckoview.TorAndroidIntegration
|
|
|
10
|
+import org.mozilla.geckoview.TorConnectStage
|
|
|
11
|
+import org.mozilla.geckoview.TorConnectStageName
|
|
|
12
|
+
|
|
|
13
|
+class ProviderStoppedViewModel(
|
|
|
14
|
+ application: Application,
|
|
|
15
|
+) : AndroidViewModel(application), TorAndroidIntegration.BootstrapStateChangeListener {
|
|
|
16
|
+
|
|
|
17
|
+ private val TAG = "ProviderStoppedViewModel"
|
|
|
18
|
+
|
|
|
19
|
+ internal val providerStoppedStateFlow: MutableStateFlow<Boolean> by lazy { MutableStateFlow(false) }
|
|
|
20
|
+
|
|
|
21
|
+ private val _maybeConfigIssue = MutableStateFlow(false)
|
|
|
22
|
+ internal val maybeConfigIssue: StateFlow<Boolean> = _maybeConfigIssue
|
|
|
23
|
+
|
|
|
24
|
+ override fun onBootstrapStageChange(stage: TorConnectStage) {
|
|
|
25
|
+ when (stage.name) {
|
|
|
26
|
+ TorConnectStageName.ProviderStopped -> {
|
|
|
27
|
+ Log.d(TAG, "ProviderStopped detected")
|
|
|
28
|
+ providerStoppedStateFlow.value = true
|
|
|
29
|
+ }
|
|
|
30
|
+
|
|
|
31
|
+ else -> {
|
|
|
32
|
+ providerStoppedStateFlow.value = false
|
|
|
33
|
+ }
|
|
|
34
|
+ }
|
|
|
35
|
+
|
|
|
36
|
+ _maybeConfigIssue.value = stage.providerStatus.maybeConfigIssue
|
|
|
37
|
+ }
|
|
|
38
|
+
|
|
|
39
|
+ init {
|
|
|
40
|
+ getApplication<Application>().components.core.geckoRuntime.torIntegrationController.registerBootstrapStateChangeListener(this)
|
|
|
41
|
+ }
|
|
|
42
|
+
|
|
|
43
|
+ override fun onCleared() {
|
|
|
44
|
+ getApplication<Application>().components.core.geckoRuntime.torIntegrationController.unregisterBootstrapStateChangeListener(this)
|
|
|
45
|
+ }
|
|
|
46
|
+
|
|
|
47
|
+ override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) {}
|
|
|
48
|
+
|
|
|
49
|
+} |
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistFragment.kt
| ... |
... |
@@ -8,6 +8,7 @@ import android.graphics.Color |
|
8
|
8
|
import android.graphics.Typeface
|
|
9
|
9
|
import android.os.Build
|
|
10
|
10
|
import android.os.Bundle
|
|
|
11
|
+import android.os.PowerManager
|
|
11
|
12
|
import android.text.SpannableString
|
|
12
|
13
|
import android.text.Spanned
|
|
13
|
14
|
import android.text.TextPaint
|
| ... |
... |
@@ -17,9 +18,11 @@ import android.util.Log |
|
17
|
18
|
import android.view.LayoutInflater
|
|
18
|
19
|
import android.view.View
|
|
19
|
20
|
import android.view.ViewGroup
|
|
|
21
|
+import androidx.annotation.StringRes
|
|
20
|
22
|
import androidx.appcompat.content.res.AppCompatResources
|
|
21
|
23
|
import androidx.compose.foundation.Image
|
|
22
|
24
|
import androidx.compose.foundation.background
|
|
|
25
|
+import androidx.compose.foundation.layout.Arrangement
|
|
23
|
26
|
import androidx.compose.foundation.layout.Box
|
|
24
|
27
|
import androidx.compose.foundation.layout.Column
|
|
25
|
28
|
import androidx.compose.foundation.layout.Row
|
| ... |
... |
@@ -43,14 +46,22 @@ import androidx.compose.runtime.getValue |
|
43
|
46
|
import androidx.compose.runtime.mutableStateOf
|
|
44
|
47
|
import androidx.compose.runtime.saveable.rememberSaveable
|
|
45
|
48
|
import androidx.compose.runtime.setValue
|
|
|
49
|
+import androidx.compose.ui.Alignment
|
|
46
|
50
|
import androidx.compose.ui.Modifier
|
|
47
|
51
|
import androidx.compose.ui.platform.ViewCompositionStrategy
|
|
48
|
52
|
import androidx.compose.ui.res.painterResource
|
|
|
53
|
+import androidx.compose.ui.res.stringResource
|
|
|
54
|
+import androidx.compose.ui.text.LinkAnnotation
|
|
|
55
|
+import androidx.compose.ui.text.TextLinkStyles
|
|
49
|
56
|
import androidx.compose.ui.text.TextStyle
|
|
|
57
|
+import androidx.compose.ui.text.buildAnnotatedString
|
|
50
|
58
|
import androidx.compose.ui.text.font.FontWeight
|
|
|
59
|
+import androidx.compose.ui.text.style.TextDecoration
|
|
|
60
|
+import androidx.compose.ui.tooling.preview.Preview
|
|
51
|
61
|
import androidx.compose.ui.unit.DpOffset
|
|
52
|
62
|
import androidx.compose.ui.unit.dp
|
|
53
|
63
|
import androidx.compose.ui.unit.sp
|
|
|
64
|
+import androidx.core.content.getSystemService
|
|
54
|
65
|
import androidx.core.view.isEmpty
|
|
55
|
66
|
import androidx.fragment.app.Fragment
|
|
56
|
67
|
import androidx.fragment.app.activityViewModels
|
| ... |
... |
@@ -68,6 +79,7 @@ import org.mozilla.fenix.HomeActivity |
|
68
|
79
|
import org.mozilla.fenix.R
|
|
69
|
80
|
import org.mozilla.fenix.databinding.FragmentTorConnectionAssistBinding
|
|
70
|
81
|
import org.mozilla.fenix.e2e.SystemInsetsPaddedFragment
|
|
|
82
|
+import org.mozilla.fenix.ext.components
|
|
71
|
83
|
import org.mozilla.fenix.ext.hideToolbar
|
|
72
|
84
|
|
|
73
|
85
|
class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemInsetsPaddedFragment {
|
| ... |
... |
@@ -76,6 +88,7 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemIn |
|
76
|
88
|
private val progressViewModel: TorBootstrapProgressViewModel by viewModels()
|
|
77
|
89
|
private val quickstartViewModel: QuickstartViewModel by activityViewModels()
|
|
78
|
90
|
private val torConnectionAssistViewModel : TorConnectionAssistViewModel by viewModels()
|
|
|
91
|
+ private val providerStoppedViewModel : ProviderStoppedViewModel by activityViewModels()
|
|
79
|
92
|
|
|
80
|
93
|
private var _binding: FragmentTorConnectionAssistBinding? = null
|
|
81
|
94
|
private val binding get() = _binding!!
|
| ... |
... |
@@ -103,6 +116,7 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemIn |
|
103
|
116
|
Log.d(TAG, "shouldOpenHome = $it")
|
|
104
|
117
|
if (it) {
|
|
105
|
118
|
openHome()
|
|
|
119
|
+ torConnectionAssistViewModel.shouldOpenHome.value = false
|
|
106
|
120
|
}
|
|
107
|
121
|
}
|
|
108
|
122
|
|
| ... |
... |
@@ -200,13 +214,142 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemIn |
|
200
|
214
|
binding.torConnectImage.setImageResource(screen.torConnectImageResource)
|
|
201
|
215
|
}
|
|
202
|
216
|
|
|
|
217
|
+ @Composable
|
|
|
218
|
+ fun TextWithClickable(
|
|
|
219
|
+ @StringRes mainTextRes: Int,
|
|
|
220
|
+ @StringRes clickableTextRes: Int,
|
|
|
221
|
+ onClick: () -> Unit,
|
|
|
222
|
+ style: TextStyle,
|
|
|
223
|
+ tag: String,
|
|
|
224
|
+ ) {
|
|
|
225
|
+ Text(
|
|
|
226
|
+ text = buildAnnotatedString {
|
|
|
227
|
+ val clickableText = stringResource(clickableTextRes)
|
|
|
228
|
+ val plainText = stringResource(mainTextRes, clickableText)
|
|
|
229
|
+ append(plainText)
|
|
|
230
|
+ addLink(
|
|
|
231
|
+ clickable = LinkAnnotation.Clickable(
|
|
|
232
|
+ tag = tag,
|
|
|
233
|
+ styles = TextLinkStyles(
|
|
|
234
|
+ style = style.toSpanStyle().copy(textDecoration = TextDecoration.Underline),
|
|
|
235
|
+ pressedStyle = style.toSpanStyle(),
|
|
|
236
|
+ ),
|
|
|
237
|
+ linkInteractionListener = { onClick() }
|
|
|
238
|
+ ),
|
|
|
239
|
+ start = plainText.indexOf(clickableText),
|
|
|
240
|
+ end = plainText.indexOf(clickableText) + clickableText.length,
|
|
|
241
|
+ )
|
|
|
242
|
+ },
|
|
|
243
|
+ style = style,
|
|
|
244
|
+ )
|
|
|
245
|
+ }
|
|
|
246
|
+
|
|
|
247
|
+ @Preview
|
|
|
248
|
+ @Composable
|
|
|
249
|
+ fun DaemonFailedScreen(
|
|
|
250
|
+ isDeviceInPowerSaveMode: Boolean = false,
|
|
|
251
|
+ maybeConfigIssue: Boolean = false,
|
|
|
252
|
+ style: TextStyle = TextStyle(
|
|
|
253
|
+ fontSize = 16.sp,
|
|
|
254
|
+ lineHeight = 24.sp,
|
|
|
255
|
+ fontWeight = FontWeight(400),
|
|
|
256
|
+ color = PhotonColors.LightGrey05,
|
|
|
257
|
+ letterSpacing = 0.5.sp,
|
|
|
258
|
+ )
|
|
|
259
|
+ ) {
|
|
|
260
|
+ Column(
|
|
|
261
|
+ verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterVertically),
|
|
|
262
|
+ ) {
|
|
|
263
|
+ Text(
|
|
|
264
|
+ text = stringResource(R.string.connection_assist_provider_stopped_description1),
|
|
|
265
|
+ style = style,
|
|
|
266
|
+ )
|
|
|
267
|
+ Text(
|
|
|
268
|
+ text = stringResource(R.string.connection_assist_provider_stopped_description2),
|
|
|
269
|
+ style = style.copy(fontWeight = FontWeight.Bold),
|
|
|
270
|
+ )
|
|
|
271
|
+ if (isDeviceInPowerSaveMode && !maybeConfigIssue) {
|
|
|
272
|
+ Row {
|
|
|
273
|
+ Image(
|
|
|
274
|
+ painter = painterResource(R.drawable.bullet_point),
|
|
|
275
|
+ contentDescription = null,
|
|
|
276
|
+ modifier = Modifier.padding(6.dp)
|
|
|
277
|
+ )
|
|
|
278
|
+ Text(
|
|
|
279
|
+ style = style,
|
|
|
280
|
+ text = stringResource(R.string.connection_assist_provider_stopped_description_battery1),
|
|
|
281
|
+ )
|
|
|
282
|
+ }
|
|
|
283
|
+ }
|
|
|
284
|
+ Row {
|
|
|
285
|
+ Image(
|
|
|
286
|
+ painter = painterResource(R.drawable.bullet_point),
|
|
|
287
|
+ contentDescription = null,
|
|
|
288
|
+ modifier = Modifier.padding(6.dp)
|
|
|
289
|
+ )
|
|
|
290
|
+ Text(
|
|
|
291
|
+ style = style,
|
|
|
292
|
+ text = stringResource(R.string.connection_assist_provider_stopped_description3),
|
|
|
293
|
+ )
|
|
|
294
|
+ }
|
|
|
295
|
+ Text(
|
|
|
296
|
+ text = stringResource(R.string.connection_assist_provider_stopped_description4),
|
|
|
297
|
+ style = style.copy(fontWeight = FontWeight.Bold),
|
|
|
298
|
+ )
|
|
|
299
|
+ if (isDeviceInPowerSaveMode && !maybeConfigIssue) {
|
|
|
300
|
+ Row {
|
|
|
301
|
+ Image(
|
|
|
302
|
+ painter = painterResource(R.drawable.bullet_point),
|
|
|
303
|
+ contentDescription = null,
|
|
|
304
|
+ modifier = Modifier.padding(6.dp),
|
|
|
305
|
+ )
|
|
|
306
|
+ TextWithClickable(
|
|
|
307
|
+ mainTextRes = R.string.connection_assist_provider_stopped_description_turn_off_battery_saver2,
|
|
|
308
|
+ clickableTextRes = R.string.connection_assist_provider_stopped_description_turn_off_battery_saver_clickable,
|
|
|
309
|
+ onClick = { (requireActivity() as HomeActivity).openBatterySaverSettings() },
|
|
|
310
|
+ style = style,
|
|
|
311
|
+ tag = BATTERY_SETTINGS_TAG,
|
|
|
312
|
+ )
|
|
|
313
|
+ }
|
|
|
314
|
+ } else {
|
|
|
315
|
+ Row {
|
|
|
316
|
+ Image(
|
|
|
317
|
+ painter = painterResource(R.drawable.bullet_point),
|
|
|
318
|
+ contentDescription = null,
|
|
|
319
|
+ modifier = Modifier.padding(6.dp),
|
|
|
320
|
+ )
|
|
|
321
|
+ Text(
|
|
|
322
|
+ text = stringResource(R.string.connection_assist_provider_stopped_description5),
|
|
|
323
|
+ style = style,
|
|
|
324
|
+ )
|
|
|
325
|
+ }
|
|
|
326
|
+ }
|
|
|
327
|
+ Text(
|
|
|
328
|
+ text = stringResource(R.string.connection_assist_provider_stopped_description6,
|
|
|
329
|
+ stringResource(R.string.connection_assist_provider_stopped_description7)
|
|
|
330
|
+ ),
|
|
|
331
|
+ style = style,
|
|
|
332
|
+ )
|
|
|
333
|
+ }
|
|
|
334
|
+ }
|
|
|
335
|
+
|
|
203
|
336
|
private fun setTitle(screen: ConnectAssistUiState) {
|
|
204
|
337
|
binding.titleLargeTextView.visibility =
|
|
205
|
338
|
if (screen.titleLargeTextViewVisible) View.VISIBLE else View.GONE
|
|
206
|
339
|
binding.titleLargeTextView.text = getString(screen.titleLargeTextViewTextStringResource)
|
|
207
|
340
|
binding.titleDescription.visibility =
|
|
208
|
341
|
if (screen.titleDescriptionVisible) View.VISIBLE else View.GONE
|
|
209
|
|
- if (screen.learnMoreStringResource != null && screen.internetErrorDescription != null) {
|
|
|
342
|
+ binding.daemonFailedDescription.visibility = View.GONE
|
|
|
343
|
+ if (screen == ConnectAssistUiState.ProviderStopped) {
|
|
|
344
|
+ binding.titleDescription.visibility = View.GONE
|
|
|
345
|
+ binding.daemonFailedDescription.setContent {
|
|
|
346
|
+ DaemonFailedScreen(
|
|
|
347
|
+ isDeviceInPowerSaveMode = requireContext().getSystemService<PowerManager>()?.isPowerSaveMode ?: false,
|
|
|
348
|
+ maybeConfigIssue = providerStoppedViewModel.maybeConfigIssue.collectAsState().value,
|
|
|
349
|
+ )
|
|
|
350
|
+ }
|
|
|
351
|
+ binding.daemonFailedDescription.visibility = View.VISIBLE
|
|
|
352
|
+ } else if (screen.learnMoreStringResource != null && screen.internetErrorDescription != null) {
|
|
210
|
353
|
val learnMore: String = "" // getString(screen.learnMoreStringResource) tor-browser#43198 uncomment and add back once we have the "Learn more" screens for relevant pages
|
|
211
|
354
|
val internetErrorDescription: String =
|
|
212
|
355
|
if (screen.internetErrorDescription1 == null) {
|
| ... |
... |
@@ -434,6 +577,13 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemIn |
|
434
|
577
|
setOnClickListener {
|
|
435
|
578
|
if (screen.torBootstrapButton1ShouldOpenSettings) {
|
|
436
|
579
|
openTorConnectionSettings()
|
|
|
580
|
+ } else if (screen.torBootstrapButton1ShouldRestartTor) {
|
|
|
581
|
+ requireContext().components.core.geckoRuntime.torIntegrationController.restartProvider()
|
|
|
582
|
+ backgroundTintList = AppCompatResources.getColorStateList(
|
|
|
583
|
+ requireContext(),
|
|
|
584
|
+ R.color.disabled_connect_button_purple,
|
|
|
585
|
+ )
|
|
|
586
|
+ text = getString(R.string.connection_assist_restarting_connection_button)
|
|
437
|
587
|
} else {
|
|
438
|
588
|
torConnectionAssistViewModel.handleConnect(screen)
|
|
439
|
589
|
}
|
| ... |
... |
@@ -561,8 +711,11 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler, SystemIn |
|
561
|
711
|
}
|
|
562
|
712
|
|
|
563
|
713
|
override fun onBackPressed(): Boolean {
|
|
564
|
|
- torConnectionAssistViewModel.handleBackButtonPressed(requireActivity() as HomeActivity)
|
|
565
|
|
- return true
|
|
|
714
|
+ return torConnectionAssistViewModel.handleBackButtonPressed(requireActivity() as HomeActivity)
|
|
|
715
|
+ }
|
|
|
716
|
+
|
|
|
717
|
+ companion object {
|
|
|
718
|
+ const val BATTERY_SETTINGS_TAG = "BATTERY_SETTINGS_TAG"
|
|
566
|
719
|
}
|
|
567
|
720
|
|
|
568
|
721
|
} |
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistViewModel.kt
| ... |
... |
@@ -138,17 +138,18 @@ class TorConnectionAssistViewModel( |
|
138
|
138
|
torConnectStage.collect {
|
|
139
|
139
|
Log.d(TAG, "torConnectStageName: ${it?.name}")
|
|
140
|
140
|
when (it?.name) {
|
|
141
|
|
- TorConnectStageName.Disabled -> shouldOpenHome.value = true // TODO use TorConnect.enabled instead to determine this
|
|
142
|
|
- TorConnectStageName.Loading -> _torConnectScreen.value = ConnectAssistUiState.Loading
|
|
143
|
|
- TorConnectStageName.Start -> _torConnectScreen.value = ConnectAssistUiState.Start
|
|
144
|
|
- TorConnectStageName.Bootstrapping -> _torConnectScreen.value = handleBootstrapTrigger(it.bootstrapTrigger)
|
|
145
|
|
- TorConnectStageName.Offline -> _torConnectScreen.value = ConnectAssistUiState.Offline
|
|
146
|
|
- TorConnectStageName.ChooseRegion -> _torConnectScreen.value = ConnectAssistUiState.ChooseRegion
|
|
147
|
|
- TorConnectStageName.RegionNotFound -> _torConnectScreen.value = ConnectAssistUiState.RegionNotFound
|
|
148
|
|
- TorConnectStageName.ConfirmRegion -> _torConnectScreen.value = ConnectAssistUiState.ConfirmRegion
|
|
149
|
|
- TorConnectStageName.FinalError -> _torConnectScreen.value = ConnectAssistUiState.FinalError
|
|
150
|
|
- TorConnectStageName.Bootstrapped -> shouldOpenHome.value = true
|
|
151
|
|
- null -> {}
|
|
|
141
|
+ TorConnectStageName.Disabled -> shouldOpenHome.value = true // TODO use TorConnect.enabled instead to determine this
|
|
|
142
|
+ TorConnectStageName.Loading -> _torConnectScreen.value = ConnectAssistUiState.Loading
|
|
|
143
|
+ TorConnectStageName.ProviderStopped -> _torConnectScreen.value = ConnectAssistUiState.ProviderStopped
|
|
|
144
|
+ TorConnectStageName.Start -> _torConnectScreen.value = ConnectAssistUiState.Start
|
|
|
145
|
+ TorConnectStageName.Bootstrapping -> _torConnectScreen.value = handleBootstrapTrigger(it.bootstrapTrigger)
|
|
|
146
|
+ TorConnectStageName.Offline -> _torConnectScreen.value = ConnectAssistUiState.Offline
|
|
|
147
|
+ TorConnectStageName.ChooseRegion -> _torConnectScreen.value = ConnectAssistUiState.ChooseRegion
|
|
|
148
|
+ TorConnectStageName.RegionNotFound -> _torConnectScreen.value = ConnectAssistUiState.RegionNotFound
|
|
|
149
|
+ TorConnectStageName.ConfirmRegion -> _torConnectScreen.value = ConnectAssistUiState.ConfirmRegion
|
|
|
150
|
+ TorConnectStageName.FinalError -> _torConnectScreen.value = ConnectAssistUiState.FinalError
|
|
|
151
|
+ TorConnectStageName.Bootstrapped -> shouldOpenHome.value = true
|
|
|
152
|
+ null -> {}
|
|
152
|
153
|
}
|
|
153
|
154
|
}
|
|
154
|
155
|
}
|
| ... |
... |
@@ -168,11 +169,12 @@ class TorConnectionAssistViewModel( |
|
168
|
169
|
}
|
|
169
|
170
|
}
|
|
170
|
171
|
|
|
171
|
|
- fun handleBackButtonPressed(homeActivity: HomeActivity) {
|
|
172
|
|
- when (torConnectScreen.value) {
|
|
173
|
|
- ConnectAssistUiState.Loading -> homeActivity.shutDown()
|
|
174
|
|
- ConnectAssistUiState.Start -> homeActivity.shutDown()
|
|
175
|
|
- else -> torAndroidIntegration.startAgain()
|
|
|
172
|
+ fun handleBackButtonPressed(homeActivity: HomeActivity): Boolean {
|
|
|
173
|
+ return when (torConnectScreen.value) {
|
|
|
174
|
+ ConnectAssistUiState.Loading -> homeActivity.shutDown()
|
|
|
175
|
+ ConnectAssistUiState.Start -> homeActivity.shutDown()
|
|
|
176
|
+ ConnectAssistUiState.ProviderStopped -> false
|
|
|
177
|
+ else -> torAndroidIntegration.startAgain().let { true }
|
|
176
|
178
|
}
|
|
177
|
179
|
}
|
|
178
|
180
|
|
mobile/android/fenix/app/src/main/res/drawable/bullet_point.xml
|
|
1
|
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
|
2
|
+ android:autoMirrored="true"
|
|
|
3
|
+ android:height="6dp"
|
|
|
4
|
+ android:viewportHeight="6"
|
|
|
5
|
+ android:viewportWidth="6"
|
|
|
6
|
+ android:width="6dp">
|
|
|
7
|
+ <path
|
|
|
8
|
+ android:fillColor="#FBFBFE"
|
|
|
9
|
+ android:pathData="M3,3m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0" />
|
|
|
10
|
+</vector> |
mobile/android/fenix/app/src/main/res/drawable/loading_wheel.xml
|
|
1
|
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
|
2
|
+ android:autoMirrored="true"
|
|
|
3
|
+ android:height="16dp"
|
|
|
4
|
+ android:viewportHeight="16"
|
|
|
5
|
+ android:viewportWidth="16"
|
|
|
6
|
+ android:width="16dp">
|
|
|
7
|
+ <path
|
|
|
8
|
+ android:fillAlpha="0.4"
|
|
|
9
|
+ android:fillColor="#FBFBFE"
|
|
|
10
|
+ android:fillType="evenOdd"
|
|
|
11
|
+ android:pathData="M8,15C8,14.448 7.549,14.009 7.004,13.918C4.164,13.443 2,10.974 2,8C2,4.686 4.686,2 8,2C10.974,2 13.443,4.164 13.918,7.004C14.009,7.549 14.448,8 15,8C15.552,8 16.007,7.55 15.938,7.002C15.447,3.055 12.08,0 8,0C3.582,0 0,3.582 0,8C0,12.08 3.055,15.447 7.002,15.938C7.55,16.007 8,15.552 8,15Z" />
|
|
|
12
|
+</vector> |
mobile/android/fenix/app/src/main/res/drawable/onion_broken.xml
|
|
1
|
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="40dp" android:viewportHeight="40" android:viewportWidth="40" android:width="40dp">
|
|
|
2
|
+
|
|
|
3
|
+ <path android:fillColor="#FBFBFE" android:pathData="M33.259,33.258C29.865,36.651 25.178,38.75 20,38.75C9.645,38.75 1.25,30.355 1.25,20C1.25,14.823 3.348,10.135 6.741,6.742L8.813,8.814C5.95,11.677 4.18,15.632 4.18,20C4.18,28.737 11.263,35.82 20,35.82C24.369,35.82 28.324,34.049 31.187,31.186L33.259,33.258Z"/>
|
|
|
4
|
+
|
|
|
5
|
+ <path android:fillColor="#FBFBFE" android:pathData="M35.284,30.863C37.466,27.798 38.75,24.049 38.75,20C38.75,9.645 30.355,1.25 20,1.25C15.951,1.25 12.202,2.533 9.137,4.716L11.243,6.822C13.751,5.153 16.762,4.18 20,4.18C28.737,4.18 35.82,11.263 35.82,20C35.82,23.238 34.847,26.249 33.178,28.757L35.284,30.863Z"/>
|
|
|
6
|
+
|
|
|
7
|
+ <path android:fillColor="#FBFBFE" android:pathData="M31.226,26.805C32.431,24.82 33.125,22.491 33.125,20C33.125,12.751 27.249,6.875 20,6.875C17.509,6.875 15.18,7.569 13.195,8.774L15.347,10.926C16.742,10.209 18.324,9.805 20,9.805C25.631,9.805 30.195,14.369 30.195,20C30.195,21.676 29.791,23.258 29.074,24.653L31.226,26.805Z"/>
|
|
|
8
|
+
|
|
|
9
|
+ <path android:fillColor="#FBFBFE" android:pathData="M29.281,29.281L27.209,27.209C25.364,29.054 22.815,30.195 20,30.195C14.369,30.195 9.805,25.631 9.805,20C9.805,17.185 10.946,14.636 12.79,12.791L10.719,10.72C8.344,13.095 6.875,16.376 6.875,20C6.875,27.249 12.751,33.125 20,33.125C23.625,33.125 26.906,31.656 29.281,29.281Z"/>
|
|
|
10
|
+
|
|
|
11
|
+ <path android:fillColor="#FBFBFE" android:pathData="M14.696,14.697C13.339,16.054 12.5,17.929 12.5,20C12.5,24.142 15.858,27.5 20,27.5C22.071,27.5 23.946,26.66 25.303,25.303L23.232,23.232C22.405,24.059 21.262,24.57 20,24.57C17.476,24.57 15.43,22.524 15.43,20C15.43,18.738 15.941,17.596 16.768,16.769L14.696,14.697Z"/>
|
|
|
12
|
+
|
|
|
13
|
+ <path android:fillColor="#FBFBFE" android:pathData="M24.568,20.147C24.569,20.098 24.57,20.049 24.57,20C24.57,17.476 22.524,15.43 20,15.43C19.951,15.43 19.902,15.431 19.853,15.432L17.388,12.967C18.202,12.665 19.081,12.5 20,12.5C24.142,12.5 27.5,15.858 27.5,20C27.5,20.919 27.335,21.799 27.033,22.612L24.568,20.147Z"/>
|
|
|
14
|
+
|
|
|
15
|
+ <path android:fillColor="#FBFBFE" android:pathData="M20,38.75C9.645,38.75 1.25,30.355 1.25,20C1.25,14.823 3.348,10.135 6.741,6.742L20,20V38.75Z"/>
|
|
|
16
|
+
|
|
|
17
|
+ <path android:fillColor="#FBFBFE" android:pathData="M20,15.579V1.25C15.951,1.25 12.202,2.533 9.137,4.716L20,15.579Z"/>
|
|
|
18
|
+
|
|
|
19
|
+ <path android:fillColor="#FF9AA2" android:pathData="M35.291,39.061C35.085,39.062 34.882,39.021 34.692,38.943C34.503,38.864 34.33,38.749 34.186,38.604L2.31,6.731C2.037,6.434 1.889,6.043 1.898,5.64C1.906,5.236 2.07,4.851 2.355,4.566C2.64,4.28 3.025,4.116 3.428,4.107C3.832,4.099 4.223,4.246 4.52,4.519L36.396,36.394C36.688,36.688 36.851,37.085 36.851,37.5C36.851,37.915 36.688,38.312 36.396,38.606C36.25,38.751 36.078,38.866 35.888,38.944C35.699,39.022 35.496,39.062 35.291,39.061Z"/>
|
|
|
20
|
+
|
|
|
21
|
+</vector> |
mobile/android/fenix/app/src/main/res/layout/fragment_tor_connection_assist.xml
| ... |
... |
@@ -99,6 +99,19 @@ |
|
99
|
99
|
android:textSize="14sp"
|
|
100
|
100
|
app:layout_constraintTop_toBottomOf="@id/title_large_text_view" />
|
|
101
|
101
|
|
|
|
102
|
+ <androidx.compose.ui.platform.ComposeView
|
|
|
103
|
+ android:id="@+id/daemon_failed_description"
|
|
|
104
|
+ android:layout_width="match_parent"
|
|
|
105
|
+ android:layout_height="wrap_content"
|
|
|
106
|
+ android:visibility="gone"
|
|
|
107
|
+ android:paddingHorizontal="24dp"
|
|
|
108
|
+ android:paddingVertical="16dp"
|
|
|
109
|
+ app:layout_constraintBottom_toTopOf="@id/tor_bootstrap_button_1"
|
|
|
110
|
+ app:layout_constraintEnd_toEndOf="parent"
|
|
|
111
|
+ app:layout_constraintStart_toStartOf="parent"
|
|
|
112
|
+ app:layout_constraintTop_toBottomOf="@id/title_large_text_view"
|
|
|
113
|
+ app:layout_constraintVertical_bias="0" />
|
|
|
114
|
+
|
|
102
|
115
|
<androidx.appcompat.widget.SwitchCompat
|
|
103
|
116
|
android:id="@+id/quickstart_switch"
|
|
104
|
117
|
android:layout_width="match_parent"
|
mobile/android/fenix/app/src/main/res/navigation/nav_graph.xml
| ... |
... |
@@ -27,6 +27,10 @@ |
|
27
|
27
|
app:popUpTo="@id/torConnectionAssistFragment"
|
|
28
|
28
|
app:popUpToInclusive="true"/>
|
|
29
|
29
|
|
|
|
30
|
+ <action
|
|
|
31
|
+ android:id="@+id/action_navigate_to_connection_assist_from_anywhere"
|
|
|
32
|
+ app:destination="@id/torConnectionAssistFragment" />
|
|
|
33
|
+
|
|
30
|
34
|
<action
|
|
31
|
35
|
android:id="@+id/action_global_home"
|
|
32
|
36
|
app:destination="@id/homeFragment"
|
mobile/android/fenix/app/src/main/res/values/preference_keys.xml
| ... |
... |
@@ -652,6 +652,7 @@ |
|
652
|
652
|
<string name="pref_key_tor_network_settings_bridge_config" translatable="false">pref_key_tor_network_settings_bridge_config</string>
|
|
653
|
653
|
<string name="pref_key_tor_logs" translatable="false">pref_key_tor_logs</string>
|
|
654
|
654
|
<string name="pref_key_about_config_shortcut" translatable="false">pref_key_about_config_shortcut</string>
|
|
|
655
|
+ <string name="pref_key_test_kill_tor" translatable="false">pref_key_test_kill_tor</string>
|
|
655
|
656
|
<string name="pref_key_tor_network_settings_bridge_config_explanation" translatable="false">pref_key_tor_network_settings_bridge_config_explanation</string>
|
|
656
|
657
|
<string name="pref_key_tor_network_settings_bridge_config_toggle" translatable="false">pref_key_tor_network_settings_bridge_config_toggle</string>
|
|
657
|
658
|
<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>
|
mobile/android/fenix/app/src/main/res/values/torbrowser_strings.xml
| ... |
... |
@@ -135,6 +135,32 @@ |
|
135
|
135
|
<string name="connection_assist_back_button_content_description_start_again">Start again</string>
|
|
136
|
136
|
<!-- Connection assist. This message is shown briefly after the connection to the Tor network completes. -->
|
|
137
|
137
|
<string name="connection_assist_bootstrap_succeeded_toast_message">Connected to Tor</string>
|
|
|
138
|
+ <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
|
|
|
139
|
+ <string name="connection_assist_provider_stopped_title">The Tor process has stopped working</string>
|
|
|
140
|
+ <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. -->
|
|
|
141
|
+ <string name="connection_assist_provider_stopped_description1">The underlying process that controls your connection to the Tor network has stopped working.</string>
|
|
|
142
|
+ <!-- Connection assist. -->
|
|
|
143
|
+ <string name="connection_assist_provider_stopped_description2">What could be causing this?</string>
|
|
|
144
|
+ <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. -->
|
|
|
145
|
+ <string name="connection_assist_provider_stopped_description_battery1">Your device has quit the process to save battery.</string>
|
|
|
146
|
+ <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
|
|
|
147
|
+ <string name="connection_assist_provider_stopped_description3">The Tor process has stopped working due to a technical issue.</string>
|
|
|
148
|
+ <!-- Connection assist. -->
|
|
|
149
|
+ <string name="connection_assist_provider_stopped_description4">What can you do about it?</string>
|
|
|
150
|
+ <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
|
|
|
151
|
+ <string name="connection_assist_provider_stopped_description5">Try restarting the Tor process (this won’t close your browser tabs).</string>
|
|
|
152
|
+ <!-- Connection assist.-->
|
|
|
153
|
+ <string name="connection_assist_provider_stopped_description_turn_off_battery_saver_clickable">Turn off Battery Saver on your device</string>
|
|
|
154
|
+ <!-- Connection assist. "%1$s" will be replaced with connection_assist_provider_stopped_description_turn_off_battery_saver_clickable. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
|
|
|
155
|
+ <string name="connection_assist_provider_stopped_description_turn_off_battery_saver2">%1$s and try restarting the Tor process (this won’t close your browser tabs).</string>
|
|
|
156
|
+ <!-- Connection assist. "%1$s" will be replaced with connection_assist_provider_stopped_description7. -->
|
|
|
157
|
+ <string name="connection_assist_provider_stopped_description6">If the problem remains, get in contact with us through one of our %1$s.</string>
|
|
|
158
|
+ <!-- Connection assist. -->
|
|
|
159
|
+ <string name="connection_assist_provider_stopped_description7">support channels</string>
|
|
|
160
|
+ <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
|
|
|
161
|
+ <string name="connection_assist_restart_connection_button">Restart Tor process</string>
|
|
|
162
|
+ <!-- Connection assist. Here "process" is a noun, referring to the execution of a computer program. "Tor process" specifically refers to the execution of the tor program, which is the program that handles the connection to the "Tor network". -->
|
|
|
163
|
+ <string name="connection_assist_restarting_connection_button">Restarting Tor process…</string>
|
|
138
|
164
|
|
|
139
|
165
|
<!-- Notification title for closing browser tabs. "%s" will be replaced with the localised application name, such as "Tor Browser". -->
|
|
140
|
166
|
<string name="notification_close_tor_browser_tabs">Close %s’s tabs?</string>
|
mobile/android/fenix/app/src/main/res/xml/secret_settings_preferences.xml
| ... |
... |
@@ -135,6 +135,10 @@ |
|
135
|
135
|
android:key="@string/pref_key_enable_lna_tracker_blocking_enabled"
|
|
136
|
136
|
android:title="@string/preferences_debug_settings_enable_lna_tracker_blocking"
|
|
137
|
137
|
app:iconSpaceReserved="false" />
|
|
|
138
|
+ <Preference
|
|
|
139
|
+ android:key="@string/pref_key_test_kill_tor"
|
|
|
140
|
+ android:title="TEST kill tor daemon"
|
|
|
141
|
+ app:iconSpaceReserved="false" />
|
|
138
|
142
|
</PreferenceCategory>
|
|
139
|
143
|
|
|
140
|
144
|
<PreferenceCategory
|
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ProviderStatus.java
|
|
1
|
+package org.mozilla.geckoview;
|
|
|
2
|
+
|
|
|
3
|
+import org.mozilla.gecko.util.GeckoBundle;
|
|
|
4
|
+
|
|
|
5
|
+public class ProviderStatus {
|
|
|
6
|
+ public Boolean maybeConfigIssue;
|
|
|
7
|
+
|
|
|
8
|
+ public ProviderStatus(GeckoBundle bundle) {
|
|
|
9
|
+ maybeConfigIssue = bundle.getBoolean("maybeConfigIssue");
|
|
|
10
|
+ }
|
|
|
11
|
+} |
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorAndroidIntegration.java
| ... |
... |
@@ -57,6 +57,7 @@ public class TorAndroidIntegration implements BundleEventListener { |
|
57
|
57
|
private static final String EVENT_BOOTSTRAP_BEGIN_AUTO = "GeckoView:Tor:BootstrapBeginAuto";
|
|
58
|
58
|
private static final String EVENT_BOOTSTRAP_CANCEL = "GeckoView:Tor:BootstrapCancel";
|
|
59
|
59
|
private static final String EVENT_START_AGAIN = "GeckoView:Tor:StartAgain";
|
|
|
60
|
+ private static final String EVENT_RESTART_PROVIDER = "GeckoView:Tor:RestartProvider";
|
|
60
|
61
|
private static final String EVENT_QUICKSTART_GET = "GeckoView:Tor:QuickstartGet";
|
|
61
|
62
|
private static final String EVENT_QUICKSTART_SET = "GeckoView:Tor:QuickstartSet";
|
|
62
|
63
|
private static final String EVENT_REGION_NAMES_GET = "GeckoView:Tor:RegionNamesGet";
|
| ... |
... |
@@ -706,6 +707,10 @@ public class TorAndroidIntegration implements BundleEventListener { |
|
706
|
707
|
return EventDispatcher.getInstance().queryVoid(EVENT_START_AGAIN);
|
|
707
|
708
|
}
|
|
708
|
709
|
|
|
|
710
|
+ public @NonNull GeckoResult<Void> restartProvider() {
|
|
|
711
|
+ return EventDispatcher.getInstance().queryVoid(EVENT_RESTART_PROVIDER);
|
|
|
712
|
+ }
|
|
|
713
|
+
|
|
709
|
714
|
public interface QuickstartGetter {
|
|
710
|
715
|
void onValue(boolean enabled);
|
|
711
|
716
|
}
|
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorConnectStage.java
| ... |
... |
@@ -13,6 +13,7 @@ public class TorConnectStage { |
|
13
|
13
|
public Boolean potentiallyBlocked;
|
|
14
|
14
|
public Boolean tryAgain;
|
|
15
|
15
|
public TorBootstrappingStatus bootstrappingStatus;
|
|
|
16
|
+ public ProviderStatus providerStatus;
|
|
16
|
17
|
|
|
17
|
18
|
public TorConnectStage(GeckoBundle bundle) {
|
|
18
|
19
|
name = TorConnectStageName.fromString(bundle.getString("name"));
|
| ... |
... |
@@ -26,6 +27,7 @@ public class TorConnectStage { |
|
26
|
27
|
error = new TorConnectError(bundle.getBundle("error"));
|
|
27
|
28
|
}
|
|
28
|
29
|
bootstrappingStatus = new TorBootstrappingStatus(bundle.getBundle("bootstrappingStatus"));
|
|
|
30
|
+ providerStatus = new ProviderStatus(bundle.getBundle("providerStatus"));
|
|
29
|
31
|
}
|
|
30
|
32
|
|
|
31
|
33
|
public Boolean isBootstrapped() {
|
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorConnectStageName.java
| ... |
... |
@@ -3,9 +3,10 @@ package org.mozilla.geckoview; |
|
3
|
3
|
import java.security.InvalidParameterException;
|
|
4
|
4
|
|
|
5
|
5
|
public enum TorConnectStageName {
|
|
6
|
|
- // These names should match entries from TorConnectStage in TorConnect.sys.mjs at ~ln163.
|
|
|
6
|
+ // These names should match entries from TorConnectStage in TorConnect.sys.mjs at ~ln674.
|
|
7
|
7
|
Disabled("Disabled"),
|
|
8
|
8
|
Loading("Loading"),
|
|
|
9
|
+ ProviderStopped("ProviderStopped"),
|
|
9
|
10
|
Start("Start"),
|
|
10
|
11
|
Bootstrapping("Bootstrapping"),
|
|
11
|
12
|
Offline("Offline"),
|
toolkit/components/tor-launcher/TorProcessAndroid.sys.mjs
| ... |
... |
@@ -51,6 +51,11 @@ export class TorProcessAndroid { |
|
51
|
51
|
* it failed to start tor.
|
|
52
|
52
|
*/
|
|
53
|
53
|
#startReject = null;
|
|
|
54
|
+ /**
|
|
|
55
|
+ * Tells whether we ever registered ourself as the listener to the various
|
|
|
56
|
+ * process events.
|
|
|
57
|
+ */
|
|
|
58
|
+ #registeredListeners = false;
|
|
54
|
59
|
|
|
55
|
60
|
onExit = () => {};
|
|
56
|
61
|
|
| ... |
... |
@@ -74,6 +79,7 @@ export class TorProcessAndroid { |
|
74
|
79
|
this,
|
|
75
|
80
|
Object.values(TorIncomingEvents)
|
|
76
|
81
|
);
|
|
|
82
|
+ this.#registeredListeners = true;
|
|
77
|
83
|
let config;
|
|
78
|
84
|
try {
|
|
79
|
85
|
config = await lazy.EventDispatcher.instance.sendRequestForResult(
|
| ... |
... |
@@ -103,10 +109,13 @@ export class TorProcessAndroid { |
|
103
|
109
|
});
|
|
104
|
110
|
logger.debug("Sent the stop event.");
|
|
105
|
111
|
this.#processHandle = null;
|
|
106
|
|
- lazy.EventDispatcher.instance.unregisterListener(
|
|
107
|
|
- this,
|
|
108
|
|
- Object.values(TorIncomingEvents)
|
|
109
|
|
- );
|
|
|
112
|
+ if (this.#registeredListeners) {
|
|
|
113
|
+ lazy.EventDispatcher.instance.unregisterListener(
|
|
|
114
|
+ this,
|
|
|
115
|
+ Object.values(TorIncomingEvents)
|
|
|
116
|
+ );
|
|
|
117
|
+ this.#registeredListeners = false;
|
|
|
118
|
+ }
|
|
110
|
119
|
}
|
|
111
|
120
|
|
|
112
|
121
|
onEvent(event, data, _callback) {
|
toolkit/modules/TorAndroidIntegration.sys.mjs
| ... |
... |
@@ -48,6 +48,7 @@ const ListenedEvents = Object.freeze({ |
|
48
|
48
|
bootstrapBeginAuto: "GeckoView:Tor:BootstrapBeginAuto",
|
|
49
|
49
|
bootstrapCancel: "GeckoView:Tor:BootstrapCancel",
|
|
50
|
50
|
startAgain: "GeckoView:Tor:StartAgain",
|
|
|
51
|
+ restartProvider: "GeckoView:Tor:RestartProvider",
|
|
51
|
52
|
quickstartGet: "GeckoView:Tor:QuickstartGet",
|
|
52
|
53
|
quickstartSet: "GeckoView:Tor:QuickstartSet",
|
|
53
|
54
|
regionNamesGet: "GeckoView:Tor:RegionNamesGet",
|
| ... |
... |
@@ -98,11 +99,6 @@ class TorAndroidIntegrationImpl { |
|
98
|
99
|
lazy.TorConnect.init();
|
|
99
|
100
|
|
|
100
|
101
|
lazy.TorDomainIsolator.init();
|
|
101
|
|
-
|
|
102
|
|
- // On Android immediately call firstWindowLoaded. This should be safe to
|
|
103
|
|
- // call since it will await the initialisation of the TorProvider set up
|
|
104
|
|
- // by TorProviderBuilder.init.
|
|
105
|
|
- lazy.TorProviderBuilder.firstWindowLoaded();
|
|
106
|
102
|
}
|
|
107
|
103
|
|
|
108
|
104
|
observe(subj, topic) {
|
| ... |
... |
@@ -203,6 +199,9 @@ class TorAndroidIntegrationImpl { |
|
203
|
199
|
case ListenedEvents.startAgain:
|
|
204
|
200
|
lazy.TorConnect.startAgain();
|
|
205
|
201
|
break;
|
|
|
202
|
+ case ListenedEvents.restartProvider:
|
|
|
203
|
+ lazy.TorConnect.restartProvider();
|
|
|
204
|
+ break;
|
|
206
|
205
|
case ListenedEvents.quickstartGet:
|
|
207
|
206
|
callback?.onSuccess(lazy.TorConnect.quickstart);
|
|
208
|
207
|
return;
|
toolkit/modules/TorConnect.sys.mjs
| ... |
... |
@@ -1109,12 +1109,9 @@ export const TorConnect = { |
|
1109
|
1109
|
throw new Error(`Trying to set the stage to ${name} during a bootstrap`);
|
|
1110
|
1110
|
}
|
|
1111
|
1111
|
if (!this._providerRunning && name !== TorConnectStage.ProviderStopped) {
|
|
1112
|
|
- if (!lazy.TorLauncherUtil.isAndroid) {
|
|
1113
|
|
- // TODO: Remove Android exception.
|
|
1114
|
|
- throw new Error(
|
|
1115
|
|
- `Trying to set the stage to ${name} when provider is not running`
|
|
1116
|
|
- );
|
|
1117
|
|
- }
|
|
|
1112
|
+ throw new Error(
|
|
|
1113
|
+ `Trying to set the stage to ${name} when provider is not running`
|
|
|
1114
|
+ );
|
|
1118
|
1115
|
}
|
|
1119
|
1116
|
|
|
1120
|
1117
|
lazy.logger.info(`Entering stage ${name}`);
|
| ... |
... |
@@ -1596,13 +1593,8 @@ export const TorConnect = { |
|
1596
|
1593
|
return;
|
|
1597
|
1594
|
}
|
|
1598
|
1595
|
if (!this._providerRunning && stage !== TorConnectStage.ProviderStopped) {
|
|
1599
|
|
- if (!lazy.TorLauncherUtil.isAndroid) {
|
|
1600
|
|
- // TODO: Remove Android exception.
|
|
1601
|
|
- lazy.logger.warn(
|
|
1602
|
|
- `Cannot move to ${stage} when provider is not running`
|
|
1603
|
|
- );
|
|
1604
|
|
- return;
|
|
1605
|
|
- }
|
|
|
1596
|
+ lazy.logger.warn(`Cannot move to ${stage} when provider is not running`);
|
|
|
1597
|
+ return;
|
|
1606
|
1598
|
}
|
|
1607
|
1599
|
if (this._stageName === TorConnectStage.Loading) {
|
|
1608
|
1600
|
if (stage === TorConnectStage.ProviderStopped) {
|
| ... |
... |
@@ -1709,13 +1701,7 @@ export const TorConnect = { |
|
1709
|
1701
|
// But other methods should take into account that _providerRunning is now
|
|
1710
|
1702
|
// `false` to early return and guarantee that we enter this
|
|
1711
|
1703
|
// ProviderStopped stage.
|
|
1712
|
|
- if (lazy.TorLauncherUtil.isAndroid) {
|
|
1713
|
|
- // TODO: Remove this Android path when android supports the
|
|
1714
|
|
- // `ProviderStopped` stage.
|
|
1715
|
|
- this._makeStageRequest(TorConnectStage.Start, true);
|
|
1716
|
|
- } else {
|
|
1717
|
|
- this._makeStageRequest(TorConnectStage.ProviderStopped, true);
|
|
1718
|
|
- }
|
|
|
1704
|
+ this._makeStageRequest(TorConnectStage.ProviderStopped, true);
|
|
1719
|
1705
|
}
|
|
1720
|
1706
|
}
|
|
1721
|
1707
|
|
|