diff -r 000000000000 -r 6474c204b198 mobile/android/base/fxa/FirefoxAccounts.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mobile/android/base/fxa/FirefoxAccounts.java Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,267 @@ +/* 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 java.io.File; +import java.util.EnumSet; +import java.util.concurrent.CountDownLatch; + +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.sync.FxAccountSyncAdapter; +import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper; +import org.mozilla.gecko.sync.ThreadPool; +import org.mozilla.gecko.sync.Utils; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.ContentResolver; +import android.content.Context; +import android.os.Bundle; + +/** + * Simple public accessors for Firefox account objects. + */ +public class FirefoxAccounts { + private static final String LOG_TAG = FirefoxAccounts.class.getSimpleName(); + + public enum SyncHint { + /** + * Hint that a requested sync is preferred immediately. + *
+ * On many devices, not including SCHEDULE_NOW
means a delay of
+ * at least 30 seconds.
+ */
+ SCHEDULE_NOW,
+
+ /**
+ * Hint that a requested sync may ignore local rate limiting.
+ *
+ * This is just a hint; the actual requested sync may not obey the hint. + */ + IGNORE_LOCAL_RATE_LIMIT, + + /** + * Hint that a requested sync may ignore remote server backoffs. + *
+ * This is just a hint; the actual requested sync may not obey the hint.
+ */
+ IGNORE_REMOTE_SERVER_BACKOFF,
+ }
+
+ public static final EnumSet
+ * If no accounts exist in the AccountManager, one may be created
+ * via a pickled FirefoxAccount, if available, and that account
+ * will be added to the AccountManager and returned.
+ *
+ * Note that this can be called from any thread.
+ *
+ * @param context Android context.
+ * @return Firefox account objects.
+ */
+ public static Account[] getFirefoxAccounts(final Context context) {
+ final Account[] accounts =
+ AccountManager.get(context).getAccountsByType(FxAccountConstants.ACCOUNT_TYPE);
+ if (accounts.length > 0) {
+ return accounts;
+ }
+
+ final Account pickledAccount = getPickledAccount(context);
+ return (pickledAccount != null) ? new Account[] {pickledAccount} : new Account[0];
+ }
+
+ private static Account getPickledAccount(final Context context) {
+ // To avoid a StrictMode violation for disk access, we call this from a background thread.
+ // We do this every time, so the caller doesn't have to care.
+ final CountDownLatch latch = new CountDownLatch(1);
+ final Account[] accounts = new Account[1];
+ ThreadPool.run(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ final File file = context.getFileStreamPath(FxAccountConstants.ACCOUNT_PICKLE_FILENAME);
+ if (!file.exists()) {
+ accounts[0] = null;
+ return;
+ }
+
+ // There is a small race window here: if the user creates a new Firefox account
+ // between our checks, this could erroneously report that no Firefox accounts
+ // exist.
+ final AndroidFxAccount fxAccount =
+ AccountPickler.unpickle(context, FxAccountConstants.ACCOUNT_PICKLE_FILENAME);
+ accounts[0] = fxAccount.getAndroidAccount();
+ } finally {
+ latch.countDown();
+ }
+ }
+ });
+
+ try {
+ latch.await(); // Wait for the background thread to return.
+ } catch (InterruptedException e) {
+ Logger.warn(LOG_TAG,
+ "Foreground thread unexpectedly interrupted while getting pickled account", e);
+ return null;
+ }
+
+ return accounts[0];
+ }
+
+ /**
+ * @param context Android context.
+ * @return the configured Firefox account if one exists, or null otherwise.
+ */
+ public static Account getFirefoxAccount(final Context context) {
+ Account[] accounts = getFirefoxAccounts(context);
+ if (accounts.length > 0) {
+ return accounts[0];
+ }
+ return null;
+ }
+
+ protected static void putHintsToSync(final Bundle extras, EnumSet
+ * Any hints are strictly optional: the actual requested sync is scheduled by
+ * the Android sync scheduler, and the sync mechanism may ignore hints as it
+ * sees fit.
+ *
+ * It is safe to call this method from any thread.
+ *
+ * @param account to sync.
+ * @param syncHints to pass to sync.
+ * @param stagesToSync stage names to sync.
+ * @param stagesToSkip stage names to skip.
+ */
+ public static void requestSync(final Account account, EnumSet
+ * Only a weak reference to syncStatusListener
of sync status changes.
+ * syncStatusListener
is held.
+ *
+ * @param syncStatusListener to start notifying.
+ */
+ public static void addSyncStatusListener(SyncStatusListener syncStatusListener) {
+ // startObserving null-checks its argument.
+ FxAccountSyncStatusHelper.getInstance().startObserving(syncStatusListener);
+ }
+
+ /**
+ * Stop notifying syncStatusListener
of sync status changes.
+ *
+ * @param syncStatusListener to stop notifying.
+ */
+ public static void removeSyncStatusListener(SyncStatusListener syncStatusListener) {
+ // stopObserving null-checks its argument.
+ FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusListener);
+ }
+}