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
This commit is contained in:
Hans-Christoph Steiner 2016-11-10 16:00:11 +01:00
parent e14cb9d16a
commit 7e7ec966ee
3 changed files with 55 additions and 13 deletions

View File

@ -231,7 +231,7 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
return preferences.getBoolean(PREF_AUTO_DOWNLOAD_INSTALL_UPDATES, false); return preferences.getBoolean(PREF_AUTO_DOWNLOAD_INSTALL_UPDATES, false);
} }
public boolean isUpdateOnlyOnWifi() { public boolean isUpdateOnlyOnUnmeteredNetworks() {
return preferences.getBoolean(PREF_UPD_WIFI_ONLY, false); return preferences.getBoolean(PREF_UPD_WIFI_ONLY, false);
} }

View File

@ -31,6 +31,8 @@ import android.database.Cursor;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Build; import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Process; import android.os.Process;
import android.os.SystemClock; import android.os.SystemClock;
import android.preference.PreferenceManager; 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_UPDATING = 0;
private static final int NOTIFY_ID_UPDATES_AVAILABLE = 1; 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 NotificationManager notificationManager;
private NotificationCompat.Builder notificationBuilder; private NotificationCompat.Builder notificationBuilder;
@ -279,31 +287,52 @@ public class UpdateService extends IntentService {
return false; 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); ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
// this could be cellular or wifi
NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (activeNetwork == null) { if (activeNetwork == null || !activeNetwork.isConnected()) {
return false; return FLAG_NET_UNAVAILABLE;
} }
int networkType = activeNetwork.getType(); int networkType = activeNetwork.getType();
switch (networkType) { switch (networkType) {
case ConnectivityManager.TYPE_ETHERNET: case ConnectivityManager.TYPE_ETHERNET:
case ConnectivityManager.TYPE_WIFI: 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: 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 @Override
protected void onHandleIntent(Intent intent) { protected void onHandleIntent(Intent intent) {
Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST); Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);
@ -318,9 +347,21 @@ public class UpdateService extends IntentService {
try { try {
// See if it's time to actually do anything yet... // See if it's time to actually do anything yet...
if (manualUpdate) { int netState = getNetworkState(this);
Utils.debugLog(TAG, "Unscheduled (manually requested) update"); if (netState == FLAG_NET_UNAVAILABLE) {
} else if (!verifyIsTimeForScheduledRun()) { 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; return;
} }

View File

@ -21,7 +21,7 @@
<string name="update_interval">Automatic update interval</string> <string name="update_interval">Automatic update interval</string>
<string name="update_interval_zero">No automatic app list updates</string> <string name="update_interval_zero">No automatic app list updates</string>
<string name="automatic_scan_wifi">Only on Wi-Fi</string> <string name="automatic_scan_wifi">Only on Wi-Fi</string>
<string name="automatic_scan_wifi_on">Update app lists automatically only on Wi-Fi</string> <string name="automatic_scan_wifi_on">Only update automatically on unmetered networks like Wi-Fi</string>
<string name="update_auto_download">Automatically download updates</string> <string name="update_auto_download">Automatically download updates</string>
<string name="update_auto_download_summary">Download the update files in the background</string> <string name="update_auto_download_summary">Download the update files in the background</string>
<string name="update_auto_install">Automatically install updates</string> <string name="update_auto_install">Automatically install updates</string>
@ -201,6 +201,7 @@
<string name="repos_unchanged">All repositories are up to date</string> <string name="repos_unchanged">All repositories are up to date</string>
<string name="all_other_repos_fine">All other repos didn\'t create errors.</string> <string name="all_other_repos_fine">All other repos didn\'t create errors.</string>
<string name="global_error_updating_repos">Error during update: %s</string> <string name="global_error_updating_repos">Error during update: %s</string>
<string name="warning_no_internet">Cannot update, are you connected to the internet?</string>
<string name="no_permissions">No permissions are used.</string> <string name="no_permissions">No permissions are used.</string>
<string name="permissions">Permissions</string> <string name="permissions">Permissions</string>
<string name="no_handler_app">You don\'t have any available app that can handle %s.</string> <string name="no_handler_app">You don\'t have any available app that can handle %s.</string>