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