Bug 1102488 - Part 0: Make FxAccountConstants independent of Logger. r=rnewman
authorNick Alexander <nalexander@mozilla.com>
Thu, 20 Nov 2014 15:07:35 -0800
changeset 217387 830deae4a41a19121d423a8a50415e174efdd980
parent 217386 e61cf17c8f22130fa66060f5fb649091ef1195b0
child 217388 51ce636dfed12a83c6b84babeb27df11c1d57ad6
push id10152
push usernalexander@mozilla.com
push dateTue, 25 Nov 2014 18:29:11 +0000
treeherderfx-team@7a2706f87fe6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrnewman
bugs1102488
milestone36.0a1
Bug 1102488 - Part 0: Make FxAccountConstants independent of Logger. r=rnewman
mobile/android/base/background/fxa/FxAccountAgeLockoutHelper.java
mobile/android/base/background/fxa/FxAccountClient20.java
mobile/android/base/background/fxa/FxAccountUtils.java
mobile/android/base/fxa/FxAccountConstants.java.in
mobile/android/base/fxa/activities/FxAccountAbstractSetupActivity.java
mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java
mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java
mobile/android/base/fxa/activities/FxAccountStatusFragment.java
mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java
mobile/android/base/fxa/authenticator/AndroidFxAccount.java
mobile/android/base/fxa/login/Cohabiting.java
mobile/android/base/fxa/login/Engaged.java
mobile/android/base/fxa/login/Married.java
mobile/android/base/fxa/login/StateFactory.java
mobile/android/base/fxa/receivers/FxAccountUpgradeReceiver.java
mobile/android/base/fxa/sync/FxAccountNotificationManager.java
mobile/android/base/fxa/sync/FxAccountSyncAdapter.java
--- a/mobile/android/base/background/fxa/FxAccountAgeLockoutHelper.java
+++ b/mobile/android/base/background/fxa/FxAccountAgeLockoutHelper.java
@@ -30,23 +30,23 @@ public class FxAccountAgeLockoutHelper {
     if (ELAPSED_REALTIME_OF_LAST_FAILED_AGE_CHECK == 0L) {
       // We never failed, so we're not locked out.
       return false;
     }
 
     // Otherwise, find out how long it's been since we last failed.
     long millsecondsSinceLastFailedAgeCheck = elapsedRealtime - ELAPSED_REALTIME_OF_LAST_FAILED_AGE_CHECK;
     boolean isLockedOut = millsecondsSinceLastFailedAgeCheck < FxAccountConstants.MINIMUM_TIME_TO_WAIT_AFTER_AGE_CHECK_FAILED_IN_MILLISECONDS;
-    FxAccountConstants.pii(LOG_TAG, "Checking if locked out: it's been " + millsecondsSinceLastFailedAgeCheck + "ms " +
+    FxAccountUtils.pii(LOG_TAG, "Checking if locked out: it's been " + millsecondsSinceLastFailedAgeCheck + "ms " +
         "since last lockout, so " + (isLockedOut ? "yes." : "no."));
     return isLockedOut;
   }
 
   public static synchronized void lockOut(long elapsedRealtime) {
-      FxAccountConstants.pii(LOG_TAG, "Locking out at time: " + elapsedRealtime);
+      FxAccountUtils.pii(LOG_TAG, "Locking out at time: " + elapsedRealtime);
       ELAPSED_REALTIME_OF_LAST_FAILED_AGE_CHECK = Math.max(elapsedRealtime, ELAPSED_REALTIME_OF_LAST_FAILED_AGE_CHECK);
   }
 
   /**
    * Return true if the age of somebody born in <code>yearOfBirth</code> is
    * definitely old enough to create an account.
    * <p>
    * This errs towards locking out users who might be old enough, but are not
@@ -55,18 +55,18 @@ public class FxAccountAgeLockoutHelper {
    * @param yearOfBirth
    * @return true if somebody born in <code>yearOfBirth</code> is definitely old
    *         enough.
    */
   public static boolean passesAgeCheck(int yearOfBirth) {
     int thisYear = Calendar.getInstance().get(Calendar.YEAR);
     int approximateAge = thisYear - yearOfBirth;
     boolean oldEnough = approximateAge >= FxAccountConstants.MINIMUM_AGE_TO_CREATE_AN_ACCOUNT;
-    if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
-      FxAccountConstants.pii(LOG_TAG, "Age check " + (oldEnough ? "passes" : "fails") +
+    if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
+      FxAccountUtils.pii(LOG_TAG, "Age check " + (oldEnough ? "passes" : "fails") +
           ": age is " + approximateAge + " = " + thisYear + " - " + yearOfBirth);
     }
     return oldEnough;
   }
 
   /**
    * Custom function for UI use only.
    */
@@ -74,23 +74,23 @@ public class FxAccountAgeLockoutHelper {
     if (yearText == null) {
       throw new IllegalArgumentException("yearText must not be null");
     }
     if (yearItems == null) {
       throw new IllegalArgumentException("yearItems must not be null");
     }
     if (!Arrays.asList(yearItems).contains(yearText)) {
       // This should never happen, but let's be careful.
-      FxAccountConstants.pii(LOG_TAG, "Failed age check: year text was not found in item list.");
+      FxAccountUtils.pii(LOG_TAG, "Failed age check: year text was not found in item list.");
       return false;
     }
     Integer yearOfBirth;
     try {
       yearOfBirth = Integer.valueOf(yearText, 10);
     } catch (NumberFormatException e) {
       // Any non-numbers in the list are ranges (and we say as much to
       // translators in the resource file), so these people pass the age check.
-      FxAccountConstants.pii(LOG_TAG, "Passed age check: year text was found in item list but was not a number.");
+      FxAccountUtils.pii(LOG_TAG, "Passed age check: year text was found in item list but was not a number.");
       return true;
     }
     return passesAgeCheck(yearOfBirth);
   }
 }
--- a/mobile/android/base/background/fxa/FxAccountClient20.java
+++ b/mobile/android/base/background/fxa/FxAccountClient20.java
@@ -8,17 +8,16 @@ import java.io.UnsupportedEncodingExcept
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URLEncoder;
 import java.util.concurrent.Executor;
 
 import org.json.simple.JSONObject;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
-import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.net.BaseResource;
 
 import ch.boye.httpclientandroidlib.HttpResponse;
 
 public class FxAccountClient20 extends FxAccountClient10 implements FxAccountClient {
   protected static final String[] LOGIN_RESPONSE_REQUIRED_STRING_FIELDS = new String[] { JSON_KEY_UID, JSON_KEY_SESSIONTOKEN };
@@ -201,17 +200,17 @@ public class FxAccountClient20 extends F
    *          addition to the standard <code>sessionToken</code>).
    * @param delegate
    *          to invoke callbacks.
    */
   public void login(final byte[] emailUTF8, final PasswordStretcher stretcher, final boolean getKeys,
       final RequestDelegate<LoginResponse> delegate) {
     byte[] quickStretchedPW;
     try {
-      FxAccountConstants.pii(LOG_TAG, "Trying user provided email: '" + new String(emailUTF8, "UTF-8") + "'" );
+      FxAccountUtils.pii(LOG_TAG, "Trying user provided email: '" + new String(emailUTF8, "UTF-8") + "'" );
       quickStretchedPW = stretcher.getQuickStretchedPW(emailUTF8);
     } catch (Exception e) {
       delegate.handleError(e);
       return;
     }
 
     this.login(emailUTF8, quickStretchedPW, getKeys, new RequestDelegate<LoginResponse>() {
       @Override
@@ -228,17 +227,17 @@ public class FxAccountClient20 extends F
       public void handleFailure(FxAccountClientRemoteException e) {
         String alternateEmail = e.body.getString(JSON_KEY_EMAIL);
         if (!e.isBadEmailCase() || alternateEmail == null) {
           delegate.handleFailure(e);
           return;
         };
 
         Logger.info(LOG_TAG, "Server returned alternate email; retrying login with provided email.");
-        FxAccountConstants.pii(LOG_TAG, "Trying server provided email: '" + alternateEmail + "'" );
+        FxAccountUtils.pii(LOG_TAG, "Trying server provided email: '" + alternateEmail + "'" );
 
         try {
           // Nota bene: this is not recursive, since we call the fixed password
           // signature here, which invokes a non-retrying version.
           byte[] alternateEmailUTF8 = alternateEmail.getBytes("UTF-8");
           byte[] alternateQuickStretchedPW = stretcher.getQuickStretchedPW(alternateEmailUTF8);
           login(alternateEmailUTF8, alternateQuickStretchedPW, getKeys, delegate);
         } catch (Exception innerException) {
--- a/mobile/android/base/background/fxa/FxAccountUtils.java
+++ b/mobile/android/base/background/fxa/FxAccountUtils.java
@@ -30,16 +30,26 @@ public class FxAccountUtils {
 
   public static final int CRYPTO_KEY_LENGTH_BYTES = 32;
   public static final int CRYPTO_KEY_LENGTH_HEX = 2 * CRYPTO_KEY_LENGTH_BYTES;
 
   public static final String KW_VERSION_STRING = "identity.mozilla.com/picl/v1/";
 
   public static final int NUMBER_OF_QUICK_STRETCH_ROUNDS = 1000;
 
+  // For extra debugging.  Not final so it can be changed from Fennec, or from
+  // an add-on.
+  public static boolean LOG_PERSONAL_INFORMATION = false;
+
+  public static void pii(String tag, String message) {
+    if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
+      Logger.info(tag, "$$FxA PII$$: " + message);
+    }
+  }
+
   public static String bytes(String string) throws UnsupportedEncodingException {
     return Utils.byte2Hex(string.getBytes("UTF-8"));
   }
 
   public static byte[] KW(String name) throws UnsupportedEncodingException {
     return Utils.concatAll(
         KW_VERSION_STRING.getBytes("UTF-8"),
         name.getBytes("UTF-8"));
--- a/mobile/android/base/fxa/FxAccountConstants.java.in
+++ b/mobile/android/base/fxa/FxAccountConstants.java.in
@@ -1,38 +1,27 @@
 //#filter substitution
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa;
 
 import org.mozilla.gecko.background.common.GlobalConstants;
-import org.mozilla.gecko.background.common.log.Logger;
 
 public class FxAccountConstants {
   public static final String GLOBAL_LOG_TAG = "FxAccounts";
   public static final String ACCOUNT_TYPE = "@MOZ_ANDROID_SHARED_FXACCOUNT_TYPE@";
 
   public static final String DEFAULT_AUTH_SERVER_ENDPOINT = "https://api.accounts.firefox.com/v1";
   public static final String DEFAULT_TOKEN_SERVER_ENDPOINT = "https://token.services.mozilla.com/1.0/sync/1.5";
 
   public static final String STAGE_AUTH_SERVER_ENDPOINT = "https://api-accounts.stage.mozaws.net/v1";
   public static final String STAGE_TOKEN_SERVER_ENDPOINT = "https://token.stage.mozaws.net/1.0/sync/1.5";
 
-  // For extra debugging.  Not final so it can be changed from Fennec, or from
-  // an add-on.
-  public static boolean LOG_PERSONAL_INFORMATION = false;
-
-  public static void pii(String tag, String message) {
-    if (LOG_PERSONAL_INFORMATION) {
-      Logger.info(tag, "$$FxA PII$$: " + message);
-    }
-  }
-
   // You must be at least 14 years old to create a Firefox Account.
   public static final int MINIMUM_AGE_TO_CREATE_AN_ACCOUNT = 14;
 
   // You must wait 15 minutes after failing an age check before trying to create a different account.
   public static final long MINIMUM_TIME_TO_WAIT_AFTER_AGE_CHECK_FAILED_IN_MILLISECONDS = 15 * 60 * 1000;
 
   public static final String USER_AGENT = "Firefox-Android-FxAccounts/" + GlobalConstants.MOZ_APP_VERSION + " (" + GlobalConstants.MOZ_APP_DISPLAYNAME + ")";
 
--- a/mobile/android/base/fxa/activities/FxAccountAbstractSetupActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountAbstractSetupActivity.java
@@ -319,17 +319,17 @@ abstract public class FxAccountAbstractS
           SyncConfiguration.storeSelectedEnginesToPrefs(fxAccount.getSyncPrefs(), selectedEngines);
         }
       } catch (Exception e) {
         handleError(e);
         return;
       }
 
       // For great debugging.
-      if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
+      if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
         fxAccount.dump();
       }
 
       // The GetStarted activity has called us and needs to return a result to the authenticator.
       final Intent intent = new Intent();
       intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, email);
       intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, FxAccountConstants.ACCOUNT_TYPE);
       // intent.putExtra(AccountManager.KEY_AUTHTOKEN, accountType);
@@ -398,19 +398,19 @@ abstract public class FxAccountAbstractS
       emailEdit.setText(bundle.getString(EXTRA_EMAIL));
       passwordEdit.setText(bundle.getString(EXTRA_PASSWORD));
       setPasswordButtonShown(bundle.getBoolean(EXTRA_PASSWORD_SHOWN, false));
     }
 
     // This sets defaults as well as extracting from extras, so it's not conditional.
     updateServersFromIntentExtras(getIntent());
 
-    if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
-      FxAccountConstants.pii(LOG_TAG, "Using auth server: " + authServerEndpoint);
-      FxAccountConstants.pii(LOG_TAG, "Using sync server: " + syncServerEndpoint);
+    if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
+      FxAccountUtils.pii(LOG_TAG, "Using auth server: " + authServerEndpoint);
+      FxAccountUtils.pii(LOG_TAG, "Using sync server: " + syncServerEndpoint);
     }
 
     updateCustomServerView();
   }
 
   @Override
   public void onResume() {
     super.onResume();
--- a/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java
@@ -14,18 +14,18 @@ import java.util.concurrent.Executors;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper;
 import org.mozilla.gecko.background.fxa.FxAccountClient;
 import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate;
 import org.mozilla.gecko.background.fxa.FxAccountClient20;
 import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse;
 import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.background.fxa.PasswordStretcher;
-import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.tasks.FxAccountCreateAccountTask;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.SystemClock;
@@ -245,20 +245,20 @@ public class FxAccountCreateAccountActiv
         }
         final String email = emailEdit.getText().toString();
         final String password = passwordEdit.getText().toString();
         // Only include selected engines if the user currently has the option checked.
         final Map<String, Boolean> engines = chooseCheckBox.isChecked()
             ? selectedEngines
             : null;
         if (FxAccountAgeLockoutHelper.passesAgeCheck(yearEdit.getText().toString(), yearItems)) {
-          FxAccountConstants.pii(LOG_TAG, "Passed age check.");
+          FxAccountUtils.pii(LOG_TAG, "Passed age check.");
           createAccount(email, password, engines);
         } else {
-          FxAccountConstants.pii(LOG_TAG, "Failed age check!");
+          FxAccountUtils.pii(LOG_TAG, "Failed age check!");
           FxAccountAgeLockoutHelper.lockOut(SystemClock.elapsedRealtime());
           setResult(RESULT_CANCELED);
           redirectToActivity(FxAccountCreateAccountNotAllowedActivity.class);
         }
       }
     });
   }
 
@@ -299,17 +299,17 @@ public class FxAccountCreateAccountActiv
         ListView selectionsList = ((AlertDialog) dialog).getListView();
         for (int i = 0; i < NUMBER_OF_ENGINES; i++) {
           checkedItems[i] = selectionsList.isItemChecked(i);
         }
         selectedEngines.put("bookmarks", checkedItems[INDEX_BOOKMARKS]);
         selectedEngines.put("history", checkedItems[INDEX_HISTORY]);
         selectedEngines.put("tabs", checkedItems[INDEX_TABS]);
         selectedEngines.put("passwords", checkedItems[INDEX_PASSWORDS]);
-        FxAccountConstants.pii(LOG_TAG, "Updating selectedEngines: " + selectedEngines.toString());
+        FxAccountUtils.pii(LOG_TAG, "Updating selectedEngines: " + selectedEngines.toString());
       }
     };
 
     final DialogInterface.OnMultiChoiceClickListener multiChoiceClickListener = new DialogInterface.OnMultiChoiceClickListener() {
       @Override
       public void onClick(DialogInterface dialog, int which, boolean isChecked) {
         // Display multi-selection clicks in UI.
         ListView selectionsList = ((AlertDialog) dialog).getListView();
--- a/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java
@@ -4,16 +4,17 @@
 
 package org.mozilla.gecko.fxa.activities;
 
 import java.util.Locale;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper;
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
 import org.mozilla.gecko.LocaleAware;
 
 import android.accounts.AccountAuthenticatorActivity;
 import android.content.Intent;
 import android.os.Bundle;
@@ -128,12 +129,12 @@ public class FxAccountGetStartedActivity
       this.finish();
     }
   }
 
   protected void linkifyOldFirefoxLink() {
     TextView oldFirefox = (TextView) findViewById(R.id.old_firefox);
     String text = getResources().getString(R.string.fxaccount_getting_started_old_firefox);
     final String url = FirefoxAccounts.getOldSyncUpgradeURL(getResources(), Locale.getDefault());
-    FxAccountConstants.pii(LOG_TAG, "Old Firefox url is: " + url); // Don't want to leak locale in particular.
+    FxAccountUtils.pii(LOG_TAG, "Old Firefox url is: " + url); // Don't want to leak locale in particular.
     ActivityUtils.linkTextView(oldFirefox, text, url);
   }
 }
--- a/mobile/android/base/fxa/activities/FxAccountStatusFragment.java
+++ b/mobile/android/base/fxa/activities/FxAccountStatusFragment.java
@@ -5,16 +5,17 @@
 package org.mozilla.gecko.fxa.activities;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.background.preferences.PreferenceFragment;
 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.Married;
 import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
 import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender;
@@ -140,17 +141,17 @@ public class FxAccountStatusFragment
 
     syncCategory = (PreferenceCategory) ensureFindPreference("sync_category");
 
     bookmarksPreference = (CheckBoxPreference) ensureFindPreference("bookmarks");
     historyPreference = (CheckBoxPreference) ensureFindPreference("history");
     tabsPreference = (CheckBoxPreference) ensureFindPreference("tabs");
     passwordsPreference = (CheckBoxPreference) ensureFindPreference("passwords");
 
-    if (!FxAccountConstants.LOG_PERSONAL_INFORMATION) {
+    if (!FxAccountUtils.LOG_PERSONAL_INFORMATION) {
       removeDebugButtons();
     } else {
       connectDebugButtons();
       ALWAYS_SHOW_AUTH_SERVER = true;
       ALWAYS_SHOW_SYNC_SERVER = true;
     }
 
     needsPasswordPreference.setOnPreferenceClickListener(this);
--- a/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java
@@ -12,17 +12,16 @@ import org.mozilla.gecko.background.comm
 import org.mozilla.gecko.background.fxa.FxAccountClient;
 import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate;
 import org.mozilla.gecko.background.fxa.FxAccountClient20;
 import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse;
 import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
 import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.background.fxa.PasswordStretcher;
 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.Engaged;
 import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.fxa.login.State.StateLabel;
 import org.mozilla.gecko.fxa.tasks.FxAccountSignInTask;
 import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
 
 import android.os.Bundle;
@@ -151,17 +150,17 @@ public class FxAccountUpdateCredentialsA
       } catch (Exception e) {
         this.handleError(e);
         return;
       }
       fxAccount.setState(new Engaged(email, result.uid, result.verified, unwrapkB, result.sessionToken, result.keyFetchToken));
       fxAccount.requestSync(FirefoxAccounts.FORCE);
 
       // For great debugging.
-      if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
+      if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
         fxAccount.dump();
       }
 
       setResult(RESULT_OK);
       finish();
     }
   }
 
--- a/mobile/android/base/fxa/authenticator/AndroidFxAccount.java
+++ b/mobile/android/base/fxa/authenticator/AndroidFxAccount.java
@@ -511,24 +511,24 @@ public class AndroidFxAccount {
       throw new IllegalStateException("could not get state", e);
     }
   }
 
   /**
    * <b>For debugging only!</b>
    */
   public void dump() {
-    if (!FxAccountConstants.LOG_PERSONAL_INFORMATION) {
+    if (!FxAccountUtils.LOG_PERSONAL_INFORMATION) {
       return;
     }
     ExtendedJSONObject o = toJSONObject();
     ArrayList<String> list = new ArrayList<String>(o.keySet());
     Collections.sort(list);
     for (String key : list) {
-      FxAccountConstants.pii(LOG_TAG, key + ": " + o.get(key));
+      FxAccountUtils.pii(LOG_TAG, key + ": " + o.get(key));
     }
   }
 
   /**
    * Return the Firefox Account's local email address.
    * <p>
    * It is important to note that this is the local email address, and not
    * necessarily the normalized remote email address that the server expects.
--- a/mobile/android/base/fxa/login/Cohabiting.java
+++ b/mobile/android/base/fxa/login/Cohabiting.java
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.login;
 
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.browserid.BrowserIDKeyPair;
 import org.mozilla.gecko.browserid.JSONWebTokenUtils;
-import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.login.FxAccountLoginStateMachine.ExecuteDelegate;
 import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.LogMessage;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 
 public class Cohabiting extends TokensAndKeysState {
   private static final String LOG_TAG = Cohabiting.class.getSimpleName();
 
   public Cohabiting(String email, String uid, byte[] sessionToken, byte[] kA, byte[] kB, BrowserIDKeyPair keyPair) {
@@ -19,28 +19,28 @@ public class Cohabiting extends TokensAn
   }
 
   @Override
   public void execute(final ExecuteDelegate delegate) {
     delegate.getClient().sign(sessionToken, keyPair.getPublic().toJSONObject(), delegate.getCertificateDurationInMilliseconds(),
         new BaseRequestDelegate<String>(this, delegate) {
       @Override
       public void handleSuccess(String certificate) {
-        if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
+        if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
           try {
-            FxAccountConstants.pii(LOG_TAG, "Fetched certificate: " + certificate);
+            FxAccountUtils.pii(LOG_TAG, "Fetched certificate: " + certificate);
             ExtendedJSONObject c = JSONWebTokenUtils.parseCertificate(certificate);
             if (c != null) {
-              FxAccountConstants.pii(LOG_TAG, "Header   : " + c.getObject("header"));
-              FxAccountConstants.pii(LOG_TAG, "Payload  : " + c.getObject("payload"));
-              FxAccountConstants.pii(LOG_TAG, "Signature: " + c.getString("signature"));
+              FxAccountUtils.pii(LOG_TAG, "Header   : " + c.getObject("header"));
+              FxAccountUtils.pii(LOG_TAG, "Payload  : " + c.getObject("payload"));
+              FxAccountUtils.pii(LOG_TAG, "Signature: " + c.getString("signature"));
             } else {
-              FxAccountConstants.pii(LOG_TAG, "Could not parse certificate!");
+              FxAccountUtils.pii(LOG_TAG, "Could not parse certificate!");
             }
           } catch (Exception e) {
-            FxAccountConstants.pii(LOG_TAG, "Could not parse certificate!");
+            FxAccountUtils.pii(LOG_TAG, "Could not parse certificate!");
           }
         }
         delegate.handleTransition(new LogMessage("sign succeeded"), new Married(email, uid, sessionToken, kA, kB, keyPair, certificate));
       }
     });
   }
 }
--- a/mobile/android/base/fxa/login/Engaged.java
+++ b/mobile/android/base/fxa/login/Engaged.java
@@ -4,17 +4,16 @@
 
 package org.mozilla.gecko.fxa.login;
 
 import java.security.NoSuchAlgorithmException;
 
 import org.mozilla.gecko.background.fxa.FxAccountClient10.TwoKeys;
 import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.browserid.BrowserIDKeyPair;
-import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.login.FxAccountLoginStateMachine.ExecuteDelegate;
 import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.AccountVerified;
 import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.LocalError;
 import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.LogMessage;
 import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.RemoteError;
 import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.Transition;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.Utils;
@@ -56,20 +55,20 @@ public class Engaged extends State {
     final BrowserIDKeyPair keyPair = theKeyPair;
 
     delegate.getClient().keys(keyFetchToken, new BaseRequestDelegate<TwoKeys>(this, delegate) {
       @Override
       public void handleSuccess(TwoKeys result) {
         byte[] kB;
         try {
           kB = FxAccountUtils.unwrapkB(unwrapkB, result.wrapkB);
-          if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
-            FxAccountConstants.pii(LOG_TAG, "Fetched kA: " + Utils.byte2Hex(result.kA));
-            FxAccountConstants.pii(LOG_TAG, "And wrapkB: " + Utils.byte2Hex(result.wrapkB));
-            FxAccountConstants.pii(LOG_TAG, "Giving kB : " + Utils.byte2Hex(kB));
+          if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
+            FxAccountUtils.pii(LOG_TAG, "Fetched kA: " + Utils.byte2Hex(result.kA));
+            FxAccountUtils.pii(LOG_TAG, "And wrapkB: " + Utils.byte2Hex(result.wrapkB));
+            FxAccountUtils.pii(LOG_TAG, "Giving kB : " + Utils.byte2Hex(kB));
           }
         } catch (Exception e) {
           delegate.handleTransition(new RemoteError(e), new Separated(email, uid, verified));
           return;
         }
         Transition transition = verified
             ? new LogMessage("keys succeeded")
             : new AccountVerified();
--- a/mobile/android/base/fxa/login/Married.java
+++ b/mobile/android/base/fxa/login/Married.java
@@ -12,17 +12,16 @@ import java.security.NoSuchAlgorithmExce
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 
 import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.browserid.BrowserIDKeyPair;
 import org.mozilla.gecko.browserid.JSONWebTokenUtils;
-import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.login.FxAccountLoginStateMachine.ExecuteDelegate;
 import org.mozilla.gecko.fxa.login.FxAccountLoginTransition.LogMessage;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 
 public class Married extends TokensAndKeysState {
@@ -56,64 +55,64 @@ public class Married extends TokensAndKe
     delegate.handleTransition(new LogMessage("staying married"), this);
   }
 
   public String generateAssertion(String audience, String issuer) throws NonObjectJSONException, IOException, ParseException, GeneralSecurityException {
     // We generate assertions with no iat and an exp after 2050 to avoid
     // invalid-timestamp errors from the token server.
     final long expiresAt = JSONWebTokenUtils.DEFAULT_FUTURE_EXPIRES_AT_IN_MILLISECONDS;
     String assertion = JSONWebTokenUtils.createAssertion(keyPair.getPrivate(), certificate, audience, issuer, null, expiresAt);
-    if (!FxAccountConstants.LOG_PERSONAL_INFORMATION) {
+    if (!FxAccountUtils.LOG_PERSONAL_INFORMATION) {
       return assertion;
     }
 
     try {
-      FxAccountConstants.pii(LOG_TAG, "Generated assertion: " + assertion);
+      FxAccountUtils.pii(LOG_TAG, "Generated assertion: " + assertion);
       ExtendedJSONObject a = JSONWebTokenUtils.parseAssertion(assertion);
       if (a != null) {
-        FxAccountConstants.pii(LOG_TAG, "aHeader   : " + a.getObject("header"));
-        FxAccountConstants.pii(LOG_TAG, "aPayload  : " + a.getObject("payload"));
-        FxAccountConstants.pii(LOG_TAG, "aSignature: " + a.getString("signature"));
+        FxAccountUtils.pii(LOG_TAG, "aHeader   : " + a.getObject("header"));
+        FxAccountUtils.pii(LOG_TAG, "aPayload  : " + a.getObject("payload"));
+        FxAccountUtils.pii(LOG_TAG, "aSignature: " + a.getString("signature"));
         String certificate = a.getString("certificate");
         if (certificate != null) {
           ExtendedJSONObject c = JSONWebTokenUtils.parseCertificate(certificate);
-          FxAccountConstants.pii(LOG_TAG, "cHeader   : " + c.getObject("header"));
-          FxAccountConstants.pii(LOG_TAG, "cPayload  : " + c.getObject("payload"));
-          FxAccountConstants.pii(LOG_TAG, "cSignature: " + c.getString("signature"));
+          FxAccountUtils.pii(LOG_TAG, "cHeader   : " + c.getObject("header"));
+          FxAccountUtils.pii(LOG_TAG, "cPayload  : " + c.getObject("payload"));
+          FxAccountUtils.pii(LOG_TAG, "cSignature: " + c.getString("signature"));
           // Print the relevant timestamps in sorted order with labels.
           HashMap<Long, String> map = new HashMap<Long, String>();
           map.put(a.getObject("payload").getLong("iat"), "aiat");
           map.put(a.getObject("payload").getLong("exp"), "aexp");
           map.put(c.getObject("payload").getLong("iat"), "ciat");
           map.put(c.getObject("payload").getLong("exp"), "cexp");
           ArrayList<Long> values = new ArrayList<Long>(map.keySet());
           Collections.sort(values);
           for (Long value : values) {
-            FxAccountConstants.pii(LOG_TAG, map.get(value) + ": " + value);
+            FxAccountUtils.pii(LOG_TAG, map.get(value) + ": " + value);
           }
         } else {
-          FxAccountConstants.pii(LOG_TAG, "Could not parse certificate!");
+          FxAccountUtils.pii(LOG_TAG, "Could not parse certificate!");
         }
       } else {
-        FxAccountConstants.pii(LOG_TAG, "Could not parse assertion!");
+        FxAccountUtils.pii(LOG_TAG, "Could not parse assertion!");
       }
     } catch (Exception e) {
-      FxAccountConstants.pii(LOG_TAG, "Got exception dumping assertion debug info.");
+      FxAccountUtils.pii(LOG_TAG, "Got exception dumping assertion debug info.");
     }
     return assertion;
   }
 
   public KeyBundle getSyncKeyBundle() throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
     // TODO Document this choice for deriving from kB.
     return FxAccountUtils.generateSyncKeyBundle(kB);
   }
 
   public String getClientState() {
-    if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
-      FxAccountConstants.pii(LOG_TAG, "Client state: " + this.clientState);
+    if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
+      FxAccountUtils.pii(LOG_TAG, "Client state: " + this.clientState);
     }
     return this.clientState;
   }
 
   public State makeCohabitingState() {
     return new Cohabiting(email, uid, sessionToken, kA, kB, keyPair);
   }
 }
--- a/mobile/android/base/fxa/login/StateFactory.java
+++ b/mobile/android/base/fxa/login/StateFactory.java
@@ -3,20 +3,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.login;
 
 import java.security.NoSuchAlgorithmException;
 import java.security.spec.InvalidKeySpecException;
 
 import org.mozilla.gecko.background.common.log.Logger;
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.browserid.BrowserIDKeyPair;
 import org.mozilla.gecko.browserid.DSACryptoImplementation;
 import org.mozilla.gecko.browserid.RSACryptoImplementation;
-import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.login.State.StateLabel;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.Utils;
 
 /**
  * Create {@link State} instances from serialized representations.
  * <p>
@@ -130,25 +130,25 @@ public class StateFactory {
           keyPairFromJSONObjectV2(o.getObject("keyPair")),
           o.getString("certificate"));
     default:
       return fromJSONObjectV1(stateLabel, o);
     }
   }
 
   protected static void logMigration(State from, State to) {
-    if (!FxAccountConstants.LOG_PERSONAL_INFORMATION) {
+    if (!FxAccountUtils.LOG_PERSONAL_INFORMATION) {
       return;
     }
     try {
-      FxAccountConstants.pii(LOG_TAG, "V1 persisted state is: " + from.toJSONObject().toJSONString());
+      FxAccountUtils.pii(LOG_TAG, "V1 persisted state is: " + from.toJSONObject().toJSONString());
     } catch (Exception e) {
       Logger.warn(LOG_TAG, "Error producing JSON representation of V1 state.", e);
     }
-    FxAccountConstants.pii(LOG_TAG, "Generated new V2 state: " + to.toJSONObject().toJSONString());
+    FxAccountUtils.pii(LOG_TAG, "Generated new V2 state: " + to.toJSONObject().toJSONString());
   }
 
   protected static State migrateV1toV2(StateLabel stateLabel, State state) throws NoSuchAlgorithmException {
     if (state == null) {
       // This should never happen, but let's be careful.
       Logger.error(LOG_TAG, "Got null state in migrateV1toV2; returning null.");
       return state;
     }
--- a/mobile/android/base/fxa/receivers/FxAccountUpgradeReceiver.java
+++ b/mobile/android/base/fxa/receivers/FxAccountUpgradeReceiver.java
@@ -5,16 +5,17 @@
 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.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;
@@ -107,17 +108,17 @@ public class FxAccountUpgradeReceiver ex
     @Override
     public void run() {
       final Account[] accounts = FirefoxAccounts.getFirefoxAccounts(context);
       Logger.info(LOG_TAG, "Trying to advance " + accounts.length + " existing Firefox Accounts from the Doghouse to Separated (if necessary).");
       for (Account account : accounts) {
         try {
           final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
           // For great debugging.
-          if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
+          if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
             fxAccount.dump();
           }
           State state = fxAccount.getState();
           if (state == null || state.getStateLabel() != StateLabel.Doghouse) {
             Logger.debug(LOG_TAG, "Account named like " + Utils.obfuscateEmail(account.name) + " is not in the Doghouse; skipping.");
             continue;
           }
           Logger.debug(LOG_TAG, "Account named like " + Utils.obfuscateEmail(account.name) + " is in the Doghouse; advancing to Separated.");
--- a/mobile/android/base/fxa/sync/FxAccountNotificationManager.java
+++ b/mobile/android/base/fxa/sync/FxAccountNotificationManager.java
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.sync;
 
 import org.mozilla.gecko.BrowserLocaleManager;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.fxa.FxAccountConstants;
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.fxa.activities.FxAccountStatusActivity;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.fxa.login.State.Action;
 
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -65,17 +65,17 @@ public class FxAccountNotificationManage
     if (!localeUpdated) {
       localeUpdated = true;
       BrowserLocaleManager.getInstance().getAndApplyPersistedLocale(context);
     }
 
     final String title = context.getResources().getString(R.string.fxaccount_sync_sign_in_error_notification_title);
     final String text = context.getResources().getString(R.string.fxaccount_sync_sign_in_error_notification_text, state.email);
     Logger.info(LOG_TAG, "State " + state.getStateLabel() + " needs action; offering notification with title: " + title);
-    FxAccountConstants.pii(LOG_TAG, "And text: " + text);
+    FxAccountUtils.pii(LOG_TAG, "And text: " + text);
 
     final Intent notificationIntent = new Intent(context, FxAccountStatusActivity.class);
     final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
 
     final Builder builder = new NotificationCompat.Builder(context);
     builder
     .setContentTitle(title)
     .setContentText(text)
--- a/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java
+++ b/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java
@@ -12,16 +12,17 @@ import java.util.Collections;
 import java.util.EnumSet;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.fxa.FxAccountClient;
 import org.mozilla.gecko.background.fxa.FxAccountClient20;
+import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.background.fxa.SkewHandler;
 import org.mozilla.gecko.browserid.BrowserIDKeyPair;
 import org.mozilla.gecko.browserid.JSONWebTokenUtils;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.authenticator.AccountPickler;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.fxa.authenticator.FxAccountAuthenticator;
@@ -310,17 +311,17 @@ public class FxAccountSyncAdapter extend
 
       @Override
       public String getUserAgent() {
         return FxAccountConstants.USER_AGENT;
       }
 
       @Override
       public void handleSuccess(final TokenServerToken token) {
-        FxAccountConstants.pii(LOG_TAG, "Got token! uid is " + token.uid + " and endpoint is " + token.endpoint + ".");
+        FxAccountUtils.pii(LOG_TAG, "Got token! uid is " + token.uid + " and endpoint is " + token.endpoint + ".");
 
         if (!didReceiveBackoff) {
           // We must be OK to touch this token server.
           tokenBackoffHandler.setEarliestNextRequest(0L);
         }
 
         final URI storageServerURI;
         try {
@@ -353,19 +354,19 @@ public class FxAccountSyncAdapter extend
 
         // Invalidate the previous backoff, because our storage host has changed,
         // or we never had one at all, or we're OK to sync.
         storageBackoffHandler.setEarliestNextRequest(0L);
 
         FxAccountGlobalSession globalSession = null;
         try {
           final ClientsDataDelegate clientsDataDelegate = new SharedPreferencesClientsDataDelegate(sharedPrefs, getContext());
-          if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
-            FxAccountConstants.pii(LOG_TAG, "Client device name is: '" + clientsDataDelegate.getClientName() + "'.");
-            FxAccountConstants.pii(LOG_TAG, "Client device data last modified: " + clientsDataDelegate.getLastModifiedTimestamp());
+          if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
+            FxAccountUtils.pii(LOG_TAG, "Client device name is: '" + clientsDataDelegate.getClientName() + "'.");
+            FxAccountUtils.pii(LOG_TAG, "Client device data last modified: " + clientsDataDelegate.getLastModifiedTimestamp());
           }
 
           // We compute skew over time using SkewHandler. This yields an unchanging
           // skew adjustment that the HawkAuthHeaderProvider uses to adjust its
           // timestamps. Eventually we might want this to adapt within the scope of a
           // global session.
           final SkewHandler storageServerSkewHandler = SkewHandler.getSkewHandlerForHostname(storageHostname);
           final long storageServerSkew = storageServerSkewHandler.getSkewInSeconds();
@@ -439,17 +440,17 @@ public class FxAccountSyncAdapter extend
 
     Logger.info(LOG_TAG, "Syncing FxAccount" +
         " account named like " + Utils.obfuscateEmail(account.name) +
         " for authority " + authority +
         " with instance " + this + ".");
 
     Logger.info(LOG_TAG, "Account last synced at: " + fxAccount.getLastSyncedTimestamp());
 
-    if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
+    if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
       fxAccount.dump();
     }
 
     final EnumSet<FirefoxAccounts.SyncHint> syncHints = FirefoxAccounts.getHintsToSyncFromBundle(extras);
     FirefoxAccounts.logSyncHints(syncHints);
 
     // This applies even to forced syncs, but only on success.
     if (this.lastSyncRealtimeMillis > 0L &&