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