diff options
Diffstat (limited to 'data/patches/disable')
3 files changed, 2230 insertions, 0 deletions
diff --git a/data/patches/disable/0001-upgrade-mobile-fxa-to-v32.patch b/data/patches/disable/0001-upgrade-mobile-fxa-to-v32.patch new file mode 100644 index 0000000..e420727 --- /dev/null +++ b/data/patches/disable/0001-upgrade-mobile-fxa-to-v32.patch @@ -0,0 +1,992 @@ +diff -ruN mozilla-esr31/mobile/android/base/fxa/FirefoxAccounts.java mozilla-release/mobile/android/base/fxa/FirefoxAccounts.java +--- mozilla-esr31/mobile/android/base/fxa/FirefoxAccounts.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/FirefoxAccounts.java 2014-09-24 03:05:32.000000000 +0200 +@@ -6,13 +6,18 @@ + + import java.io.File; + import java.util.EnumSet; ++import java.util.Locale; + import java.util.concurrent.CountDownLatch; + ++import org.mozilla.gecko.AppConstants; ++import org.mozilla.gecko.R; + import org.mozilla.gecko.background.common.log.Logger; + import org.mozilla.gecko.fxa.authenticator.AccountPickler; + import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; ++import org.mozilla.gecko.fxa.login.State; + import org.mozilla.gecko.fxa.sync.FxAccountSyncAdapter; + import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper; ++import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender; + import org.mozilla.gecko.sync.ThreadPool; + import org.mozilla.gecko.sync.Utils; + +@@ -20,6 +25,7 @@ + import android.accounts.AccountManager; + import android.content.ContentResolver; + import android.content.Context; ++import android.content.res.Resources; + import android.os.Bundle; + + /** +@@ -152,6 +158,38 @@ + return null; + } + ++ /** ++ * @return ++ * the {@link State} instance associated with the current account, or <code>null</code> if ++ * no accounts exist. ++ */ ++ public static State getFirefoxAccountState(final Context context) { ++ final Account account = getFirefoxAccount(context); ++ if (account == null) { ++ return null; ++ } ++ ++ final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account); ++ try { ++ return fxAccount.getState(); ++ } catch (final Exception ex) { ++ Logger.warn(LOG_TAG, "Could not get FX account state.", ex); ++ return null; ++ } ++ } ++ ++ /* ++ * @param context Android context ++ * @return the email address associated with the configured Firefox account if one exists; null otherwise. ++ */ ++ public static String getFirefoxAccountEmail(final Context context) { ++ final Account account = getFirefoxAccount(context); ++ if (account == null) { ++ return null; ++ } ++ return account.name; ++ } ++ + protected static void putHintsToSync(final Bundle extras, EnumSet<SyncHint> syncHints) { + // stagesToSync and stagesToSkip are allowed to be null. + if (syncHints == null) { +@@ -264,4 +302,33 @@ + // stopObserving null-checks its argument. + FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusListener); + } ++ ++ public static String getOldSyncUpgradeURL(final Resources res, final Locale locale) { ++ final String VERSION = AppConstants.MOZ_APP_VERSION; ++ final String OS = AppConstants.OS_TARGET; ++ final String LOCALE = Utils.getLanguageTag(locale); ++ return res.getString(R.string.fxaccount_link_old_firefox, VERSION, OS, LOCALE); ++ } ++ ++ /** ++ * Resends the account verification email, and displays an appropriate ++ * toast on both send success and failure. Note that because the underlying implementation ++ * uses {@link AsyncTask}, the provided context must be UI-capable, and this ++ * method called from the UI thread (see ++ * {@link org.mozilla.gecko.fxa.tasks.FxAccountCodeResender#resendCode(Context, AndroidFxAccount)} ++ * for more). ++ * ++ * @param context a UI-capable Android context. ++ * @return true if an account exists, false otherwise. ++ */ ++ public static boolean resendVerificationEmail(final Context context) { ++ final Account account = getFirefoxAccount(context); ++ if (account == null) { ++ return false; ++ } ++ ++ final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account); ++ FxAccountCodeResender.resendCode(context, fxAccount); ++ return true; ++ } + } +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountAbstractSetupActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountAbstractSetupActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountAbstractSetupActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountAbstractSetupActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -19,10 +19,10 @@ + import org.mozilla.gecko.background.fxa.PasswordStretcher; + import org.mozilla.gecko.background.fxa.QuickPasswordStretcher; + import org.mozilla.gecko.fxa.FxAccountConstants; +-import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.ProgressDisplay; + 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.tasks.FxAccountSetupTask.ProgressDisplay; + import org.mozilla.gecko.sync.SyncConfiguration; + import org.mozilla.gecko.sync.setup.Constants; + import org.mozilla.gecko.sync.setup.activities.ActivityUtils; +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -4,21 +4,15 @@ + + package org.mozilla.gecko.fxa.activities; + +-import java.util.concurrent.Executor; +-import java.util.concurrent.Executors; +- + import org.mozilla.gecko.R; + import org.mozilla.gecko.background.common.log.Logger; +-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.FxAccountClientException.FxAccountClientRemoteException; + import org.mozilla.gecko.fxa.FirefoxAccounts; + 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.Action; + import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper; ++import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender; + import org.mozilla.gecko.sync.setup.activities.ActivityUtils; + + import android.accounts.Account; +@@ -28,7 +22,6 @@ + import android.view.View; + import android.view.View.OnClickListener; + import android.widget.TextView; +-import android.widget.Toast; + + /** + * Activity which displays account created successfully screen to the user, and +@@ -164,76 +157,8 @@ + resendLink.setClickable(resendLinkShouldBeEnabled); + } + +- public static class FxAccountResendCodeTask extends FxAccountSetupTask<Void> { +- protected static final String LOG_TAG = FxAccountResendCodeTask.class.getSimpleName(); +- +- protected final byte[] sessionToken; +- +- public FxAccountResendCodeTask(Context context, byte[] sessionToken, FxAccountClient client, RequestDelegate<Void> delegate) { +- super(context, null, client, delegate); +- this.sessionToken = sessionToken; +- } +- +- @Override +- protected InnerRequestDelegate<Void> doInBackground(Void... arg0) { +- try { +- client.resendCode(sessionToken, innerDelegate); +- latch.await(); +- return innerDelegate; +- } catch (Exception e) { +- Logger.error(LOG_TAG, "Got exception signing in.", e); +- delegate.handleError(e); +- } +- return null; +- } +- } +- +- protected static class ResendCodeDelegate implements RequestDelegate<Void> { +- public final Context context; +- +- public ResendCodeDelegate(Context context) { +- this.context = context; +- } +- +- @Override +- public void handleError(Exception e) { +- Logger.warn(LOG_TAG, "Got exception requesting fresh confirmation link; ignoring.", e); +- Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_not_sent, Toast.LENGTH_LONG).show(); +- } +- +- @Override +- public void handleFailure(FxAccountClientRemoteException e) { +- handleError(e); +- } +- +- @Override +- public void handleSuccess(Void result) { +- Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_sent, Toast.LENGTH_SHORT).show(); +- } +- } +- +- public static void resendCode(Context context, AndroidFxAccount fxAccount) { +- RequestDelegate<Void> delegate = new ResendCodeDelegate(context); +- +- byte[] sessionToken; +- try { +- sessionToken = ((Engaged) fxAccount.getState()).getSessionToken(); +- } catch (Exception e) { +- delegate.handleError(e); +- return; +- } +- if (sessionToken == null) { +- delegate.handleError(new IllegalStateException("sessionToken should not be null")); +- return; +- } +- +- Executor executor = Executors.newSingleThreadExecutor(); +- FxAccountClient client = new FxAccountClient20(fxAccount.getAccountServerURI(), executor); +- new FxAccountResendCodeTask(context, sessionToken, client, delegate).execute(); +- } +- + @Override + public void onClick(View v) { +- resendCode(this, fxAccount); ++ FxAccountCodeResender.resendCode(this, fxAccount); + } + } +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -21,7 +21,7 @@ + import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; + import org.mozilla.gecko.background.fxa.PasswordStretcher; + import org.mozilla.gecko.fxa.FxAccountConstants; +-import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.FxAccountCreateAccountTask; ++import org.mozilla.gecko.fxa.tasks.FxAccountCreateAccountTask; + + import android.app.AlertDialog; + import android.app.Dialog; +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -6,13 +6,11 @@ + + import java.util.Locale; + +-import org.mozilla.gecko.AppConstants; + import org.mozilla.gecko.R; + import org.mozilla.gecko.background.common.log.Logger; + import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper; + import org.mozilla.gecko.fxa.FirefoxAccounts; + import org.mozilla.gecko.fxa.FxAccountConstants; +-import org.mozilla.gecko.sync.Utils; + import org.mozilla.gecko.sync.setup.activities.ActivityUtils; + import org.mozilla.gecko.sync.setup.activities.LocaleAware; + +@@ -109,11 +107,7 @@ + protected void linkifyOldFirefoxLink() { + TextView oldFirefox = (TextView) findViewById(R.id.old_firefox); + String text = getResources().getString(R.string.fxaccount_getting_started_old_firefox); +- String VERSION = AppConstants.MOZ_APP_VERSION; +- String OS = AppConstants.OS_TARGET; +- +- String LOCALE = Utils.getLanguageTag(Locale.getDefault()); +- String url = getResources().getString(R.string.fxaccount_link_old_firefox, VERSION, OS, LOCALE); ++ 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. + ActivityUtils.linkTextView(oldFirefox, text, url); + } +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountSetupTask.java mozilla-release/mobile/android/base/fxa/activities/FxAccountSetupTask.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountSetupTask.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountSetupTask.java 1970-01-01 01:00:00.000000000 +0100 +@@ -1,172 +0,0 @@ +-/* 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.activities; +- +-import java.io.UnsupportedEncodingException; +-import java.util.concurrent.CountDownLatch; +- +-import org.mozilla.gecko.background.common.log.Logger; +-import org.mozilla.gecko.background.fxa.FxAccountClient; +-import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; +-import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse; +-import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; +-import org.mozilla.gecko.background.fxa.PasswordStretcher; +-import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.InnerRequestDelegate; +- +-import android.content.Context; +-import android.os.AsyncTask; +- +-/** +- * An <code>AsyncTask</code> wrapper around signing up for, and signing in to, a +- * Firefox Account. +- * <p> +- * It's strange to add explicit blocking to callback-threading code, but we do +- * it here to take advantage of Android's built in support for background work. +- * We really want to avoid making a threading mistake that brings down the whole +- * process. +- */ +-abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestDelegate<T>> { +- private static final String LOG_TAG = FxAccountSetupTask.class.getSimpleName(); +- +- public interface ProgressDisplay { +- public void showProgress(); +- public void dismissProgress(); +- } +- +- protected final Context context; +- protected final FxAccountClient client; +- protected final ProgressDisplay progressDisplay; +- +- // Initialized lazily. +- protected byte[] quickStretchedPW; +- +- // AsyncTask's are one-time-use, so final members are fine. +- protected final CountDownLatch latch = new CountDownLatch(1); +- protected final InnerRequestDelegate<T> innerDelegate = new InnerRequestDelegate<T>(latch); +- +- protected final RequestDelegate<T> delegate; +- +- public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient client, RequestDelegate<T> delegate) { +- this.context = context; +- this.client = client; +- this.delegate = delegate; +- this.progressDisplay = progressDisplay; +- } +- +- @Override +- protected void onPreExecute() { +- if (progressDisplay != null) { +- progressDisplay.showProgress(); +- } +- } +- +- @Override +- protected void onPostExecute(InnerRequestDelegate<T> result) { +- if (progressDisplay != null) { +- progressDisplay.dismissProgress(); +- } +- +- // We are on the UI thread, and need to invoke these callbacks here to allow UI updating. +- if (innerDelegate.failure != null) { +- delegate.handleFailure(innerDelegate.failure); +- } else if (innerDelegate.exception != null) { +- delegate.handleError(innerDelegate.exception); +- } else { +- delegate.handleSuccess(result.response); +- } +- } +- +- @Override +- protected void onCancelled(InnerRequestDelegate<T> result) { +- if (progressDisplay != null) { +- progressDisplay.dismissProgress(); +- } +- delegate.handleError(new IllegalStateException("Task was cancelled.")); +- } +- +- protected static class InnerRequestDelegate<T> implements RequestDelegate<T> { +- protected final CountDownLatch latch; +- public T response = null; +- public Exception exception = null; +- public FxAccountClientRemoteException failure = null; +- +- protected InnerRequestDelegate(CountDownLatch latch) { +- this.latch = latch; +- } +- +- @Override +- public void handleError(Exception e) { +- Logger.error(LOG_TAG, "Got exception."); +- this.exception = e; +- latch.countDown(); +- } +- +- @Override +- public void handleFailure(FxAccountClientRemoteException e) { +- Logger.warn(LOG_TAG, "Got failure."); +- this.failure = e; +- latch.countDown(); +- } +- +- @Override +- public void handleSuccess(T result) { +- Logger.info(LOG_TAG, "Got success."); +- this.response = result; +- latch.countDown(); +- } +- } +- +- public static class FxAccountCreateAccountTask extends FxAccountSetupTask<LoginResponse> { +- private static final String LOG_TAG = FxAccountCreateAccountTask.class.getSimpleName(); +- +- protected final byte[] emailUTF8; +- protected final PasswordStretcher passwordStretcher; +- +- public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { +- super(context, progressDisplay, client, delegate); +- this.emailUTF8 = email.getBytes("UTF-8"); +- this.passwordStretcher = passwordStretcher; +- } +- +- @Override +- protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { +- try { +- client.createAccountAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); +- latch.await(); +- return innerDelegate; +- } catch (Exception e) { +- Logger.error(LOG_TAG, "Got exception logging in.", e); +- delegate.handleError(e); +- } +- return null; +- } +- } +- +- public static class FxAccountSignInTask extends FxAccountSetupTask<LoginResponse> { +- protected static final String LOG_TAG = FxAccountSignInTask.class.getSimpleName(); +- +- protected final byte[] emailUTF8; +- protected final PasswordStretcher passwordStretcher; +- +- public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { +- super(context, progressDisplay, client, delegate); +- this.emailUTF8 = email.getBytes("UTF-8"); +- this.passwordStretcher = passwordStretcher; +- } +- +- @Override +- protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { +- try { +- client.loginAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); +- latch.await(); +- return innerDelegate; +- } catch (Exception e) { +- Logger.error(LOG_TAG, "Got exception signing in.", e); +- delegate.handleError(e); +- } +- return null; +- } +- } +-} +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountSignInActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountSignInActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountSignInActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountSignInActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -16,7 +16,7 @@ + import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; + import org.mozilla.gecko.background.fxa.PasswordStretcher; + import org.mozilla.gecko.fxa.FxAccountConstants; +-import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.FxAccountSignInTask; ++import org.mozilla.gecko.fxa.tasks.FxAccountSignInTask; + import org.mozilla.gecko.sync.setup.activities.ActivityUtils; + + import android.content.Intent; +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountStatusFragment.java mozilla-release/mobile/android/base/fxa/activities/FxAccountStatusFragment.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountStatusFragment.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountStatusFragment.java 2014-09-24 03:05:32.000000000 +0200 +@@ -17,6 +17,8 @@ + 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; ++import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate; + import org.mozilla.gecko.sync.SyncConfiguration; + + import android.accounts.Account; +@@ -27,10 +29,13 @@ + import android.os.Bundle; + import android.os.Handler; + import android.preference.CheckBoxPreference; ++import android.preference.EditTextPreference; + import android.preference.Preference; ++import android.preference.Preference.OnPreferenceChangeListener; + import android.preference.Preference.OnPreferenceClickListener; + import android.preference.PreferenceCategory; + import android.preference.PreferenceScreen; ++import android.text.TextUtils; + + /** + * A fragment that displays the status of an AndroidFxAccount. +@@ -38,7 +43,9 @@ + * The owning activity is responsible for providing an AndroidFxAccount at + * appropriate times. + */ +-public class FxAccountStatusFragment extends PreferenceFragment implements OnPreferenceClickListener { ++public class FxAccountStatusFragment ++ extends PreferenceFragment ++ implements OnPreferenceClickListener, OnPreferenceChangeListener { + private static final String LOG_TAG = FxAccountStatusFragment.class.getSimpleName(); + + // When a checkbox is toggled, wait 5 seconds (for other checkbox actions) +@@ -64,7 +71,12 @@ + protected CheckBoxPreference tabsPreference; + protected CheckBoxPreference passwordsPreference; + ++ protected EditTextPreference deviceNamePreference; ++ + protected volatile AndroidFxAccount fxAccount; ++ // The contract is: when fxAccount is non-null, then clientsDataDelegate is ++ // non-null. If violated then an IllegalStateException is thrown. ++ protected volatile SharedPreferencesClientsDataDelegate clientsDataDelegate; + + // Used to post delayed sync requests. + protected Handler handler; +@@ -87,6 +99,10 @@ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); ++ addPreferences(); ++ } ++ ++ protected void addPreferences() { + addPreferencesFromResource(R.xml.fxaccount_status_prefscreen); + + emailPreference = ensureFindPreference("email"); +@@ -118,6 +134,9 @@ + historyPreference.setOnPreferenceClickListener(this); + tabsPreference.setOnPreferenceClickListener(this); + passwordsPreference.setOnPreferenceClickListener(this); ++ ++ deviceNamePreference = (EditTextPreference) ensureFindPreference("device_name"); ++ deviceNamePreference.setOnPreferenceChangeListener(this); + } + + /** +@@ -142,7 +161,7 @@ + } + + if (preference == needsVerificationPreference) { +- FxAccountConfirmAccountActivity.resendCode(getActivity().getApplicationContext(), fxAccount); ++ FxAccountCodeResender.resendCode(getActivity().getApplicationContext(), fxAccount); + + Intent intent = new Intent(getActivity(), FxAccountConfirmAccountActivity.class); + // Per http://stackoverflow.com/a/8992365, this triggers a known bug with +@@ -176,6 +195,8 @@ + historyPreference.setEnabled(enabled); + tabsPreference.setEnabled(enabled); + passwordsPreference.setEnabled(enabled); ++ // Since we can't sync, we can't update our remote client record. ++ deviceNamePreference.setEnabled(enabled); + } + + /** +@@ -293,6 +314,14 @@ + throw new IllegalArgumentException("fxAccount must not be null"); + } + this.fxAccount = fxAccount; ++ try { ++ this.clientsDataDelegate = new SharedPreferencesClientsDataDelegate(fxAccount.getSyncPrefs()); ++ } catch (Exception e) { ++ Logger.error(LOG_TAG, "Got exception fetching Sync prefs associated to Firefox Account; aborting.", e); ++ // Something is terribly wrong; best to get a stack trace rather than ++ // continue with a null clients delegate. ++ throw new IllegalStateException(e); ++ } + + handler = new Handler(); // Attached to current (assumed to be UI) thread. + +@@ -318,6 +347,17 @@ + FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusDelegate); + } + ++ protected void hardRefresh() { ++ // This is the only way to guarantee that the EditText dialogs created by ++ // EditTextPreferences are re-created. This works around the issue described ++ // at http://androiddev.orkitra.com/?p=112079. ++ final PreferenceScreen statusScreen = (PreferenceScreen) ensureFindPreference("status_screen"); ++ statusScreen.removeAll(); ++ addPreferences(); ++ ++ refresh(); ++ } ++ + protected void refresh() { + // refresh is called from our onResume, which can happen before the owning + // Activity tells us about an account (via our public +@@ -371,6 +411,10 @@ + // No matter our state, we should update the checkboxes. + updateSelectedEngines(); + } ++ ++ final String clientName = clientsDataDelegate.getClientName(); ++ deviceNamePreference.setSummary(clientName); ++ deviceNamePreference.setText(clientName); + } + + /** +@@ -570,4 +614,22 @@ + button.setOnPreferenceClickListener(listener); + } + } ++ ++ @Override ++ public boolean onPreferenceChange(Preference preference, Object newValue) { ++ if (preference == deviceNamePreference) { ++ String newClientName = (String) newValue; ++ if (TextUtils.isEmpty(newClientName)) { ++ newClientName = clientsDataDelegate.getDefaultClientName(); ++ } ++ final long now = System.currentTimeMillis(); ++ clientsDataDelegate.setClientName(newClientName, now); ++ requestDelayedSync(); // Try to update our remote client record. ++ hardRefresh(); // Updates the value displayed to the user, among other things. ++ return true; ++ } ++ ++ // For everything else, accept the change. ++ return true; ++ } + } +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -18,11 +18,11 @@ + import org.mozilla.gecko.background.fxa.PasswordStretcher; + import org.mozilla.gecko.fxa.FirefoxAccounts; + import org.mozilla.gecko.fxa.FxAccountConstants; +-import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.FxAccountSignInTask; + 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; +diff -ruN mozilla-esr31/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java mozilla-release/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java +--- mozilla-esr31/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java 2014-09-24 03:05:33.000000000 +0200 +@@ -357,7 +357,11 @@ + + FxAccountGlobalSession globalSession = null; + try { +- ClientsDataDelegate clientsDataDelegate = new SharedPreferencesClientsDataDelegate(sharedPrefs); ++ final ClientsDataDelegate clientsDataDelegate = new SharedPreferencesClientsDataDelegate(sharedPrefs); ++ 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()); ++ } + + // We compute skew over time using SkewHandler. This yields an unchanging + // skew adjustment that the HawkAuthHeaderProvider uses to adjust its +diff -ruN mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountCodeResender.java mozilla-release/mobile/android/base/fxa/tasks/FxAccountCodeResender.java +--- mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountCodeResender.java 1970-01-01 01:00:00.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/tasks/FxAccountCodeResender.java 2014-09-24 03:05:33.000000000 +0200 +@@ -0,0 +1,108 @@ ++/* 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.tasks; ++ ++import java.util.concurrent.Executor; ++import java.util.concurrent.Executors; ++ ++import org.mozilla.gecko.R; ++import org.mozilla.gecko.background.common.log.Logger; ++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.FxAccountClientException.FxAccountClientRemoteException; ++import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; ++import org.mozilla.gecko.fxa.login.Engaged; ++ ++import android.content.Context; ++import android.widget.Toast; ++ ++/** ++ * A helper class that provides a simple interface for requesting ++ * a Firefox Account verification email to be resent. ++ */ ++public class FxAccountCodeResender { ++ private static final String LOG_TAG = FxAccountCodeResender.class.getSimpleName(); ++ ++ private static class FxAccountResendCodeTask extends FxAccountSetupTask<Void> { ++ protected static final String LOG_TAG = FxAccountResendCodeTask.class.getSimpleName(); ++ ++ protected final byte[] sessionToken; ++ ++ public FxAccountResendCodeTask(Context context, byte[] sessionToken, FxAccountClient client, RequestDelegate<Void> delegate) { ++ super(context, null, client, delegate); ++ this.sessionToken = sessionToken; ++ } ++ ++ @Override ++ protected InnerRequestDelegate<Void> doInBackground(Void... arg0) { ++ try { ++ client.resendCode(sessionToken, innerDelegate); ++ latch.await(); ++ return innerDelegate; ++ } catch (Exception e) { ++ Logger.error(LOG_TAG, "Got exception signing in.", e); ++ delegate.handleError(e); ++ } ++ return null; ++ } ++ } ++ ++ private static class ResendCodeDelegate implements RequestDelegate<Void> { ++ public final Context context; ++ ++ public ResendCodeDelegate(Context context) { ++ this.context = context; ++ } ++ ++ @Override ++ public void handleError(Exception e) { ++ Logger.warn(LOG_TAG, "Got exception requesting fresh confirmation link; ignoring.", e); ++ Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_not_sent, Toast.LENGTH_LONG).show(); ++ } ++ ++ @Override ++ public void handleFailure(FxAccountClientRemoteException e) { ++ handleError(e); ++ } ++ ++ @Override ++ public void handleSuccess(Void result) { ++ Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_sent, Toast.LENGTH_SHORT).show(); ++ } ++ } ++ ++ /** ++ * Resends the account verification email, and displays an appropriate ++ * toast on both send success and failure. Note that because the underlying implementation ++ * uses {@link AsyncTask}, the provided context must be UI-capable and ++ * this method called from the UI thread. ++ * ++ * Note that it may actually be possible to run this (and the {@link AsyncTask}) method ++ * from a background thread - but this hasn't been tested. ++ * ++ * @param context A UI-capable Android context. ++ * @param fxAccount The Firefox Account to resend the code to. ++ */ ++ public static void resendCode(Context context, AndroidFxAccount fxAccount) { ++ RequestDelegate<Void> delegate = new ResendCodeDelegate(context); ++ ++ byte[] sessionToken; ++ try { ++ sessionToken = ((Engaged) fxAccount.getState()).getSessionToken(); ++ } catch (Exception e) { ++ delegate.handleError(e); ++ return; ++ } ++ if (sessionToken == null) { ++ delegate.handleError(new IllegalStateException("sessionToken should not be null")); ++ return; ++ } ++ ++ Executor executor = Executors.newSingleThreadExecutor(); ++ FxAccountClient client = new FxAccountClient20(fxAccount.getAccountServerURI(), executor); ++ new FxAccountResendCodeTask(context, sessionToken, client, delegate).execute(); ++ } ++} +diff -ruN mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountCreateAccountTask.java mozilla-release/mobile/android/base/fxa/tasks/FxAccountCreateAccountTask.java +--- mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountCreateAccountTask.java 1970-01-01 01:00:00.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/tasks/FxAccountCreateAccountTask.java 2014-09-24 03:05:33.000000000 +0200 +@@ -0,0 +1,41 @@ ++/* 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.tasks; ++ ++import java.io.UnsupportedEncodingException; ++ ++import org.mozilla.gecko.background.common.log.Logger; ++import org.mozilla.gecko.background.fxa.FxAccountClient; ++import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; ++import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse; ++import org.mozilla.gecko.background.fxa.PasswordStretcher; ++ ++import android.content.Context; ++ ++public class FxAccountCreateAccountTask extends FxAccountSetupTask<LoginResponse> { ++ private static final String LOG_TAG = FxAccountCreateAccountTask.class.getSimpleName(); ++ ++ protected final byte[] emailUTF8; ++ protected final PasswordStretcher passwordStretcher; ++ ++ public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { ++ super(context, progressDisplay, client, delegate); ++ this.emailUTF8 = email.getBytes("UTF-8"); ++ this.passwordStretcher = passwordStretcher; ++ } ++ ++ @Override ++ protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { ++ try { ++ client.createAccountAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); ++ latch.await(); ++ return innerDelegate; ++ } catch (Exception e) { ++ Logger.error(LOG_TAG, "Got exception logging in.", e); ++ delegate.handleError(e); ++ } ++ return null; ++ } ++} +diff -ruN mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountSetupTask.java mozilla-release/mobile/android/base/fxa/tasks/FxAccountSetupTask.java +--- mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountSetupTask.java 1970-01-01 01:00:00.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/tasks/FxAccountSetupTask.java 2014-09-24 03:05:33.000000000 +0200 +@@ -0,0 +1,117 @@ ++/* 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.tasks; ++ ++import java.util.concurrent.CountDownLatch; ++ ++import org.mozilla.gecko.background.common.log.Logger; ++import org.mozilla.gecko.background.fxa.FxAccountClient; ++import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; ++import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; ++import org.mozilla.gecko.fxa.tasks.FxAccountSetupTask.InnerRequestDelegate; ++ ++import android.content.Context; ++import android.os.AsyncTask; ++ ++/** ++ * An <code>AsyncTask</code> wrapper around signing up for, and signing in to, a ++ * Firefox Account. ++ * <p> ++ * It's strange to add explicit blocking to callback-threading code, but we do ++ * it here to take advantage of Android's built in support for background work. ++ * We really want to avoid making a threading mistake that brings down the whole ++ * process. ++ */ ++public abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestDelegate<T>> { ++ private static final String LOG_TAG = FxAccountSetupTask.class.getSimpleName(); ++ ++ public interface ProgressDisplay { ++ public void showProgress(); ++ public void dismissProgress(); ++ } ++ ++ protected final Context context; ++ protected final FxAccountClient client; ++ protected final ProgressDisplay progressDisplay; ++ ++ // Initialized lazily. ++ protected byte[] quickStretchedPW; ++ ++ // AsyncTask's are one-time-use, so final members are fine. ++ protected final CountDownLatch latch = new CountDownLatch(1); ++ protected final InnerRequestDelegate<T> innerDelegate = new InnerRequestDelegate<T>(latch); ++ ++ protected final RequestDelegate<T> delegate; ++ ++ public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient client, RequestDelegate<T> delegate) { ++ this.context = context; ++ this.client = client; ++ this.delegate = delegate; ++ this.progressDisplay = progressDisplay; ++ } ++ ++ @Override ++ protected void onPreExecute() { ++ if (progressDisplay != null) { ++ progressDisplay.showProgress(); ++ } ++ } ++ ++ @Override ++ protected void onPostExecute(InnerRequestDelegate<T> result) { ++ if (progressDisplay != null) { ++ progressDisplay.dismissProgress(); ++ } ++ ++ // We are on the UI thread, and need to invoke these callbacks here to allow UI updating. ++ if (innerDelegate.failure != null) { ++ delegate.handleFailure(innerDelegate.failure); ++ } else if (innerDelegate.exception != null) { ++ delegate.handleError(innerDelegate.exception); ++ } else { ++ delegate.handleSuccess(result.response); ++ } ++ } ++ ++ @Override ++ protected void onCancelled(InnerRequestDelegate<T> result) { ++ if (progressDisplay != null) { ++ progressDisplay.dismissProgress(); ++ } ++ delegate.handleError(new IllegalStateException("Task was cancelled.")); ++ } ++ ++ protected static class InnerRequestDelegate<T> implements RequestDelegate<T> { ++ protected final CountDownLatch latch; ++ public T response = null; ++ public Exception exception = null; ++ public FxAccountClientRemoteException failure = null; ++ ++ protected InnerRequestDelegate(CountDownLatch latch) { ++ this.latch = latch; ++ } ++ ++ @Override ++ public void handleError(Exception e) { ++ Logger.error(LOG_TAG, "Got exception."); ++ this.exception = e; ++ latch.countDown(); ++ } ++ ++ @Override ++ public void handleFailure(FxAccountClientRemoteException e) { ++ Logger.warn(LOG_TAG, "Got failure."); ++ this.failure = e; ++ latch.countDown(); ++ } ++ ++ @Override ++ public void handleSuccess(T result) { ++ Logger.info(LOG_TAG, "Got success."); ++ this.response = result; ++ latch.countDown(); ++ } ++ } ++} +diff -ruN mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountSignInTask.java mozilla-release/mobile/android/base/fxa/tasks/FxAccountSignInTask.java +--- mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountSignInTask.java 1970-01-01 01:00:00.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/tasks/FxAccountSignInTask.java 2014-09-24 03:05:33.000000000 +0200 +@@ -0,0 +1,41 @@ ++/* 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.tasks; ++ ++import java.io.UnsupportedEncodingException; ++ ++import org.mozilla.gecko.background.common.log.Logger; ++import org.mozilla.gecko.background.fxa.FxAccountClient; ++import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; ++import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse; ++import org.mozilla.gecko.background.fxa.PasswordStretcher; ++ ++import android.content.Context; ++ ++public class FxAccountSignInTask extends FxAccountSetupTask<LoginResponse> { ++ protected static final String LOG_TAG = FxAccountSignInTask.class.getSimpleName(); ++ ++ protected final byte[] emailUTF8; ++ protected final PasswordStretcher passwordStretcher; ++ ++ public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { ++ super(context, progressDisplay, client, delegate); ++ this.emailUTF8 = email.getBytes("UTF-8"); ++ this.passwordStretcher = passwordStretcher; ++ } ++ ++ @Override ++ protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { ++ try { ++ client.loginAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); ++ latch.await(); ++ return innerDelegate; ++ } catch (Exception e) { ++ Logger.error(LOG_TAG, "Got exception signing in.", e); ++ delegate.handleError(e); ++ } ++ return null; ++ } ++} +--- mozilla-esr31/mobile/android/base/android-services.mozbuild 2015-02-25 19:21:05.000000000 +0100 ++++ mozilla-release/mobile/android/base/android-services.mozbuild 2014-09-24 03:05:32.000000000 +0200 +@@ -555,7 +557,6 @@ + 'fxa/activities/FxAccountCreateAccountActivity.java', + 'fxa/activities/FxAccountCreateAccountNotAllowedActivity.java', + 'fxa/activities/FxAccountGetStartedActivity.java', +- 'fxa/activities/FxAccountSetupTask.java', + 'fxa/activities/FxAccountSignInActivity.java', + 'fxa/activities/FxAccountStatusActivity.java', + 'fxa/activities/FxAccountStatusFragment.java', +@@ -589,6 +590,10 @@ + 'fxa/sync/FxAccountSyncService.java', + 'fxa/sync/FxAccountSyncStatusHelper.java', + 'fxa/sync/SchedulePolicy.java', ++ 'fxa/tasks/FxAccountCodeResender.java', ++ 'fxa/tasks/FxAccountCreateAccountTask.java', ++ 'fxa/tasks/FxAccountSetupTask.java', ++ 'fxa/tasks/FxAccountSignInTask.java', + 'sync/AlreadySyncingException.java', + 'sync/BackoffHandler.java', + 'sync/BadRequiredFieldJSONException.java', diff --git a/data/patches/disable/0002-update-mobile-sqlite-to-v35.patch b/data/patches/disable/0002-update-mobile-sqlite-to-v35.patch new file mode 100644 index 0000000..9a99ea2 --- /dev/null +++ b/data/patches/disable/0002-update-mobile-sqlite-to-v35.patch @@ -0,0 +1,246 @@ +diff -ru mobile/android/base/sqlite/ByteBufferInputStream.java /tmp/mozilla-release/mobile/android/base/sqlite/ByteBufferInputStream.java +--- a/mobile/android/base/sqlite/ByteBufferInputStream.java 2015-02-23 22:40:38.708934982 +0100 ++++ b/mobile/android/base/sqlite/ByteBufferInputStream.java 2015-01-23 07:00:04.000000000 +0100 +@@ -14,7 +14,7 @@ + * easier to use. + */ + public class ByteBufferInputStream extends InputStream { +- private ByteBuffer mByteBuffer; ++ private final ByteBuffer mByteBuffer; + + public ByteBufferInputStream(ByteBuffer aByteBuffer) { + mByteBuffer = aByteBuffer; +diff -ru mobile/android/base/sqlite/MatrixBlobCursor.java /tmp/mozilla-release/mobile/android/base/sqlite/MatrixBlobCursor.java +--- a/mobile/android/base/sqlite/MatrixBlobCursor.java 2015-02-23 22:40:38.720934982 +0100 ++++ b/mobile/android/base/sqlite/MatrixBlobCursor.java 2015-01-23 07:00:04.000000000 +0100 +@@ -17,34 +17,37 @@ + + package org.mozilla.gecko.sqlite; + ++import java.nio.ByteBuffer; ++import java.util.ArrayList; ++ ++import org.mozilla.gecko.AppConstants; + import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI; + + import android.database.AbstractCursor; + import android.database.CursorIndexOutOfBoundsException; ++import android.util.Log; + +-import java.nio.ByteBuffer; +-import java.util.ArrayList; +- +-/* +- * Android's AbstractCursor throws on getBlob() +- * and MatrixCursor forgot to override it. This was fixed +- * at some point but old devices are still SOL. +- * Oh, and everything in MatrixCursor is private instead of +- * protected, so we need to entirely duplicate it here, +- * instad of just being able to add the missing method. +- */ + /** + * A mutable cursor implementation backed by an array of {@code Object}s. Use + * {@link #newRow()} to add rows. Automatically expands internal capacity + * as needed. ++ * ++ * This class provides one missing feature from Android's MatrixCursor: ++ * the implementation of getBlob that was inadvertently omitted from API 9 (and ++ * perhaps later; it's present in 14). ++ * ++ * MatrixCursor is all private, so we entirely duplicate it here. + */ + public class MatrixBlobCursor extends AbstractCursor { ++ private static final String LOGTAG = "GeckoMatrixCursor"; + + private final String[] columnNames; +- private Object[] data; +- private int rowCount = 0; + private final int columnCount; + ++ private int rowCount; ++ ++ Object[] data; ++ + /** + * Constructs a new cursor with the given initial capacity. + * +@@ -140,17 +143,18 @@ + */ + @WrapElementForJNI + public void addRow(Iterable<?> columnValues) { +- int start = rowCount * columnCount; +- int end = start + columnCount; +- ensureCapacity(end); ++ final int start = rowCount * columnCount; + + if (columnValues instanceof ArrayList<?>) { + addRow((ArrayList<?>) columnValues, start); + return; + } + ++ final int end = start + columnCount; + int current = start; +- Object[] localData = data; ++ ++ ensureCapacity(end); ++ final Object[] localData = data; + for (Object columnValue : columnValues) { + if (current == end) { + // TODO: null out row? +@@ -173,39 +177,47 @@ + /** Optimization for {@link ArrayList}. */ + @WrapElementForJNI + private void addRow(ArrayList<?> columnValues, int start) { +- int size = columnValues.size(); ++ final int size = columnValues.size(); + if (size != columnCount) { + throw new IllegalArgumentException("columnNames.length = " + + columnCount + ", columnValues.size() = " + size); + } + +- rowCount++; +- Object[] localData = data; ++ final int end = start + columnCount; ++ ensureCapacity(end); ++ ++ // Take a reference just in case someone calls ensureCapacity ++ // and `data` gets replaced by a new array! ++ final Object[] localData = data; + for (int i = 0; i < size; i++) { + localData[start + i] = columnValues.get(i); + } ++ ++ rowCount++; + } + +- /** Ensures that this cursor has enough capacity. */ +- private void ensureCapacity(int size) { +- if (size > data.length) { +- Object[] oldData = this.data; +- int newSize = data.length * 2; +- if (newSize < size) { +- newSize = size; +- } +- this.data = new Object[newSize]; +- System.arraycopy(oldData, 0, this.data, 0, oldData.length); ++ /** ++ * Ensures that this cursor has enough capacity. If it needs to allocate ++ * a new array, the existing capacity will be at least doubled. ++ */ ++ private void ensureCapacity(final int size) { ++ if (size <= data.length) { ++ return; + } ++ ++ final Object[] oldData = this.data; ++ this.data = new Object[Math.max(size, data.length * 2)]; ++ System.arraycopy(oldData, 0, this.data, 0, oldData.length); + } + + /** + * Builds a row, starting from the left-most column and adding one column + * value at a time. Follows the same ordering as the column names specified + * at cursor construction time. ++ * ++ * Not thread-safe. + */ + public class RowBuilder { +- + private int index; + private final int endIndex; + +@@ -221,10 +233,9 @@ + * values + * @return this builder to support chaining + */ +- public RowBuilder add(Object columnValue) { ++ public RowBuilder add(final Object columnValue) { + if (index == endIndex) { +- throw new CursorIndexOutOfBoundsException( +- "No more columns left."); ++ throw new CursorIndexOutOfBoundsException("No more columns left."); + } + + data[index++] = columnValue; +@@ -232,6 +243,9 @@ + } + } + ++ /** ++ * Not thread safe. ++ */ + public void set(int column, Object value) { + if (column < 0 || column >= columnCount) { + throw new CursorIndexOutOfBoundsException("Requested column: " +@@ -266,7 +280,7 @@ + + @Override + public short getShort(int column) { +- Object value = get(column); ++ final Object value = get(column); + if (value == null) return 0; + if (value instanceof Number) return ((Number) value).shortValue(); + return Short.parseShort(value.toString()); +@@ -311,10 +325,11 @@ + if (value instanceof byte[]) { + return (byte[]) value; + } ++ + if (value instanceof ByteBuffer) { +- ByteBuffer data = (ByteBuffer)value; +- byte[] byteArray = new byte[data.remaining()]; +- data.get(byteArray); ++ final ByteBuffer bytes = (ByteBuffer) value; ++ byte[] byteArray = new byte[bytes.remaining()]; ++ bytes.get(byteArray); + return byteArray; + } + throw new UnsupportedOperationException("BLOB Object not of known type"); +@@ -324,4 +339,15 @@ + public boolean isNull(int column) { + return get(column) == null; + } ++ ++ @Override ++ protected void finalize() { ++ if (AppConstants.DEBUG_BUILD) { ++ if (!isClosed()) { ++ Log.e(LOGTAG, "Cursor finalized without being closed", new RuntimeException("stack")); ++ } ++ } ++ ++ super.finalize(); ++ } + } +diff -ru mobile/android/base/sqlite/SQLiteBridge.java /tmp/mozilla-release/mobile/android/base/sqlite/SQLiteBridge.java +--- a/mobile/android/base/sqlite/SQLiteBridge.java 2015-02-23 22:40:38.716934982 +0100 ++++ b/mobile/android/base/sqlite/SQLiteBridge.java 2015-01-23 07:00:04.000000000 +0100 +@@ -26,16 +26,16 @@ + private static final String LOGTAG = "SQLiteBridge"; + + // Path to the database. If this database was not opened with openDatabase, we reopen it every query. +- private String mDb; ++ private final String mDb; + + // Pointer to the database if it was opened with openDatabase. 0 implies closed. +- protected volatile long mDbPointer = 0L; ++ protected volatile long mDbPointer; + + // Values remembered after a query. + private long[] mQueryResults; + +- private boolean mTransactionSuccess = false; +- private boolean mInTransaction = false; ++ private boolean mTransactionSuccess; ++ private boolean mInTransaction; + + private static final int RESULT_INSERT_ROW_ID = 0; + private static final int RESULT_ROWS_CHANGED = 1; +@@ -227,6 +227,7 @@ + cursor.moveToFirst(); + String version = cursor.getString(0); + ret = Integer.parseInt(version); ++ cursor.close(); + } + return ret; + } diff --git a/data/patches/disable/0003-upgrade-mobile-sync-to-v32.patch b/data/patches/disable/0003-upgrade-mobile-sync-to-v32.patch new file mode 100644 index 0000000..e420727 --- /dev/null +++ b/data/patches/disable/0003-upgrade-mobile-sync-to-v32.patch @@ -0,0 +1,992 @@ +diff -ruN mozilla-esr31/mobile/android/base/fxa/FirefoxAccounts.java mozilla-release/mobile/android/base/fxa/FirefoxAccounts.java +--- mozilla-esr31/mobile/android/base/fxa/FirefoxAccounts.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/FirefoxAccounts.java 2014-09-24 03:05:32.000000000 +0200 +@@ -6,13 +6,18 @@ + + import java.io.File; + import java.util.EnumSet; ++import java.util.Locale; + import java.util.concurrent.CountDownLatch; + ++import org.mozilla.gecko.AppConstants; ++import org.mozilla.gecko.R; + import org.mozilla.gecko.background.common.log.Logger; + import org.mozilla.gecko.fxa.authenticator.AccountPickler; + import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; ++import org.mozilla.gecko.fxa.login.State; + import org.mozilla.gecko.fxa.sync.FxAccountSyncAdapter; + import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper; ++import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender; + import org.mozilla.gecko.sync.ThreadPool; + import org.mozilla.gecko.sync.Utils; + +@@ -20,6 +25,7 @@ + import android.accounts.AccountManager; + import android.content.ContentResolver; + import android.content.Context; ++import android.content.res.Resources; + import android.os.Bundle; + + /** +@@ -152,6 +158,38 @@ + return null; + } + ++ /** ++ * @return ++ * the {@link State} instance associated with the current account, or <code>null</code> if ++ * no accounts exist. ++ */ ++ public static State getFirefoxAccountState(final Context context) { ++ final Account account = getFirefoxAccount(context); ++ if (account == null) { ++ return null; ++ } ++ ++ final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account); ++ try { ++ return fxAccount.getState(); ++ } catch (final Exception ex) { ++ Logger.warn(LOG_TAG, "Could not get FX account state.", ex); ++ return null; ++ } ++ } ++ ++ /* ++ * @param context Android context ++ * @return the email address associated with the configured Firefox account if one exists; null otherwise. ++ */ ++ public static String getFirefoxAccountEmail(final Context context) { ++ final Account account = getFirefoxAccount(context); ++ if (account == null) { ++ return null; ++ } ++ return account.name; ++ } ++ + protected static void putHintsToSync(final Bundle extras, EnumSet<SyncHint> syncHints) { + // stagesToSync and stagesToSkip are allowed to be null. + if (syncHints == null) { +@@ -264,4 +302,33 @@ + // stopObserving null-checks its argument. + FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusListener); + } ++ ++ public static String getOldSyncUpgradeURL(final Resources res, final Locale locale) { ++ final String VERSION = AppConstants.MOZ_APP_VERSION; ++ final String OS = AppConstants.OS_TARGET; ++ final String LOCALE = Utils.getLanguageTag(locale); ++ return res.getString(R.string.fxaccount_link_old_firefox, VERSION, OS, LOCALE); ++ } ++ ++ /** ++ * Resends the account verification email, and displays an appropriate ++ * toast on both send success and failure. Note that because the underlying implementation ++ * uses {@link AsyncTask}, the provided context must be UI-capable, and this ++ * method called from the UI thread (see ++ * {@link org.mozilla.gecko.fxa.tasks.FxAccountCodeResender#resendCode(Context, AndroidFxAccount)} ++ * for more). ++ * ++ * @param context a UI-capable Android context. ++ * @return true if an account exists, false otherwise. ++ */ ++ public static boolean resendVerificationEmail(final Context context) { ++ final Account account = getFirefoxAccount(context); ++ if (account == null) { ++ return false; ++ } ++ ++ final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account); ++ FxAccountCodeResender.resendCode(context, fxAccount); ++ return true; ++ } + } +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountAbstractSetupActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountAbstractSetupActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountAbstractSetupActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountAbstractSetupActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -19,10 +19,10 @@ + import org.mozilla.gecko.background.fxa.PasswordStretcher; + import org.mozilla.gecko.background.fxa.QuickPasswordStretcher; + import org.mozilla.gecko.fxa.FxAccountConstants; +-import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.ProgressDisplay; + 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.tasks.FxAccountSetupTask.ProgressDisplay; + import org.mozilla.gecko.sync.SyncConfiguration; + import org.mozilla.gecko.sync.setup.Constants; + import org.mozilla.gecko.sync.setup.activities.ActivityUtils; +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -4,21 +4,15 @@ + + package org.mozilla.gecko.fxa.activities; + +-import java.util.concurrent.Executor; +-import java.util.concurrent.Executors; +- + import org.mozilla.gecko.R; + import org.mozilla.gecko.background.common.log.Logger; +-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.FxAccountClientException.FxAccountClientRemoteException; + import org.mozilla.gecko.fxa.FirefoxAccounts; + 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.Action; + import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper; ++import org.mozilla.gecko.fxa.tasks.FxAccountCodeResender; + import org.mozilla.gecko.sync.setup.activities.ActivityUtils; + + import android.accounts.Account; +@@ -28,7 +22,6 @@ + import android.view.View; + import android.view.View.OnClickListener; + import android.widget.TextView; +-import android.widget.Toast; + + /** + * Activity which displays account created successfully screen to the user, and +@@ -164,76 +157,8 @@ + resendLink.setClickable(resendLinkShouldBeEnabled); + } + +- public static class FxAccountResendCodeTask extends FxAccountSetupTask<Void> { +- protected static final String LOG_TAG = FxAccountResendCodeTask.class.getSimpleName(); +- +- protected final byte[] sessionToken; +- +- public FxAccountResendCodeTask(Context context, byte[] sessionToken, FxAccountClient client, RequestDelegate<Void> delegate) { +- super(context, null, client, delegate); +- this.sessionToken = sessionToken; +- } +- +- @Override +- protected InnerRequestDelegate<Void> doInBackground(Void... arg0) { +- try { +- client.resendCode(sessionToken, innerDelegate); +- latch.await(); +- return innerDelegate; +- } catch (Exception e) { +- Logger.error(LOG_TAG, "Got exception signing in.", e); +- delegate.handleError(e); +- } +- return null; +- } +- } +- +- protected static class ResendCodeDelegate implements RequestDelegate<Void> { +- public final Context context; +- +- public ResendCodeDelegate(Context context) { +- this.context = context; +- } +- +- @Override +- public void handleError(Exception e) { +- Logger.warn(LOG_TAG, "Got exception requesting fresh confirmation link; ignoring.", e); +- Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_not_sent, Toast.LENGTH_LONG).show(); +- } +- +- @Override +- public void handleFailure(FxAccountClientRemoteException e) { +- handleError(e); +- } +- +- @Override +- public void handleSuccess(Void result) { +- Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_sent, Toast.LENGTH_SHORT).show(); +- } +- } +- +- public static void resendCode(Context context, AndroidFxAccount fxAccount) { +- RequestDelegate<Void> delegate = new ResendCodeDelegate(context); +- +- byte[] sessionToken; +- try { +- sessionToken = ((Engaged) fxAccount.getState()).getSessionToken(); +- } catch (Exception e) { +- delegate.handleError(e); +- return; +- } +- if (sessionToken == null) { +- delegate.handleError(new IllegalStateException("sessionToken should not be null")); +- return; +- } +- +- Executor executor = Executors.newSingleThreadExecutor(); +- FxAccountClient client = new FxAccountClient20(fxAccount.getAccountServerURI(), executor); +- new FxAccountResendCodeTask(context, sessionToken, client, delegate).execute(); +- } +- + @Override + public void onClick(View v) { +- resendCode(this, fxAccount); ++ FxAccountCodeResender.resendCode(this, fxAccount); + } + } +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountCreateAccountActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -21,7 +21,7 @@ + import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; + import org.mozilla.gecko.background.fxa.PasswordStretcher; + import org.mozilla.gecko.fxa.FxAccountConstants; +-import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.FxAccountCreateAccountTask; ++import org.mozilla.gecko.fxa.tasks.FxAccountCreateAccountTask; + + import android.app.AlertDialog; + import android.app.Dialog; +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -6,13 +6,11 @@ + + import java.util.Locale; + +-import org.mozilla.gecko.AppConstants; + import org.mozilla.gecko.R; + import org.mozilla.gecko.background.common.log.Logger; + import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper; + import org.mozilla.gecko.fxa.FirefoxAccounts; + import org.mozilla.gecko.fxa.FxAccountConstants; +-import org.mozilla.gecko.sync.Utils; + import org.mozilla.gecko.sync.setup.activities.ActivityUtils; + import org.mozilla.gecko.sync.setup.activities.LocaleAware; + +@@ -109,11 +107,7 @@ + protected void linkifyOldFirefoxLink() { + TextView oldFirefox = (TextView) findViewById(R.id.old_firefox); + String text = getResources().getString(R.string.fxaccount_getting_started_old_firefox); +- String VERSION = AppConstants.MOZ_APP_VERSION; +- String OS = AppConstants.OS_TARGET; +- +- String LOCALE = Utils.getLanguageTag(Locale.getDefault()); +- String url = getResources().getString(R.string.fxaccount_link_old_firefox, VERSION, OS, LOCALE); ++ 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. + ActivityUtils.linkTextView(oldFirefox, text, url); + } +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountSetupTask.java mozilla-release/mobile/android/base/fxa/activities/FxAccountSetupTask.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountSetupTask.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountSetupTask.java 1970-01-01 01:00:00.000000000 +0100 +@@ -1,172 +0,0 @@ +-/* 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.activities; +- +-import java.io.UnsupportedEncodingException; +-import java.util.concurrent.CountDownLatch; +- +-import org.mozilla.gecko.background.common.log.Logger; +-import org.mozilla.gecko.background.fxa.FxAccountClient; +-import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; +-import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse; +-import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; +-import org.mozilla.gecko.background.fxa.PasswordStretcher; +-import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.InnerRequestDelegate; +- +-import android.content.Context; +-import android.os.AsyncTask; +- +-/** +- * An <code>AsyncTask</code> wrapper around signing up for, and signing in to, a +- * Firefox Account. +- * <p> +- * It's strange to add explicit blocking to callback-threading code, but we do +- * it here to take advantage of Android's built in support for background work. +- * We really want to avoid making a threading mistake that brings down the whole +- * process. +- */ +-abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestDelegate<T>> { +- private static final String LOG_TAG = FxAccountSetupTask.class.getSimpleName(); +- +- public interface ProgressDisplay { +- public void showProgress(); +- public void dismissProgress(); +- } +- +- protected final Context context; +- protected final FxAccountClient client; +- protected final ProgressDisplay progressDisplay; +- +- // Initialized lazily. +- protected byte[] quickStretchedPW; +- +- // AsyncTask's are one-time-use, so final members are fine. +- protected final CountDownLatch latch = new CountDownLatch(1); +- protected final InnerRequestDelegate<T> innerDelegate = new InnerRequestDelegate<T>(latch); +- +- protected final RequestDelegate<T> delegate; +- +- public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient client, RequestDelegate<T> delegate) { +- this.context = context; +- this.client = client; +- this.delegate = delegate; +- this.progressDisplay = progressDisplay; +- } +- +- @Override +- protected void onPreExecute() { +- if (progressDisplay != null) { +- progressDisplay.showProgress(); +- } +- } +- +- @Override +- protected void onPostExecute(InnerRequestDelegate<T> result) { +- if (progressDisplay != null) { +- progressDisplay.dismissProgress(); +- } +- +- // We are on the UI thread, and need to invoke these callbacks here to allow UI updating. +- if (innerDelegate.failure != null) { +- delegate.handleFailure(innerDelegate.failure); +- } else if (innerDelegate.exception != null) { +- delegate.handleError(innerDelegate.exception); +- } else { +- delegate.handleSuccess(result.response); +- } +- } +- +- @Override +- protected void onCancelled(InnerRequestDelegate<T> result) { +- if (progressDisplay != null) { +- progressDisplay.dismissProgress(); +- } +- delegate.handleError(new IllegalStateException("Task was cancelled.")); +- } +- +- protected static class InnerRequestDelegate<T> implements RequestDelegate<T> { +- protected final CountDownLatch latch; +- public T response = null; +- public Exception exception = null; +- public FxAccountClientRemoteException failure = null; +- +- protected InnerRequestDelegate(CountDownLatch latch) { +- this.latch = latch; +- } +- +- @Override +- public void handleError(Exception e) { +- Logger.error(LOG_TAG, "Got exception."); +- this.exception = e; +- latch.countDown(); +- } +- +- @Override +- public void handleFailure(FxAccountClientRemoteException e) { +- Logger.warn(LOG_TAG, "Got failure."); +- this.failure = e; +- latch.countDown(); +- } +- +- @Override +- public void handleSuccess(T result) { +- Logger.info(LOG_TAG, "Got success."); +- this.response = result; +- latch.countDown(); +- } +- } +- +- public static class FxAccountCreateAccountTask extends FxAccountSetupTask<LoginResponse> { +- private static final String LOG_TAG = FxAccountCreateAccountTask.class.getSimpleName(); +- +- protected final byte[] emailUTF8; +- protected final PasswordStretcher passwordStretcher; +- +- public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { +- super(context, progressDisplay, client, delegate); +- this.emailUTF8 = email.getBytes("UTF-8"); +- this.passwordStretcher = passwordStretcher; +- } +- +- @Override +- protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { +- try { +- client.createAccountAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); +- latch.await(); +- return innerDelegate; +- } catch (Exception e) { +- Logger.error(LOG_TAG, "Got exception logging in.", e); +- delegate.handleError(e); +- } +- return null; +- } +- } +- +- public static class FxAccountSignInTask extends FxAccountSetupTask<LoginResponse> { +- protected static final String LOG_TAG = FxAccountSignInTask.class.getSimpleName(); +- +- protected final byte[] emailUTF8; +- protected final PasswordStretcher passwordStretcher; +- +- public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { +- super(context, progressDisplay, client, delegate); +- this.emailUTF8 = email.getBytes("UTF-8"); +- this.passwordStretcher = passwordStretcher; +- } +- +- @Override +- protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { +- try { +- client.loginAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); +- latch.await(); +- return innerDelegate; +- } catch (Exception e) { +- Logger.error(LOG_TAG, "Got exception signing in.", e); +- delegate.handleError(e); +- } +- return null; +- } +- } +-} +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountSignInActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountSignInActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountSignInActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountSignInActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -16,7 +16,7 @@ + import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; + import org.mozilla.gecko.background.fxa.PasswordStretcher; + import org.mozilla.gecko.fxa.FxAccountConstants; +-import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.FxAccountSignInTask; ++import org.mozilla.gecko.fxa.tasks.FxAccountSignInTask; + import org.mozilla.gecko.sync.setup.activities.ActivityUtils; + + import android.content.Intent; +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountStatusFragment.java mozilla-release/mobile/android/base/fxa/activities/FxAccountStatusFragment.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountStatusFragment.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountStatusFragment.java 2014-09-24 03:05:32.000000000 +0200 +@@ -17,6 +17,8 @@ + 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; ++import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate; + import org.mozilla.gecko.sync.SyncConfiguration; + + import android.accounts.Account; +@@ -27,10 +29,13 @@ + import android.os.Bundle; + import android.os.Handler; + import android.preference.CheckBoxPreference; ++import android.preference.EditTextPreference; + import android.preference.Preference; ++import android.preference.Preference.OnPreferenceChangeListener; + import android.preference.Preference.OnPreferenceClickListener; + import android.preference.PreferenceCategory; + import android.preference.PreferenceScreen; ++import android.text.TextUtils; + + /** + * A fragment that displays the status of an AndroidFxAccount. +@@ -38,7 +43,9 @@ + * The owning activity is responsible for providing an AndroidFxAccount at + * appropriate times. + */ +-public class FxAccountStatusFragment extends PreferenceFragment implements OnPreferenceClickListener { ++public class FxAccountStatusFragment ++ extends PreferenceFragment ++ implements OnPreferenceClickListener, OnPreferenceChangeListener { + private static final String LOG_TAG = FxAccountStatusFragment.class.getSimpleName(); + + // When a checkbox is toggled, wait 5 seconds (for other checkbox actions) +@@ -64,7 +71,12 @@ + protected CheckBoxPreference tabsPreference; + protected CheckBoxPreference passwordsPreference; + ++ protected EditTextPreference deviceNamePreference; ++ + protected volatile AndroidFxAccount fxAccount; ++ // The contract is: when fxAccount is non-null, then clientsDataDelegate is ++ // non-null. If violated then an IllegalStateException is thrown. ++ protected volatile SharedPreferencesClientsDataDelegate clientsDataDelegate; + + // Used to post delayed sync requests. + protected Handler handler; +@@ -87,6 +99,10 @@ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); ++ addPreferences(); ++ } ++ ++ protected void addPreferences() { + addPreferencesFromResource(R.xml.fxaccount_status_prefscreen); + + emailPreference = ensureFindPreference("email"); +@@ -118,6 +134,9 @@ + historyPreference.setOnPreferenceClickListener(this); + tabsPreference.setOnPreferenceClickListener(this); + passwordsPreference.setOnPreferenceClickListener(this); ++ ++ deviceNamePreference = (EditTextPreference) ensureFindPreference("device_name"); ++ deviceNamePreference.setOnPreferenceChangeListener(this); + } + + /** +@@ -142,7 +161,7 @@ + } + + if (preference == needsVerificationPreference) { +- FxAccountConfirmAccountActivity.resendCode(getActivity().getApplicationContext(), fxAccount); ++ FxAccountCodeResender.resendCode(getActivity().getApplicationContext(), fxAccount); + + Intent intent = new Intent(getActivity(), FxAccountConfirmAccountActivity.class); + // Per http://stackoverflow.com/a/8992365, this triggers a known bug with +@@ -176,6 +195,8 @@ + historyPreference.setEnabled(enabled); + tabsPreference.setEnabled(enabled); + passwordsPreference.setEnabled(enabled); ++ // Since we can't sync, we can't update our remote client record. ++ deviceNamePreference.setEnabled(enabled); + } + + /** +@@ -293,6 +314,14 @@ + throw new IllegalArgumentException("fxAccount must not be null"); + } + this.fxAccount = fxAccount; ++ try { ++ this.clientsDataDelegate = new SharedPreferencesClientsDataDelegate(fxAccount.getSyncPrefs()); ++ } catch (Exception e) { ++ Logger.error(LOG_TAG, "Got exception fetching Sync prefs associated to Firefox Account; aborting.", e); ++ // Something is terribly wrong; best to get a stack trace rather than ++ // continue with a null clients delegate. ++ throw new IllegalStateException(e); ++ } + + handler = new Handler(); // Attached to current (assumed to be UI) thread. + +@@ -318,6 +347,17 @@ + FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusDelegate); + } + ++ protected void hardRefresh() { ++ // This is the only way to guarantee that the EditText dialogs created by ++ // EditTextPreferences are re-created. This works around the issue described ++ // at http://androiddev.orkitra.com/?p=112079. ++ final PreferenceScreen statusScreen = (PreferenceScreen) ensureFindPreference("status_screen"); ++ statusScreen.removeAll(); ++ addPreferences(); ++ ++ refresh(); ++ } ++ + protected void refresh() { + // refresh is called from our onResume, which can happen before the owning + // Activity tells us about an account (via our public +@@ -371,6 +411,10 @@ + // No matter our state, we should update the checkboxes. + updateSelectedEngines(); + } ++ ++ final String clientName = clientsDataDelegate.getClientName(); ++ deviceNamePreference.setSummary(clientName); ++ deviceNamePreference.setText(clientName); + } + + /** +@@ -570,4 +614,22 @@ + button.setOnPreferenceClickListener(listener); + } + } ++ ++ @Override ++ public boolean onPreferenceChange(Preference preference, Object newValue) { ++ if (preference == deviceNamePreference) { ++ String newClientName = (String) newValue; ++ if (TextUtils.isEmpty(newClientName)) { ++ newClientName = clientsDataDelegate.getDefaultClientName(); ++ } ++ final long now = System.currentTimeMillis(); ++ clientsDataDelegate.setClientName(newClientName, now); ++ requestDelayedSync(); // Try to update our remote client record. ++ hardRefresh(); // Updates the value displayed to the user, among other things. ++ return true; ++ } ++ ++ // For everything else, accept the change. ++ return true; ++ } + } +diff -ruN mozilla-esr31/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java mozilla-release/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java +--- mozilla-esr31/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/activities/FxAccountUpdateCredentialsActivity.java 2014-09-24 03:05:32.000000000 +0200 +@@ -18,11 +18,11 @@ + import org.mozilla.gecko.background.fxa.PasswordStretcher; + import org.mozilla.gecko.fxa.FirefoxAccounts; + import org.mozilla.gecko.fxa.FxAccountConstants; +-import org.mozilla.gecko.fxa.activities.FxAccountSetupTask.FxAccountSignInTask; + 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; +diff -ruN mozilla-esr31/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java mozilla-release/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java +--- mozilla-esr31/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java 2015-02-25 19:21:06.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java 2014-09-24 03:05:33.000000000 +0200 +@@ -357,7 +357,11 @@ + + FxAccountGlobalSession globalSession = null; + try { +- ClientsDataDelegate clientsDataDelegate = new SharedPreferencesClientsDataDelegate(sharedPrefs); ++ final ClientsDataDelegate clientsDataDelegate = new SharedPreferencesClientsDataDelegate(sharedPrefs); ++ 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()); ++ } + + // We compute skew over time using SkewHandler. This yields an unchanging + // skew adjustment that the HawkAuthHeaderProvider uses to adjust its +diff -ruN mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountCodeResender.java mozilla-release/mobile/android/base/fxa/tasks/FxAccountCodeResender.java +--- mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountCodeResender.java 1970-01-01 01:00:00.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/tasks/FxAccountCodeResender.java 2014-09-24 03:05:33.000000000 +0200 +@@ -0,0 +1,108 @@ ++/* 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.tasks; ++ ++import java.util.concurrent.Executor; ++import java.util.concurrent.Executors; ++ ++import org.mozilla.gecko.R; ++import org.mozilla.gecko.background.common.log.Logger; ++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.FxAccountClientException.FxAccountClientRemoteException; ++import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; ++import org.mozilla.gecko.fxa.login.Engaged; ++ ++import android.content.Context; ++import android.widget.Toast; ++ ++/** ++ * A helper class that provides a simple interface for requesting ++ * a Firefox Account verification email to be resent. ++ */ ++public class FxAccountCodeResender { ++ private static final String LOG_TAG = FxAccountCodeResender.class.getSimpleName(); ++ ++ private static class FxAccountResendCodeTask extends FxAccountSetupTask<Void> { ++ protected static final String LOG_TAG = FxAccountResendCodeTask.class.getSimpleName(); ++ ++ protected final byte[] sessionToken; ++ ++ public FxAccountResendCodeTask(Context context, byte[] sessionToken, FxAccountClient client, RequestDelegate<Void> delegate) { ++ super(context, null, client, delegate); ++ this.sessionToken = sessionToken; ++ } ++ ++ @Override ++ protected InnerRequestDelegate<Void> doInBackground(Void... arg0) { ++ try { ++ client.resendCode(sessionToken, innerDelegate); ++ latch.await(); ++ return innerDelegate; ++ } catch (Exception e) { ++ Logger.error(LOG_TAG, "Got exception signing in.", e); ++ delegate.handleError(e); ++ } ++ return null; ++ } ++ } ++ ++ private static class ResendCodeDelegate implements RequestDelegate<Void> { ++ public final Context context; ++ ++ public ResendCodeDelegate(Context context) { ++ this.context = context; ++ } ++ ++ @Override ++ public void handleError(Exception e) { ++ Logger.warn(LOG_TAG, "Got exception requesting fresh confirmation link; ignoring.", e); ++ Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_not_sent, Toast.LENGTH_LONG).show(); ++ } ++ ++ @Override ++ public void handleFailure(FxAccountClientRemoteException e) { ++ handleError(e); ++ } ++ ++ @Override ++ public void handleSuccess(Void result) { ++ Toast.makeText(context, R.string.fxaccount_confirm_account_verification_link_sent, Toast.LENGTH_SHORT).show(); ++ } ++ } ++ ++ /** ++ * Resends the account verification email, and displays an appropriate ++ * toast on both send success and failure. Note that because the underlying implementation ++ * uses {@link AsyncTask}, the provided context must be UI-capable and ++ * this method called from the UI thread. ++ * ++ * Note that it may actually be possible to run this (and the {@link AsyncTask}) method ++ * from a background thread - but this hasn't been tested. ++ * ++ * @param context A UI-capable Android context. ++ * @param fxAccount The Firefox Account to resend the code to. ++ */ ++ public static void resendCode(Context context, AndroidFxAccount fxAccount) { ++ RequestDelegate<Void> delegate = new ResendCodeDelegate(context); ++ ++ byte[] sessionToken; ++ try { ++ sessionToken = ((Engaged) fxAccount.getState()).getSessionToken(); ++ } catch (Exception e) { ++ delegate.handleError(e); ++ return; ++ } ++ if (sessionToken == null) { ++ delegate.handleError(new IllegalStateException("sessionToken should not be null")); ++ return; ++ } ++ ++ Executor executor = Executors.newSingleThreadExecutor(); ++ FxAccountClient client = new FxAccountClient20(fxAccount.getAccountServerURI(), executor); ++ new FxAccountResendCodeTask(context, sessionToken, client, delegate).execute(); ++ } ++} +diff -ruN mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountCreateAccountTask.java mozilla-release/mobile/android/base/fxa/tasks/FxAccountCreateAccountTask.java +--- mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountCreateAccountTask.java 1970-01-01 01:00:00.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/tasks/FxAccountCreateAccountTask.java 2014-09-24 03:05:33.000000000 +0200 +@@ -0,0 +1,41 @@ ++/* 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.tasks; ++ ++import java.io.UnsupportedEncodingException; ++ ++import org.mozilla.gecko.background.common.log.Logger; ++import org.mozilla.gecko.background.fxa.FxAccountClient; ++import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; ++import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse; ++import org.mozilla.gecko.background.fxa.PasswordStretcher; ++ ++import android.content.Context; ++ ++public class FxAccountCreateAccountTask extends FxAccountSetupTask<LoginResponse> { ++ private static final String LOG_TAG = FxAccountCreateAccountTask.class.getSimpleName(); ++ ++ protected final byte[] emailUTF8; ++ protected final PasswordStretcher passwordStretcher; ++ ++ public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { ++ super(context, progressDisplay, client, delegate); ++ this.emailUTF8 = email.getBytes("UTF-8"); ++ this.passwordStretcher = passwordStretcher; ++ } ++ ++ @Override ++ protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { ++ try { ++ client.createAccountAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); ++ latch.await(); ++ return innerDelegate; ++ } catch (Exception e) { ++ Logger.error(LOG_TAG, "Got exception logging in.", e); ++ delegate.handleError(e); ++ } ++ return null; ++ } ++} +diff -ruN mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountSetupTask.java mozilla-release/mobile/android/base/fxa/tasks/FxAccountSetupTask.java +--- mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountSetupTask.java 1970-01-01 01:00:00.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/tasks/FxAccountSetupTask.java 2014-09-24 03:05:33.000000000 +0200 +@@ -0,0 +1,117 @@ ++/* 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.tasks; ++ ++import java.util.concurrent.CountDownLatch; ++ ++import org.mozilla.gecko.background.common.log.Logger; ++import org.mozilla.gecko.background.fxa.FxAccountClient; ++import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; ++import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException; ++import org.mozilla.gecko.fxa.tasks.FxAccountSetupTask.InnerRequestDelegate; ++ ++import android.content.Context; ++import android.os.AsyncTask; ++ ++/** ++ * An <code>AsyncTask</code> wrapper around signing up for, and signing in to, a ++ * Firefox Account. ++ * <p> ++ * It's strange to add explicit blocking to callback-threading code, but we do ++ * it here to take advantage of Android's built in support for background work. ++ * We really want to avoid making a threading mistake that brings down the whole ++ * process. ++ */ ++public abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerRequestDelegate<T>> { ++ private static final String LOG_TAG = FxAccountSetupTask.class.getSimpleName(); ++ ++ public interface ProgressDisplay { ++ public void showProgress(); ++ public void dismissProgress(); ++ } ++ ++ protected final Context context; ++ protected final FxAccountClient client; ++ protected final ProgressDisplay progressDisplay; ++ ++ // Initialized lazily. ++ protected byte[] quickStretchedPW; ++ ++ // AsyncTask's are one-time-use, so final members are fine. ++ protected final CountDownLatch latch = new CountDownLatch(1); ++ protected final InnerRequestDelegate<T> innerDelegate = new InnerRequestDelegate<T>(latch); ++ ++ protected final RequestDelegate<T> delegate; ++ ++ public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient client, RequestDelegate<T> delegate) { ++ this.context = context; ++ this.client = client; ++ this.delegate = delegate; ++ this.progressDisplay = progressDisplay; ++ } ++ ++ @Override ++ protected void onPreExecute() { ++ if (progressDisplay != null) { ++ progressDisplay.showProgress(); ++ } ++ } ++ ++ @Override ++ protected void onPostExecute(InnerRequestDelegate<T> result) { ++ if (progressDisplay != null) { ++ progressDisplay.dismissProgress(); ++ } ++ ++ // We are on the UI thread, and need to invoke these callbacks here to allow UI updating. ++ if (innerDelegate.failure != null) { ++ delegate.handleFailure(innerDelegate.failure); ++ } else if (innerDelegate.exception != null) { ++ delegate.handleError(innerDelegate.exception); ++ } else { ++ delegate.handleSuccess(result.response); ++ } ++ } ++ ++ @Override ++ protected void onCancelled(InnerRequestDelegate<T> result) { ++ if (progressDisplay != null) { ++ progressDisplay.dismissProgress(); ++ } ++ delegate.handleError(new IllegalStateException("Task was cancelled.")); ++ } ++ ++ protected static class InnerRequestDelegate<T> implements RequestDelegate<T> { ++ protected final CountDownLatch latch; ++ public T response = null; ++ public Exception exception = null; ++ public FxAccountClientRemoteException failure = null; ++ ++ protected InnerRequestDelegate(CountDownLatch latch) { ++ this.latch = latch; ++ } ++ ++ @Override ++ public void handleError(Exception e) { ++ Logger.error(LOG_TAG, "Got exception."); ++ this.exception = e; ++ latch.countDown(); ++ } ++ ++ @Override ++ public void handleFailure(FxAccountClientRemoteException e) { ++ Logger.warn(LOG_TAG, "Got failure."); ++ this.failure = e; ++ latch.countDown(); ++ } ++ ++ @Override ++ public void handleSuccess(T result) { ++ Logger.info(LOG_TAG, "Got success."); ++ this.response = result; ++ latch.countDown(); ++ } ++ } ++} +diff -ruN mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountSignInTask.java mozilla-release/mobile/android/base/fxa/tasks/FxAccountSignInTask.java +--- mozilla-esr31/mobile/android/base/fxa/tasks/FxAccountSignInTask.java 1970-01-01 01:00:00.000000000 +0100 ++++ mozilla-release/mobile/android/base/fxa/tasks/FxAccountSignInTask.java 2014-09-24 03:05:33.000000000 +0200 +@@ -0,0 +1,41 @@ ++/* 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.tasks; ++ ++import java.io.UnsupportedEncodingException; ++ ++import org.mozilla.gecko.background.common.log.Logger; ++import org.mozilla.gecko.background.fxa.FxAccountClient; ++import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate; ++import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse; ++import org.mozilla.gecko.background.fxa.PasswordStretcher; ++ ++import android.content.Context; ++ ++public class FxAccountSignInTask extends FxAccountSetupTask<LoginResponse> { ++ protected static final String LOG_TAG = FxAccountSignInTask.class.getSimpleName(); ++ ++ protected final byte[] emailUTF8; ++ protected final PasswordStretcher passwordStretcher; ++ ++ public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException { ++ super(context, progressDisplay, client, delegate); ++ this.emailUTF8 = email.getBytes("UTF-8"); ++ this.passwordStretcher = passwordStretcher; ++ } ++ ++ @Override ++ protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) { ++ try { ++ client.loginAndGetKeys(emailUTF8, passwordStretcher, innerDelegate); ++ latch.await(); ++ return innerDelegate; ++ } catch (Exception e) { ++ Logger.error(LOG_TAG, "Got exception signing in.", e); ++ delegate.handleError(e); ++ } ++ return null; ++ } ++} +--- mozilla-esr31/mobile/android/base/android-services.mozbuild 2015-02-25 19:21:05.000000000 +0100 ++++ mozilla-release/mobile/android/base/android-services.mozbuild 2014-09-24 03:05:32.000000000 +0200 +@@ -555,7 +557,6 @@ + 'fxa/activities/FxAccountCreateAccountActivity.java', + 'fxa/activities/FxAccountCreateAccountNotAllowedActivity.java', + 'fxa/activities/FxAccountGetStartedActivity.java', +- 'fxa/activities/FxAccountSetupTask.java', + 'fxa/activities/FxAccountSignInActivity.java', + 'fxa/activities/FxAccountStatusActivity.java', + 'fxa/activities/FxAccountStatusFragment.java', +@@ -589,6 +590,10 @@ + 'fxa/sync/FxAccountSyncService.java', + 'fxa/sync/FxAccountSyncStatusHelper.java', + 'fxa/sync/SchedulePolicy.java', ++ 'fxa/tasks/FxAccountCodeResender.java', ++ 'fxa/tasks/FxAccountCreateAccountTask.java', ++ 'fxa/tasks/FxAccountSetupTask.java', ++ 'fxa/tasks/FxAccountSignInTask.java', + 'sync/AlreadySyncingException.java', + 'sync/BackoffHandler.java', + 'sync/BadRequiredFieldJSONException.java', |