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