Bug 1456487 - Update Firefox Account's first run UUID when re-connecting. r=rnewman draft
authorNick Alexander <nalexander@mozilla.com>
Wed, 25 Apr 2018 12:17:05 -0700
changeset 787985 170735bbe59f488b9c78f57ac11ae12fd2fa430e
parent 787984 88abda604f7b3f8523bdb3dcc46b77932bf13af0
push id107864
push usernalexander@mozilla.com
push dateWed, 25 Apr 2018 19:17:46 +0000
reviewersrnewman
bugs1456487
milestone61.0a1
Bug 1456487 - Update Firefox Account's first run UUID when re-connecting. r=rnewman The behaviour of Android Firefox Account instances recently changed in the face of system "Clear data" commands. To align more closely with common Apps like Dropbox and Whatsapp (which generally don't use Android Account instances), after a "Clear data" Firefox Account's are moved to the Separated state, requiring the user to re-connect them with a password challenge. To achieve this, newly created accounts include a first run UUID; after a "Clear data", the App is killed and restarted, Sync sees a different first run UUID, and the Account is moved to the Separated state. (I honestly don't know what happens if the Sync code never sees a different first run UUID, but that's for another day.) If the user then, in the same first run session, re-connects the Firefox Account... the Sync code will again see the different first run UUID and move the Account to the Separated state. This patch updates the first run UUID when the Account is re-connected, breaking that cycle. MozReview-Commit-ID: 9jcO9Ym54an
mobile/android/base/java/org/mozilla/gecko/AccountsHelper.java
mobile/android/services/src/main/java/org/mozilla/gecko/fxa/authenticator/AndroidFxAccount.java
--- a/mobile/android/base/java/org/mozilla/gecko/AccountsHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/AccountsHelper.java
@@ -187,16 +187,17 @@ public class AccountsHelper implements B
                 return;
             }
 
             final State state = new Engaged(email, uid, verified, unwrapkB,
                                             sessionToken, keyFetchToken);
 
             final AndroidFxAccount fxAccount = new AndroidFxAccount(mContext, account);
             fxAccount.setState(state);
+            fxAccount.updateFirstRunScope(mContext);
 
             if (callback != null) {
                 callback.sendSuccess(true);
             }
 
         } else if ("Accounts:Create".equals(event)) {
             // Do exactly the same thing as if you tapped 'Sync' in Settings.
             final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/authenticator/AndroidFxAccount.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/authenticator/AndroidFxAccount.java
@@ -640,16 +640,30 @@ public class AndroidFxAccount {
    */
   private static void optionallyTagWithFirstRunScope(final Context context, final Bundle userdata) {
     final String firstRunUUID = EnvironmentUtils.firstRunUUID(context);
     if (firstRunUUID != null) {
       userdata.putString(ACCOUNT_KEY_FIRST_RUN_SCOPE, firstRunUUID);
     }
   }
 
+  /**
+   * If there's an active First Run session, tag the given account with it.  If there's no active
+   * First Run session, remove any existing tag.
+   * We do this in order to reliably determine if an account was created during the current
+   * "first run"; this allows us to re-connect an account that was no created during the current
+   * "first run".
+   *
+   * See {@link FirefoxAccounts#optionallySeparateAccountsDuringFirstRun} for details.
+   */
+  public void updateFirstRunScope(final Context context) {
+    String firstRunUUID = EnvironmentUtils.firstRunUUID(context);
+    accountManager.setUserData(account, ACCOUNT_KEY_FIRST_RUN_SCOPE, firstRunUUID);
+  }
+
   private void clearSyncPrefs() throws UnsupportedEncodingException, GeneralSecurityException {
     getSyncPrefs().edit().clear().apply();
   }
 
   private void setAuthoritiesToSyncAutomaticallyMap(Map<String, Boolean> authoritiesToSyncAutomaticallyMap) {
     if (authoritiesToSyncAutomaticallyMap == null) {
       throw new IllegalArgumentException("authoritiesToSyncAutomaticallyMap must not be null");
     }