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