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