Home | History | Annotate | Download | only in accounts
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.accounts;
     18 
     19 import static android.Manifest.permission.GET_ACCOUNTS;
     20 
     21 import android.annotation.NonNull;
     22 import android.annotation.RequiresPermission;
     23 import android.annotation.Size;
     24 import android.annotation.SystemApi;
     25 import android.app.Activity;
     26 import android.content.BroadcastReceiver;
     27 import android.content.ComponentName;
     28 import android.content.Context;
     29 import android.content.Intent;
     30 import android.content.IntentFilter;
     31 import android.content.IntentSender;
     32 import android.content.res.Resources;
     33 import android.database.SQLException;
     34 import android.os.Build;
     35 import android.os.Bundle;
     36 import android.os.Handler;
     37 import android.os.Looper;
     38 import android.os.Parcelable;
     39 import android.os.Process;
     40 import android.os.RemoteException;
     41 import android.os.UserHandle;
     42 import android.text.TextUtils;
     43 import android.util.Log;
     44 
     45 import com.android.internal.R;
     46 import com.google.android.collect.Maps;
     47 
     48 import java.io.IOException;
     49 import java.util.ArrayList;
     50 import java.util.HashMap;
     51 import java.util.List;
     52 import java.util.Map;
     53 import java.util.concurrent.Callable;
     54 import java.util.concurrent.CancellationException;
     55 import java.util.concurrent.ExecutionException;
     56 import java.util.concurrent.FutureTask;
     57 import java.util.concurrent.TimeUnit;
     58 import java.util.concurrent.TimeoutException;
     59 
     60 /**
     61  * This class provides access to a centralized registry of the user's
     62  * online accounts.  The user enters credentials (username and password) once
     63  * per account, granting applications access to online resources with
     64  * "one-click" approval.
     65  *
     66  * <p>Different online services have different ways of handling accounts and
     67  * authentication, so the account manager uses pluggable <em>authenticator</em>
     68  * modules for different <em>account types</em>.  Authenticators (which may be
     69  * written by third parties) handle the actual details of validating account
     70  * credentials and storing account information.  For example, Google, Facebook,
     71  * and Microsoft Exchange each have their own authenticator.
     72  *
     73  * <p>Many servers support some notion of an <em>authentication token</em>,
     74  * which can be used to authenticate a request to the server without sending
     75  * the user's actual password.  (Auth tokens are normally created with a
     76  * separate request which does include the user's credentials.)  AccountManager
     77  * can generate auth tokens for applications, so the application doesn't need to
     78  * handle passwords directly.  Auth tokens are normally reusable and cached by
     79  * AccountManager, but must be refreshed periodically.  It's the responsibility
     80  * of applications to <em>invalidate</em> auth tokens when they stop working so
     81  * the AccountManager knows it needs to regenerate them.
     82  *
     83  * <p>Applications accessing a server normally go through these steps:
     84  *
     85  * <ul>
     86  * <li>Get an instance of AccountManager using {@link #get(Context)}.
     87  *
     88  * <li>List the available accounts using {@link #getAccountsByType} or
     89  * {@link #getAccountsByTypeAndFeatures}.  Normally applications will only
     90  * be interested in accounts with one particular <em>type</em>, which
     91  * identifies the authenticator.  Account <em>features</em> are used to
     92  * identify particular account subtypes and capabilities.  Both the account
     93  * type and features are authenticator-specific strings, and must be known by
     94  * the application in coordination with its preferred authenticators.
     95  *
     96  * <li>Select one or more of the available accounts, possibly by asking the
     97  * user for their preference.  If no suitable accounts are available,
     98  * {@link #addAccount} may be called to prompt the user to create an
     99  * account of the appropriate type.
    100  *
    101  * <li><b>Important:</b> If the application is using a previously remembered
    102  * account selection, it must make sure the account is still in the list
    103  * of accounts returned by {@link #getAccountsByType}.  Requesting an auth token
    104  * for an account no longer on the device results in an undefined failure.
    105  *
    106  * <li>Request an auth token for the selected account(s) using one of the
    107  * {@link #getAuthToken} methods or related helpers.  Refer to the description
    108  * of each method for exact usage and error handling details.
    109  *
    110  * <li>Make the request using the auth token.  The form of the auth token,
    111  * the format of the request, and the protocol used are all specific to the
    112  * service you are accessing.  The application may use whatever network and
    113  * protocol libraries are useful.
    114  *
    115  * <li><b>Important:</b> If the request fails with an authentication error,
    116  * it could be that a cached auth token is stale and no longer honored by
    117  * the server.  The application must call {@link #invalidateAuthToken} to remove
    118  * the token from the cache, otherwise requests will continue failing!  After
    119  * invalidating the auth token, immediately go back to the "Request an auth
    120  * token" step above.  If the process fails the second time, then it can be
    121  * treated as a "genuine" authentication failure and the user notified or other
    122  * appropriate actions taken.
    123  * </ul>
    124  *
    125  * <p>Some AccountManager methods may need to interact with the user to
    126  * prompt for credentials, present options, or ask the user to add an account.
    127  * The caller may choose whether to allow AccountManager to directly launch the
    128  * necessary user interface and wait for the user, or to return an Intent which
    129  * the caller may use to launch the interface, or (in some cases) to install a
    130  * notification which the user can select at any time to launch the interface.
    131  * To have AccountManager launch the interface directly, the caller must supply
    132  * the current foreground {@link Activity} context.
    133  *
    134  * <p>Many AccountManager methods take {@link AccountManagerCallback} and
    135  * {@link Handler} as parameters.  These methods return immediately and
    136  * run asynchronously. If a callback is provided then
    137  * {@link AccountManagerCallback#run} will be invoked on the Handler's
    138  * thread when the request completes, successfully or not.
    139  * The result is retrieved by calling {@link AccountManagerFuture#getResult()}
    140  * on the {@link AccountManagerFuture} returned by the method (and also passed
    141  * to the callback).  This method waits for the operation to complete (if
    142  * necessary) and either returns the result or throws an exception if an error
    143  * occurred during the operation.  To make the request synchronously, call
    144  * {@link AccountManagerFuture#getResult()} immediately on receiving the
    145  * future from the method; no callback need be supplied.
    146  *
    147  * <p>Requests which may block, including
    148  * {@link AccountManagerFuture#getResult()}, must never be called on
    149  * the application's main event thread.  These operations throw
    150  * {@link IllegalStateException} if they are used on the main thread.
    151  */
    152 public class AccountManager {
    153     private static final String TAG = "AccountManager";
    154 
    155     public static final int ERROR_CODE_REMOTE_EXCEPTION = 1;
    156     public static final int ERROR_CODE_NETWORK_ERROR = 3;
    157     public static final int ERROR_CODE_CANCELED = 4;
    158     public static final int ERROR_CODE_INVALID_RESPONSE = 5;
    159     public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6;
    160     public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
    161     public static final int ERROR_CODE_BAD_REQUEST = 8;
    162     public static final int ERROR_CODE_BAD_AUTHENTICATION = 9;
    163 
    164     /** @hide */
    165     public static final int ERROR_CODE_USER_RESTRICTED = 100;
    166     /** @hide */
    167     public static final int ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE = 101;
    168 
    169     /**
    170      * Bundle key used for the {@link String} account name in results
    171      * from methods which return information about a particular account.
    172      */
    173     public static final String KEY_ACCOUNT_NAME = "authAccount";
    174 
    175     /**
    176      * Bundle key used for the {@link String} account type in results
    177      * from methods which return information about a particular account.
    178      */
    179     public static final String KEY_ACCOUNT_TYPE = "accountType";
    180 
    181     /**
    182      * Bundle key used for the account access id used for noting the
    183      * account was accessed when unmarshalled from a parcel.
    184      *
    185      * @hide
    186      */
    187     public static final String KEY_ACCOUNT_ACCESS_ID = "accountAccessId";
    188 
    189     /**
    190      * Bundle key used for the auth token value in results
    191      * from {@link #getAuthToken} and friends.
    192      */
    193     public static final String KEY_AUTHTOKEN = "authtoken";
    194 
    195     /**
    196      * Bundle key used for an {@link Intent} in results from methods that
    197      * may require the caller to interact with the user.  The Intent can
    198      * be used to start the corresponding user interface activity.
    199      */
    200     public static final String KEY_INTENT = "intent";
    201 
    202     /**
    203      * Bundle key used to supply the password directly in options to
    204      * {@link #confirmCredentials}, rather than prompting the user with
    205      * the standard password prompt.
    206      */
    207     public static final String KEY_PASSWORD = "password";
    208 
    209     public static final String KEY_ACCOUNTS = "accounts";
    210 
    211     public static final String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
    212     public static final String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
    213     public static final String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
    214     public static final String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage";
    215     public static final String KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey";
    216     public static final String KEY_BOOLEAN_RESULT = "booleanResult";
    217     public static final String KEY_ERROR_CODE = "errorCode";
    218     public static final String KEY_ERROR_MESSAGE = "errorMessage";
    219     public static final String KEY_USERDATA = "userdata";
    220 
    221     /**
    222      * Bundle key used to supply the last time the credentials of the account
    223      * were authenticated successfully. Time is specified in milliseconds since
    224      * epoch. Associated time is updated on successful authentication of account
    225      * on adding account, confirming credentials, or updating credentials.
    226      */
    227     public static final String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
    228 
    229     /**
    230      * Authenticators using 'customTokens' option will also get the UID of the
    231      * caller
    232      */
    233     public static final String KEY_CALLER_UID = "callerUid";
    234     public static final String KEY_CALLER_PID = "callerPid";
    235 
    236     /**
    237      * The Android package of the caller will be set in the options bundle by the
    238      * {@link AccountManager} and will be passed to the AccountManagerService and
    239      * to the AccountAuthenticators. The uid of the caller will be known by the
    240      * AccountManagerService as well as the AccountAuthenticators so they will be able to
    241      * verify that the package is consistent with the uid (a uid might be shared by many
    242      * packages).
    243      */
    244     public static final String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
    245 
    246     /**
    247      * Boolean, if set and 'customTokens' the authenticator is responsible for
    248      * notifications.
    249      * @hide
    250      */
    251     public static final String KEY_NOTIFY_ON_FAILURE = "notifyOnAuthFailure";
    252 
    253     /**
    254      * Bundle key used for a {@link Bundle} in result from
    255      * {@link #startAddAccountSession} and friends which returns session data
    256      * for installing an account later.
    257      * @hide
    258      */
    259     @SystemApi
    260     public static final String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
    261 
    262     /**
    263      * Bundle key used for the {@link String} account status token in result
    264      * from {@link #startAddAccountSession} and friends which returns
    265      * information about a particular account.
    266      * @hide
    267      */
    268     @SystemApi
    269     public static final String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
    270 
    271     public static final String ACTION_AUTHENTICATOR_INTENT =
    272             "android.accounts.AccountAuthenticator";
    273     public static final String AUTHENTICATOR_META_DATA_NAME =
    274             "android.accounts.AccountAuthenticator";
    275     public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
    276 
    277     /**
    278      * Token type for the special case where a UID has access only to an account
    279      * but no authenticator specific auth token types.
    280      *
    281      * @hide
    282      */
    283     public static final String ACCOUNT_ACCESS_TOKEN_TYPE =
    284             "com.android.AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE";
    285 
    286     private final Context mContext;
    287     private final IAccountManager mService;
    288     private final Handler mMainHandler;
    289 
    290     /**
    291      * Action sent as a broadcast Intent by the AccountsService
    292      * when accounts are added, accounts are removed, or an
    293      * account's credentials (saved password, etc) are changed.
    294      *
    295      * @see #addOnAccountsUpdatedListener
    296      */
    297     public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
    298         "android.accounts.LOGIN_ACCOUNTS_CHANGED";
    299 
    300     /**
    301      * @hide
    302      */
    303     public AccountManager(Context context, IAccountManager service) {
    304         mContext = context;
    305         mService = service;
    306         mMainHandler = new Handler(mContext.getMainLooper());
    307     }
    308 
    309     /**
    310      * @hide used for testing only
    311      */
    312     public AccountManager(Context context, IAccountManager service, Handler handler) {
    313         mContext = context;
    314         mService = service;
    315         mMainHandler = handler;
    316     }
    317 
    318     /**
    319      * @hide for internal use only
    320      */
    321     public static Bundle sanitizeResult(Bundle result) {
    322         if (result != null) {
    323             if (result.containsKey(KEY_AUTHTOKEN)
    324                     && !TextUtils.isEmpty(result.getString(KEY_AUTHTOKEN))) {
    325                 final Bundle newResult = new Bundle(result);
    326                 newResult.putString(KEY_AUTHTOKEN, "<omitted for logging purposes>");
    327                 return newResult;
    328             }
    329         }
    330         return result;
    331     }
    332 
    333     /**
    334      * Gets an AccountManager instance associated with a Context.
    335      * The {@link Context} will be used as long as the AccountManager is
    336      * active, so make sure to use a {@link Context} whose lifetime is
    337      * commensurate with any listeners registered to
    338      * {@link #addOnAccountsUpdatedListener} or similar methods.
    339      *
    340      * <p>It is safe to call this method from the main thread.
    341      *
    342      * <p>No permission is required to call this method.
    343      *
    344      * @param context The {@link Context} to use when necessary
    345      * @return An {@link AccountManager} instance
    346      */
    347     public static AccountManager get(Context context) {
    348         if (context == null) throw new IllegalArgumentException("context is null");
    349         return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
    350     }
    351 
    352     /**
    353      * Gets the saved password associated with the account.
    354      * This is intended for authenticators and related code; applications
    355      * should get an auth token instead.
    356      *
    357      * <p>It is safe to call this method from the main thread.
    358      *
    359      * <p>This method requires the caller to have a signature match with the
    360      * authenticator that owns the specified account.
    361      *
    362      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
    363      * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs for
    364      * this function in API level 22.
    365      *
    366      * @param account The account to query for a password. Must not be {@code null}.
    367      * @return The account's password, null if none or if the account doesn't exist
    368      */
    369     public String getPassword(final Account account) {
    370         if (account == null) throw new IllegalArgumentException("account is null");
    371         try {
    372             return mService.getPassword(account);
    373         } catch (RemoteException e) {
    374             throw e.rethrowFromSystemServer();
    375         }
    376     }
    377 
    378     /**
    379      * Gets the user data named by "key" associated with the account.
    380      * This is intended for authenticators and related code to store
    381      * arbitrary metadata along with accounts.  The meaning of the keys
    382      * and values is up to the authenticator for the account.
    383      *
    384      * <p>It is safe to call this method from the main thread.
    385      *
    386      * <p>This method requires the caller to have a signature match with the
    387      * authenticator that owns the specified account.
    388      *
    389      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
    390      * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs
    391      * for this function in API level 22.
    392      *
    393      * @param account The account to query for user data
    394      * @return The user data, null if the account or key doesn't exist
    395      */
    396     public String getUserData(final Account account, final String key) {
    397         if (account == null) throw new IllegalArgumentException("account is null");
    398         if (key == null) throw new IllegalArgumentException("key is null");
    399         try {
    400             return mService.getUserData(account, key);
    401         } catch (RemoteException e) {
    402             throw e.rethrowFromSystemServer();
    403         }
    404     }
    405 
    406     /**
    407      * Lists the currently registered authenticators.
    408      *
    409      * <p>It is safe to call this method from the main thread.
    410      *
    411      * <p>No permission is required to call this method.
    412      *
    413      * @return An array of {@link AuthenticatorDescription} for every
    414      *     authenticator known to the AccountManager service.  Empty (never
    415      *     null) if no authenticators are known.
    416      */
    417     public AuthenticatorDescription[] getAuthenticatorTypes() {
    418         try {
    419             return mService.getAuthenticatorTypes(UserHandle.getCallingUserId());
    420         } catch (RemoteException e) {
    421             throw e.rethrowFromSystemServer();
    422         }
    423     }
    424 
    425     /**
    426      * @hide
    427      * Lists the currently registered authenticators for a given user id.
    428      *
    429      * <p>It is safe to call this method from the main thread.
    430      *
    431      * <p>The caller has to be in the same user or have the permission
    432      * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
    433      *
    434      * @return An array of {@link AuthenticatorDescription} for every
    435      *     authenticator known to the AccountManager service.  Empty (never
    436      *     null) if no authenticators are known.
    437      */
    438     public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) {
    439         try {
    440             return mService.getAuthenticatorTypes(userId);
    441         } catch (RemoteException e) {
    442             throw e.rethrowFromSystemServer();
    443         }
    444     }
    445 
    446     /**
    447      * Lists all accounts of any type registered on the device.
    448      * Equivalent to getAccountsByType(null).
    449      *
    450      * <p>It is safe to call this method from the main thread.
    451      *
    452      * <p>Clients of this method that have not been granted the
    453      * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
    454      * will only see those accounts managed by AbstractAccountAuthenticators whose
    455      * signature matches the client.
    456      *
    457      * @return An array of {@link Account}, one for each account.  Empty
    458      *     (never null) if no accounts have been added.
    459      */
    460     @NonNull
    461     @RequiresPermission(GET_ACCOUNTS)
    462     public Account[] getAccounts() {
    463         try {
    464             return mService.getAccounts(null, mContext.getOpPackageName());
    465         } catch (RemoteException e) {
    466             throw e.rethrowFromSystemServer();
    467         }
    468     }
    469 
    470     /**
    471      * @hide
    472      * Lists all accounts of any type registered on the device for a given
    473      * user id. Equivalent to getAccountsByType(null).
    474      *
    475      * <p>It is safe to call this method from the main thread.
    476      *
    477      * <p>Clients of this method that have not been granted the
    478      * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
    479      * will only see those accounts managed by AbstractAccountAuthenticators whose
    480      * signature matches the client.
    481      *
    482      * @return An array of {@link Account}, one for each account.  Empty
    483      *     (never null) if no accounts have been added.
    484      */
    485     @NonNull
    486     @RequiresPermission(GET_ACCOUNTS)
    487     public Account[] getAccountsAsUser(int userId) {
    488         try {
    489             return mService.getAccountsAsUser(null, userId, mContext.getOpPackageName());
    490         } catch (RemoteException e) {
    491             throw e.rethrowFromSystemServer();
    492         }
    493     }
    494 
    495     /**
    496      * @hide
    497      * For use by internal activities. Returns the list of accounts that the calling package
    498      * is authorized to use, particularly for shared accounts.
    499      * @param packageName package name of the calling app.
    500      * @param uid the uid of the calling app.
    501      * @return the accounts that are available to this package and user.
    502      */
    503     @NonNull
    504     public Account[] getAccountsForPackage(String packageName, int uid) {
    505         try {
    506             return mService.getAccountsForPackage(packageName, uid, mContext.getOpPackageName());
    507         } catch (RemoteException re) {
    508             throw re.rethrowFromSystemServer();
    509         }
    510     }
    511 
    512     /**
    513      * Returns the accounts visible to the specified package, in an environment where some apps
    514      * are not authorized to view all accounts. This method can only be called by system apps.
    515      * @param type The type of accounts to return, null to retrieve all accounts
    516      * @param packageName The package name of the app for which the accounts are to be returned
    517      * @return An array of {@link Account}, one per matching account.  Empty
    518      *     (never null) if no accounts of the specified type have been added.
    519      */
    520     @NonNull
    521     public Account[] getAccountsByTypeForPackage(String type, String packageName) {
    522         try {
    523             return mService.getAccountsByTypeForPackage(type, packageName,
    524                     mContext.getOpPackageName());
    525         } catch (RemoteException re) {
    526             throw re.rethrowFromSystemServer();
    527         }
    528     }
    529 
    530     /**
    531      * Lists all accounts of a particular type.  The account type is a
    532      * string token corresponding to the authenticator and useful domain
    533      * of the account.  For example, there are types corresponding to Google
    534      * and Facebook.  The exact string token to use will be published somewhere
    535      * associated with the authenticator in question.
    536      *
    537      * <p>It is safe to call this method from the main thread.
    538      *
    539      * <p>Clients of this method that have not been granted the
    540      * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
    541      * will only see those accounts managed by AbstractAccountAuthenticators whose
    542      * signature matches the client.
    543      *
    544      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
    545      * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
    546      * or signature match. See docs for this function in API level 22.
    547      *
    548      * @param type The type of accounts to return, null to retrieve all accounts
    549      * @return An array of {@link Account}, one per matching account.  Empty
    550      *     (never null) if no accounts of the specified type have been added.
    551      */
    552     @NonNull
    553     @RequiresPermission(GET_ACCOUNTS)
    554     public Account[] getAccountsByType(String type) {
    555         return getAccountsByTypeAsUser(type, Process.myUserHandle());
    556     }
    557 
    558     /** @hide Same as {@link #getAccountsByType(String)} but for a specific user. */
    559     @NonNull
    560     public Account[] getAccountsByTypeAsUser(String type, UserHandle userHandle) {
    561         try {
    562             return mService.getAccountsAsUser(type, userHandle.getIdentifier(),
    563                     mContext.getOpPackageName());
    564         } catch (RemoteException e) {
    565             throw e.rethrowFromSystemServer();
    566         }
    567     }
    568 
    569     /**
    570      * Change whether or not an app (identified by its uid) is allowed to retrieve an authToken
    571      * for an account.
    572      * <p>
    573      * This is only meant to be used by system activities and is not in the SDK.
    574      * @param account The account whose permissions are being modified
    575      * @param authTokenType The type of token whose permissions are being modified
    576      * @param uid The uid that identifies the app which is being granted or revoked permission.
    577      * @param value true is permission is being granted, false for revoked
    578      * @hide
    579      */
    580     public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) {
    581         try {
    582             mService.updateAppPermission(account, authTokenType, uid, value);
    583         } catch (RemoteException e) {
    584             throw e.rethrowFromSystemServer();
    585         }
    586     }
    587 
    588     /**
    589      * Get the user-friendly label associated with an authenticator's auth token.
    590      * @param accountType the type of the authenticator. must not be null.
    591      * @param authTokenType the token type. must not be null.
    592      * @param callback callback to invoke when the result is available. may be null.
    593      * @param handler the handler on which to invoke the callback, or null for the main thread
    594      * @return a future containing the label string
    595      * @hide
    596      */
    597     public AccountManagerFuture<String> getAuthTokenLabel(
    598             final String accountType, final String authTokenType,
    599             AccountManagerCallback<String> callback, Handler handler) {
    600         if (accountType == null) throw new IllegalArgumentException("accountType is null");
    601         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
    602         return new Future2Task<String>(handler, callback) {
    603             @Override
    604             public void doWork() throws RemoteException {
    605                 mService.getAuthTokenLabel(mResponse, accountType, authTokenType);
    606             }
    607 
    608             @Override
    609             public String bundleToResult(Bundle bundle) throws AuthenticatorException {
    610                 if (!bundle.containsKey(KEY_AUTH_TOKEN_LABEL)) {
    611                     throw new AuthenticatorException("no result in response");
    612                 }
    613                 return bundle.getString(KEY_AUTH_TOKEN_LABEL);
    614             }
    615         }.start();
    616     }
    617 
    618     /**
    619      * Finds out whether a particular account has all the specified features.
    620      * Account features are authenticator-specific string tokens identifying
    621      * boolean account properties.  For example, features are used to tell
    622      * whether Google accounts have a particular service (such as Google
    623      * Calendar or Google Talk) enabled.  The feature names and their meanings
    624      * are published somewhere associated with the authenticator in question.
    625      *
    626      * <p>This method may be called from any thread, but the returned
    627      * {@link AccountManagerFuture} must not be used on the main thread.
    628      *
    629      * <p>This method requires the caller to hold the permission
    630      * {@link android.Manifest.permission#GET_ACCOUNTS} or be a signature
    631      * match with the AbstractAccountAuthenticator that manages the account.
    632      *
    633      * @param account The {@link Account} to test
    634      * @param features An array of the account features to check
    635      * @param callback Callback to invoke when the request completes,
    636      *     null for no callback
    637      * @param handler {@link Handler} identifying the callback thread,
    638      *     null for the main thread
    639      * @return An {@link AccountManagerFuture} which resolves to a Boolean,
    640      * true if the account exists and has all of the specified features.
    641      */
    642     @RequiresPermission(GET_ACCOUNTS)
    643     public AccountManagerFuture<Boolean> hasFeatures(final Account account,
    644             final String[] features,
    645             AccountManagerCallback<Boolean> callback, Handler handler) {
    646         if (account == null) throw new IllegalArgumentException("account is null");
    647         if (features == null) throw new IllegalArgumentException("features is null");
    648         return new Future2Task<Boolean>(handler, callback) {
    649             @Override
    650             public void doWork() throws RemoteException {
    651                 mService.hasFeatures(mResponse, account, features, mContext.getOpPackageName());
    652             }
    653             @Override
    654             public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
    655                 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
    656                     throw new AuthenticatorException("no result in response");
    657                 }
    658                 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
    659             }
    660         }.start();
    661     }
    662 
    663     /**
    664      * Lists all accounts of a type which have certain features.  The account
    665      * type identifies the authenticator (see {@link #getAccountsByType}).
    666      * Account features are authenticator-specific string tokens identifying
    667      * boolean account properties (see {@link #hasFeatures}).
    668      *
    669      * <p>Unlike {@link #getAccountsByType}, this method calls the authenticator,
    670      * which may contact the server or do other work to check account features,
    671      * so the method returns an {@link AccountManagerFuture}.
    672      *
    673      * <p>This method may be called from any thread, but the returned
    674      * {@link AccountManagerFuture} must not be used on the main thread.
    675      *
    676      * <p>Clients of this method that have not been granted the
    677      * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
    678      * will only see those accounts managed by AbstractAccountAuthenticators whose
    679      * signature matches the client.
    680      *
    681      * @param type The type of accounts to return, must not be null
    682      * @param features An array of the account features to require,
    683      *     may be null or empty
    684      *
    685      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
    686      * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
    687      * or signature match. See docs for this function in API level 22.
    688      *
    689      * @param callback Callback to invoke when the request completes,
    690      *     null for no callback
    691      * @param handler {@link Handler} identifying the callback thread,
    692      *     null for the main thread
    693      * @return An {@link AccountManagerFuture} which resolves to an array of
    694      *     {@link Account}, one per account of the specified type which
    695      *     matches the requested features.
    696      */
    697     @RequiresPermission(GET_ACCOUNTS)
    698     public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
    699             final String type, final String[] features,
    700             AccountManagerCallback<Account[]> callback, Handler handler) {
    701         if (type == null) throw new IllegalArgumentException("type is null");
    702         return new Future2Task<Account[]>(handler, callback) {
    703             @Override
    704             public void doWork() throws RemoteException {
    705                 mService.getAccountsByFeatures(mResponse, type, features,
    706                         mContext.getOpPackageName());
    707             }
    708             @Override
    709             public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
    710                 if (!bundle.containsKey(KEY_ACCOUNTS)) {
    711                     throw new AuthenticatorException("no result in response");
    712                 }
    713                 final Parcelable[] parcelables = bundle.getParcelableArray(KEY_ACCOUNTS);
    714                 Account[] descs = new Account[parcelables.length];
    715                 for (int i = 0; i < parcelables.length; i++) {
    716                     descs[i] = (Account) parcelables[i];
    717                 }
    718                 return descs;
    719             }
    720         }.start();
    721     }
    722 
    723     /**
    724      * Adds an account directly to the AccountManager. Normally used by sign-up
    725      * wizards associated with authenticators, not directly by applications.
    726      * <p>Calling this method does not update the last authenticated timestamp,
    727      * referred by {@link #KEY_LAST_AUTHENTICATED_TIME}. To update it, call
    728      * {@link #notifyAccountAuthenticated(Account)} after getting success.
    729      * However, if this method is called when it is triggered by addAccount() or
    730      * addAccountAsUser() or similar functions, then there is no need to update
    731      * timestamp manually as it is updated automatically by framework on
    732      * successful completion of the mentioned functions.
    733      * <p>It is safe to call this method from the main thread.
    734      * <p>This method requires the caller to have a signature match with the
    735      * authenticator that owns the specified account.
    736      *
    737      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
    738      * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs
    739      * for this function in API level 22.
    740      *
    741      * @param account The {@link Account} to add
    742      * @param password The password to associate with the account, null for none
    743      * @param userdata String values to use for the account's userdata, null for
    744      *            none
    745      * @return True if the account was successfully added, false if the account
    746      *         already exists, the account is null, or another error occurs.
    747      */
    748     public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
    749         if (account == null) throw new IllegalArgumentException("account is null");
    750         try {
    751             return mService.addAccountExplicitly(account, password, userdata);
    752         } catch (RemoteException e) {
    753             throw e.rethrowFromSystemServer();
    754         }
    755     }
    756 
    757     /**
    758      * Notifies the system that the account has just been authenticated. This
    759      * information may be used by other applications to verify the account. This
    760      * should be called only when the user has entered correct credentials for
    761      * the account.
    762      * <p>
    763      * It is not safe to call this method from the main thread. As such, call it
    764      * from another thread.
    765      * <p>This method requires the caller to have a signature match with the
    766      * authenticator that owns the specified account.
    767      *
    768      * @param account The {@link Account} to be updated.
    769      * @return boolean {@code true} if the authentication of the account has been successfully
    770      *         acknowledged. Otherwise {@code false}.
    771      */
    772     public boolean notifyAccountAuthenticated(Account account) {
    773         if (account == null)
    774             throw new IllegalArgumentException("account is null");
    775         try {
    776             return mService.accountAuthenticated(account);
    777         } catch (RemoteException e) {
    778             throw e.rethrowFromSystemServer();
    779         }
    780     }
    781 
    782     /**
    783      * Rename the specified {@link Account}.  This is equivalent to removing
    784      * the existing account and adding a new renamed account with the old
    785      * account's user data.
    786      *
    787      * <p>It is safe to call this method from the main thread.
    788      *
    789      * <p>This method requires the caller to have a signature match with the
    790      * authenticator that manages the specified account.
    791      *
    792      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
    793      * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
    794      * is needed for those platforms. See docs for this function in API level 22.
    795      *
    796      * @param account The {@link Account} to rename
    797      * @param newName String name to be associated with the account.
    798      * @param callback Callback to invoke when the request completes, null for
    799      *     no callback
    800      * @param handler {@link Handler} identifying the callback thread, null for
    801      *     the main thread
    802      * @return An {@link AccountManagerFuture} which resolves to the Account
    803      *     after the name change. If successful the account's name will be the
    804      *     specified new name.
    805      */
    806     public AccountManagerFuture<Account> renameAccount(
    807             final Account account,
    808             @Size(min = 1) final String newName,
    809             AccountManagerCallback<Account> callback,
    810             Handler handler) {
    811         if (account == null) throw new IllegalArgumentException("account is null.");
    812         if (TextUtils.isEmpty(newName)) {
    813               throw new IllegalArgumentException("newName is empty or null.");
    814         }
    815         return new Future2Task<Account>(handler, callback) {
    816             @Override
    817             public void doWork() throws RemoteException {
    818                 mService.renameAccount(mResponse, account, newName);
    819             }
    820             @Override
    821             public Account bundleToResult(Bundle bundle) throws AuthenticatorException {
    822                 String name = bundle.getString(KEY_ACCOUNT_NAME);
    823                 String type = bundle.getString(KEY_ACCOUNT_TYPE);
    824                 String accessId = bundle.getString(KEY_ACCOUNT_ACCESS_ID);
    825                 return new Account(name, type, accessId);
    826             }
    827         }.start();
    828     }
    829 
    830     /**
    831      * Gets the previous name associated with the account or {@code null}, if
    832      * none. This is intended so that clients of {@link
    833      * #LOGIN_ACCOUNTS_CHANGED_ACTION} broadcasts can determine if an
    834      * authenticator has renamed an account.
    835      *
    836      * <p>It is safe to call this method from the main thread.
    837      *
    838      * @param account The account to query for a previous name.
    839      * @return The account's previous name, null if the account has never been
    840      *         renamed.
    841      */
    842     public String getPreviousName(final Account account) {
    843         if (account == null) throw new IllegalArgumentException("account is null");
    844         try {
    845             return mService.getPreviousName(account);
    846         } catch (RemoteException e) {
    847             throw e.rethrowFromSystemServer();
    848         }
    849     }
    850 
    851     /**
    852      * Removes an account from the AccountManager.  Does nothing if the account
    853      * does not exist.  Does not delete the account from the server.
    854      * The authenticator may have its own policies preventing account
    855      * deletion, in which case the account will not be deleted.
    856      *
    857      * <p>This method requires the caller to have a signature match with the
    858      * authenticator that manages the specified account.
    859      *
    860      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
    861      * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
    862      * this function in API level 22.
    863      *
    864      * @param account The {@link Account} to remove
    865      * @param callback Callback to invoke when the request completes,
    866      *     null for no callback
    867      * @param handler {@link Handler} identifying the callback thread,
    868      *     null for the main thread
    869      * @return An {@link AccountManagerFuture} which resolves to a Boolean,
    870      *     true if the account has been successfully removed
    871      * @deprecated use
    872      *     {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)}
    873      *     instead
    874      */
    875     @Deprecated
    876     public AccountManagerFuture<Boolean> removeAccount(final Account account,
    877             AccountManagerCallback<Boolean> callback, Handler handler) {
    878         if (account == null) throw new IllegalArgumentException("account is null");
    879         return new Future2Task<Boolean>(handler, callback) {
    880             @Override
    881             public void doWork() throws RemoteException {
    882                 mService.removeAccount(mResponse, account, false);
    883             }
    884             @Override
    885             public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
    886                 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
    887                     throw new AuthenticatorException("no result in response");
    888                 }
    889                 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
    890             }
    891         }.start();
    892     }
    893 
    894     /**
    895      * Removes an account from the AccountManager. Does nothing if the account
    896      * does not exist.  Does not delete the account from the server.
    897      * The authenticator may have its own policies preventing account
    898      * deletion, in which case the account will not be deleted.
    899      *
    900      * <p>This method may be called from any thread, but the returned
    901      * {@link AccountManagerFuture} must not be used on the main thread.
    902      *
    903      * <p>This method requires the caller to have a signature match with the
    904      * authenticator that manages the specified account.
    905      *
    906      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
    907      * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
    908      * this function in API level 22.
    909      *
    910      * @param account The {@link Account} to remove
    911      * @param activity The {@link Activity} context to use for launching a new
    912      *     authenticator-defined sub-Activity to prompt the user to delete an
    913      *     account; used only to call startActivity(); if null, the prompt
    914      *     will not be launched directly, but the {@link Intent} may be
    915      *     returned to the caller instead
    916      * @param callback Callback to invoke when the request completes,
    917      *     null for no callback
    918      * @param handler {@link Handler} identifying the callback thread,
    919      *     null for the main thread
    920      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
    921      *     {@link #KEY_BOOLEAN_RESULT} if activity was specified and an account
    922      *     was removed or if active. If no activity was specified, the returned
    923      *     Bundle contains only {@link #KEY_INTENT} with the {@link Intent}
    924      *     needed to launch the actual account removal process, if authenticator
    925      *     needs the activity launch. If an error occurred,
    926      *     {@link AccountManagerFuture#getResult()} throws:
    927      * <ul>
    928      * <li> {@link AuthenticatorException} if no authenticator was registered for
    929      *      this account type or the authenticator failed to respond
    930      * <li> {@link OperationCanceledException} if the operation was canceled for
    931      *      any reason, including the user canceling the creation process or
    932      *      adding accounts (of this type) has been disabled by policy
    933      * </ul>
    934      */
    935     public AccountManagerFuture<Bundle> removeAccount(final Account account,
    936             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
    937         if (account == null) throw new IllegalArgumentException("account is null");
    938         return new AmsTask(activity, handler, callback) {
    939             @Override
    940             public void doWork() throws RemoteException {
    941                 mService.removeAccount(mResponse, account, activity != null);
    942             }
    943         }.start();
    944     }
    945 
    946     /**
    947      * @see #removeAccount(Account, AccountManagerCallback, Handler)
    948      * @hide
    949      * @deprecated use
    950      *     {@link #removeAccountAsUser(Account, Activity, AccountManagerCallback, Handler)}
    951      *     instead
    952      */
    953     @Deprecated
    954     public AccountManagerFuture<Boolean> removeAccountAsUser(final Account account,
    955             AccountManagerCallback<Boolean> callback, Handler handler,
    956             final UserHandle userHandle) {
    957         if (account == null) throw new IllegalArgumentException("account is null");
    958         if (userHandle == null) throw new IllegalArgumentException("userHandle is null");
    959         return new Future2Task<Boolean>(handler, callback) {
    960             @Override
    961             public void doWork() throws RemoteException {
    962                 mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier());
    963             }
    964             @Override
    965             public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
    966                 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
    967                     throw new AuthenticatorException("no result in response");
    968                 }
    969                 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
    970             }
    971         }.start();
    972     }
    973 
    974     /**
    975      * @see #removeAccount(Account, Activity, AccountManagerCallback, Handler)
    976      * @hide
    977      */
    978     public AccountManagerFuture<Bundle> removeAccountAsUser(final Account account,
    979             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler,
    980             final UserHandle userHandle) {
    981         if (account == null)
    982             throw new IllegalArgumentException("account is null");
    983         if (userHandle == null)
    984             throw new IllegalArgumentException("userHandle is null");
    985         return new AmsTask(activity, handler, callback) {
    986             @Override
    987             public void doWork() throws RemoteException {
    988                 mService.removeAccountAsUser(mResponse, account, activity != null,
    989                         userHandle.getIdentifier());
    990             }
    991         }.start();
    992     }
    993 
    994     /**
    995      * Removes an account directly. Normally used by authenticators, not
    996      * directly by applications. Does not delete the account from the server.
    997      * The authenticator may have its own policies preventing account deletion,
    998      * in which case the account will not be deleted.
    999      * <p>
   1000      * It is safe to call this method from the main thread.
   1001      * <p>This method requires the caller to have a signature match with the
   1002      * authenticator that manages the specified account.
   1003      *
   1004      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1005      * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
   1006      * is needed for those platforms. See docs for this function in API level 22.
   1007      *
   1008      * @param account The {@link Account} to delete.
   1009      * @return True if the account was successfully deleted, false if the
   1010      *         account did not exist, the account is null, or another error
   1011      *         occurs.
   1012      */
   1013     public boolean removeAccountExplicitly(Account account) {
   1014         if (account == null) throw new IllegalArgumentException("account is null");
   1015         try {
   1016             return mService.removeAccountExplicitly(account);
   1017         } catch (RemoteException e) {
   1018             throw e.rethrowFromSystemServer();
   1019         }
   1020     }
   1021 
   1022     /**
   1023      * Removes an auth token from the AccountManager's cache.  Does nothing if
   1024      * the auth token is not currently in the cache.  Applications must call this
   1025      * method when the auth token is found to have expired or otherwise become
   1026      * invalid for authenticating requests.  The AccountManager does not validate
   1027      * or expire cached auth tokens otherwise.
   1028      *
   1029      * <p>It is safe to call this method from the main thread.
   1030      *
   1031      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1032      * MANAGE_ACCOUNTS or USE_CREDENTIALS permission is needed for those
   1033      * platforms. See docs for this function in API level 22.
   1034      *
   1035      * @param accountType The account type of the auth token to invalidate, must not be null
   1036      * @param authToken The auth token to invalidate, may be null
   1037      */
   1038     public void invalidateAuthToken(final String accountType, final String authToken) {
   1039         if (accountType == null) throw new IllegalArgumentException("accountType is null");
   1040         try {
   1041             if (authToken != null) {
   1042                 mService.invalidateAuthToken(accountType, authToken);
   1043             }
   1044         } catch (RemoteException e) {
   1045             throw e.rethrowFromSystemServer();
   1046         }
   1047     }
   1048 
   1049     /**
   1050      * Gets an auth token from the AccountManager's cache.  If no auth
   1051      * token is cached for this account, null will be returned -- a new
   1052      * auth token will not be generated, and the server will not be contacted.
   1053      * Intended for use by the authenticator, not directly by applications.
   1054      *
   1055      * <p>It is safe to call this method from the main thread.
   1056      *
   1057      * <p>This method requires the caller to have a signature match with the
   1058      * authenticator that manages the specified account.
   1059      *
   1060      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1061      * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
   1062      * is needed for those platforms. See docs for this function in API level 22.
   1063      *
   1064      * @param account The account for which an auth token is to be fetched. Cannot be {@code null}.
   1065      * @param authTokenType The type of auth token to fetch. Cannot be {@code null}.
   1066      * @return The cached auth token for this account and type, or null if
   1067      *     no auth token is cached or the account does not exist.
   1068      * @see #getAuthToken
   1069      */
   1070     public String peekAuthToken(final Account account, final String authTokenType) {
   1071         if (account == null) throw new IllegalArgumentException("account is null");
   1072         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
   1073         try {
   1074             return mService.peekAuthToken(account, authTokenType);
   1075         } catch (RemoteException e) {
   1076             throw e.rethrowFromSystemServer();
   1077         }
   1078     }
   1079 
   1080     /**
   1081      * Sets or forgets a saved password. This modifies the local copy of the
   1082      * password used to automatically authenticate the user; it does not change
   1083      * the user's account password on the server. Intended for use by the
   1084      * authenticator, not directly by applications.
   1085      * <p>Calling this method does not update the last authenticated timestamp,
   1086      * referred by {@link #KEY_LAST_AUTHENTICATED_TIME}. To update it, call
   1087      * {@link #notifyAccountAuthenticated(Account)} after getting success.
   1088      * <p>It is safe to call this method from the main thread.
   1089      * <p>This method requires the caller to have a signature match with the
   1090      * authenticator that manages the specified account.
   1091      *
   1092      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1093      * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
   1094      * is needed for those platforms. See docs for this function in API level 22.
   1095      *
   1096      * @param account The account whose password is to be set. Cannot be
   1097      *            {@code null}.
   1098      * @param password The password to set, null to clear the password
   1099      */
   1100     public void setPassword(final Account account, final String password) {
   1101         if (account == null) throw new IllegalArgumentException("account is null");
   1102         try {
   1103             mService.setPassword(account, password);
   1104         } catch (RemoteException e) {
   1105             throw e.rethrowFromSystemServer();
   1106         }
   1107     }
   1108 
   1109     /**
   1110      * Forgets a saved password.  This erases the local copy of the password;
   1111      * it does not change the user's account password on the server.
   1112      * Has the same effect as setPassword(account, null) but requires fewer
   1113      * permissions, and may be used by applications or management interfaces
   1114      * to "sign out" from an account.
   1115      *
   1116      * <p>This method only successfully clear the account's password when the
   1117      * caller has the same signature as the authenticator that owns the
   1118      * specified account. Otherwise, this method will silently fail.
   1119      *
   1120      * <p>It is safe to call this method from the main thread.
   1121      *
   1122      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1123      * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
   1124      * this function in API level 22.
   1125      *
   1126      * @param account The account whose password to clear
   1127      */
   1128     public void clearPassword(final Account account) {
   1129         if (account == null) throw new IllegalArgumentException("account is null");
   1130         try {
   1131             mService.clearPassword(account);
   1132         } catch (RemoteException e) {
   1133             throw e.rethrowFromSystemServer();
   1134         }
   1135     }
   1136 
   1137     /**
   1138      * Sets one userdata key for an account.  Intended by use for the
   1139      * authenticator to stash state for itself, not directly by applications.
   1140      * The meaning of the keys and values is up to the authenticator.
   1141      *
   1142      * <p>It is safe to call this method from the main thread.
   1143      *
   1144      * <p>This method requires the caller to have a signature match with the
   1145      * authenticator that manages the specified account.
   1146      *
   1147      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1148      * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
   1149      * is needed for those platforms. See docs for this function in API level 22.
   1150      *
   1151      * @param account Account whose user data is to be set. Must not be {@code null}.
   1152      * @param key String user data key to set.  Must not be null
   1153      * @param value String value to set, {@code null} to clear this user data key
   1154      */
   1155     public void setUserData(final Account account, final String key, final String value) {
   1156         if (account == null) throw new IllegalArgumentException("account is null");
   1157         if (key == null) throw new IllegalArgumentException("key is null");
   1158         try {
   1159             mService.setUserData(account, key, value);
   1160         } catch (RemoteException e) {
   1161             throw e.rethrowFromSystemServer();
   1162         }
   1163     }
   1164 
   1165     /**
   1166      * Adds an auth token to the AccountManager cache for an account.
   1167      * If the account does not exist then this call has no effect.
   1168      * Replaces any previous auth token for this account and auth token type.
   1169      * Intended for use by the authenticator, not directly by applications.
   1170      *
   1171      * <p>It is safe to call this method from the main thread.
   1172      *
   1173      * <p>This method requires the caller to have a signature match with the
   1174      * authenticator that manages the specified account.
   1175      *
   1176      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1177      * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
   1178      * is needed for those platforms. See docs for this function in API level 22.
   1179      *
   1180      * @param account The account to set an auth token for
   1181      * @param authTokenType The type of the auth token, see {#getAuthToken}
   1182      * @param authToken The auth token to add to the cache
   1183      */
   1184     public void setAuthToken(Account account, final String authTokenType, final String authToken) {
   1185         if (account == null) throw new IllegalArgumentException("account is null");
   1186         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
   1187         try {
   1188             mService.setAuthToken(account, authTokenType, authToken);
   1189         } catch (RemoteException e) {
   1190             throw e.rethrowFromSystemServer();
   1191         }
   1192     }
   1193 
   1194     /**
   1195      * This convenience helper synchronously gets an auth token with
   1196      * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, Handler)}.
   1197      *
   1198      * <p>This method may block while a network request completes, and must
   1199      * never be made from the main thread.
   1200      *
   1201      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1202      * USE_CREDENTIALS permission is needed for those platforms. See docs for
   1203      * this function in API level 22.
   1204      *
   1205      * @param account The account to fetch an auth token for
   1206      * @param authTokenType The auth token type, see {@link #getAuthToken getAuthToken()}
   1207      * @param notifyAuthFailure If true, display a notification and return null
   1208      *     if authentication fails; if false, prompt and wait for the user to
   1209      *     re-enter correct credentials before returning
   1210      * @return An auth token of the specified type for this account, or null
   1211      *     if authentication fails or none can be fetched.
   1212      * @throws AuthenticatorException if the authenticator failed to respond
   1213      * @throws OperationCanceledException if the request was canceled for any
   1214      *     reason, including the user canceling a credential request
   1215      * @throws java.io.IOException if the authenticator experienced an I/O problem
   1216      *     creating a new auth token, usually because of network trouble
   1217      */
   1218     public String blockingGetAuthToken(Account account, String authTokenType,
   1219             boolean notifyAuthFailure)
   1220             throws OperationCanceledException, IOException, AuthenticatorException {
   1221         if (account == null) throw new IllegalArgumentException("account is null");
   1222         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
   1223         Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */,
   1224                 null /* handler */).getResult();
   1225         if (bundle == null) {
   1226             // This should never happen, but it does, occasionally. If it does return null to
   1227             // signify that we were not able to get the authtoken.
   1228             // TODO: remove this when the bug is found that sometimes causes a null bundle to be
   1229             // returned
   1230             Log.e(TAG, "blockingGetAuthToken: null was returned from getResult() for "
   1231                     + account + ", authTokenType " + authTokenType);
   1232             return null;
   1233         }
   1234         return bundle.getString(KEY_AUTHTOKEN);
   1235     }
   1236 
   1237     /**
   1238      * Gets an auth token of the specified type for a particular account,
   1239      * prompting the user for credentials if necessary.  This method is
   1240      * intended for applications running in the foreground where it makes
   1241      * sense to ask the user directly for a password.
   1242      *
   1243      * <p>If a previously generated auth token is cached for this account and
   1244      * type, then it is returned.  Otherwise, if a saved password is
   1245      * available, it is sent to the server to generate a new auth token.
   1246      * Otherwise, the user is prompted to enter a password.
   1247      *
   1248      * <p>Some authenticators have auth token <em>types</em>, whose value
   1249      * is authenticator-dependent.  Some services use different token types to
   1250      * access different functionality -- for example, Google uses different auth
   1251      * tokens to access Gmail and Google Calendar for the same account.
   1252      *
   1253      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1254      * USE_CREDENTIALS permission is needed for those platforms. See docs for
   1255      * this function in API level 22.
   1256      *
   1257      * <p>This method may be called from any thread, but the returned
   1258      * {@link AccountManagerFuture} must not be used on the main thread.
   1259      *
   1260      * @param account The account to fetch an auth token for
   1261      * @param authTokenType The auth token type, an authenticator-dependent
   1262      *     string token, must not be null
   1263      * @param options Authenticator-specific options for the request,
   1264      *     may be null or empty
   1265      * @param activity The {@link Activity} context to use for launching a new
   1266      *     authenticator-defined sub-Activity to prompt the user for a password
   1267      *     if necessary; used only to call startActivity(); must not be null.
   1268      * @param callback Callback to invoke when the request completes,
   1269      *     null for no callback
   1270      * @param handler {@link Handler} identifying the callback thread,
   1271      *     null for the main thread
   1272      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
   1273      *     at least the following fields:
   1274      * <ul>
   1275      * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
   1276      * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
   1277      * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
   1278      * </ul>
   1279      *
   1280      * (Other authenticator-specific values may be returned.)  If an auth token
   1281      * could not be fetched, {@link AccountManagerFuture#getResult()} throws:
   1282      * <ul>
   1283      * <li> {@link AuthenticatorException} if the authenticator failed to respond
   1284      * <li> {@link OperationCanceledException} if the operation is canceled for
   1285      *      any reason, incluidng the user canceling a credential request
   1286      * <li> {@link IOException} if the authenticator experienced an I/O problem
   1287      *      creating a new auth token, usually because of network trouble
   1288      * </ul>
   1289      * If the account is no longer present on the device, the return value is
   1290      * authenticator-dependent.  The caller should verify the validity of the
   1291      * account before requesting an auth token.
   1292      */
   1293     public AccountManagerFuture<Bundle> getAuthToken(
   1294             final Account account, final String authTokenType, final Bundle options,
   1295             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
   1296         if (account == null) throw new IllegalArgumentException("account is null");
   1297         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
   1298         final Bundle optionsIn = new Bundle();
   1299         if (options != null) {
   1300             optionsIn.putAll(options);
   1301         }
   1302         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
   1303         return new AmsTask(activity, handler, callback) {
   1304             @Override
   1305             public void doWork() throws RemoteException {
   1306                 mService.getAuthToken(mResponse, account, authTokenType,
   1307                         false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
   1308                         optionsIn);
   1309             }
   1310         }.start();
   1311     }
   1312 
   1313     /**
   1314      * Gets an auth token of the specified type for a particular account,
   1315      * optionally raising a notification if the user must enter credentials.
   1316      * This method is intended for background tasks and services where the
   1317      * user should not be immediately interrupted with a password prompt.
   1318      *
   1319      * <p>If a previously generated auth token is cached for this account and
   1320      * type, then it is returned.  Otherwise, if a saved password is
   1321      * available, it is sent to the server to generate a new auth token.
   1322      * Otherwise, an {@link Intent} is returned which, when started, will
   1323      * prompt the user for a password.  If the notifyAuthFailure parameter is
   1324      * set, a status bar notification is also created with the same Intent,
   1325      * alerting the user that they need to enter a password at some point.
   1326      *
   1327      * <p>In that case, you may need to wait until the user responds, which
   1328      * could take hours or days or forever.  When the user does respond and
   1329      * supply a new password, the account manager will broadcast the
   1330      * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
   1331      * use to try again.
   1332      *
   1333      * <p>If notifyAuthFailure is not set, it is the application's
   1334      * responsibility to launch the returned Intent at some point.
   1335      * Either way, the result from this call will not wait for user action.
   1336      *
   1337      * <p>Some authenticators have auth token <em>types</em>, whose value
   1338      * is authenticator-dependent.  Some services use different token types to
   1339      * access different functionality -- for example, Google uses different auth
   1340      * tokens to access Gmail and Google Calendar for the same account.
   1341      *
   1342      * <p>This method may be called from any thread, but the returned
   1343      * {@link AccountManagerFuture} must not be used on the main thread.
   1344      *
   1345      * @param account The account to fetch an auth token for
   1346      * @param authTokenType The auth token type, an authenticator-dependent
   1347      *     string token, must not be null
   1348      * @param notifyAuthFailure True to add a notification to prompt the
   1349      *     user for a password if necessary, false to leave that to the caller
   1350      * @param callback Callback to invoke when the request completes,
   1351      *     null for no callback
   1352      * @param handler {@link Handler} identifying the callback thread,
   1353      *     null for the main thread
   1354      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
   1355      *     at least the following fields on success:
   1356      * <ul>
   1357      * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
   1358      * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
   1359      * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
   1360      * </ul>
   1361      *
   1362      * (Other authenticator-specific values may be returned.)  If the user
   1363      * must enter credentials, the returned Bundle contains only
   1364      * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
   1365      *
   1366      * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
   1367      * <ul>
   1368      * <li> {@link AuthenticatorException} if the authenticator failed to respond
   1369      * <li> {@link OperationCanceledException} if the operation is canceled for
   1370      *      any reason, incluidng the user canceling a credential request
   1371      * <li> {@link IOException} if the authenticator experienced an I/O problem
   1372      *      creating a new auth token, usually because of network trouble
   1373      * </ul>
   1374      * If the account is no longer present on the device, the return value is
   1375      * authenticator-dependent.  The caller should verify the validity of the
   1376      * account before requesting an auth token.
   1377      * @deprecated use {@link #getAuthToken(Account, String, android.os.Bundle,
   1378      * boolean, AccountManagerCallback, android.os.Handler)} instead
   1379      */
   1380     @Deprecated
   1381     public AccountManagerFuture<Bundle> getAuthToken(
   1382             final Account account, final String authTokenType,
   1383             final boolean notifyAuthFailure,
   1384             AccountManagerCallback<Bundle> callback, Handler handler) {
   1385         return getAuthToken(account, authTokenType, null, notifyAuthFailure, callback,
   1386                 handler);
   1387     }
   1388 
   1389     /**
   1390      * Gets an auth token of the specified type for a particular account,
   1391      * optionally raising a notification if the user must enter credentials.
   1392      * This method is intended for background tasks and services where the
   1393      * user should not be immediately interrupted with a password prompt.
   1394      *
   1395      * <p>If a previously generated auth token is cached for this account and
   1396      * type, then it is returned.  Otherwise, if a saved password is
   1397      * available, it is sent to the server to generate a new auth token.
   1398      * Otherwise, an {@link Intent} is returned which, when started, will
   1399      * prompt the user for a password.  If the notifyAuthFailure parameter is
   1400      * set, a status bar notification is also created with the same Intent,
   1401      * alerting the user that they need to enter a password at some point.
   1402      *
   1403      * <p>In that case, you may need to wait until the user responds, which
   1404      * could take hours or days or forever.  When the user does respond and
   1405      * supply a new password, the account manager will broadcast the
   1406      * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
   1407      * use to try again.
   1408      *
   1409      * <p>If notifyAuthFailure is not set, it is the application's
   1410      * responsibility to launch the returned Intent at some point.
   1411      * Either way, the result from this call will not wait for user action.
   1412      *
   1413      * <p>Some authenticators have auth token <em>types</em>, whose value
   1414      * is authenticator-dependent.  Some services use different token types to
   1415      * access different functionality -- for example, Google uses different auth
   1416      * tokens to access Gmail and Google Calendar for the same account.
   1417      *
   1418      * <p>This method may be called from any thread, but the returned
   1419      * {@link AccountManagerFuture} must not be used on the main thread.
   1420      *
   1421      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1422      * USE_CREDENTIALS permission is needed for those platforms. See docs for
   1423      * this function in API level 22.
   1424      *
   1425      * @param account The account to fetch an auth token for
   1426      * @param authTokenType The auth token type, an authenticator-dependent
   1427      *     string token, must not be null
   1428      * @param options Authenticator-specific options for the request,
   1429      *     may be null or empty
   1430      * @param notifyAuthFailure True to add a notification to prompt the
   1431      *     user for a password if necessary, false to leave that to the caller
   1432      * @param callback Callback to invoke when the request completes,
   1433      *     null for no callback
   1434      * @param handler {@link Handler} identifying the callback thread,
   1435      *     null for the main thread
   1436      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
   1437      *     at least the following fields on success:
   1438      * <ul>
   1439      * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
   1440      * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
   1441      * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
   1442      * </ul>
   1443      *
   1444      * (Other authenticator-specific values may be returned.)  If the user
   1445      * must enter credentials, the returned Bundle contains only
   1446      * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
   1447      *
   1448      * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
   1449      * <ul>
   1450      * <li> {@link AuthenticatorException} if the authenticator failed to respond
   1451      * <li> {@link OperationCanceledException} if the operation is canceled for
   1452      *      any reason, incluidng the user canceling a credential request
   1453      * <li> {@link IOException} if the authenticator experienced an I/O problem
   1454      *      creating a new auth token, usually because of network trouble
   1455      * </ul>
   1456      * If the account is no longer present on the device, the return value is
   1457      * authenticator-dependent.  The caller should verify the validity of the
   1458      * account before requesting an auth token.
   1459      */
   1460     public AccountManagerFuture<Bundle> getAuthToken(
   1461             final Account account, final String authTokenType, final Bundle options,
   1462             final boolean notifyAuthFailure,
   1463             AccountManagerCallback<Bundle> callback, Handler handler) {
   1464 
   1465         if (account == null) throw new IllegalArgumentException("account is null");
   1466         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
   1467         final Bundle optionsIn = new Bundle();
   1468         if (options != null) {
   1469             optionsIn.putAll(options);
   1470         }
   1471         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
   1472         return new AmsTask(null, handler, callback) {
   1473             @Override
   1474             public void doWork() throws RemoteException {
   1475                 mService.getAuthToken(mResponse, account, authTokenType,
   1476                         notifyAuthFailure, false /* expectActivityLaunch */, optionsIn);
   1477             }
   1478         }.start();
   1479     }
   1480 
   1481     /**
   1482      * Asks the user to add an account of a specified type.  The authenticator
   1483      * for this account type processes this request with the appropriate user
   1484      * interface.  If the user does elect to create a new account, the account
   1485      * name is returned.
   1486      *
   1487      * <p>This method may be called from any thread, but the returned
   1488      * {@link AccountManagerFuture} must not be used on the main thread.
   1489      *
   1490      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1491      * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
   1492      * this function in API level 22.
   1493      *
   1494      * @param accountType The type of account to add; must not be null
   1495      * @param authTokenType The type of auth token (see {@link #getAuthToken})
   1496      *     this account will need to be able to generate, null for none
   1497      * @param requiredFeatures The features (see {@link #hasFeatures}) this
   1498      *     account must have, null for none
   1499      * @param addAccountOptions Authenticator-specific options for the request,
   1500      *     may be null or empty
   1501      * @param activity The {@link Activity} context to use for launching a new
   1502      *     authenticator-defined sub-Activity to prompt the user to create an
   1503      *     account; used only to call startActivity(); if null, the prompt
   1504      *     will not be launched directly, but the necessary {@link Intent}
   1505      *     will be returned to the caller instead
   1506      * @param callback Callback to invoke when the request completes,
   1507      *     null for no callback
   1508      * @param handler {@link Handler} identifying the callback thread,
   1509      *     null for the main thread
   1510      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
   1511      *     these fields if activity was specified and an account was created:
   1512      * <ul>
   1513      * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
   1514      * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
   1515      * </ul>
   1516      *
   1517      * If no activity was specified, the returned Bundle contains only
   1518      * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
   1519      * actual account creation process.  If an error occurred,
   1520      * {@link AccountManagerFuture#getResult()} throws:
   1521      * <ul>
   1522      * <li> {@link AuthenticatorException} if no authenticator was registered for
   1523      *      this account type or the authenticator failed to respond
   1524      * <li> {@link OperationCanceledException} if the operation was canceled for
   1525      *      any reason, including the user canceling the creation process or adding accounts
   1526      *      (of this type) has been disabled by policy
   1527      * <li> {@link IOException} if the authenticator experienced an I/O problem
   1528      *      creating a new account, usually because of network trouble
   1529      * </ul>
   1530      */
   1531     public AccountManagerFuture<Bundle> addAccount(final String accountType,
   1532             final String authTokenType, final String[] requiredFeatures,
   1533             final Bundle addAccountOptions,
   1534             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
   1535         if (accountType == null) throw new IllegalArgumentException("accountType is null");
   1536         final Bundle optionsIn = new Bundle();
   1537         if (addAccountOptions != null) {
   1538             optionsIn.putAll(addAccountOptions);
   1539         }
   1540         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
   1541 
   1542         return new AmsTask(activity, handler, callback) {
   1543             @Override
   1544             public void doWork() throws RemoteException {
   1545                 mService.addAccount(mResponse, accountType, authTokenType,
   1546                         requiredFeatures, activity != null, optionsIn);
   1547             }
   1548         }.start();
   1549     }
   1550 
   1551     /**
   1552      * @see #addAccount(String, String, String[], Bundle, Activity, AccountManagerCallback, Handler)
   1553      * @hide
   1554      */
   1555     public AccountManagerFuture<Bundle> addAccountAsUser(final String accountType,
   1556             final String authTokenType, final String[] requiredFeatures,
   1557             final Bundle addAccountOptions, final Activity activity,
   1558             AccountManagerCallback<Bundle> callback, Handler handler, final UserHandle userHandle) {
   1559         if (accountType == null) throw new IllegalArgumentException("accountType is null");
   1560         if (userHandle == null) throw new IllegalArgumentException("userHandle is null");
   1561         final Bundle optionsIn = new Bundle();
   1562         if (addAccountOptions != null) {
   1563             optionsIn.putAll(addAccountOptions);
   1564         }
   1565         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
   1566 
   1567         return new AmsTask(activity, handler, callback) {
   1568             @Override
   1569             public void doWork() throws RemoteException {
   1570                 mService.addAccountAsUser(mResponse, accountType, authTokenType,
   1571                         requiredFeatures, activity != null, optionsIn, userHandle.getIdentifier());
   1572             }
   1573         }.start();
   1574     }
   1575 
   1576 
   1577     /**
   1578      * Adds shared accounts from a parent user to a secondary user. Adding the shared account
   1579      * doesn't take effect immediately. When the target user starts up, any pending shared accounts
   1580      * are attempted to be copied to the target user from the primary via calls to the
   1581      * authenticator.
   1582      * @param parentUser parent user
   1583      * @param user target user
   1584      * @hide
   1585      */
   1586     public void addSharedAccountsFromParentUser(UserHandle parentUser, UserHandle user) {
   1587         try {
   1588             mService.addSharedAccountsFromParentUser(parentUser.getIdentifier(),
   1589                     user.getIdentifier());
   1590         } catch (RemoteException re) {
   1591             throw re.rethrowFromSystemServer();
   1592         }
   1593     }
   1594 
   1595     /**
   1596      * Copies an account from one user to another user.
   1597      * @param account the account to copy
   1598      * @param fromUser the user to copy the account from
   1599      * @param toUser the target user
   1600      * @param callback Callback to invoke when the request completes,
   1601      *     null for no callback
   1602      * @param handler {@link Handler} identifying the callback thread,
   1603      *     null for the main thread
   1604      * @return An {@link AccountManagerFuture} which resolves to a Boolean indicated wether it
   1605      * succeeded.
   1606      * @hide
   1607      */
   1608     public AccountManagerFuture<Boolean> copyAccountToUser(
   1609             final Account account, final UserHandle fromUser, final UserHandle toUser,
   1610             AccountManagerCallback<Boolean> callback, Handler handler) {
   1611         if (account == null) throw new IllegalArgumentException("account is null");
   1612         if (toUser == null || fromUser == null) {
   1613             throw new IllegalArgumentException("fromUser and toUser cannot be null");
   1614         }
   1615 
   1616         return new Future2Task<Boolean>(handler, callback) {
   1617             @Override
   1618             public void doWork() throws RemoteException {
   1619                 mService.copyAccountToUser(
   1620                         mResponse, account, fromUser.getIdentifier(), toUser.getIdentifier());
   1621             }
   1622             @Override
   1623             public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
   1624                 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
   1625                     throw new AuthenticatorException("no result in response");
   1626                 }
   1627                 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
   1628             }
   1629         }.start();
   1630     }
   1631 
   1632     /**
   1633      * @hide
   1634      * Removes the shared account.
   1635      * @param account the account to remove
   1636      * @param user the user to remove the account from
   1637      * @return
   1638      */
   1639     public boolean removeSharedAccount(final Account account, UserHandle user) {
   1640         try {
   1641             boolean val = mService.removeSharedAccountAsUser(account, user.getIdentifier());
   1642             return val;
   1643         } catch (RemoteException re) {
   1644             throw re.rethrowFromSystemServer();
   1645         }
   1646     }
   1647 
   1648     /**
   1649      * @hide
   1650      * @param user
   1651      * @return
   1652      */
   1653     public Account[] getSharedAccounts(UserHandle user) {
   1654         try {
   1655             return mService.getSharedAccountsAsUser(user.getIdentifier());
   1656         } catch (RemoteException re) {
   1657             throw re.rethrowFromSystemServer();
   1658         }
   1659     }
   1660 
   1661     /**
   1662      * Confirms that the user knows the password for an account to make extra
   1663      * sure they are the owner of the account.  The user-entered password can
   1664      * be supplied directly, otherwise the authenticator for this account type
   1665      * prompts the user with the appropriate interface.  This method is
   1666      * intended for applications which want extra assurance; for example, the
   1667      * phone lock screen uses this to let the user unlock the phone with an
   1668      * account password if they forget the lock pattern.
   1669      *
   1670      * <p>If the user-entered password matches a saved password for this
   1671      * account, the request is considered valid; otherwise the authenticator
   1672      * verifies the password (usually by contacting the server).
   1673      *
   1674      * <p>This method may be called from any thread, but the returned
   1675      * {@link AccountManagerFuture} must not be used on the main thread.
   1676      *
   1677      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1678      * MANAGE_ACCOUNTS permission is needed for those platforms. See docs
   1679      * for this function in API level 22.
   1680      *
   1681      * @param account The account to confirm password knowledge for
   1682      * @param options Authenticator-specific options for the request;
   1683      *     if the {@link #KEY_PASSWORD} string field is present, the
   1684      *     authenticator may use it directly rather than prompting the user;
   1685      *     may be null or empty
   1686      * @param activity The {@link Activity} context to use for launching a new
   1687      *     authenticator-defined sub-Activity to prompt the user to enter a
   1688      *     password; used only to call startActivity(); if null, the prompt
   1689      *     will not be launched directly, but the necessary {@link Intent}
   1690      *     will be returned to the caller instead
   1691      * @param callback Callback to invoke when the request completes,
   1692      *     null for no callback
   1693      * @param handler {@link Handler} identifying the callback thread,
   1694      *     null for the main thread
   1695      * @return An {@link AccountManagerFuture} which resolves to a Bundle
   1696      *     with these fields if activity or password was supplied and
   1697      *     the account was successfully verified:
   1698      * <ul>
   1699      * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account verified
   1700      * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
   1701      * <li> {@link #KEY_BOOLEAN_RESULT} - true to indicate success
   1702      * </ul>
   1703      *
   1704      * If no activity or password was specified, the returned Bundle contains
   1705      * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
   1706      * password prompt.
   1707      *
   1708      * <p>Also the returning Bundle may contain {@link
   1709      * #KEY_LAST_AUTHENTICATED_TIME} indicating the last time the
   1710      * credential was validated/created.
   1711      *
   1712      * If an error occurred,{@link AccountManagerFuture#getResult()} throws:
   1713      * <ul>
   1714      * <li> {@link AuthenticatorException} if the authenticator failed to respond
   1715      * <li> {@link OperationCanceledException} if the operation was canceled for
   1716      *      any reason, including the user canceling the password prompt
   1717      * <li> {@link IOException} if the authenticator experienced an I/O problem
   1718      *      verifying the password, usually because of network trouble
   1719      * </ul>
   1720      */
   1721     public AccountManagerFuture<Bundle> confirmCredentials(final Account account,
   1722             final Bundle options,
   1723             final Activity activity,
   1724             final AccountManagerCallback<Bundle> callback,
   1725             final Handler handler) {
   1726         return confirmCredentialsAsUser(account, options, activity, callback, handler,
   1727                 Process.myUserHandle());
   1728     }
   1729 
   1730     /**
   1731      * @hide
   1732      * Same as {@link #confirmCredentials(Account, Bundle, Activity, AccountManagerCallback, Handler)}
   1733      * but for the specified user.
   1734      */
   1735     public AccountManagerFuture<Bundle> confirmCredentialsAsUser(final Account account,
   1736             final Bundle options,
   1737             final Activity activity,
   1738             final AccountManagerCallback<Bundle> callback,
   1739             final Handler handler, UserHandle userHandle) {
   1740         if (account == null) throw new IllegalArgumentException("account is null");
   1741         final int userId = userHandle.getIdentifier();
   1742         return new AmsTask(activity, handler, callback) {
   1743             @Override
   1744             public void doWork() throws RemoteException {
   1745                 mService.confirmCredentialsAsUser(mResponse, account, options, activity != null,
   1746                         userId);
   1747             }
   1748         }.start();
   1749     }
   1750 
   1751     /**
   1752      * Asks the user to enter a new password for an account, updating the
   1753      * saved credentials for the account.  Normally this happens automatically
   1754      * when the server rejects credentials during an auth token fetch, but this
   1755      * can be invoked directly to ensure we have the correct credentials stored.
   1756      *
   1757      * <p>This method may be called from any thread, but the returned
   1758      * {@link AccountManagerFuture} must not be used on the main thread.
   1759      *
   1760      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1761      * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
   1762      * this function in API level 22.
   1763      *
   1764      * @param account The account to update credentials for
   1765      * @param authTokenType The credentials entered must allow an auth token
   1766      *     of this type to be created (but no actual auth token is returned);
   1767      *     may be null
   1768      * @param options Authenticator-specific options for the request;
   1769      *     may be null or empty
   1770      * @param activity The {@link Activity} context to use for launching a new
   1771      *     authenticator-defined sub-Activity to prompt the user to enter a
   1772      *     password; used only to call startActivity(); if null, the prompt
   1773      *     will not be launched directly, but the necessary {@link Intent}
   1774      *     will be returned to the caller instead
   1775      * @param callback Callback to invoke when the request completes,
   1776      *     null for no callback
   1777      * @param handler {@link Handler} identifying the callback thread,
   1778      *     null for the main thread
   1779      * @return An {@link AccountManagerFuture} which resolves to a Bundle
   1780      *     with these fields if an activity was supplied and the account
   1781      *     credentials were successfully updated:
   1782      * <ul>
   1783      * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account
   1784      * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
   1785      * </ul>
   1786      *
   1787      * If no activity was specified, the returned Bundle contains
   1788      * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
   1789      * password prompt. If an error occurred,
   1790      * {@link AccountManagerFuture#getResult()} throws:
   1791      * <ul>
   1792      * <li> {@link AuthenticatorException} if the authenticator failed to respond
   1793      * <li> {@link OperationCanceledException} if the operation was canceled for
   1794      *      any reason, including the user canceling the password prompt
   1795      * <li> {@link IOException} if the authenticator experienced an I/O problem
   1796      *      verifying the password, usually because of network trouble
   1797      * </ul>
   1798      */
   1799     public AccountManagerFuture<Bundle> updateCredentials(final Account account,
   1800             final String authTokenType,
   1801             final Bundle options, final Activity activity,
   1802             final AccountManagerCallback<Bundle> callback,
   1803             final Handler handler) {
   1804         if (account == null) throw new IllegalArgumentException("account is null");
   1805         return new AmsTask(activity, handler, callback) {
   1806             @Override
   1807             public void doWork() throws RemoteException {
   1808                 mService.updateCredentials(mResponse, account, authTokenType, activity != null,
   1809                         options);
   1810             }
   1811         }.start();
   1812     }
   1813 
   1814     /**
   1815      * Offers the user an opportunity to change an authenticator's settings.
   1816      * These properties are for the authenticator in general, not a particular
   1817      * account.  Not all authenticators support this method.
   1818      *
   1819      * <p>This method may be called from any thread, but the returned
   1820      * {@link AccountManagerFuture} must not be used on the main thread.
   1821      *
   1822      * <p>This method requires the caller to have the same signature as the
   1823      * authenticator associated with the specified account type.
   1824      *
   1825      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   1826      * MANAGE_ACCOUNTS permission is needed for those platforms. See docs
   1827      * for this function in API level 22.
   1828      *
   1829      * @param accountType The account type associated with the authenticator
   1830      *     to adjust
   1831      * @param activity The {@link Activity} context to use for launching a new
   1832      *     authenticator-defined sub-Activity to adjust authenticator settings;
   1833      *     used only to call startActivity(); if null, the settings dialog will
   1834      *     not be launched directly, but the necessary {@link Intent} will be
   1835      *     returned to the caller instead
   1836      * @param callback Callback to invoke when the request completes,
   1837      *     null for no callback
   1838      * @param handler {@link Handler} identifying the callback thread,
   1839      *     null for the main thread
   1840      * @return An {@link AccountManagerFuture} which resolves to a Bundle
   1841      *     which is empty if properties were edited successfully, or
   1842      *     if no activity was specified, contains only {@link #KEY_INTENT}
   1843      *     needed to launch the authenticator's settings dialog.
   1844      *     If an error occurred, {@link AccountManagerFuture#getResult()}
   1845      *     throws:
   1846      * <ul>
   1847      * <li> {@link AuthenticatorException} if no authenticator was registered for
   1848      *      this account type or the authenticator failed to respond
   1849      * <li> {@link OperationCanceledException} if the operation was canceled for
   1850      *      any reason, including the user canceling the settings dialog
   1851      * <li> {@link IOException} if the authenticator experienced an I/O problem
   1852      *      updating settings, usually because of network trouble
   1853      * </ul>
   1854      */
   1855     public AccountManagerFuture<Bundle> editProperties(final String accountType,
   1856             final Activity activity, final AccountManagerCallback<Bundle> callback,
   1857             final Handler handler) {
   1858         if (accountType == null) throw new IllegalArgumentException("accountType is null");
   1859         return new AmsTask(activity, handler, callback) {
   1860             @Override
   1861             public void doWork() throws RemoteException {
   1862                 mService.editProperties(mResponse, accountType, activity != null);
   1863             }
   1864         }.start();
   1865     }
   1866 
   1867     /**
   1868      * @hide
   1869      * Checks if the given account exists on any of the users on the device.
   1870      * Only the system process can call this method.
   1871      *
   1872      * @param account The account to check for existence.
   1873      * @return whether any user has this account
   1874      */
   1875     public boolean someUserHasAccount(@NonNull final Account account) {
   1876         try {
   1877             return mService.someUserHasAccount(account);
   1878         } catch (RemoteException re) {
   1879             throw re.rethrowFromSystemServer();
   1880         }
   1881     }
   1882 
   1883     private void ensureNotOnMainThread() {
   1884         final Looper looper = Looper.myLooper();
   1885         if (looper != null && looper == mContext.getMainLooper()) {
   1886             final IllegalStateException exception = new IllegalStateException(
   1887                     "calling this from your main thread can lead to deadlock");
   1888             Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs",
   1889                     exception);
   1890             if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.FROYO) {
   1891                 throw exception;
   1892             }
   1893         }
   1894     }
   1895 
   1896     private void postToHandler(Handler handler, final AccountManagerCallback<Bundle> callback,
   1897             final AccountManagerFuture<Bundle> future) {
   1898         handler = handler == null ? mMainHandler : handler;
   1899         handler.post(new Runnable() {
   1900             @Override
   1901             public void run() {
   1902                 callback.run(future);
   1903             }
   1904         });
   1905     }
   1906 
   1907     private void postToHandler(Handler handler, final OnAccountsUpdateListener listener,
   1908             final Account[] accounts) {
   1909         final Account[] accountsCopy = new Account[accounts.length];
   1910         // send a copy to make sure that one doesn't
   1911         // change what another sees
   1912         System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
   1913         handler = (handler == null) ? mMainHandler : handler;
   1914         handler.post(new Runnable() {
   1915             @Override
   1916             public void run() {
   1917                 try {
   1918                     listener.onAccountsUpdated(accountsCopy);
   1919                 } catch (SQLException e) {
   1920                     // Better luck next time.  If the problem was disk-full,
   1921                     // the STORAGE_OK intent will re-trigger the update.
   1922                     Log.e(TAG, "Can't update accounts", e);
   1923                 }
   1924             }
   1925         });
   1926     }
   1927 
   1928     private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> {
   1929         final IAccountManagerResponse mResponse;
   1930         final Handler mHandler;
   1931         final AccountManagerCallback<Bundle> mCallback;
   1932         final Activity mActivity;
   1933         public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) {
   1934             super(new Callable<Bundle>() {
   1935                 @Override
   1936                 public Bundle call() throws Exception {
   1937                     throw new IllegalStateException("this should never be called");
   1938                 }
   1939             });
   1940 
   1941             mHandler = handler;
   1942             mCallback = callback;
   1943             mActivity = activity;
   1944             mResponse = new Response();
   1945         }
   1946 
   1947         public final AccountManagerFuture<Bundle> start() {
   1948             try {
   1949                 doWork();
   1950             } catch (RemoteException e) {
   1951                 setException(e);
   1952             }
   1953             return this;
   1954         }
   1955 
   1956         @Override
   1957         protected void set(Bundle bundle) {
   1958             // TODO: somehow a null is being set as the result of the Future. Log this
   1959             // case to help debug where this is occurring. When this bug is fixed this
   1960             // condition statement should be removed.
   1961             if (bundle == null) {
   1962                 Log.e(TAG, "the bundle must not be null", new Exception());
   1963             }
   1964             super.set(bundle);
   1965         }
   1966 
   1967         public abstract void doWork() throws RemoteException;
   1968 
   1969         private Bundle internalGetResult(Long timeout, TimeUnit unit)
   1970                 throws OperationCanceledException, IOException, AuthenticatorException {
   1971             if (!isDone()) {
   1972                 ensureNotOnMainThread();
   1973             }
   1974             try {
   1975                 if (timeout == null) {
   1976                     return get();
   1977                 } else {
   1978                     return get(timeout, unit);
   1979                 }
   1980             } catch (CancellationException e) {
   1981                 throw new OperationCanceledException();
   1982             } catch (TimeoutException e) {
   1983                 // fall through and cancel
   1984             } catch (InterruptedException e) {
   1985                 // fall through and cancel
   1986             } catch (ExecutionException e) {
   1987                 final Throwable cause = e.getCause();
   1988                 if (cause instanceof IOException) {
   1989                     throw (IOException) cause;
   1990                 } else if (cause instanceof UnsupportedOperationException) {
   1991                     throw new AuthenticatorException(cause);
   1992                 } else if (cause instanceof AuthenticatorException) {
   1993                     throw (AuthenticatorException) cause;
   1994                 } else if (cause instanceof RuntimeException) {
   1995                     throw (RuntimeException) cause;
   1996                 } else if (cause instanceof Error) {
   1997                     throw (Error) cause;
   1998                 } else {
   1999                     throw new IllegalStateException(cause);
   2000                 }
   2001             } finally {
   2002                 cancel(true /* interrupt if running */);
   2003             }
   2004             throw new OperationCanceledException();
   2005         }
   2006 
   2007         @Override
   2008         public Bundle getResult()
   2009                 throws OperationCanceledException, IOException, AuthenticatorException {
   2010             return internalGetResult(null, null);
   2011         }
   2012 
   2013         @Override
   2014         public Bundle getResult(long timeout, TimeUnit unit)
   2015                 throws OperationCanceledException, IOException, AuthenticatorException {
   2016             return internalGetResult(timeout, unit);
   2017         }
   2018 
   2019         @Override
   2020         protected void done() {
   2021             if (mCallback != null) {
   2022                 postToHandler(mHandler, mCallback, this);
   2023             }
   2024         }
   2025 
   2026         /** Handles the responses from the AccountManager */
   2027         private class Response extends IAccountManagerResponse.Stub {
   2028             @Override
   2029             public void onResult(Bundle bundle) {
   2030                 Intent intent = bundle.getParcelable(KEY_INTENT);
   2031                 if (intent != null && mActivity != null) {
   2032                     // since the user provided an Activity we will silently start intents
   2033                     // that we see
   2034                     mActivity.startActivity(intent);
   2035                     // leave the Future running to wait for the real response to this request
   2036                 } else if (bundle.getBoolean("retry")) {
   2037                     try {
   2038                         doWork();
   2039                     } catch (RemoteException e) {
   2040                         throw e.rethrowFromSystemServer();
   2041                     }
   2042                 } else {
   2043                     set(bundle);
   2044                 }
   2045             }
   2046 
   2047             @Override
   2048             public void onError(int code, String message) {
   2049                 if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
   2050                         || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
   2051                     // the authenticator indicated that this request was canceled or we were
   2052                     // forbidden to fulfill; cancel now
   2053                     cancel(true /* mayInterruptIfRunning */);
   2054                     return;
   2055                 }
   2056                 setException(convertErrorToException(code, message));
   2057             }
   2058         }
   2059 
   2060     }
   2061 
   2062     private abstract class BaseFutureTask<T> extends FutureTask<T> {
   2063         final public IAccountManagerResponse mResponse;
   2064         final Handler mHandler;
   2065 
   2066         public BaseFutureTask(Handler handler) {
   2067             super(new Callable<T>() {
   2068                 @Override
   2069                 public T call() throws Exception {
   2070                     throw new IllegalStateException("this should never be called");
   2071                 }
   2072             });
   2073             mHandler = handler;
   2074             mResponse = new Response();
   2075         }
   2076 
   2077         public abstract void doWork() throws RemoteException;
   2078 
   2079         public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException;
   2080 
   2081         protected void postRunnableToHandler(Runnable runnable) {
   2082             Handler handler = (mHandler == null) ? mMainHandler : mHandler;
   2083             handler.post(runnable);
   2084         }
   2085 
   2086         protected void startTask() {
   2087             try {
   2088                 doWork();
   2089             } catch (RemoteException e) {
   2090                 setException(e);
   2091             }
   2092         }
   2093 
   2094         protected class Response extends IAccountManagerResponse.Stub {
   2095             @Override
   2096             public void onResult(Bundle bundle) {
   2097                 try {
   2098                     T result = bundleToResult(bundle);
   2099                     if (result == null) {
   2100                         return;
   2101                     }
   2102                     set(result);
   2103                     return;
   2104                 } catch (ClassCastException e) {
   2105                     // we will set the exception below
   2106                 } catch (AuthenticatorException e) {
   2107                     // we will set the exception below
   2108                 }
   2109                 onError(ERROR_CODE_INVALID_RESPONSE, "no result in response");
   2110             }
   2111 
   2112             @Override
   2113             public void onError(int code, String message) {
   2114                 if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
   2115                         || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
   2116                     // the authenticator indicated that this request was canceled or we were
   2117                     // forbidden to fulfill; cancel now
   2118                     cancel(true /* mayInterruptIfRunning */);
   2119                     return;
   2120                 }
   2121                 setException(convertErrorToException(code, message));
   2122             }
   2123         }
   2124     }
   2125 
   2126     private abstract class Future2Task<T>
   2127             extends BaseFutureTask<T> implements AccountManagerFuture<T> {
   2128         final AccountManagerCallback<T> mCallback;
   2129         public Future2Task(Handler handler, AccountManagerCallback<T> callback) {
   2130             super(handler);
   2131             mCallback = callback;
   2132         }
   2133 
   2134         @Override
   2135         protected void done() {
   2136             if (mCallback != null) {
   2137                 postRunnableToHandler(new Runnable() {
   2138                     @Override
   2139                     public void run() {
   2140                         mCallback.run(Future2Task.this);
   2141                     }
   2142                 });
   2143             }
   2144         }
   2145 
   2146         public Future2Task<T> start() {
   2147             startTask();
   2148             return this;
   2149         }
   2150 
   2151         private T internalGetResult(Long timeout, TimeUnit unit)
   2152                 throws OperationCanceledException, IOException, AuthenticatorException {
   2153             if (!isDone()) {
   2154                 ensureNotOnMainThread();
   2155             }
   2156             try {
   2157                 if (timeout == null) {
   2158                     return get();
   2159                 } else {
   2160                     return get(timeout, unit);
   2161                 }
   2162             } catch (InterruptedException e) {
   2163                 // fall through and cancel
   2164             } catch (TimeoutException e) {
   2165                 // fall through and cancel
   2166             } catch (CancellationException e) {
   2167                 // fall through and cancel
   2168             } catch (ExecutionException e) {
   2169                 final Throwable cause = e.getCause();
   2170                 if (cause instanceof IOException) {
   2171                     throw (IOException) cause;
   2172                 } else if (cause instanceof UnsupportedOperationException) {
   2173                     throw new AuthenticatorException(cause);
   2174                 } else if (cause instanceof AuthenticatorException) {
   2175                     throw (AuthenticatorException) cause;
   2176                 } else if (cause instanceof RuntimeException) {
   2177                     throw (RuntimeException) cause;
   2178                 } else if (cause instanceof Error) {
   2179                     throw (Error) cause;
   2180                 } else {
   2181                     throw new IllegalStateException(cause);
   2182                 }
   2183             } finally {
   2184                 cancel(true /* interrupt if running */);
   2185             }
   2186             throw new OperationCanceledException();
   2187         }
   2188 
   2189         @Override
   2190         public T getResult()
   2191                 throws OperationCanceledException, IOException, AuthenticatorException {
   2192             return internalGetResult(null, null);
   2193         }
   2194 
   2195         @Override
   2196         public T getResult(long timeout, TimeUnit unit)
   2197                 throws OperationCanceledException, IOException, AuthenticatorException {
   2198             return internalGetResult(timeout, unit);
   2199         }
   2200 
   2201     }
   2202 
   2203     private Exception convertErrorToException(int code, String message) {
   2204         if (code == ERROR_CODE_NETWORK_ERROR) {
   2205             return new IOException(message);
   2206         }
   2207 
   2208         if (code == ERROR_CODE_UNSUPPORTED_OPERATION) {
   2209             return new UnsupportedOperationException(message);
   2210         }
   2211 
   2212         if (code == ERROR_CODE_INVALID_RESPONSE) {
   2213             return new AuthenticatorException(message);
   2214         }
   2215 
   2216         if (code == ERROR_CODE_BAD_ARGUMENTS) {
   2217             return new IllegalArgumentException(message);
   2218         }
   2219 
   2220         return new AuthenticatorException(message);
   2221     }
   2222 
   2223     private class GetAuthTokenByTypeAndFeaturesTask
   2224             extends AmsTask implements AccountManagerCallback<Bundle> {
   2225         GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
   2226                 final String[] features, Activity activityForPrompting,
   2227                 final Bundle addAccountOptions, final Bundle loginOptions,
   2228                 AccountManagerCallback<Bundle> callback, Handler handler) {
   2229             super(activityForPrompting, handler, callback);
   2230             if (accountType == null) throw new IllegalArgumentException("account type is null");
   2231             mAccountType = accountType;
   2232             mAuthTokenType = authTokenType;
   2233             mFeatures = features;
   2234             mAddAccountOptions = addAccountOptions;
   2235             mLoginOptions = loginOptions;
   2236             mMyCallback = this;
   2237         }
   2238         volatile AccountManagerFuture<Bundle> mFuture = null;
   2239         final String mAccountType;
   2240         final String mAuthTokenType;
   2241         final String[] mFeatures;
   2242         final Bundle mAddAccountOptions;
   2243         final Bundle mLoginOptions;
   2244         final AccountManagerCallback<Bundle> mMyCallback;
   2245         private volatile int mNumAccounts = 0;
   2246 
   2247         @Override
   2248         public void doWork() throws RemoteException {
   2249             getAccountsByTypeAndFeatures(mAccountType, mFeatures,
   2250                     new AccountManagerCallback<Account[]>() {
   2251                         @Override
   2252                         public void run(AccountManagerFuture<Account[]> future) {
   2253                             Account[] accounts;
   2254                             try {
   2255                                 accounts = future.getResult();
   2256                             } catch (OperationCanceledException e) {
   2257                                 setException(e);
   2258                                 return;
   2259                             } catch (IOException e) {
   2260                                 setException(e);
   2261                                 return;
   2262                             } catch (AuthenticatorException e) {
   2263                                 setException(e);
   2264                                 return;
   2265                             }
   2266 
   2267                             mNumAccounts = accounts.length;
   2268 
   2269                             if (accounts.length == 0) {
   2270                                 if (mActivity != null) {
   2271                                     // no accounts, add one now. pretend that the user directly
   2272                                     // made this request
   2273                                     mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures,
   2274                                             mAddAccountOptions, mActivity, mMyCallback, mHandler);
   2275                                 } else {
   2276                                     // send result since we can't prompt to add an account
   2277                                     Bundle result = new Bundle();
   2278                                     result.putString(KEY_ACCOUNT_NAME, null);
   2279                                     result.putString(KEY_ACCOUNT_TYPE, null);
   2280                                     result.putString(KEY_AUTHTOKEN, null);
   2281                                     result.putBinder(KEY_ACCOUNT_ACCESS_ID, null);
   2282                                     try {
   2283                                         mResponse.onResult(result);
   2284                                     } catch (RemoteException e) {
   2285                                         // this will never happen
   2286                                     }
   2287                                     // we are done
   2288                                 }
   2289                             } else if (accounts.length == 1) {
   2290                                 // have a single account, return an authtoken for it
   2291                                 if (mActivity == null) {
   2292                                     mFuture = getAuthToken(accounts[0], mAuthTokenType,
   2293                                             false /* notifyAuthFailure */, mMyCallback, mHandler);
   2294                                 } else {
   2295                                     mFuture = getAuthToken(accounts[0],
   2296                                             mAuthTokenType, mLoginOptions,
   2297                                             mActivity, mMyCallback, mHandler);
   2298                                 }
   2299                             } else {
   2300                                 if (mActivity != null) {
   2301                                     IAccountManagerResponse chooseResponse =
   2302                                             new IAccountManagerResponse.Stub() {
   2303                                         @Override
   2304                                         public void onResult(Bundle value) throws RemoteException {
   2305                                             Account account = new Account(
   2306                                                     value.getString(KEY_ACCOUNT_NAME),
   2307                                                     value.getString(KEY_ACCOUNT_TYPE),
   2308                                                     value.getString(KEY_ACCOUNT_ACCESS_ID));
   2309                                             mFuture = getAuthToken(account, mAuthTokenType,
   2310                                                     mLoginOptions,  mActivity, mMyCallback,
   2311                                                     mHandler);
   2312                                         }
   2313 
   2314                                         @Override
   2315                                         public void onError(int errorCode, String errorMessage)
   2316                                                 throws RemoteException {
   2317                                             mResponse.onError(errorCode, errorMessage);
   2318                                         }
   2319                                     };
   2320                                     // have many accounts, launch the chooser
   2321                                     Intent intent = new Intent();
   2322                                     ComponentName componentName = ComponentName.unflattenFromString(
   2323                                             Resources.getSystem().getString(
   2324                                                     R.string.config_chooseAccountActivity));
   2325                                     intent.setClassName(componentName.getPackageName(),
   2326                                             componentName.getClassName());
   2327                                     intent.putExtra(KEY_ACCOUNTS, accounts);
   2328                                     intent.putExtra(KEY_ACCOUNT_MANAGER_RESPONSE,
   2329                                             new AccountManagerResponse(chooseResponse));
   2330                                     mActivity.startActivity(intent);
   2331                                     // the result will arrive via the IAccountManagerResponse
   2332                                 } else {
   2333                                     // send result since we can't prompt to select an account
   2334                                     Bundle result = new Bundle();
   2335                                     result.putString(KEY_ACCOUNTS, null);
   2336                                     try {
   2337                                         mResponse.onResult(result);
   2338                                     } catch (RemoteException e) {
   2339                                         // this will never happen
   2340                                     }
   2341                                     // we are done
   2342                                 }
   2343                             }
   2344                         }}, mHandler);
   2345         }
   2346 
   2347         @Override
   2348         public void run(AccountManagerFuture<Bundle> future) {
   2349             try {
   2350                 final Bundle result = future.getResult();
   2351                 if (mNumAccounts == 0) {
   2352                     final String accountName = result.getString(KEY_ACCOUNT_NAME);
   2353                     final String accountType = result.getString(KEY_ACCOUNT_TYPE);
   2354                     if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
   2355                         setException(new AuthenticatorException("account not in result"));
   2356                         return;
   2357                     }
   2358                     final String accessId = result.getString(KEY_ACCOUNT_ACCESS_ID);
   2359                     final Account account = new Account(accountName, accountType, accessId);
   2360                     mNumAccounts = 1;
   2361                     getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
   2362                             mMyCallback, mHandler);
   2363                     return;
   2364                 }
   2365                 set(result);
   2366             } catch (OperationCanceledException e) {
   2367                 cancel(true /* mayInterruptIfRUnning */);
   2368             } catch (IOException e) {
   2369                 setException(e);
   2370             } catch (AuthenticatorException e) {
   2371                 setException(e);
   2372             }
   2373         }
   2374     }
   2375 
   2376     /**
   2377      * This convenience helper combines the functionality of
   2378      * {@link #getAccountsByTypeAndFeatures}, {@link #getAuthToken}, and
   2379      * {@link #addAccount}.
   2380      *
   2381      * <p>This method gets a list of the accounts matching the
   2382      * specified type and feature set; if there is exactly one, it is
   2383      * used; if there are more than one, the user is prompted to pick one;
   2384      * if there are none, the user is prompted to add one.  Finally,
   2385      * an auth token is acquired for the chosen account.
   2386      *
   2387      * <p>This method may be called from any thread, but the returned
   2388      * {@link AccountManagerFuture} must not be used on the main thread.
   2389      *
   2390      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
   2391      * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
   2392      * this function in API level 22.
   2393      *
   2394      * @param accountType The account type required
   2395      *     (see {@link #getAccountsByType}), must not be null
   2396      * @param authTokenType The desired auth token type
   2397      *     (see {@link #getAuthToken}), must not be null
   2398      * @param features Required features for the account
   2399      *     (see {@link #getAccountsByTypeAndFeatures}), may be null or empty
   2400      * @param activity The {@link Activity} context to use for launching new
   2401      *     sub-Activities to prompt to add an account, select an account,
   2402      *     and/or enter a password, as necessary; used only to call
   2403      *     startActivity(); should not be null
   2404      * @param addAccountOptions Authenticator-specific options to use for
   2405      *     adding new accounts; may be null or empty
   2406      * @param getAuthTokenOptions Authenticator-specific options to use for
   2407      *     getting auth tokens; may be null or empty
   2408      * @param callback Callback to invoke when the request completes,
   2409      *     null for no callback
   2410      * @param handler {@link Handler} identifying the callback thread,
   2411      *     null for the main thread
   2412      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
   2413      *     at least the following fields:
   2414      * <ul>
   2415      * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account
   2416      * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
   2417      * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
   2418      * </ul>
   2419      *
   2420      * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
   2421      * <ul>
   2422      * <li> {@link AuthenticatorException} if no authenticator was registered for
   2423      *      this account type or the authenticator failed to respond
   2424      * <li> {@link OperationCanceledException} if the operation was canceled for
   2425      *      any reason, including the user canceling any operation
   2426      * <li> {@link IOException} if the authenticator experienced an I/O problem
   2427      *      updating settings, usually because of network trouble
   2428      * </ul>
   2429      */
   2430     public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
   2431             final String accountType, final String authTokenType, final String[] features,
   2432             final Activity activity, final Bundle addAccountOptions,
   2433             final Bundle getAuthTokenOptions,
   2434             final AccountManagerCallback<Bundle> callback, final Handler handler) {
   2435         if (accountType == null) throw new IllegalArgumentException("account type is null");
   2436         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
   2437         final GetAuthTokenByTypeAndFeaturesTask task =
   2438                 new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features,
   2439                 activity, addAccountOptions, getAuthTokenOptions, callback, handler);
   2440         task.start();
   2441         return task;
   2442     }
   2443 
   2444     /**
   2445      * Deprecated in favor of {@link #newChooseAccountIntent(Account, List, String[], String,
   2446      * String, String[], Bundle)}.
   2447      *
   2448      * Returns an intent to an {@link Activity} that prompts the user to choose from a list of
   2449      * accounts.
   2450      * The caller will then typically start the activity by calling
   2451      * <code>startActivityForResult(intent, ...);</code>.
   2452      * <p>
   2453      * On success the activity returns a Bundle with the account name and type specified using
   2454      * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
   2455      * <p>
   2456      * The most common case is to call this with one account type, e.g.:
   2457      * <p>
   2458      * <pre>  newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null,
   2459      * null, null, null);</pre>
   2460      * @param selectedAccount if specified, indicates that the {@link Account} is the currently
   2461      * selected one, according to the caller's definition of selected.
   2462      * @param allowableAccounts an optional {@link List} of accounts that are allowed to be
   2463      * shown. If not specified then this field will not limit the displayed accounts.
   2464      * @param allowableAccountTypes an optional string array of account types. These are used
   2465      * both to filter the shown accounts and to filter the list of account types that are shown
   2466      * when adding an account. If not specified then this field will not limit the displayed
   2467      * account types when adding an account.
   2468      * @param alwaysPromptForAccount boolean that is ignored.
   2469      * @param descriptionOverrideText if non-null this string is used as the description in the
   2470      * accounts chooser screen rather than the default
   2471      * @param addAccountAuthTokenType this string is passed as the {@link #addAccount}
   2472      * authTokenType parameter
   2473      * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount}
   2474      * requiredFeatures parameter
   2475      * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options
   2476      * parameter
   2477      * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow.
   2478      */
   2479     @Deprecated
   2480     static public Intent newChooseAccountIntent(
   2481             Account selectedAccount,
   2482             ArrayList<Account> allowableAccounts,
   2483             String[] allowableAccountTypes,
   2484             boolean alwaysPromptForAccount,
   2485             String descriptionOverrideText,
   2486             String addAccountAuthTokenType,
   2487             String[] addAccountRequiredFeatures,
   2488             Bundle addAccountOptions) {
   2489         return newChooseAccountIntent(
   2490                 selectedAccount,
   2491                 allowableAccounts,
   2492                 allowableAccountTypes,
   2493                 descriptionOverrideText,
   2494                 addAccountAuthTokenType,
   2495                 addAccountRequiredFeatures,
   2496                 addAccountOptions);
   2497     }
   2498 
   2499     /**
   2500      * Returns an intent to an {@link Activity} that prompts the user to choose from a list of
   2501      * accounts.
   2502      * The caller will then typically start the activity by calling
   2503      * <code>startActivityForResult(intent, ...);</code>.
   2504      * <p>
   2505      * On success the activity returns a Bundle with the account name and type specified using
   2506      * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
   2507      * <p>
   2508      * The most common case is to call this with one account type, e.g.:
   2509      * <p>
   2510      * <pre>  newChooseAccountIntent(null, null, new String[]{"com.google"}, null, null, null,
   2511      * null);</pre>
   2512      * @param selectedAccount if specified, indicates that the {@link Account} is the currently
   2513      * selected one, according to the caller's definition of selected.
   2514      * @param allowableAccounts an optional {@link List} of accounts that are allowed to be
   2515      * shown. If not specified then this field will not limit the displayed accounts.
   2516      * @param allowableAccountTypes an optional string array of account types. These are used
   2517      * both to filter the shown accounts and to filter the list of account types that are shown
   2518      * when adding an account. If not specified then this field will not limit the displayed
   2519      * account types when adding an account.
   2520      * @param descriptionOverrideText if non-null this string is used as the description in the
   2521      * accounts chooser screen rather than the default
   2522      * @param addAccountAuthTokenType this string is passed as the {@link #addAccount}
   2523      * authTokenType parameter
   2524      * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount}
   2525      * requiredFeatures parameter
   2526      * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options
   2527      * parameter
   2528      * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow.
   2529      */
   2530     static public Intent newChooseAccountIntent(
   2531             Account selectedAccount,
   2532             List<Account> allowableAccounts,
   2533             String[] allowableAccountTypes,
   2534             String descriptionOverrideText,
   2535             String addAccountAuthTokenType,
   2536             String[] addAccountRequiredFeatures,
   2537             Bundle addAccountOptions) {
   2538         Intent intent = new Intent();
   2539         ComponentName componentName = ComponentName.unflattenFromString(
   2540                 Resources.getSystem().getString(R.string.config_chooseTypeAndAccountActivity));
   2541         intent.setClassName(componentName.getPackageName(),
   2542                 componentName.getClassName());
   2543         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST,
   2544                 allowableAccounts == null ? null : new ArrayList<Account>(allowableAccounts));
   2545         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
   2546                 allowableAccountTypes);
   2547         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
   2548                 addAccountOptions);
   2549         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_SELECTED_ACCOUNT, selectedAccount);
   2550         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_DESCRIPTION_TEXT_OVERRIDE,
   2551                 descriptionOverrideText);
   2552         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,
   2553                 addAccountAuthTokenType);
   2554         intent.putExtra(
   2555                 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,
   2556                 addAccountRequiredFeatures);
   2557         return intent;
   2558     }
   2559 
   2560     private final HashMap<OnAccountsUpdateListener, Handler> mAccountsUpdatedListeners =
   2561             Maps.newHashMap();
   2562 
   2563     /**
   2564      * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
   2565      * so that it can read the updated list of accounts and send them to the listener
   2566      * in mAccountsUpdatedListeners.
   2567      */
   2568     private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
   2569         @Override
   2570         public void onReceive(final Context context, final Intent intent) {
   2571             final Account[] accounts = getAccounts();
   2572             // send the result to the listeners
   2573             synchronized (mAccountsUpdatedListeners) {
   2574                 for (Map.Entry<OnAccountsUpdateListener, Handler> entry :
   2575                         mAccountsUpdatedListeners.entrySet()) {
   2576                     postToHandler(entry.getValue(), entry.getKey(), accounts);
   2577                 }
   2578             }
   2579         }
   2580     };
   2581 
   2582     /**
   2583      * Adds an {@link OnAccountsUpdateListener} to this instance of the
   2584      * {@link AccountManager}.  This listener will be notified whenever the
   2585      * list of accounts on the device changes.
   2586      *
   2587      * <p>As long as this listener is present, the AccountManager instance
   2588      * will not be garbage-collected, and neither will the {@link Context}
   2589      * used to retrieve it, which may be a large Activity instance.  To avoid
   2590      * memory leaks, you must remove this listener before then.  Normally
   2591      * listeners are added in an Activity or Service's {@link Activity#onCreate}
   2592      * and removed in {@link Activity#onDestroy}.
   2593      *
   2594      * <p>The listener will only be informed of accounts that would be returned
   2595      * to the caller via {@link #getAccounts()}. Typically this means that to
   2596      * get any accounts, the caller will need to be grated the GET_ACCOUNTS
   2597      * permission.
   2598      *
   2599      * <p>It is safe to call this method from the main thread.
   2600      *
   2601      * @param listener The listener to send notifications to
   2602      * @param handler {@link Handler} identifying the thread to use
   2603      *     for notifications, null for the main thread
   2604      * @param updateImmediately If true, the listener will be invoked
   2605      *     (on the handler thread) right away with the current account list
   2606      * @throws IllegalArgumentException if listener is null
   2607      * @throws IllegalStateException if listener was already added
   2608      */
   2609     @RequiresPermission(GET_ACCOUNTS)
   2610     public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
   2611             Handler handler, boolean updateImmediately) {
   2612         if (listener == null) {
   2613             throw new IllegalArgumentException("the listener is null");
   2614         }
   2615         synchronized (mAccountsUpdatedListeners) {
   2616             if (mAccountsUpdatedListeners.containsKey(listener)) {
   2617                 throw new IllegalStateException("this listener is already added");
   2618             }
   2619             final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
   2620 
   2621             mAccountsUpdatedListeners.put(listener, handler);
   2622 
   2623             if (wasEmpty) {
   2624                 // Register a broadcast receiver to monitor account changes
   2625                 IntentFilter intentFilter = new IntentFilter();
   2626                 intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
   2627                 // To recover from disk-full.
   2628                 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
   2629                 mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
   2630             }
   2631         }
   2632 
   2633         if (updateImmediately) {
   2634             postToHandler(handler, listener, getAccounts());
   2635         }
   2636     }
   2637 
   2638     /**
   2639      * Removes an {@link OnAccountsUpdateListener} previously registered with
   2640      * {@link #addOnAccountsUpdatedListener}.  The listener will no longer
   2641      * receive notifications of account changes.
   2642      *
   2643      * <p>It is safe to call this method from the main thread.
   2644      *
   2645      * <p>No permission is required to call this method.
   2646      *
   2647      * @param listener The previously added listener to remove
   2648      * @throws IllegalArgumentException if listener is null
   2649      * @throws IllegalStateException if listener was not already added
   2650      */
   2651     public void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) {
   2652         if (listener == null) throw new IllegalArgumentException("listener is null");
   2653         synchronized (mAccountsUpdatedListeners) {
   2654             if (!mAccountsUpdatedListeners.containsKey(listener)) {
   2655                 Log.e(TAG, "Listener was not previously added");
   2656                 return;
   2657             }
   2658             mAccountsUpdatedListeners.remove(listener);
   2659             if (mAccountsUpdatedListeners.isEmpty()) {
   2660                 mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
   2661             }
   2662         }
   2663     }
   2664 
   2665     /**
   2666      * Asks the user to authenticate with an account of a specified type. The
   2667      * authenticator for this account type processes this request with the
   2668      * appropriate user interface. If the user does elect to authenticate with a
   2669      * new account, a bundle of session data for installing the account later is
   2670      * returned with optional account password and account status token.
   2671      * <p>
   2672      * This method may be called from any thread, but the returned
   2673      * {@link AccountManagerFuture} must not be used on the main thread.
   2674      * <p>
   2675      * <p>
   2676      * <b>NOTE:</b> The account will not be installed to the device by calling
   2677      * this api alone. #finishSession should be called after this to install the
   2678      * account on device.
   2679      *
   2680      * @param accountType The type of account to add; must not be null
   2681      * @param authTokenType The type of auth token (see {@link #getAuthToken})
   2682      *            this account will need to be able to generate, null for none
   2683      * @param requiredFeatures The features (see {@link #hasFeatures}) this
   2684      *            account must have, null for none
   2685      * @param options Authenticator-specific options for the request, may be
   2686      *            null or empty
   2687      * @param activity The {@link Activity} context to use for launching a new
   2688      *            authenticator-defined sub-Activity to prompt the user to
   2689      *            create an account; used only to call startActivity(); if null,
   2690      *            the prompt will not be launched directly, but the necessary
   2691      *            {@link Intent} will be returned to the caller instead
   2692      * @param callback Callback to invoke when the request completes, null for
   2693      *            no callback
   2694      * @param handler {@link Handler} identifying the callback thread, null for
   2695      *            the main thread
   2696      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
   2697      *         these fields if activity was specified and user was authenticated
   2698      *         with an account:
   2699      *         <ul>
   2700      *         <li>{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for
   2701      *         adding the the to the device later.
   2702      *         <li>{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
   2703      *         status of the account
   2704      *         </ul>
   2705      *         If no activity was specified, the returned Bundle contains only
   2706      *         {@link #KEY_INTENT} with the {@link Intent} needed to launch the
   2707      *         actual account creation process. If authenticator doesn't support
   2708      *         this method, the returned Bundle contains only
   2709      *         {@link #KEY_ACCOUNT_SESSION_BUNDLE} with encrypted
   2710      *         {@code options} needed to add account later. If an error
   2711      *         occurred, {@link AccountManagerFuture#getResult()} throws:
   2712      *         <ul>
   2713      *         <li>{@link AuthenticatorException} if no authenticator was
   2714      *         registered for this account type or the authenticator failed to
   2715      *         respond
   2716      *         <li>{@link OperationCanceledException} if the operation was
   2717      *         canceled for any reason, including the user canceling the
   2718      *         creation process or adding accounts (of this type) has been
   2719      *         disabled by policy
   2720      *         <li>{@link IOException} if the authenticator experienced an I/O
   2721      *         problem creating a new account, usually because of network
   2722      *         trouble
   2723      *         </ul>
   2724      * @see #finishSession
   2725      * @hide
   2726      */
   2727     @SystemApi
   2728     public AccountManagerFuture<Bundle> startAddAccountSession(
   2729             final String accountType,
   2730             final String authTokenType,
   2731             final String[] requiredFeatures,
   2732             final Bundle options,
   2733             final Activity activity,
   2734             AccountManagerCallback<Bundle> callback,
   2735             Handler handler) {
   2736         if (accountType == null) throw new IllegalArgumentException("accountType is null");
   2737         final Bundle optionsIn = new Bundle();
   2738         if (options != null) {
   2739             optionsIn.putAll(options);
   2740         }
   2741         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
   2742 
   2743         return new AmsTask(activity, handler, callback) {
   2744             @Override
   2745             public void doWork() throws RemoteException {
   2746                 mService.startAddAccountSession(
   2747                         mResponse,
   2748                         accountType,
   2749                         authTokenType,
   2750                         requiredFeatures,
   2751                         activity != null,
   2752                         optionsIn);
   2753             }
   2754         }.start();
   2755     }
   2756 
   2757     /**
   2758      * Asks the user to enter a new password for an account but not updating the
   2759      * saved credentials for the account until {@link #finishSession} is called.
   2760      * <p>
   2761      * This method may be called from any thread, but the returned
   2762      * {@link AccountManagerFuture} must not be used on the main thread.
   2763      * <p>
   2764      * <b>NOTE:</b> The saved credentials for the account alone will not be
   2765      * updated by calling this API alone. #finishSession should be called after
   2766      * this to update local credentials
   2767      *
   2768      * @param account The account to update credentials for
   2769      * @param authTokenType The credentials entered must allow an auth token of
   2770      *            this type to be created (but no actual auth token is
   2771      *            returned); may be null
   2772      * @param options Authenticator-specific options for the request; may be
   2773      *            null or empty
   2774      * @param activity The {@link Activity} context to use for launching a new
   2775      *            authenticator-defined sub-Activity to prompt the user to enter
   2776      *            a password; used only to call startActivity(); if null, the
   2777      *            prompt will not be launched directly, but the necessary
   2778      *            {@link Intent} will be returned to the caller instead
   2779      * @param callback Callback to invoke when the request completes, null for
   2780      *            no callback
   2781      * @param handler {@link Handler} identifying the callback thread, null for
   2782      *            the main thread
   2783      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
   2784      *         these fields if an activity was supplied and user was
   2785      *         successfully re-authenticated to the account:
   2786      *         <ul>
   2787      *         <li>{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for
   2788      *         updating the local credentials on device later.
   2789      *         <li>{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
   2790      *         status of the account
   2791      *         </ul>
   2792      *         If no activity was specified, the returned Bundle contains
   2793      *         {@link #KEY_INTENT} with the {@link Intent} needed to launch the
   2794      *         password prompt. If an error occurred,
   2795      *         {@link AccountManagerFuture#getResult()} throws:
   2796      *         <ul>
   2797      *         <li>{@link AuthenticatorException} if the authenticator failed to
   2798      *         respond
   2799      *         <li>{@link OperationCanceledException} if the operation was
   2800      *         canceled for any reason, including the user canceling the
   2801      *         password prompt
   2802      *         <li>{@link IOException} if the authenticator experienced an I/O
   2803      *         problem verifying the password, usually because of network
   2804      *         trouble
   2805      *         </ul>
   2806      * @see #finishSession
   2807      * @hide
   2808      */
   2809     @SystemApi
   2810     public AccountManagerFuture<Bundle> startUpdateCredentialsSession(
   2811             final Account account,
   2812             final String authTokenType,
   2813             final Bundle options,
   2814             final Activity activity,
   2815             final AccountManagerCallback<Bundle> callback,
   2816             final Handler handler) {
   2817         if (account == null) {
   2818             throw new IllegalArgumentException("account is null");
   2819         }
   2820 
   2821         // Always include the calling package name. This just makes life easier
   2822         // down stream.
   2823         final Bundle optionsIn = new Bundle();
   2824         if (options != null) {
   2825             optionsIn.putAll(options);
   2826         }
   2827         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
   2828 
   2829         return new AmsTask(activity, handler, callback) {
   2830             @Override
   2831             public void doWork() throws RemoteException {
   2832                 mService.startUpdateCredentialsSession(
   2833                         mResponse,
   2834                         account,
   2835                         authTokenType,
   2836                         activity != null,
   2837                         optionsIn);
   2838             }
   2839         }.start();
   2840     }
   2841 
   2842     /**
   2843      * Finishes the session started by {@link #startAddAccountSession} or
   2844      * {@link #startUpdateCredentialsSession}. This will either add the account
   2845      * to AccountManager or update the local credentials stored.
   2846      * <p>
   2847      * This method may be called from any thread, but the returned
   2848      * {@link AccountManagerFuture} must not be used on the main thread.
   2849      *
   2850      * @param sessionBundle a {@link Bundle} created by {@link #startAddAccountSession} or
   2851      *            {@link #startUpdateCredentialsSession}
   2852      * @param activity The {@link Activity} context to use for launching a new
   2853      *            authenticator-defined sub-Activity to prompt the user to
   2854      *            create an account or reauthenticate existing account; used
   2855      *            only to call startActivity(); if null, the prompt will not
   2856      *            be launched directly, but the necessary {@link Intent} will
   2857      *            be returned to the caller instead
   2858      * @param callback Callback to invoke when the request completes, null for
   2859      *            no callback
   2860      * @param handler {@link Handler} identifying the callback thread, null for
   2861      *            the main thread
   2862      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
   2863      *         these fields if an activity was supplied and an account was added
   2864      *         to device or local credentials were updated::
   2865      *         <ul>
   2866      *         <li>{@link #KEY_ACCOUNT_NAME} - the name of the account created
   2867      *         <li>{@link #KEY_ACCOUNT_TYPE} - the type of the account
   2868      *         </ul>
   2869      *         If no activity was specified and additional information is needed
   2870      *         from user, the returned Bundle may contains only
   2871      *         {@link #KEY_INTENT} with the {@link Intent} needed to launch the
   2872      *         actual account creation process. If an error occurred,
   2873      *         {@link AccountManagerFuture#getResult()} throws:
   2874      *         <ul>
   2875      *         <li>{@link AuthenticatorException} if no authenticator was
   2876      *         registered for this account type or the authenticator failed to
   2877      *         respond
   2878      *         <li>{@link OperationCanceledException} if the operation was
   2879      *         canceled for any reason, including the user canceling the
   2880      *         creation process or adding accounts (of this type) has been
   2881      *         disabled by policy
   2882      *         <li>{@link IOException} if the authenticator experienced an I/O
   2883      *         problem creating a new account, usually because of network
   2884      *         trouble
   2885      *         </ul>
   2886      * @see #startAddAccountSession and #startUpdateCredentialsSession
   2887      * @hide
   2888      */
   2889     @SystemApi
   2890     public AccountManagerFuture<Bundle> finishSession(
   2891             final Bundle sessionBundle,
   2892             final Activity activity,
   2893             AccountManagerCallback<Bundle> callback,
   2894             Handler handler) {
   2895         return finishSessionAsUser(
   2896                 sessionBundle,
   2897                 activity,
   2898                 Process.myUserHandle(),
   2899                 callback,
   2900                 handler);
   2901     }
   2902 
   2903     /**
   2904      * @see #finishSession
   2905      * @hide
   2906      */
   2907     @SystemApi
   2908     public AccountManagerFuture<Bundle> finishSessionAsUser(
   2909             final Bundle sessionBundle,
   2910             final Activity activity,
   2911             final UserHandle userHandle,
   2912             AccountManagerCallback<Bundle> callback,
   2913             Handler handler) {
   2914         if (sessionBundle == null) {
   2915             throw new IllegalArgumentException("sessionBundle is null");
   2916         }
   2917 
   2918         /* Add information required by add account flow */
   2919         final Bundle appInfo = new Bundle();
   2920         appInfo.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
   2921 
   2922         return new AmsTask(activity, handler, callback) {
   2923             @Override
   2924             public void doWork() throws RemoteException {
   2925                 mService.finishSessionAsUser(
   2926                         mResponse,
   2927                         sessionBundle,
   2928                         activity != null,
   2929                         appInfo,
   2930                         userHandle.getIdentifier());
   2931             }
   2932         }.start();
   2933     }
   2934 
   2935     /**
   2936      * Checks whether {@link #updateCredentials} or {@link #startUpdateCredentialsSession} should be
   2937      * called with respect to the specified account.
   2938      * <p>
   2939      * This method may be called from any thread, but the returned {@link AccountManagerFuture} must
   2940      * not be used on the main thread.
   2941      *
   2942      * @param account The {@link Account} to be checked whether {@link #updateCredentials} or
   2943      * {@link #startUpdateCredentialsSession} should be called
   2944      * @param statusToken a String of token to check account staus
   2945      * @param callback Callback to invoke when the request completes, null for no callback
   2946      * @param handler {@link Handler} identifying the callback thread, null for the main thread
   2947      * @return An {@link AccountManagerFuture} which resolves to a Boolean, true if the credentials
   2948      *         of the account should be updated.
   2949      * @hide
   2950      */
   2951     @SystemApi
   2952     public AccountManagerFuture<Boolean> isCredentialsUpdateSuggested(
   2953             final Account account,
   2954             final String statusToken,
   2955             AccountManagerCallback<Boolean> callback,
   2956             Handler handler) {
   2957         if (account == null) {
   2958             throw new IllegalArgumentException("account is null");
   2959         }
   2960 
   2961         if (TextUtils.isEmpty(statusToken)) {
   2962             throw new IllegalArgumentException("status token is empty");
   2963         }
   2964 
   2965         return new Future2Task<Boolean>(handler, callback) {
   2966             @Override
   2967             public void doWork() throws RemoteException {
   2968                 mService.isCredentialsUpdateSuggested(
   2969                         mResponse,
   2970                         account,
   2971                         statusToken);
   2972             }
   2973             @Override
   2974             public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
   2975                 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
   2976                     throw new AuthenticatorException("no result in response");
   2977                 }
   2978                 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
   2979             }
   2980         }.start();
   2981     }
   2982 
   2983     /**
   2984      * Gets whether a given package under a user has access to an account.
   2985      * Can be called only from the system UID.
   2986      *
   2987      * @param account The account for which to check.
   2988      * @param packageName The package for which to check.
   2989      * @param userHandle The user for which to check.
   2990      * @return True if the package can access the account.
   2991      *
   2992      * @hide
   2993      */
   2994     public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
   2995             @NonNull UserHandle userHandle) {
   2996         try {
   2997             return mService.hasAccountAccess(account, packageName, userHandle);
   2998         } catch (RemoteException e) {
   2999             throw e.rethrowFromSystemServer();
   3000         }
   3001     }
   3002 
   3003     /**
   3004      * Creates an intent to request access to a given account for a UID.
   3005      * The returned intent should be stated for a result where {@link
   3006      * Activity#RESULT_OK} result means access was granted whereas {@link
   3007      * Activity#RESULT_CANCELED} result means access wasn't granted. Can
   3008      * be called only from the system UID.
   3009      *
   3010      * @param account The account for which to request.
   3011      * @param packageName The package name which to request.
   3012      * @param userHandle The user for which to request.
   3013      * @return The intent to request account access or null if the package
   3014      *     doesn't exist.
   3015      *
   3016      * @hide
   3017      */
   3018     public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
   3019             @NonNull String packageName, @NonNull UserHandle userHandle) {
   3020         try {
   3021             return mService.createRequestAccountAccessIntentSenderAsUser(account, packageName,
   3022                     userHandle);
   3023         } catch (RemoteException e) {
   3024             throw e.rethrowFromSystemServer();
   3025         }
   3026     }
   3027 }
   3028