Commits:
-
6199983c
by Dan Ballard at 2025-03-13T11:17:04-07:00
fixup! TB 42247: Android helpers for the TorProvider
Bug 41188: Add staging event wiring
-
d9c0e220
by Dan Ballard at 2025-03-13T11:17:04-07:00
fixup! TB 41878: [android] Add standalone Tor Bootstrap
Bug 41188: Add staging event wiring
-
f545b853
by Dan Ballard at 2025-03-13T11:17:04-07:00
fixup! [android] Implement Android-native Connection Assist UI
Bug 41188: Add staging event wiring
-
da17f78c
by Dan Ballard at 2025-03-13T11:17:05-07:00
fixup! TB 40597: Implement TorSettings module
Bug 41188: pt1 add android stages
9 changed files:
Changes:
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
| ... |
... |
@@ -157,6 +157,7 @@ import org.mozilla.fenix.components.FenixSnackbar |
|
157
|
157
|
import org.mozilla.fenix.home.HomeFragment
|
|
158
|
158
|
import org.mozilla.fenix.tor.UrlQuickLoadViewModel
|
|
159
|
159
|
import org.mozilla.geckoview.TorAndroidIntegration
|
|
|
160
|
+import org.mozilla.geckoview.TorConnectStage
|
|
160
|
161
|
|
|
161
|
162
|
/**
|
|
162
|
163
|
* The main activity of the application. The application is primarily a single Activity (this one)
|
| ... |
... |
@@ -1453,6 +1454,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorAn |
|
1453
|
1454
|
}
|
|
1454
|
1455
|
|
|
1455
|
1456
|
override fun onBootstrapStateChange(state: String) = Unit
|
|
|
1457
|
+ override fun onBootstrapStageChange(stage: TorConnectStage) = Unit
|
|
1456
|
1458
|
override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) = Unit
|
|
1457
|
1459
|
override fun onBootstrapComplete() {
|
|
1458
|
1460
|
if (settings().useHtmlConnectionUi) {
|
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorBootstrapProgressViewModel.kt
| ... |
... |
@@ -5,6 +5,7 @@ import androidx.lifecycle.AndroidViewModel |
|
5
|
5
|
import androidx.lifecycle.MutableLiveData
|
|
6
|
6
|
import org.mozilla.fenix.ext.components
|
|
7
|
7
|
import org.mozilla.geckoview.TorAndroidIntegration.BootstrapStateChangeListener
|
|
|
8
|
+import org.mozilla.geckoview.TorConnectStage
|
|
8
|
9
|
|
|
9
|
10
|
class TorBootstrapProgressViewModel(
|
|
10
|
11
|
application: Application,
|
| ... |
... |
@@ -27,6 +28,7 @@ class TorBootstrapProgressViewModel( |
|
27
|
28
|
}
|
|
28
|
29
|
|
|
29
|
30
|
override fun onBootstrapStateChange(state: String?) {}
|
|
|
31
|
+ override fun onBootstrapStageChange(stage: TorConnectStage) = Unit
|
|
30
|
32
|
|
|
31
|
33
|
override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) {
|
|
32
|
34
|
this.progress.value = progress.toInt()
|
mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerGV.kt
| ... |
... |
@@ -11,6 +11,7 @@ import org.mozilla.fenix.ext.components |
|
11
|
11
|
import org.mozilla.geckoview.TorAndroidIntegration
|
|
12
|
12
|
import org.mozilla.geckoview.TorAndroidIntegration.BootstrapStateChangeListener
|
|
13
|
13
|
import org.mozilla.geckoview.TorAndroidIntegration.TorLogListener
|
|
|
14
|
+import org.mozilla.geckoview.TorConnectStage
|
|
14
|
15
|
import org.mozilla.geckoview.TorSettings
|
|
15
|
16
|
import org.mozilla.geckoview.TorSettings.BridgeBuiltinType
|
|
16
|
17
|
import org.mozilla.geckoview.TorSettings.BridgeSource
|
| ... |
... |
@@ -322,6 +323,8 @@ class TorControllerGV( |
|
322
|
323
|
onTorStatusUpdate(null, newStateVal, null)
|
|
323
|
324
|
}
|
|
324
|
325
|
|
|
|
326
|
+ override fun onBootstrapStageChange(stage: TorConnectStage) = Unit
|
|
|
327
|
+
|
|
325
|
328
|
// TorEventsBootstrapStateChangeListener
|
|
326
|
329
|
override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) {
|
|
327
|
330
|
Log.d(TAG, "onBootstrapProgress(progress = $progress, hasWarnings = $hasWarnings)")
|
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorAndroidIntegration.java
| ... |
... |
@@ -37,7 +37,8 @@ public class TorAndroidIntegration implements BundleEventListener { |
|
37
|
37
|
private static final String EVENT_TOR_STOP = "GeckoView:Tor:StopTor";
|
|
38
|
38
|
private static final String EVENT_MEEK_START = "GeckoView:Tor:StartMeek";
|
|
39
|
39
|
private static final String EVENT_MEEK_STOP = "GeckoView:Tor:StopMeek";
|
|
40
|
|
- private static final String EVENT_CONNECT_STATE_CHANGED = "GeckoView:Tor:ConnectStateChanged";
|
|
|
40
|
+ private static final String EVENT_CONNECT_STATE_CHANGED = "GeckoView:Tor:ConnectStateChanged"; // deprecation path
|
|
|
41
|
+ private static final String EVENT_CONNECT_STAGE_CHANGED = "GeckoView:Tor:ConnectStageChanged"; // replacement path
|
|
41
|
42
|
private static final String EVENT_CONNECT_ERROR = "GeckoView:Tor:ConnectError";
|
|
42
|
43
|
private static final String EVENT_BOOTSTRAP_PROGRESS = "GeckoView:Tor:BootstrapProgress";
|
|
43
|
44
|
private static final String EVENT_BOOTSTRAP_COMPLETE = "GeckoView:Tor:BootstrapComplete";
|
| ... |
... |
@@ -114,6 +115,7 @@ public class TorAndroidIntegration implements BundleEventListener { |
|
114
|
115
|
EVENT_SETTINGS_READY,
|
|
115
|
116
|
EVENT_SETTINGS_CHANGED,
|
|
116
|
117
|
EVENT_CONNECT_STATE_CHANGED,
|
|
|
118
|
+ EVENT_CONNECT_STAGE_CHANGED,
|
|
117
|
119
|
EVENT_CONNECT_ERROR,
|
|
118
|
120
|
EVENT_BOOTSTRAP_PROGRESS,
|
|
119
|
121
|
EVENT_BOOTSTRAP_COMPLETE,
|
| ... |
... |
@@ -150,6 +152,11 @@ public class TorAndroidIntegration implements BundleEventListener { |
|
150
|
152
|
for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
|
|
151
|
153
|
listener.onBootstrapStateChange(state);
|
|
152
|
154
|
}
|
|
|
155
|
+ } else if (EVENT_CONNECT_STAGE_CHANGED.equals(event)) {
|
|
|
156
|
+ TorConnectStage stage = new TorConnectStage(message.getBundle("stage"));
|
|
|
157
|
+ for (BootstrapStateChangeListener listener : mBootstrapStateListeners) {
|
|
|
158
|
+ listener.onBootstrapStageChange(stage);
|
|
|
159
|
+ }
|
|
153
|
160
|
} else if (EVENT_CONNECT_ERROR.equals(event)) {
|
|
154
|
161
|
String code = message.getString("code");
|
|
155
|
162
|
String msg = message.getString("message");
|
| ... |
... |
@@ -629,7 +636,9 @@ public class TorAndroidIntegration implements BundleEventListener { |
|
629
|
636
|
}
|
|
630
|
637
|
|
|
631
|
638
|
public interface BootstrapStateChangeListener {
|
|
632
|
|
- void onBootstrapStateChange(String state);
|
|
|
639
|
+ void onBootstrapStateChange(String state); // depreaction path
|
|
|
640
|
+
|
|
|
641
|
+ void onBootstrapStageChange(TorConnectStage stage); // new upgrade
|
|
633
|
642
|
|
|
634
|
643
|
void onBootstrapProgress(double progress, boolean hasWarnings);
|
|
635
|
644
|
|
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorBootstrappingStatus.java
|
|
1
|
+package org.mozilla.geckoview;
|
|
|
2
|
+
|
|
|
3
|
+import org.mozilla.gecko.util.GeckoBundle;
|
|
|
4
|
+
|
|
|
5
|
+// Class to receive BootstrappingStatus object from TorConnect.sys.mjs ~ln698
|
|
|
6
|
+public class TorBootstrappingStatus {
|
|
|
7
|
+ public int progress; // percent of bootstrap progress
|
|
|
8
|
+ public boolean hasWarning; // Whether this bootstrap has a warning in the tor log
|
|
|
9
|
+
|
|
|
10
|
+ public TorBootstrappingStatus(GeckoBundle bundle) {
|
|
|
11
|
+ progress = bundle.getInt("progress");
|
|
|
12
|
+ hasWarning = bundle.getBoolean("hasWarning");
|
|
|
13
|
+ }
|
|
|
14
|
+} |
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorConnectStage.java
|
|
1
|
+package org.mozilla.geckoview;
|
|
|
2
|
+
|
|
|
3
|
+import org.mozilla.gecko.util.GeckoBundle;
|
|
|
4
|
+
|
|
|
5
|
+// Class to receive ConnectStage object from TorConnect.sys.mjs ~ln677
|
|
|
6
|
+public class TorConnectStage {
|
|
|
7
|
+
|
|
|
8
|
+ public class Error {
|
|
|
9
|
+ public String code;
|
|
|
10
|
+ public String message;
|
|
|
11
|
+ public String phase;
|
|
|
12
|
+ public String reason;
|
|
|
13
|
+
|
|
|
14
|
+ public Error(GeckoBundle bundle) {
|
|
|
15
|
+ code = bundle.getString("code");
|
|
|
16
|
+ message = bundle.getString("message");
|
|
|
17
|
+ phase = bundle.getString("phase");
|
|
|
18
|
+ reason = bundle.getString("reason");
|
|
|
19
|
+ }
|
|
|
20
|
+ }
|
|
|
21
|
+
|
|
|
22
|
+ public TorConnectStageName name;
|
|
|
23
|
+ // The TorConnectStage prior to this bootstrap attempt. Only set during the "Bootstrapping" stage.
|
|
|
24
|
+ public TorConnectStageName bootstrapTrigger;
|
|
|
25
|
+ public Error error;
|
|
|
26
|
+ public String defaultRegion;
|
|
|
27
|
+ public Boolean potentiallyBlocked;
|
|
|
28
|
+ public Boolean tryAgain;
|
|
|
29
|
+ public TorBootstrappingStatus bootstrappingStatus;
|
|
|
30
|
+
|
|
|
31
|
+ public TorConnectStage(GeckoBundle bundle) {
|
|
|
32
|
+ name = TorConnectStageName.fromString(bundle.getString("name"));
|
|
|
33
|
+ if (bundle.getString("bootstrapTrigger") != null) {
|
|
|
34
|
+ bootstrapTrigger = TorConnectStageName.fromString(bundle.getString("bootstrapTrigger"));
|
|
|
35
|
+ }
|
|
|
36
|
+ defaultRegion = bundle.getString("defaultRegion");
|
|
|
37
|
+ potentiallyBlocked = bundle.getBoolean("potentiallyBlocked");
|
|
|
38
|
+ tryAgain = bundle.getBoolean("tryAgain");
|
|
|
39
|
+ if (bundle.getBundle("error") != null) {
|
|
|
40
|
+ error = new Error(bundle.getBundle("error"));
|
|
|
41
|
+ }
|
|
|
42
|
+ bootstrappingStatus = new TorBootstrappingStatus(bundle.getBundle("bootstrappingStatus"));
|
|
|
43
|
+ }
|
|
|
44
|
+
|
|
|
45
|
+ public Boolean isBootstrapped() {
|
|
|
46
|
+ return name.isBootstrapped();
|
|
|
47
|
+ }
|
|
|
48
|
+} |
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorConnectStageName.java
|
|
1
|
+package org.mozilla.geckoview;
|
|
|
2
|
+
|
|
|
3
|
+import java.security.InvalidParameterException;
|
|
|
4
|
+
|
|
|
5
|
+public enum TorConnectStageName {
|
|
|
6
|
+ // These names should match entries from TorConnectStage in TorConnect.sys.mjs at ~ln163.
|
|
|
7
|
+ Disabled("Disabled"),
|
|
|
8
|
+ Loading("Loading"),
|
|
|
9
|
+ Start("Start"),
|
|
|
10
|
+ Bootstrapping("Bootstrapping"),
|
|
|
11
|
+ Offline("Offline"),
|
|
|
12
|
+ ChooseRegion("ChooseRegion"),
|
|
|
13
|
+ RegionNotFound("RegionNotFound"),
|
|
|
14
|
+ ConfirmRegion("ConfirmRegion"),
|
|
|
15
|
+ FinalError("FinalError"),
|
|
|
16
|
+ Bootstrapped("Bootstrapped");
|
|
|
17
|
+
|
|
|
18
|
+ private String valueText;
|
|
|
19
|
+
|
|
|
20
|
+ TorConnectStageName(String valueText) {
|
|
|
21
|
+ this.valueText = valueText;
|
|
|
22
|
+ }
|
|
|
23
|
+
|
|
|
24
|
+ public Boolean isBootstrapped() {
|
|
|
25
|
+ return this == Bootstrapped;
|
|
|
26
|
+ }
|
|
|
27
|
+
|
|
|
28
|
+ public String getString() {
|
|
|
29
|
+ return this.valueText;
|
|
|
30
|
+ }
|
|
|
31
|
+
|
|
|
32
|
+ public static TorConnectStageName fromString(String text) {
|
|
|
33
|
+ for (TorConnectStageName tcs : TorConnectStageName.values()) {
|
|
|
34
|
+ if (tcs.valueText.equalsIgnoreCase(text)) {
|
|
|
35
|
+ return tcs;
|
|
|
36
|
+ }
|
|
|
37
|
+ }
|
|
|
38
|
+ if (BuildConfig.BUILD_TYPE == "debug") {
|
|
|
39
|
+ throw new InvalidParameterException("Unknown TorConnectStageName " + text);
|
|
|
40
|
+ }
|
|
|
41
|
+ return null;
|
|
|
42
|
+ }
|
|
|
43
|
+} |
toolkit/modules/TorAndroidIntegration.sys.mjs
| ... |
... |
@@ -25,7 +25,8 @@ const logger = console.createInstance({ |
|
25
|
25
|
const EmittedEvents = Object.freeze({
|
|
26
|
26
|
settingsReady: "GeckoView:Tor:SettingsReady",
|
|
27
|
27
|
settingsChanged: "GeckoView:Tor:SettingsChanged",
|
|
28
|
|
- connectStateChanged: "GeckoView:Tor:ConnectStateChanged",
|
|
|
28
|
+ connectStateChanged: "GeckoView:Tor:ConnectStateChanged", // deprecation path
|
|
|
29
|
+ connectStageChanged: "GeckoView:Tor:ConnectStageChanged", // new replacement path
|
|
29
|
30
|
connectError: "GeckoView:Tor:ConnectError",
|
|
30
|
31
|
bootstrapProgress: "GeckoView:Tor:BootstrapProgress",
|
|
31
|
32
|
bootstrapComplete: "GeckoView:Tor:BootstrapComplete",
|
| ... |
... |
@@ -106,6 +107,12 @@ class TorAndroidIntegrationImpl { |
|
106
|
107
|
state: subj.wrappedJSObject.state ?? "",
|
|
107
|
108
|
});
|
|
108
|
109
|
break;
|
|
|
110
|
+ case lazy.TorConnectTopics.StageChange:
|
|
|
111
|
+ lazy.EventDispatcher.instance.sendRequest({
|
|
|
112
|
+ type: EmittedEvents.connectStageChanged,
|
|
|
113
|
+ stage: subj.wrappedJSObject ?? "",
|
|
|
114
|
+ });
|
|
|
115
|
+ break;
|
|
109
|
116
|
case lazy.TorConnectTopics.BootstrapProgress:
|
|
110
|
117
|
lazy.EventDispatcher.instance.sendRequest({
|
|
111
|
118
|
type: EmittedEvents.bootstrapProgress,
|
toolkit/modules/TorConnect.sys.mjs
| ... |
... |
@@ -660,6 +660,7 @@ export const InternetStatus = Object.freeze({ |
|
660
|
660
|
Online: 1,
|
|
661
|
661
|
});
|
|
662
|
662
|
|
|
|
663
|
+// This enum is mirrored for Android in TorConnectStageName.java. Changes should be mirrored there
|
|
663
|
664
|
export const TorConnectStage = Object.freeze({
|
|
664
|
665
|
Disabled: "Disabled",
|
|
665
|
666
|
Loading: "Loading",
|
| ... |
... |
@@ -677,6 +678,7 @@ export const TorConnectStage = Object.freeze({ |
|
677
|
678
|
* @typedef {object} ConnectStage
|
|
678
|
679
|
*
|
|
679
|
680
|
* A summary of the user stage.
|
|
|
681
|
+ * (This class is mirrored for Android in TorConnectStage.java. Changes should be mirrored there)
|
|
680
|
682
|
*
|
|
681
|
683
|
* @property {string} name - The name of the stage.
|
|
682
|
684
|
* @property {string} defaultRegion - The default region to show in the UI.
|
| ... |
... |
@@ -698,6 +700,7 @@ export const TorConnectStage = Object.freeze({ |
|
698
|
700
|
* @typedef {object} BootstrappingStatus
|
|
699
|
701
|
*
|
|
700
|
702
|
* The status of a bootstrap.
|
|
|
703
|
+ * (This class is mirrored for Android in TorBootstrapping.java. Changes should be mirrored there)
|
|
701
|
704
|
*
|
|
702
|
705
|
* @property {number} progress - The percent progress.
|
|
703
|
706
|
* @property {boolean} hasWarning - Whether this bootstrap has a warning in the
|
| ... |
... |
@@ -708,6 +711,7 @@ export const TorConnectStage = Object.freeze({ |
|
708
|
711
|
* @typedef {object} BootstrapError
|
|
709
|
712
|
*
|
|
710
|
713
|
* Details about the error that caused bootstrapping to fail.
|
|
|
714
|
+ * (This class is mirrored for Android in TorError.java. Changes should be mirrored there)
|
|
711
|
715
|
*
|
|
712
|
716
|
* @property {string} code - The error code type.
|
|
713
|
717
|
* @property {string} message - The error message.
|
|