From 7e7ec966ee33958c26d80324047f313f5d5e6cdc Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 10 Nov 2016 16:00:11 +0100 Subject: [PATCH] improved internet state handling for updates, including metered This introduces three network states: 1. completely disconnected 2. connected only via metered networks 3. connected via unlimited networks This allows the update process to use bandwidth better, especially when the user has enabled the "Only on WiFi" setting. It also helps prevent silly, cryptic error messages in the update process is triggered when there isn't internet available. I tested this with: * 4G only, but not set up for internet * 4G only, with internet * 4G + WiFi * WiFi only airplane mode * no internet at all, full airplane mode closes #793 closes #774 --- .../java/org/fdroid/fdroid/Preferences.java | 2 +- .../java/org/fdroid/fdroid/UpdateService.java | 63 +++++++++++++++---- app/src/main/res/values/strings.xml | 3 +- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/Preferences.java b/app/src/main/java/org/fdroid/fdroid/Preferences.java index 7a5b91bed..cfe402d47 100644 --- a/app/src/main/java/org/fdroid/fdroid/Preferences.java +++ b/app/src/main/java/org/fdroid/fdroid/Preferences.java @@ -231,7 +231,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh return preferences.getBoolean(PREF_AUTO_DOWNLOAD_INSTALL_UPDATES, false); } - public boolean isUpdateOnlyOnWifi() { + public boolean isUpdateOnlyOnUnmeteredNetworks() { return preferences.getBoolean(PREF_UPD_WIFI_ONLY, false); } diff --git a/app/src/main/java/org/fdroid/fdroid/UpdateService.java b/app/src/main/java/org/fdroid/fdroid/UpdateService.java index ff8c810f9..6586bae3f 100644 --- a/app/src/main/java/org/fdroid/fdroid/UpdateService.java +++ b/app/src/main/java/org/fdroid/fdroid/UpdateService.java @@ -31,6 +31,8 @@ import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Build; +import android.os.Handler; +import android.os.Looper; import android.os.Process; import android.os.SystemClock; import android.preference.PreferenceManager; @@ -79,6 +81,12 @@ public class UpdateService extends IntentService { private static final int NOTIFY_ID_UPDATING = 0; private static final int NOTIFY_ID_UPDATES_AVAILABLE = 1; + private static final int FLAG_NET_UNAVAILABLE = 0; + private static final int FLAG_NET_METERED = 1; + private static final int FLAG_NET_NO_LIMIT = 2; + + private static Handler toastHandler; + private NotificationManager notificationManager; private NotificationCompat.Builder notificationBuilder; @@ -279,31 +287,52 @@ public class UpdateService extends IntentService { return false; } - return isNetworkAvailableForUpdate(this); + return true; } /** - * If we are to update the repos only on wifi, make sure that connection is active + * 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. */ - private static boolean isNetworkAvailableForUpdate(Context context) { + private static int getNetworkState(Context context) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - // this could be cellular or wifi NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); - if (activeNetwork == null) { - return false; + if (activeNetwork == null || !activeNetwork.isConnected()) { + return FLAG_NET_UNAVAILABLE; } int networkType = activeNetwork.getType(); switch (networkType) { case ConnectivityManager.TYPE_ETHERNET: case ConnectivityManager.TYPE_WIFI: - return activeNetwork.isConnectedOrConnecting(); + if (Build.VERSION.SDK_INT >= 16 && cm.isActiveNetworkMetered()) { + return FLAG_NET_METERED; + } else { + return FLAG_NET_NO_LIMIT; + } default: - return Preferences.get().isUpdateOnlyOnWifi(); + return FLAG_NET_METERED; } } + /** + * In order to send a {@link Toast} from a {@link IntentService}, we have to do these tricks. + */ + private void sendNoInternetToast() { + if (toastHandler == null) { + toastHandler = new Handler(Looper.getMainLooper()); + } + toastHandler.post(new Runnable() { + @Override + public void run() { + Toast.makeText(getApplicationContext(), + R.string.warning_no_internet, Toast.LENGTH_SHORT).show(); + } + }); + } + @Override protected void onHandleIntent(Intent intent) { Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST); @@ -318,9 +347,21 @@ public class UpdateService extends IntentService { try { // See if it's time to actually do anything yet... - if (manualUpdate) { - Utils.debugLog(TAG, "Unscheduled (manually requested) update"); - } else if (!verifyIsTimeForScheduledRun()) { + int netState = getNetworkState(this); + if (netState == FLAG_NET_UNAVAILABLE) { + Utils.debugLog(TAG, "No internet, cannot update"); + if (manualUpdate) { + sendNoInternetToast(); + } + return; + } + + if (manualUpdate || (netState == FLAG_NET_NO_LIMIT)) { + // triggered by the user, or by connecting to WiFi, etc. + Utils.debugLog(TAG, "manually requested update or on unlimited internet"); + } else if (Preferences.get().isUpdateOnlyOnUnmeteredNetworks() + || !verifyIsTimeForScheduledRun()) { + Utils.debugLog(TAG, "don't run update, we're on metered internet"); return; } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d23295a97..fdb4542a8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -21,7 +21,7 @@ Automatic update interval No automatic app list updates Only on Wi-Fi - Update app lists automatically only on Wi-Fi + Only update automatically on unmetered networks like Wi-Fi Automatically download updates Download the update files in the background Automatically install updates @@ -201,6 +201,7 @@ All repositories are up to date All other repos didn\'t create errors. Error during update: %s + Cannot update, are you connected to the internet? No permissions are used. Permissions You don\'t have any available app that can handle %s.