Bug 1456487 - Update Firefox Account's first run UUID when re-connecting. r=rnewman
authorNick Alexander <nalexander@mozilla.com>
Wed, 25 Apr 2018 12:17:05 -0700
changeset 471671 df36fee2b3acada69d9bd43b4febc48707adc801
parent 471670 252a244dc3d4b91d81a2e170143aeaf2802a225e
child 471672 e43c1c2ce4131918fffab239dc7b61453ce2c736
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrnewman
bugs1456487
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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" a Firefox Account is 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 not 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");
     }