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