AccountManagerHelper.java revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)package org.chromium.sync.signin;
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import com.google.common.annotations.VisibleForTesting;
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.accounts.Account;
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.accounts.AccountManager;
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.accounts.AccountManagerFuture;
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.accounts.AuthenticatorDescription;
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.accounts.AuthenticatorException;
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.accounts.OperationCanceledException;
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.app.Activity;
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.content.Context;
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.content.Intent;
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.AsyncTask;
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.Bundle;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.util.Log;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.net.NetworkChangeNotifier;
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.io.IOException;
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.util.ArrayList;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.util.concurrent.atomic.AtomicBoolean;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.util.concurrent.atomic.AtomicInteger;
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.util.List;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import javax.annotation.Nullable;
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * AccountManagerHelper wraps our access of AccountManager in Android.
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Use the AccountManagerHelper.get(someContext) to instantiate it
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)public class AccountManagerHelper {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static final String TAG = "AccountManagerHelper";
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static final String GOOGLE_ACCOUNT_TYPE = "com.google";
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static final Object lock = new Object();
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static final int MAX_TRIES = 3;
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static AccountManagerHelper sAccountManagerHelper;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final AccountManagerDelegate mAccountManager;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private Context mApplicationContext;
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public interface GetAuthTokenCallback {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        /**
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         * Invoked on the UI thread once a token has been provided by the AccountManager.
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         * @param token Auth token, or null if no token is available (bad credentials,
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         *      permission denied, etc).
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         */
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        void tokenAvailable(String token);
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @param context the Android context
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @param accountManager the account manager to use as a backend service
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private AccountManagerHelper(Context context,
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 AccountManagerDelegate accountManager) {
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mApplicationContext = context.getApplicationContext();
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mAccountManager = accountManager;
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * A factory method for the AccountManagerHelper.
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     *
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * It is possible to override the AccountManager to use in tests for the instance of the
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * AccountManagerHelper by calling overrideAccountManagerHelperForTests(...) with
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * your MockAccountManager.
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     *
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @param context the applicationContext is retrieved from the context used as an argument.
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @return a singleton instance of the AccountManagerHelper
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static AccountManagerHelper get(Context context) {
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        synchronized (lock) {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (sAccountManagerHelper == null) {
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                sAccountManagerHelper = new AccountManagerHelper(context,
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        new SystemAccountManagerDelegate(context));
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return sAccountManagerHelper;
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    @VisibleForTesting
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static void overrideAccountManagerHelperForTests(Context context,
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            AccountManagerDelegate accountManager) {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        synchronized (lock) {
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            sAccountManagerHelper = new AccountManagerHelper(context, accountManager);
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Creates an Account object for the given name.
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public static Account createAccountFromName(String name) {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return new Account(name, GOOGLE_ACCOUNT_TYPE);
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public List<String> getGoogleAccountNames() {
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        List<String> accountNames = new ArrayList<String>();
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        Account[] accounts = mAccountManager.getAccountsByType(GOOGLE_ACCOUNT_TYPE);
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        for (Account account : accounts) {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            accountNames.add(account.name);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return accountNames;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public Account[] getGoogleAccounts() {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return mAccountManager.getAccountsByType(GOOGLE_ACCOUNT_TYPE);
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public boolean hasGoogleAccounts() {
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return getGoogleAccounts().length > 0;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Returns the account if it exists, null otherwise.
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public Account getAccountFromName(String accountName) {
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        Account[] accounts = mAccountManager.getAccountsByType(GOOGLE_ACCOUNT_TYPE);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        for (Account account : accounts) {
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (account.name.equals(accountName)) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                return account;
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return null;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * @return Whether or not there is an account authenticator for Google accounts.
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public boolean hasGoogleAccountAuthenticator() {
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        AuthenticatorDescription[] descs = mAccountManager.getAuthenticatorTypes();
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        for (AuthenticatorDescription desc : descs) {
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            if (GOOGLE_ACCOUNT_TYPE.equals(desc.type)) return true;
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Gets the auth token synchronously.
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     *
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * - Assumes that the account is a valid account.
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * - Should not be called on the main thread.
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    @Deprecated
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public String getAuthTokenFromBackground(Account account, String authTokenType) {
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(account,
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    authTokenType, false, null, null);
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            AtomicBoolean errorEncountered = new AtomicBoolean(false);
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return getAuthTokenInner(future, errorEncountered);
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Gets the auth token and returns the response asynchronously.
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * This should be called when we have a foreground activity that needs an auth token.
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * If encountered an IO error, it will attempt to retry when the network is back.
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     *
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * - Assumes that the account is a valid account.
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public void getAuthTokenFromForeground(Activity activity, Account account, String authTokenType,
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                GetAuthTokenCallback callback) {
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        AtomicInteger numTries = new AtomicInteger(0);
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        AtomicBoolean errorEncountered = new AtomicBoolean(false);
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        getAuthTokenAsynchronously(activity, account, authTokenType, callback, numTries,
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                errorEncountered, null);
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private class ConnectionRetry implements NetworkChangeNotifier.ConnectionTypeObserver {
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        private final Account mAccount;
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        private final String mAuthTokenType;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        private final GetAuthTokenCallback mCallback;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        private final AtomicInteger mNumTries;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        private final AtomicBoolean mErrorEncountered;
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ConnectionRetry(Account account, String authTokenType, GetAuthTokenCallback callback,
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                AtomicInteger numTries, AtomicBoolean errorEncountered) {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mAccount = account;
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mAuthTokenType = authTokenType;
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mCallback = callback;
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mNumTries = numTries;
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mErrorEncountered = errorEncountered;
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @Override
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public void onConnectionTypeChanged(int connectionType) {
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            assert mNumTries.get() <= MAX_TRIES;
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (mNumTries.get() == MAX_TRIES) {
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                NetworkChangeNotifier.removeConnectionTypeObserver(this);
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                return;
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (NetworkChangeNotifier.isOnline()) {
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                NetworkChangeNotifier.removeConnectionTypeObserver(this);
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                getAuthTokenAsynchronously(null, mAccount, mAuthTokenType, mCallback, mNumTries,
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        mErrorEncountered, this);
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Gets the auth token synchronously
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private String getAuthTokenInner(AccountManagerFuture<Bundle> future,
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            AtomicBoolean errorEncountered) {
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        try {
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Bundle result = future.getResult();
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (result != null) {
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                if (result.containsKey(AccountManager.KEY_INTENT)) {
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    Log.d(TAG, "Starting intent to get auth credentials");
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    // Need to start intent to get credentials
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    int flags = intent.getFlags();
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    flags |= Intent.FLAG_ACTIVITY_NEW_TASK;
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    intent.setFlags(flags);
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    mApplicationContext.startActivity(intent);
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    return null;
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                }
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                return result.getString(AccountManager.KEY_AUTHTOKEN);
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            } else {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                Log.w(TAG, "Auth token - getAuthToken returned null");
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } catch (OperationCanceledException e) {
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Log.w(TAG, "Auth token - operation cancelled", e);
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } catch (AuthenticatorException e) {
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Log.w(TAG, "Auth token - authenticator exception", e);
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } catch (IOException e) {
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Log.w(TAG, "Auth token - IO exception", e);
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            errorEncountered.set(true);
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return null;
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private void getAuthTokenAsynchronously(@Nullable Activity activity, final Account account,
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            final String authTokenType, final GetAuthTokenCallback callback,
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            final AtomicInteger numTries, final AtomicBoolean errorEncountered,
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            final ConnectionRetry retry) {
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        AccountManagerFuture<Bundle> future;
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (numTries.get() == 0 && activity != null) {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            future = mAccountManager.getAuthToken(
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    account, authTokenType, null, activity, null, null);
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } else {
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            future = mAccountManager.getAuthToken(
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    account, authTokenType, false, null, null);
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        final AccountManagerFuture<Bundle> finalFuture = future;
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        errorEncountered.set(false);
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        new AsyncTask<Void, Void, String>() {
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            @Override
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            public String doInBackground(Void... params) {
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                return getAuthTokenInner(finalFuture, errorEncountered);
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            @Override
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            public void onPostExecute(String authToken) {
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                if (authToken != null || !errorEncountered.get() ||
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        numTries.incrementAndGet() == MAX_TRIES ||
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        !NetworkChangeNotifier.isInitialized()) {
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    callback.tokenAvailable(authToken);
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    return;
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                }
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                if (retry == null) {
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    ConnectionRetry newRetry = new ConnectionRetry(account, authTokenType, callback,
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            numTries, errorEncountered);
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    NetworkChangeNotifier.addConnectionTypeObserver(newRetry);
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                }
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                else {
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    NetworkChangeNotifier.addConnectionTypeObserver(retry);
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                }
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }.execute();
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Invalidates the old token (if non-null/non-empty) and synchronously generates a new one.
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Also notifies the user (via status bar) if any user action is required. The method will
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * return null if any user action is required to generate the new token.
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     *
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * - Assumes that the account is a valid account.
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * - Should not be called on the main thread.
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    @Deprecated
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public String getNewAuthToken(Account account, String authToken, String authTokenType) {
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // TODO(dsmyers): consider reimplementing using an AccountManager function with an
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // explicit timeout.
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Bug: https://code.google.com/p/chromium/issues/detail?id=172394.
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (authToken != null && !authToken.isEmpty()) {
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mAccountManager.invalidateAuthToken(GOOGLE_ACCOUNT_TYPE, authToken);
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        try {
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return mAccountManager.blockingGetAuthToken(account, authTokenType, true);
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } catch (OperationCanceledException e) {
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Log.w(TAG, "Auth token - operation cancelled", e);
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } catch (AuthenticatorException e) {
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Log.w(TAG, "Auth token - authenticator exception", e);
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        } catch (IOException e) {
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Log.w(TAG, "Auth token - IO exception", e);
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return null;
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Invalidates the old token (if non-null/non-empty) and asynchronously generates a new one.
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     *
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * - Assumes that the account is a valid account.
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public void getNewAuthTokenFromForeground(Account account, String authToken,
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                String authTokenType, GetAuthTokenCallback callback) {
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (authToken != null && !authToken.isEmpty()) {
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mAccountManager.invalidateAuthToken(GOOGLE_ACCOUNT_TYPE, authToken);
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        AtomicInteger numTries = new AtomicInteger(0);
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        AtomicBoolean errorEncountered = new AtomicBoolean(false);
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        getAuthTokenAsynchronously(
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            null, account, authTokenType, callback, numTries, errorEncountered, null);
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    /**
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     * Removes an auth token from the AccountManager's cache.
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     */
3267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    public void invalidateAuthToken(String authToken) {
3277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        mAccountManager.invalidateAuthToken(GOOGLE_ACCOUNT_TYPE, authToken);
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
330