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