Bug 1149226 - Initialize Reading List authority after upgrade. r=rnewman, a=sylvestre
authorNick Alexander <nalexander@mozilla.com>
Thu, 02 Apr 2015 20:47:23 -0700
changeset 258261 4d02b020a319
parent 258260 3f82a5a05c30
child 258262 e2efc8489eba
push id4631
push userrnewman@mozilla.com
push date2015-04-05 20:14 +0000
treeherdermozilla-beta@4d02b020a319 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrnewman, sylvestre
bugs1149226
milestone38.0
Bug 1149226 - Initialize Reading List authority after upgrade. r=rnewman, a=sylvestre ======== https://github.com/mozilla-services/android-sync/commit/3b849794e9253ae01bc680ab1a79597486b5a55b Author: Nick Alexander <nalexander@mozilla.com> Bug 1149226 - Initialize Reading List authority after upgrade. The desired behaviour is: Reading List is syncing automatically if Firefox Sync is syncing automatically. Test plan: 0) Remove all Firefox Accounts. 1) Install old version. Add a Firefox Account. Ensure that Firefox Sync is enabled. Upgrade to new version. Verify that Reading List is enabled. 2) Install old version. Add a Firefox Account. Manually disable Firefox Sync by unchecking the checkbox in Android Settings > Accounts. (This can not be done from the Firefox Account settings activity; unchecking the 4 boxes there is not the same.) Upgrade to new version. Verify that Reading List is disabled. 3) Install new version. Add a new Firefox Account. Verify that Reading List is enabled. (There are automated tests for these scenarios.)
mobile/android/base/fxa/authenticator/AndroidFxAccount.java
mobile/android/base/fxa/receivers/FxAccountUpgradeReceiver.java
--- a/mobile/android/base/fxa/authenticator/AndroidFxAccount.java
+++ b/mobile/android/base/fxa/authenticator/AndroidFxAccount.java
@@ -53,21 +53,26 @@ public class AndroidFxAccount {
   public static final int CURRENT_RL_PREFS_VERSION = 1;
 
   // When updating the account, do not forget to update AccountPickler.
   public static final int CURRENT_ACCOUNT_VERSION = 3;
   public static final String ACCOUNT_KEY_ACCOUNT_VERSION = "version";
   public static final String ACCOUNT_KEY_PROFILE = "profile";
   public static final String ACCOUNT_KEY_IDP_SERVER = "idpServerURI";
 
-  // The audience should always be a prefix of the token server URI.
-  public static final String ACCOUNT_KEY_AUDIENCE = "audience";                 // Sync-specific.
   public static final String ACCOUNT_KEY_TOKEN_SERVER = "tokenServerURI";       // Sync-specific.
   public static final String ACCOUNT_KEY_DESCRIPTOR = "descriptor";
 
+  // The set of authorities to sync automatically changes over time. The first
+  // new authority is the Reading List. This tracks if we've enabled syncing,
+  // and opted in (or out) of syncing automatically, for the new Reading List
+  // authority. This happens either on when the account is created or when
+  // upgrading.
+  public static final String ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED = "readingListAuthorityInitialized";
+
   public static final int CURRENT_BUNDLE_VERSION = 2;
   public static final String BUNDLE_KEY_BUNDLE_VERSION = "version";
   public static final String BUNDLE_KEY_STATE_LABEL = "stateLabel";
   public static final String BUNDLE_KEY_STATE = "state";
 
   public static final Map<String, Boolean> DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP;
   static {
     final HashMap<String, Boolean> m = new HashMap<String, Boolean>();
@@ -396,16 +401,20 @@ public class AndroidFxAccount {
 
     // Android has internal restrictions that require all values in this
     // bundle to be strings. *sigh*
     Bundle userdata = new Bundle();
     userdata.putString(ACCOUNT_KEY_ACCOUNT_VERSION, "" + CURRENT_ACCOUNT_VERSION);
     userdata.putString(ACCOUNT_KEY_IDP_SERVER, idpServerURI);
     userdata.putString(ACCOUNT_KEY_TOKEN_SERVER, tokenServerURI);
     userdata.putString(ACCOUNT_KEY_PROFILE, profile);
+    if (DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP.containsKey(BrowserContract.READING_LIST_AUTHORITY)) {
+      // Have we initialized the Reading List authority?
+      userdata.putString(ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED, "1");
+    }
 
     if (bundle == null) {
       bundle = new ExtendedJSONObject();
       // TODO: How to upgrade?
       bundle.put(BUNDLE_KEY_BUNDLE_VERSION, CURRENT_BUNDLE_VERSION);
     }
     bundle.put(BUNDLE_KEY_STATE_LABEL, state.getStateLabel().name());
     bundle.put(BUNDLE_KEY_STATE, state.toJSONObject().toJSONString());
--- a/mobile/android/base/fxa/receivers/FxAccountUpgradeReceiver.java
+++ b/mobile/android/base/fxa/receivers/FxAccountUpgradeReceiver.java
@@ -6,25 +6,28 @@ package org.mozilla.gecko.fxa.receivers;
 
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.fxa.FxAccountUtils;
+import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.fxa.login.State.StateLabel;
 import org.mozilla.gecko.sync.Utils;
 
 import android.accounts.Account;
+import android.accounts.AccountManager;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 
 /**
  * A receiver that takes action when our Android package is upgraded (replaced).
  */
 public class FxAccountUpgradeReceiver extends BroadcastReceiver {
   private static final String LOG_TAG = FxAccountUpgradeReceiver.class.getSimpleName();
@@ -40,16 +43,17 @@ public class FxAccountUpgradeReceiver ex
    * @return list of Runnable instances.
    */
   protected List<Runnable> onUpgradeRunnables(Context context) {
     List<Runnable> runnables = new LinkedList<Runnable>();
     runnables.add(new MaybeUnpickleRunnable(context));
     // Recovering accounts that are in the Doghouse should happen *after* we
     // unpickle any accounts saved to disk.
     runnables.add(new AdvanceFromDoghouseRunnable(context));
+    runnables.add(new MaybeInitializeReadingListAuthority(context));
     return runnables;
   }
 
   @Override
   public void onReceive(final Context context, Intent intent) {
     Logger.setThreadLogTag(FxAccountConstants.GLOBAL_LOG_TAG);
     Logger.info(LOG_TAG, "Upgrade broadcast received.");
 
@@ -125,9 +129,73 @@ public class FxAccountUpgradeReceiver ex
           fxAccount.setState(state.makeSeparatedState());
         } catch (Exception e) {
           Logger.warn(LOG_TAG, "Got exception trying to advance account named like " + Utils.obfuscateEmail(account.name) +
               " from Doghouse to Separated state; ignoring.", e);
         }
       }
     }
   }
+
+  /**
+   * A Runnable that initializes the Reading List authority (specifically, set
+   * the sync automatically flag) for existing Firefox Accounts that have not
+   * yet seen the authority. That is, if a new authority (Reading List) is added
+   * to the set of defaults, existing Firefox Accounts won't be syncing it
+   * automatically. This tries to set the sync automatically flag for such
+   * existing accounts.
+   *
+   * Public for testing only.
+   */
+  public static class MaybeInitializeReadingListAuthority implements Runnable {
+    protected final Context context;
+
+    public MaybeInitializeReadingListAuthority(Context context) {
+      this.context = context;
+    }
+
+    @Override
+    public void run() {
+      final String authority = BrowserContract.READING_LIST_AUTHORITY;
+      Boolean enabledByDefault = AndroidFxAccount.DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP.get(authority);
+      if (enabledByDefault == null || !enabledByDefault.booleanValue()) {
+        Logger.info(LOG_TAG, "Reading List authority is not enabled by default; not trying to initialize Reading List authority for any accounts.");
+      }
+
+      final AccountManager accountManager = AccountManager.get(context);
+      final Account[] accounts = FirefoxAccounts.getFirefoxAccounts(context);
+      Logger.info(LOG_TAG, "Trying to initialize Reading List authority for " + accounts.length + " existing Firefox Accounts (if necessary).");
+
+      for (Account account : accounts) {
+        try {
+          final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
+          // For great debugging.
+          if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
+            fxAccount.dump();
+          }
+
+          final boolean readingListAuthorityInitialized =
+              "1".equals(accountManager.getUserData(account, AndroidFxAccount.ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED));
+          if (readingListAuthorityInitialized) {
+            Logger.debug(LOG_TAG, "Reading List authority has already been initialized.");
+            continue;
+          }
+
+          // The Reading List authority has not been seen. This happens when an
+          // authority is added after the Firefox Account has been added (and
+          // the package last upgraded). If Firefox Sync is not syncing
+          // automatically, Reading List should not start syncing
+          // automatically: the user has elected not to upload data to Mozilla
+          // servers; we shouldn't opt them in.
+          final boolean syncAutomatically = ContentResolver.getSyncAutomatically(account, BrowserContract.AUTHORITY);
+            Logger.debug(LOG_TAG, "Setting Reading List authority " +
+                (syncAutomatically ? " to " : " to not ") + "sync automatically.");
+            ContentResolver.setSyncAutomatically(account, BrowserContract.READING_LIST_AUTHORITY, syncAutomatically);
+          // Update the account record.
+          accountManager.setUserData(account, AndroidFxAccount.ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED, "1");
+        } catch (Exception e) {
+          Logger.warn(LOG_TAG, "Got exception trying to set authoritities to sync automatically for account named like " +
+              Utils.obfuscateEmail(account.name) + "; ignoring.", e);
+        }
+      }
+    }
+  }
 }