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