Bug 799632 - Add a preference for controlling automatic update downloads on Android r=bnicholson
authorJames Willcox <jwillcox@mozilla.com>
Mon, 15 Oct 2012 09:56:42 -0400
changeset 110406 7009f7377d85f4a2c2ebd2cadbe5bff8a8cd9db1
parent 110405 a53a74e310ae6d3e5e189a37b59521f08dda0a9f
child 110407 2b96e74420878cd94b9afd8fe4095196af24e46f
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersbnicholson
bugs799632
milestone19.0a1
Bug 799632 - Add a preference for controlling automatic update downloads on Android r=bnicholson
mobile/android/app/mobile.js
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoPreferences.java
mobile/android/base/UpdateService.java
mobile/android/base/UpdateServiceHelper.java.in
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/resources/values/arrays.xml
mobile/android/base/resources/xml/preferences.xml.in
mobile/android/base/strings.xml.in
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -488,16 +488,20 @@ pref("browser.search.param.yahoo-fr", "m
 pref("browser.search.param.yahoo-fr-cjkt", "moz35");
 pref("browser.search.param.yahoo-fr-ja", "mozff");
 #endif
 
 /* prefs used by the update timer system (including blocklist pings) */
 pref("app.update.timerFirstInterval", 30000); // milliseconds
 pref("app.update.timerMinimumDelay", 30); // seconds
 
+// used by update service to decide whether or not to
+// automatically download an update
+pref("app.update.autodownload", "wifi");
+
 #ifdef MOZ_UPDATER
 /* prefs used specifically for updating the app */
 pref("app.update.enabled", false);
 pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@");
 
 // If you are looking for app.update.url, we no longer use it.
 // See mobile/android/base/UpdateServiceHelper.java.in
 #endif
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -1727,17 +1727,21 @@ abstract public class GeckoApp
 
         mPromptService = new PromptService();
 
         mTextSelection = new TextSelection((TextSelectionHandle) findViewById(R.id.start_handle),
                                            (TextSelectionHandle) findViewById(R.id.middle_handle),
                                            (TextSelectionHandle) findViewById(R.id.end_handle),
                                            GeckoAppShell.getEventDispatcher());
 
-        UpdateServiceHelper.registerForUpdates(this);
+        PrefsHelper.getPref("app.update.autodownload", new PrefsHelper.PrefHandlerBase() {
+            @Override public void prefValue(String pref, String value) {
+                UpdateServiceHelper.registerForUpdates(GeckoApp.this, value);
+            }
+        });
 
         final GeckoApp self = this;
 
         // End of the startup of our Java App
         mJavaUiStartupTimer.stop();
 
         GeckoAppShell.getHandler().postDelayed(new Runnable() {
             public void run() {
--- a/mobile/android/base/GeckoPreferences.java
+++ b/mobile/android/base/GeckoPreferences.java
@@ -49,16 +49,17 @@ public class GeckoPreferences
     private PreferenceScreen mPreferenceScreen;
     private static boolean sIsCharEncodingEnabled = false;
     private static final String NON_PREF_PREFIX = "android.not_a_preference.";
 
     // These match keys in resources/xml/preferences.xml.in.
     public static String PREFS_MP_ENABLED         = "privacy.masterpassword.enabled";
     public static String PREFS_MENU_CHAR_ENCODING = "browser.menu.showCharacterEncoding";
     public static String PREFS_ANNOUNCEMENTS_ENABLED = NON_PREF_PREFIX + "privacy.announcements.enabled";
+    public static String PREFS_UPDATER_AUTODOWNLOAD  = "app.update.autodownload";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         addPreferencesFromResource(R.xml.preferences);
         registerEventListener("Sanitize:Finished");
     }
 
@@ -205,16 +206,18 @@ public class GeckoPreferences
             showDialog((Boolean) newValue ? DIALOG_CREATE_MASTER_PASSWORD : DIALOG_REMOVE_MASTER_PASSWORD);
             return false;
         } else if (prefName != null && prefName.equals(PREFS_MENU_CHAR_ENCODING)) {
             setCharEncodingState(((String) newValue).equals("true"));
         } else if (prefName != null && prefName.equals(PREFS_ANNOUNCEMENTS_ENABLED)) {
             // Send a broadcast intent to the product announcements service, either to start or
             // to stop the repeated background checks.
             broadcastAnnouncementsPref(GeckoApp.mAppContext, ((Boolean) newValue).booleanValue());
+        } else if (prefName != null && prefName.equals(PREFS_UPDATER_AUTODOWNLOAD)) {
+            org.mozilla.gecko.updater.UpdateServiceHelper.registerForUpdates(GeckoApp.mAppContext, (String)newValue);
         }
 
         if (!TextUtils.isEmpty(prefName)) {
             PrefsHelper.setPref(prefName, newValue);
         }
         if (preference instanceof ListPreference) {
             // We need to find the entry for the new value
             int newIndex = ((ListPreference)preference).findIndexOfValue((String) newValue);
--- a/mobile/android/base/UpdateService.java
+++ b/mobile/android/base/UpdateService.java
@@ -71,16 +71,17 @@ public class UpdateService extends Inten
     private static final int INTERVAL_SHORT = 14400000; // again, in milliseconds
     private static final int INTERVAL_RETRY = 3600000;
 
     private static final String PREFS_NAME = "UpdateService";
     private static final String KEY_LAST_BUILDID = "UpdateService.lastBuildID";
     private static final String KEY_LAST_HASH_FUNCTION = "UpdateService.lastHashFunction";
     private static final String KEY_LAST_HASH_VALUE = "UpdateService.lastHashValue";
     private static final String KEY_LAST_ATTEMPT_DATE = "UpdateService.lastAttemptDate";
+    private static final String KEY_AUTODOWNLOAD_POLICY = "UpdateService.autoDownloadPolicy";
 
     private SharedPreferences mPrefs;
 
     private NotificationManager mNotificationManager;
     private ConnectivityManager mConnectivityManager;
 
     private boolean mDownloading;
     private boolean mApplyImmediately;
@@ -113,16 +114,21 @@ public class UpdateService extends Inten
         }
 
         return Service.START_REDELIVER_INTENT;
     }
 
     @Override
     protected void onHandleIntent (Intent intent) {
         if (UpdateServiceHelper.ACTION_REGISTER_FOR_UPDATES.equals(intent.getAction())) {
+            int policy = intent.getIntExtra(UpdateServiceHelper.EXTRA_AUTODOWNLOAD_NAME, -1);
+            if (policy >= 0) {
+                setAutoDownloadPolicy(policy);
+            }
+
             registerForUpdates(false);
         } else if (UpdateServiceHelper.ACTION_CHECK_FOR_UPDATE.equals(intent.getAction())) {
             startUpdate(intent.getIntExtra(UpdateServiceHelper.EXTRA_UPDATE_FLAGS_NAME, 0));
         } else if (UpdateServiceHelper.ACTION_APPLY_UPDATE.equals(intent.getAction())) {
             applyUpdate(intent.getStringExtra(UpdateServiceHelper.EXTRA_PACKAGE_PATH_NAME));
         }
     }
 
@@ -197,20 +203,23 @@ public class UpdateService extends Inten
         if (!haveUpdate) {
             Log.i(LOGTAG, "no update available");
             return;
         }
 
         Log.i(LOGTAG, "update available, buildID = " + info.buildID);
         
         int connectionType = netInfo.getType();
+        int autoDownloadPolicy = getAutoDownloadPolicy();
         if (!hasFlag(flags, UpdateServiceHelper.FLAG_FORCE_DOWNLOAD) &&
-            connectionType != ConnectivityManager.TYPE_WIFI &&
-            connectionType != ConnectivityManager.TYPE_ETHERNET) {
-            Log.i(LOGTAG, "not connected via wifi or ethernet");
+            autoDownloadPolicy != UpdateServiceHelper.AUTODOWNLOAD_ENABLED &&
+            (autoDownloadPolicy == UpdateServiceHelper.AUTODOWNLOAD_WIFI &&
+             connectionType != ConnectivityManager.TYPE_WIFI &&
+             connectionType != ConnectivityManager.TYPE_ETHERNET)) {
+            Log.i(LOGTAG, "not initiating automatic update download due to policy " + autoDownloadPolicy);
 
             // We aren't autodownloading here, so prompt to start the update
             Notification notification = new Notification(R.drawable.ic_status_logo, null, System.currentTimeMillis());
 
             Intent notificationIntent = new Intent(UpdateServiceHelper.ACTION_CHECK_FOR_UPDATE);
             notificationIntent.setClass(this, UpdateService.class);
             notificationIntent.putExtra(UpdateServiceHelper.EXTRA_UPDATE_FLAGS_NAME, UpdateServiceHelper.FLAG_FORCE_DOWNLOAD);
 
@@ -517,16 +526,26 @@ public class UpdateService extends Inten
     }
 
     private void setLastAttemptDate() {
         SharedPreferences.Editor editor = mPrefs.edit();
         editor.putLong(KEY_LAST_ATTEMPT_DATE, System.currentTimeMillis());
         editor.commit();
     }
 
+    private int getAutoDownloadPolicy() {
+        return mPrefs.getInt(KEY_AUTODOWNLOAD_POLICY, UpdateServiceHelper.AUTODOWNLOAD_WIFI);
+    }
+
+    private void setAutoDownloadPolicy(int policy) {
+        SharedPreferences.Editor editor = mPrefs.edit();
+        editor.putInt(KEY_AUTODOWNLOAD_POLICY, policy);
+        editor.commit();
+    }
+
     private void saveUpdateInfo(UpdateInfo info) {
         SharedPreferences.Editor editor = mPrefs.edit();
         editor.putString(KEY_LAST_BUILDID, info.buildID);
         editor.putString(KEY_LAST_HASH_FUNCTION, info.hashFunction);
         editor.putString(KEY_LAST_HASH_VALUE, info.hashValue);
         editor.commit();
     }
 
--- a/mobile/android/base/UpdateServiceHelper.java.in
+++ b/mobile/android/base/UpdateServiceHelper.java.in
@@ -29,16 +29,24 @@ public class UpdateServiceHelper {
     public static final String ACTION_APPLY_UPDATE = "@ANDROID_PACKAGE_NAME@.APPLY_UPDATE";
 
     // Flags for ACTION_CHECK_FOR_UPDATE
     public static final int FLAG_FORCE_DOWNLOAD = 1;
     public static final int FLAG_OVERWRITE_EXISTING = 1 << 1;
     public static final int FLAG_REINSTALL = 1 << 2;
     public static final int FLAG_RETRY = 1 << 3;
 
+    // Name of the Intent extra for the autodownload policy, used with ACTION_REGISTER_FOR_UPDATES
+    public static final String EXTRA_AUTODOWNLOAD_NAME = "autodownload";
+
+    // Values for EXTRA_AUTODOWNLOAD_NAME
+    public static final int AUTODOWNLOAD_WIFI = 0;
+    public static final int AUTODOWNLOAD_DISABLED = 1;
+    public static final int AUTODOWNLOAD_ENABLED = 2;
+
     // Name of the Intent extra that holds the flags for ACTION_CHECK_FOR_UPDATE
     public static final String EXTRA_UPDATE_FLAGS_NAME = "updateFlags";
 
     // Name of the Intent extra that holds the APK path, used with ACTION_APPLY_UPDATE
     public static final String EXTRA_PACKAGE_PATH_NAME = "packagePath";
 
     public static final String UPDATE_CHANNEL = "@MOZ_UPDATE_CHANNEL@";
 
@@ -87,15 +95,38 @@ public class UpdateServiceHelper {
     public static boolean isUpdaterEnabled() {
 #ifdef MOZ_UPDATER
         return true;
 #else
         return false;
 #endif
     }
 
-    public static void registerForUpdates(Context context) {
+    public static void registerForUpdates(Context context, String policy) {
+        if (policy == null)
+            return;
+
+        int intPolicy;
+        if (policy.equals("wifi")) {
+            intPolicy = AUTODOWNLOAD_WIFI;
+        } else if (policy.equals("disabled")) {
+            intPolicy = AUTODOWNLOAD_DISABLED;
+        } else if (policy.equals("enabled")) {
+            intPolicy = AUTODOWNLOAD_ENABLED;
+        } else {
+            Log.w(LOGTAG, "Unhandled autoupdate policy: " + policy);
+            return;
+        }
+
+        registerForUpdates(context, intPolicy);
+    }
+
+    // 'policy' should one of AUTODOWNLOAD_WIFI, AUTODOWNLOAD_DISABLED, AUTODOWNLOAD_ENABLED
+    public static void registerForUpdates(Context context, int policy) {
         if (!isUpdaterEnabled())
             return;
 
-        context.startService(new Intent(UpdateServiceHelper.ACTION_REGISTER_FOR_UPDATES, null, context, UpdateService.class));
+        Intent intent = new Intent(UpdateServiceHelper.ACTION_REGISTER_FOR_UPDATES, null, context, UpdateService.class);
+        intent.putExtra(EXTRA_AUTODOWNLOAD_NAME, policy);
+
+        context.startService(intent);
     }
 }
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -107,16 +107,21 @@ size. -->
 <!ENTITY pref_private_data_history "Browsing &amp; download history">
 <!ENTITY pref_private_data_formdata "Form &amp; search history">
 <!ENTITY pref_private_data_cookies2 "Cookies &amp; active logins">
 <!ENTITY pref_private_data_passwords "Saved passwords">
 <!ENTITY pref_private_data_cache "Cache">
 <!ENTITY pref_private_data_offlineApps "Offline website data">
 <!ENTITY pref_private_data_siteSettings "Site preferences">
 
+<!ENTITY pref_update_autodownload "Automatic updates">
+<!ENTITY pref_update_autodownload_wifi "Only over Wi-Fi">
+<!ENTITY pref_update_autodownload_disabled "Disabled">
+<!ENTITY pref_update_autodownload_enabled "Enabled">
+
 <!ENTITY quit "Quit">
 
 <!ENTITY addons "Add-ons">
 <!ENTITY downloads "Downloads">
 <!ENTITY apps "Apps">
 <!ENTITY char_encoding "Character Encoding">
 
 <!ENTITY share "Share">
--- a/mobile/android/base/resources/values/arrays.xml
+++ b/mobile/android/base/resources/values/arrays.xml
@@ -71,9 +71,19 @@
         <item>private.data.history_downloads</item>
         <item>private.data.formdata</item>
         <item>private.data.cookies_sessions</item>
         <item>private.data.passwords</item>
         <item>private.data.cache</item>
         <item>private.data.offlineApps</item>
         <item>private.data.siteSettings</item>
     </string-array>
+    <string-array name="pref_update_autodownload_entries">
+        <item>@string/pref_update_autodownload_wifi</item>
+        <item>@string/pref_update_autodownload_disabled</item>
+        <item>@string/pref_update_autodownload_enabled</item>
+    </string-array>
+    <string-array name="pref_update_autodownload_values">
+        <item>wifi</item>
+        <item>disabled</item>
+        <item>enabled</item>
+    </string-array>
 </resources>
--- a/mobile/android/base/resources/xml/preferences.xml.in
+++ b/mobile/android/base/resources/xml/preferences.xml.in
@@ -11,16 +11,24 @@
 
     <PreferenceCategory android:title="@string/pref_category_general">
         <org.mozilla.gecko.LinkPreference android:title="@string/pref_about_firefox"
                                           url="about:" />
 
         <org.mozilla.gecko.SyncPreference android:title="@string/pref_sync"
                                           android:persistent="false" />
 
+#ifdef MOZ_UPDATER
+        <ListPreference android:key="app.update.autodownload"
+                        android:title="@string/pref_update_autodownload"
+                        android:entries="@array/pref_update_autodownload_entries"
+                        android:entryValues="@array/pref_update_autodownload_values"
+                        android:persistent="false" />
+#endif
+
     </PreferenceCategory>
 
     <PreferenceCategory android:title="@string/pref_category_content">
 
         <ListPreference android:key="browser.menu.showCharacterEncoding"
                         android:title="@string/pref_char_encoding"
                         android:entries="@array/pref_char_encoding_entries"
                         android:entryValues="@array/pref_char_encoding_values"
@@ -104,10 +112,9 @@
           gecko:entryKeys="@array/pref_import_android_keys"
           gecko:initialValues="@array/pref_import_android_values"
           android:title="@string/pref_import_android"
           android:positiveButtonText="@string/bookmarkhistory_button_import"
           android:negativeButtonText="@string/button_cancel"
           android:persistent="false" />
 
     </PreferenceCategory>
-
 </PreferenceScreen>
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -102,16 +102,20 @@
   <string name="pref_private_data_history">&pref_private_data_history;</string>
   <string name="pref_private_data_formdata">&pref_private_data_formdata;</string>
   <string name="pref_private_data_cookies2">&pref_private_data_cookies2;</string>
   <string name="pref_private_data_passwords">&pref_private_data_passwords;</string>
   <string name="pref_private_data_cache">&pref_private_data_cache;</string>
   <string name="pref_private_data_offlineApps">&pref_private_data_offlineApps;</string>
   <string name="pref_private_data_siteSettings">&pref_private_data_siteSettings;</string>
   <string name="pref_import_android">&pref_import_android;</string>
+  <string name="pref_update_autodownload">&pref_update_autodownload;</string>
+  <string name="pref_update_autodownload_wifi">&pref_update_autodownload_wifi;</string>
+  <string name="pref_update_autodownload_disabled">&pref_update_autodownload_disabled;</string>
+  <string name="pref_update_autodownload_enabled">&pref_update_autodownload_enabled;</string>
 
   <string name="go">&go;</string>
   <string name="search">&search;</string>
   <string name="reload">&reload;</string>
   <string name="forward">&forward;</string>
   <string name="menu">&menu;</string>
   <string name="back">&back;</string>
   <string name="stop">&stop;</string>