From 254bd6a4db03b293a306b8368f936d27bb8301b6 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 13 Jun 2019 11:21:59 +0200 Subject: [PATCH] allow hotspots to work for swapping, even if they don't have internet It is possible to enable the Hotspot AP on a device, and disable mobile data. This setup will work fine for swapping, but the detection logic for whether there is metered internet was blocking it. So this adds a new state to represent and handle this condition. --- .../java/org/fdroid/fdroid/Preferences.java | 3 +- .../net/ConnectivityMonitorService.java | 42 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/Preferences.java b/app/src/main/java/org/fdroid/fdroid/Preferences.java index d6f455453..6fc26abbd 100644 --- a/app/src/main/java/org/fdroid/fdroid/Preferences.java +++ b/app/src/main/java/org/fdroid/fdroid/Preferences.java @@ -436,7 +436,8 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh } public boolean isOnDemandDownloadAllowed() { - if (FDroidApp.networkState == ConnectivityMonitorService.FLAG_NET_NO_LIMIT) { + if (FDroidApp.networkState == ConnectivityMonitorService.FLAG_NET_NO_LIMIT + || FDroidApp.networkState == ConnectivityMonitorService.FLAG_NET_DEVICE_AP_WITHOUT_INTERNET) { return getOverWifi() != OVER_NETWORK_NEVER; } else if (FDroidApp.networkState == ConnectivityMonitorService.FLAG_NET_METERED) { return getOverData() != OVER_NETWORK_NEVER; diff --git a/app/src/main/java/org/fdroid/fdroid/net/ConnectivityMonitorService.java b/app/src/main/java/org/fdroid/fdroid/net/ConnectivityMonitorService.java index 0bfd2bc04..f805bdf63 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/ConnectivityMonitorService.java +++ b/app/src/main/java/org/fdroid/fdroid/net/ConnectivityMonitorService.java @@ -9,10 +9,17 @@ import android.net.NetworkInfo; import android.os.Build; import android.support.annotation.NonNull; import android.support.v4.app.JobIntentService; +import android.util.Log; import com.nostra13.universalimageloader.core.ImageLoader; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; + /** * An {@link JobIntentService} subclass for tracking whether there is metered or * unmetered internet available, based on @@ -30,6 +37,7 @@ public class ConnectivityMonitorService extends JobIntentService { public static final int FLAG_NET_UNAVAILABLE = 0; public static final int FLAG_NET_METERED = 1; public static final int FLAG_NET_NO_LIMIT = 2; + public static final int FLAG_NET_DEVICE_AP_WITHOUT_INTERNET = 3; private static final String ACTION_START = "org.fdroid.fdroid.net.action.CONNECTIVITY_MONITOR"; @@ -59,7 +67,14 @@ public class ConnectivityMonitorService extends JobIntentService { /** * Gets the state of internet availability, whether there is no connection at all, * whether the connection has no usage limit (like most WiFi), or whether this is - * a metered connection like most cellular plans or hotspot WiFi connections. + * a metered connection like most cellular plans or hotspot WiFi connections. This + * also detects whether the device has a hotspot AP enabled but the mobile + * connection does not provide internet. That is a special case that is useful + * for nearby swapping, but nothing else. + *

+ * {@link NullPointerException}s are ignored in the hotspot detection since that + * detection should not affect normal usage at all, and there are often weird + * cases when looking through the network devices, especially on bad ROMs. */ public static int getNetworkState(Context context) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE); @@ -67,6 +82,31 @@ public class ConnectivityMonitorService extends JobIntentService { return FLAG_NET_UNAVAILABLE; } NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); + + if (activeNetwork == null && Build.VERSION.SDK_INT >= 21 && cm.getAllNetworks().length == 0) { + try { + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + while (networkInterfaces.hasMoreElements()) { + NetworkInterface netIf = networkInterfaces.nextElement(); + if (netIf.getDisplayName().contains("wlan0") + || netIf.getDisplayName().contains("eth0") + || netIf.getDisplayName().contains("ap0")) { + for (Enumeration addr = netIf.getInetAddresses(); addr.hasMoreElements();) { + InetAddress inetAddress = addr.nextElement(); + if (inetAddress.isLoopbackAddress() || inetAddress instanceof Inet6Address) { + continue; + } + Log.i(TAG, "FLAG_NET_DEVICE_AP_WITHOUT_INTERNET: " + netIf.getDisplayName() + + " " + inetAddress); + return FLAG_NET_DEVICE_AP_WITHOUT_INTERNET; // NOPMD + } + } + } + } catch (SocketException | NullPointerException e) { // NOPMD + // ignored + } + } + if (activeNetwork == null || !activeNetwork.isConnected()) { return FLAG_NET_UNAVAILABLE; }