15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 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 android.accounts.Account; 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.accounts.AccountManager; 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.accounts.AccountManagerFuture; 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.accounts.AuthenticatorDescription; 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.accounts.AuthenticatorException; 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.accounts.OperationCanceledException; 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.app.Activity; 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.content.Context; 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.content.Intent; 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.AsyncTask; 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.Bundle; 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.util.Log; 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)import org.chromium.base.ThreadUtils; 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport org.chromium.base.VisibleForTesting; 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; 27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import java.util.List; 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.util.concurrent.atomic.AtomicBoolean; 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.util.concurrent.atomic.AtomicInteger; 30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import javax.annotation.Nullable; 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * AccountManagerHelper wraps our access of AccountManager in Android. 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Use the AccountManagerHelper.get(someContext) to instantiate it 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)public class AccountManagerHelper { 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private static final String TAG = "AccountManagerHelper"; 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public static final String GOOGLE_ACCOUNT_TYPE = "com.google"; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private static final Object sLock = new Object(); 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private static final int MAX_TRIES = 3; 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private static AccountManagerHelper sAccountManagerHelper; 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private final AccountManagerDelegate mAccountManager; 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private Context mApplicationContext; 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public interface GetAuthTokenCallback { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Invoked on the UI thread once a token has been provided by the AccountManager. 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param token Auth token, or null if no token is available (bad credentials, 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * permission denied, etc). 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void tokenAvailable(String token); 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param context the Android context 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param accountManager the account manager to use as a backend service 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private AccountManagerHelper(Context context, 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AccountManagerDelegate accountManager) { 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mApplicationContext = context.getApplicationContext(); 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mAccountManager = accountManager; 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * A factory method for the AccountManagerHelper. 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * It is possible to override the AccountManager to use in tests for the instance of the 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * AccountManagerHelper by calling overrideAccountManagerHelperForTests(...) with 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * your MockAccountManager. 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param context the applicationContext is retrieved from the context used as an argument. 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return a singleton instance of the AccountManagerHelper 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public static AccountManagerHelper get(Context context) { 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) synchronized (sLock) { 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (sAccountManagerHelper == null) { 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sAccountManagerHelper = new AccountManagerHelper(context, 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new SystemAccountManagerDelegate(context)); 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return sAccountManagerHelper; 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) @VisibleForTesting 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public static void overrideAccountManagerHelperForTests(Context context, 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AccountManagerDelegate accountManager) { 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) synchronized (sLock) { 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sAccountManagerHelper = new AccountManagerHelper(context, accountManager); 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Creates an Account object for the given name. 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public static Account createAccountFromName(String name) { 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return new Account(name, GOOGLE_ACCOUNT_TYPE); 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public List<String> getGoogleAccountNames() { 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) List<String> accountNames = new ArrayList<String>(); 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Account[] accounts = mAccountManager.getAccountsByType(GOOGLE_ACCOUNT_TYPE); 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (Account account : accounts) { 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) accountNames.add(account.name); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return accountNames; 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public Account[] getGoogleAccounts() { 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return mAccountManager.getAccountsByType(GOOGLE_ACCOUNT_TYPE); 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public boolean hasGoogleAccounts() { 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return getGoogleAccounts().length > 0; 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Returns the account if it exists, null otherwise. 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public Account getAccountFromName(String accountName) { 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Account[] accounts = mAccountManager.getAccountsByType(GOOGLE_ACCOUNT_TYPE); 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (Account account : accounts) { 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (account.name.equals(accountName)) { 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return account; 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return null; 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 13968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) * Returns whether the accounts exists. 14068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) */ 14168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) public boolean hasAccountForName(String accountName) { 14268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return getAccountFromName(accountName) != null; 14368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 14568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) /** 146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @return Whether or not there is an account authenticator for Google accounts. 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public boolean hasGoogleAccountAuthenticator() { 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AuthenticatorDescription[] descs = mAccountManager.getAuthenticatorTypes(); 150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (AuthenticatorDescription desc : descs) { 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (GOOGLE_ACCOUNT_TYPE.equals(desc.type)) return true; 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Gets the auth token synchronously. 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * - Assumes that the account is a valid account. 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * - Should not be called on the main thread. 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) @Deprecated 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public String getAuthTokenFromBackground(Account account, String authTokenType) { 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(account, 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) authTokenType, false, null, null); 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AtomicBoolean errorEncountered = new AtomicBoolean(false); 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return getAuthTokenInner(future, errorEncountered); 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Gets the auth token and returns the response asynchronously. 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * This should be called when we have a foreground activity that needs an auth token. 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * If encountered an IO error, it will attempt to retry when the network is back. 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * - Assumes that the account is a valid account. 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public void getAuthTokenFromForeground(Activity activity, Account account, String authTokenType, 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetAuthTokenCallback callback) { 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AtomicInteger numTries = new AtomicInteger(0); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AtomicBoolean errorEncountered = new AtomicBoolean(false); 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) getAuthTokenAsynchronously(activity, account, authTokenType, callback, numTries, 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) errorEncountered, null); 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private class ConnectionRetry implements NetworkChangeNotifier.ConnectionTypeObserver { 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private final Account mAccount; 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private final String mAuthTokenType; 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private final GetAuthTokenCallback mCallback; 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private final AtomicInteger mNumTries; 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private final AtomicBoolean mErrorEncountered; 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ConnectionRetry(Account account, String authTokenType, GetAuthTokenCallback callback, 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AtomicInteger numTries, AtomicBoolean errorEncountered) { 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mAccount = account; 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mAuthTokenType = authTokenType; 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mCallback = callback; 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mNumTries = numTries; 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mErrorEncountered = errorEncountered; 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) @Override 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public void onConnectionTypeChanged(int connectionType) { 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) assert mNumTries.get() <= MAX_TRIES; 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (mNumTries.get() == MAX_TRIES) { 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NetworkChangeNotifier.removeConnectionTypeObserver(this); 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (NetworkChangeNotifier.isOnline()) { 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NetworkChangeNotifier.removeConnectionTypeObserver(this); 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) getAuthTokenAsynchronously(null, mAccount, mAuthTokenType, mCallback, mNumTries, 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mErrorEncountered, this); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Gets the auth token synchronously 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private String getAuthTokenInner(AccountManagerFuture<Bundle> future, 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AtomicBoolean errorEncountered) { 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) try { 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Bundle result = future.getResult(); 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result != null) { 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (result.containsKey(AccountManager.KEY_INTENT)) { 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Log.d(TAG, "Starting intent to get auth credentials"); 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Need to start intent to get credentials 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Intent intent = result.getParcelable(AccountManager.KEY_INTENT); 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int flags = intent.getFlags(); 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) flags |= Intent.FLAG_ACTIVITY_NEW_TASK; 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) intent.setFlags(flags); 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mApplicationContext.startActivity(intent); 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return null; 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return result.getString(AccountManager.KEY_AUTHTOKEN); 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Log.w(TAG, "Auth token - getAuthToken returned null"); 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } catch (OperationCanceledException e) { 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Log.w(TAG, "Auth token - operation cancelled", e); 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } catch (AuthenticatorException e) { 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Log.w(TAG, "Auth token - authenticator exception", e); 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } catch (IOException e) { 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Log.w(TAG, "Auth token - IO exception", e); 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) errorEncountered.set(true); 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return null; 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private void getAuthTokenAsynchronously(@Nullable Activity activity, final Account account, 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) final String authTokenType, final GetAuthTokenCallback callback, 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) final AtomicInteger numTries, final AtomicBoolean errorEncountered, 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) final ConnectionRetry retry) { 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AccountManagerFuture<Bundle> future; 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (numTries.get() == 0 && activity != null) { 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) future = mAccountManager.getAuthToken( 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) account, authTokenType, null, activity, null, null); 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) future = mAccountManager.getAuthToken( 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) account, authTokenType, false, null, null); 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) final AccountManagerFuture<Bundle> finalFuture = future; 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) errorEncountered.set(false); 261a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 262a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // On ICS onPostExecute is never called when running an AsyncTask from a different thread 263a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // than the UI thread. 264a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (ThreadUtils.runningOnUiThread()) { 265a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) new AsyncTask<Void, Void, String>() { 266a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) @Override 267a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public String doInBackground(Void... params) { 268a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return getAuthTokenInner(finalFuture, errorEncountered); 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 270a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) @Override 271a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) public void onPostExecute(String authToken) { 272a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) onGotAuthTokenResult(account, authTokenType, authToken, callback, numTries, 273a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) errorEncountered, retry); 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 275a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) }.execute(); 276a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else { 277a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) String authToken = getAuthTokenInner(finalFuture, errorEncountered); 278a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) onGotAuthTokenResult(account, authTokenType, authToken, callback, numTries, 279a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) errorEncountered, retry); 280a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 281a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 282a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 283a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) private void onGotAuthTokenResult(Account account, String authTokenType, String authToken, 284a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) GetAuthTokenCallback callback, AtomicInteger numTries, AtomicBoolean errorEncountered, 285a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ConnectionRetry retry) { 286a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (authToken != null || !errorEncountered.get() || 287a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) numTries.incrementAndGet() == MAX_TRIES || 288a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) !NetworkChangeNotifier.isInitialized()) { 289a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) callback.tokenAvailable(authToken); 290a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return; 291a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 292a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (retry == null) { 293a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ConnectionRetry newRetry = new ConnectionRetry(account, authTokenType, callback, 294a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) numTries, errorEncountered); 295a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) NetworkChangeNotifier.addConnectionTypeObserver(newRetry); 296a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else { 297a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) NetworkChangeNotifier.addConnectionTypeObserver(retry); 298a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Invalidates the old token (if non-null/non-empty) and synchronously generates a new one. 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Also notifies the user (via status bar) if any user action is required. The method will 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * return null if any user action is required to generate the new token. 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * - Assumes that the account is a valid account. 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * - Should not be called on the main thread. 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) @Deprecated 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public String getNewAuthToken(Account account, String authToken, String authTokenType) { 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(dsmyers): consider reimplementing using an AccountManager function with an 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // explicit timeout. 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Bug: https://code.google.com/p/chromium/issues/detail?id=172394. 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (authToken != null && !authToken.isEmpty()) { 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mAccountManager.invalidateAuthToken(GOOGLE_ACCOUNT_TYPE, authToken); 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) try { 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return mAccountManager.blockingGetAuthToken(account, authTokenType, true); 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } catch (OperationCanceledException e) { 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Log.w(TAG, "Auth token - operation cancelled", e); 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } catch (AuthenticatorException e) { 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Log.w(TAG, "Auth token - authenticator exception", e); 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } catch (IOException e) { 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Log.w(TAG, "Auth token - IO exception", e); 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return null; 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Invalidates the old token (if non-null/non-empty) and asynchronously generates a new one. 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * - Assumes that the account is a valid account. 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public void getNewAuthTokenFromForeground(Account account, String authToken, 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) String authTokenType, GetAuthTokenCallback callback) { 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (authToken != null && !authToken.isEmpty()) { 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mAccountManager.invalidateAuthToken(GOOGLE_ACCOUNT_TYPE, authToken); 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AtomicInteger numTries = new AtomicInteger(0); 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AtomicBoolean errorEncountered = new AtomicBoolean(false); 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) getAuthTokenAsynchronously( 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) null, account, authTokenType, callback, numTries, errorEncountered, null); 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Removes an auth token from the AccountManager's cache. 348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 3497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch public void invalidateAuthToken(String authToken) { 3507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch mAccountManager.invalidateAuthToken(GOOGLE_ACCOUNT_TYPE, authToken); 351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 353