Bug 1456487 - Update Firefox Account's first run UUID when re-connecting. r=rnewman, a=jcristau FIREFOX_60b_RELBRANCH
authorNick Alexander <nalexander@mozilla.com>
Wed, 25 Apr 2018 12:17:05 -0700
branchFIREFOX_60b_RELBRANCH
changeset 469604 4bdbddf15a016877ba545646b97f008026ac6aa2
parent 469603 158373b08a9c5e1e4ebcaded41ca5bfb5be1d699
child 469605 3a1aae811a582d2f78f893a4626e125e685caef8
push id9173
push userryanvm@gmail.com
push dateSat, 28 Apr 2018 16:43:38 +0000
treeherdermozilla-beta@3a1aae811a58 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrnewman, jcristau
bugs1456487
milestone60.0
Bug 1456487 - Update Firefox Account's first run UUID when re-connecting. r=rnewman, a=jcristau 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");
     }