diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1b717a3e5..65887dd04 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -181,7 +181,10 @@
android:name=".common.service.RunTestJobService"
android:label="Run Test Service"
android:permission="android.permission.BIND_JOB_SERVICE"/>
-
+
= Build.VERSION_CODES.M) {
+ if (network == null) return false;
+ NetworkCapabilities actNw = mConnectivityManager.getNetworkCapabilities(network);
+ return actNw != null && (actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
+ || actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+ || actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET));
+ } else {
+ NetworkInfo nwInfo = mConnectivityManager.getActiveNetworkInfo();
+ return nwInfo != null && nwInfo.isConnected();
+ }
+ }
+
+ @Override
+ public void onLost(@NonNull Network network) {
+ super.onLost(network);
+ Log.e(TAG, "onLost() called: Lost network connection");
+ }
+
+ /**
+ * Check current Network state
+ */
+ public void checkNetworkState() {
+ try {
+ NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
+ if (networkInfo != null && networkInfo.isConnected()) {
+ networkChangeProcessor.processNetworkPossibleNetworkChange();
+ }
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ }
+ }
+
+ /**
+ * Registers the Network-Request callback
+ * (Note: Register only once to prevent duplicate callbacks)
+ */
+ public void registerNetworkCallbackEvents() {
+ Log.d(TAG, "registerNetworkCallbackEvents() called");
+ mConnectivityManager.registerNetworkCallback(mNetworkRequest, this);
+ }
+}
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/NetworkChangeProcessor.java b/app/src/main/java/org/openobservatory/ooniprobe/common/NetworkChangeProcessor.java
new file mode 100644
index 000000000..709d190d0
--- /dev/null
+++ b/app/src/main/java/org/openobservatory/ooniprobe/common/NetworkChangeProcessor.java
@@ -0,0 +1,48 @@
+package org.openobservatory.ooniprobe.common;
+
+import org.openobservatory.engine.LoggerArray;
+import org.openobservatory.engine.OONIGeolocateResults;
+import org.openobservatory.engine.OONISession;
+import org.openobservatory.ooniprobe.BuildConfig;
+import org.openobservatory.ooniprobe.common.service.ServiceUtil;
+import org.openobservatory.ooniprobe.test.EngineProvider;
+
+import java.util.Objects;
+
+import javax.inject.Inject;
+
+
+public class NetworkChangeProcessor {
+
+ private final PreferenceManager pm;
+ private final Application app;
+
+ @Inject
+ NetworkChangeProcessor(Application application, PreferenceManager pm) {
+ this.pm = pm;
+ this.app = application;
+ }
+
+
+ public void processNetworkPossibleNetworkChange() {
+ try {
+ OONISession session = EngineProvider.get().newSession(
+ EngineProvider.get().getDefaultSessionConfig(
+ app,
+ BuildConfig.SOFTWARE_NAME,
+ BuildConfig.VERSION_NAME,
+ new LoggerArray(),
+ pm.getProxyURL()
+ )
+ );
+ OONIGeolocateResults geoLocateResults = session.geolocate(session.newContext());
+ System.out.println(pm.getLastKnownNetwork());
+ if (!Objects.equals(pm.getLastKnownNetwork(), geoLocateResults.getASN())) {
+ pm.setLastKnownNetwork(geoLocateResults.getASN());
+ ServiceUtil.startRunTestServiceNetworkChanged(app);
+ }
+ } catch (Exception e) {
+ ThirdPartyServices.logException(e);
+ }
+ }
+}
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/PreferenceManager.java b/app/src/main/java/org/openobservatory/ooniprobe/common/PreferenceManager.java
index ba228a80b..7cc3a0537 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/common/PreferenceManager.java
+++ b/app/src/main/java/org/openobservatory/ooniprobe/common/PreferenceManager.java
@@ -166,6 +166,14 @@ public String getProxyHostname() {
return sp.getString(r.getString(R.string.proxy_hostname), "");
}
+ public void setLastKnownNetwork(String network) {
+ sp.edit().putString("last_known_network", network).apply();
+ }
+
+ public String getLastKnownNetwork() {
+ return sp.getString("last_known_network", "");
+ }
+
public void setProxyHostname(String value) {
sp.edit()
.putString(r.getString(R.string.proxy_hostname), value)
@@ -316,6 +324,10 @@ public boolean isAskAutomaticTestDialogDisabled() {
return sp.getBoolean(AUTOTEST_DIALOG_DISABLE, false);
}
+ public boolean isAutomaticallyRunTestOnNetworkChange(){
+ return sp.getBoolean(r.getString(R.string.automatically_run_test_on_network_change), true);
+ }
+
public void disableAskAutomaticTestDialog() {
sp.edit().putBoolean(AUTOTEST_DIALOG_DISABLE, true)
.apply();
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/service/ConnectivityChangeService.java b/app/src/main/java/org/openobservatory/ooniprobe/common/service/ConnectivityChangeService.java
new file mode 100644
index 000000000..700c2b35a
--- /dev/null
+++ b/app/src/main/java/org/openobservatory/ooniprobe/common/service/ConnectivityChangeService.java
@@ -0,0 +1,58 @@
+package org.openobservatory.ooniprobe.common.service;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Build;
+import android.os.IBinder;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import org.openobservatory.ooniprobe.common.ConnectivityChangeUtil;
+import org.openobservatory.ooniprobe.receiver.ConnectivityReceiver;
+
+public class ConnectivityChangeService extends Service {
+
+ private static final String TAG = ConnectivityChangeService.class.getSimpleName();
+ private ConnectivityReceiver receiver = null;
+
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ return super.onStartCommand(intent, flags, startId);
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+
+ ConnectivityChangeUtil mNetworkMonitoringUtil = new ConnectivityChangeUtil(getApplicationContext());
+ // Check the network state before registering for the 'networkCallbackEvents'
+// mNetworkMonitoringUtil.checkNetworkState();
+ mNetworkMonitoringUtil.registerNetworkCallbackEvents();
+ } else {
+ // Create a network change broadcast receiver.
+ receiver = new ConnectivityReceiver();
+ // Register the broadcast receiver with the intent filter object.
+ registerReceiver(receiver, ConnectivityReceiver.intentFilter());
+ }
+
+ Log.d(TAG, "Service onCreate: ConnectivityReceiver is registered.");
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ // Unregister screenOnOffReceiver when destroy.
+ if (receiver != null) {
+ unregisterReceiver(receiver);
+ Log.d(TAG, "Service onDestroy: ConnectivityReceiver is unregistered.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java b/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java
index 1f7c0e9e7..7cde40c95 100644
--- a/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java
+++ b/app/src/main/java/org/openobservatory/ooniprobe/common/service/ServiceUtil.java
@@ -23,6 +23,7 @@
import org.openobservatory.ooniprobe.test.suite.ExperimentalSuite;
import org.openobservatory.ooniprobe.test.suite.InstantMessagingSuite;
import org.openobservatory.ooniprobe.test.suite.PerformanceSuite;
+import org.openobservatory.ooniprobe.test.suite.WebsitesSuite;
import java.util.ArrayList;
@@ -89,6 +90,33 @@ public static void startRunTestServiceUnattended(Application app) {
ServiceUtil.startRunTestServiceCommon(app, testSuites, false, true);
d.generateAutoRunServiceSuite.markAsRan();
+ }
+
+ /**
+ * Start Tests on Network Changed event.
+ * @param app
+ * Application context used to start `RunTestService`.
+ */
+ public static void startRunTestServiceNetworkChanged(Application app) {
+ app.getServiceComponent().inject(d);
+
+ boolean isVPNInUse = ReachabilityManager.isVPNinUse(app);
+
+ OONICheckInConfig config = app.getOONICheckInConfig();
+
+ if (!d.generateAutoRunServiceSuite.shouldStart(config.isOnWiFi(),config.isCharging(), isVPNInUse)) {
+ return;
+ }
+
+ // Tag tests with identifier required to set Settings$Options#software_name
+ ArrayList testSuites = new ArrayList<>();
+ testSuites.add(new WebsitesSuite());
+ testSuites.add(new InstantMessagingSuite());
+ testSuites.add(new CircumventionSuite());
+ testSuites.add(new PerformanceSuite());
+ testSuites.add(new ExperimentalSuite());
+ startRunTestServiceCommon(app, testSuites, false, true);
+
}
@@ -108,6 +136,16 @@ private static void startRunTestServiceCommon(Context context, ArrayListstorage_usage
send_crash
warn_vpn_in_use
+ automatically_run_test_on_network_change
run_http_invalid_request_line
run_http_header_field_manipulation
test_whatsapp
diff --git a/app/src/main/res/xml/preferences_global.xml b/app/src/main/res/xml/preferences_global.xml
index c973e7ed1..d8da510b9 100644
--- a/app/src/main/res/xml/preferences_global.xml
+++ b/app/src/main/res/xml/preferences_global.xml
@@ -395,6 +395,11 @@
android:key="@string/warn_vpn_in_use"
android:title="@string/Settings_WarmVPNInUse_Label"
app:iconSpaceReserved="false" />
+