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" /> +