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 wether 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 e) {
2388                 throw new OperationCanceledException();
2389             } catch (TimeoutException e) {
2390                 // fall through and cancel
2391             } catch (InterruptedException e) {
2392                 // fall through and cancel
2393             } catch (ExecutionException e) {
2394                 final Throwable cause = e.getCause();
2395                 if (cause instanceof IOException) {
2396                     throw (IOException) cause;
2397                 } else if (cause instanceof UnsupportedOperationException) {
2398                     throw new AuthenticatorException(cause);
2399                 } else if (cause instanceof AuthenticatorException) {
2400                     throw (AuthenticatorException) cause;
2401                 } else if (cause instanceof RuntimeException) {
2402                     throw (RuntimeException) cause;
2403                 } else if (cause instanceof Error) {
2404                     throw (Error) cause;
2405                 } else {
2406                     throw new IllegalStateException(cause);
2407                 }
2408             } finally {
2409                 cancel(true /* interrupt if running */);
2410             }
2411             throw new OperationCanceledException();
2412         }
2413 
2414         @Override
2415         public Bundle getResult()
2416                 throws OperationCanceledException, IOException, AuthenticatorException {
2417             return internalGetResult(null, null);
2418         }
2419 
2420         @Override
2421         public Bundle getResult(long timeout, TimeUnit unit)
2422                 throws OperationCanceledException, IOException, AuthenticatorException {
2423             return internalGetResult(timeout, unit);
2424         }
2425 
2426         @Override
2427         protected void done() {
2428             if (mCallback != null) {
2429                 postToHandler(mHandler, mCallback, this);
2430             }
2431         }
2432 
2433         /** Handles the responses from the AccountManager */
2434         private class Response extends IAccountManagerResponse.Stub {
2435             @Override
2436             public void onResult(Bundle bundle) {
2437                 if (bundle == null) {
2438                     onError(ERROR_CODE_INVALID_RESPONSE, "null bundle returned");
2439                     return;
2440                 }
2441                 Intent intent = bundle.getParcelable(KEY_INTENT, android.content.Intent.class);
2442                 if (intent != null && mActivity != null) {
2443                     // since the user provided an Activity we will silently start intents
2444                     // that we see
2445                     mActivity.startActivity(intent);
2446                     // leave the Future running to wait for the real response to this request
2447                 } else if (bundle.getBoolean("retry")) {
2448                     try {
2449                         doWork();
2450                     } catch (RemoteException e) {
2451                         throw e.rethrowFromSystemServer();
2452                     }
2453                 } else {
2454                     set(bundle);
2455                 }
2456             }
2457 
2458             @Override
2459             public void onError(int code, String message) {
2460                 if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
2461                         || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
2462                     // the authenticator indicated that this request was canceled or we were
2463                     // forbidden to fulfill; cancel now
2464                     cancel(true /* mayInterruptIfRunning */);
2465                     return;
2466                 }
2467                 setException(convertErrorToException(code, message));
2468             }
2469         }
2470 
2471     }
2472 
2473     private abstract class BaseFutureTask<T> extends FutureTask<T> {
2474         final public IAccountManagerResponse mResponse;
2475         final Handler mHandler;
2476 
2477         public BaseFutureTask(Handler handler) {
2478             super(new Callable<T>() {
2479                 @Override
2480                 public T call() throws Exception {
2481                     throw new IllegalStateException("this should never be called");
2482                 }
2483             });
2484             mHandler = handler;
2485             mResponse = new Response();
2486         }
2487 
2488         public abstract void doWork() throws RemoteException;
2489 
2490         public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException;
2491 
2492         protected void postRunnableToHandler(Runnable runnable) {
2493             Handler handler = (mHandler == null) ? mMainHandler : mHandler;
2494             handler.post(runnable);
2495         }
2496 
2497         protected void startTask() {
2498             try {
2499                 doWork();
2500             } catch (RemoteException e) {
2501                 setException(e);
2502             }
2503         }
2504 
2505         protected class Response extends IAccountManagerResponse.Stub {
2506             @Override
2507             public void onResult(Bundle bundle) {
2508                 try {
2509                     T result = bundleToResult(bundle);
2510                     if (result == null) {
2511                         return;
2512                     }
2513                     set(result);
2514                     return;
2515                 } catch (ClassCastException e) {
2516                     // we will set the exception below
2517                 } catch (AuthenticatorException e) {
2518                     // we will set the exception below
2519                 }
2520                 onError(ERROR_CODE_INVALID_RESPONSE, "no result in response");
2521             }
2522 
2523             @Override
2524             public void onError(int code, String message) {
2525                 if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
2526                         || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
2527                     // the authenticator indicated that this request was canceled or we were
2528                     // forbidden to fulfill; cancel now
2529                     cancel(true /* mayInterruptIfRunning */);
2530                     return;
2531                 }
2532                 setException(convertErrorToException(code, message));
2533             }
2534         }
2535     }
2536 
2537     private abstract class Future2Task<T>
2538             extends BaseFutureTask<T> implements AccountManagerFuture<T> {
2539         final AccountManagerCallback<T> mCallback;
2540         public Future2Task(Handler handler, AccountManagerCallback<T> callback) {
2541             super(handler);
2542             mCallback = callback;
2543         }
2544 
2545         @Override
2546         protected void done() {
2547             if (mCallback != null) {
2548                 postRunnableToHandler(new Runnable() {
2549                     @Override
2550                     public void run() {
2551                         mCallback.run(Future2Task.this);
2552                     }
2553                 });
2554             }
2555         }
2556 
2557         public Future2Task<T> start() {
2558             startTask();
2559             return this;
2560         }
2561 
2562         private T internalGetResult(Long timeout, TimeUnit unit)
2563                 throws OperationCanceledException, IOException, AuthenticatorException {
2564             if (!isDone()) {
2565                 ensureNotOnMainThread();
2566             }
2567             try {
2568                 if (timeout == null) {
2569                     return get();
2570                 } else {
2571                     return get(timeout, unit);
2572                 }
2573             } catch (InterruptedException e) {
2574                 // fall through and cancel
2575             } catch (TimeoutException e) {
2576                 // fall through and cancel
2577             } catch (CancellationException e) {
2578                 // fall through and cancel
2579             } catch (ExecutionException e) {
2580                 final Throwable cause = e.getCause();
2581                 if (cause instanceof IOException) {
2582                     throw (IOException) cause;
2583                 } else if (cause instanceof UnsupportedOperationException) {
2584                     throw new AuthenticatorException(cause);
2585                 } else if (cause instanceof AuthenticatorException) {
2586                     throw (AuthenticatorException) cause;
2587                 } else if (cause instanceof RuntimeException) {
2588                     throw (RuntimeException) cause;
2589                 } else if (cause instanceof Error) {
2590                     throw (Error) cause;
2591                 } else {
2592                     throw new IllegalStateException(cause);
2593                 }
2594             } finally {
2595                 cancel(true /* interrupt if running */);
2596             }
2597             throw new OperationCanceledException();
2598         }
2599 
2600         @Override
2601         public T getResult()
2602                 throws OperationCanceledException, IOException, AuthenticatorException {
2603             return internalGetResult(null, null);
2604         }
2605 
2606         @Override
2607         public T getResult(long timeout, TimeUnit unit)
2608                 throws OperationCanceledException, IOException, AuthenticatorException {
2609             return internalGetResult(timeout, unit);
2610         }
2611 
2612     }
2613 
2614     private Exception convertErrorToException(int code, String message) {
2615         if (code == ERROR_CODE_NETWORK_ERROR) {
2616             return new IOException(message);
2617         }
2618 
2619         if (code == ERROR_CODE_UNSUPPORTED_OPERATION) {
2620             return new UnsupportedOperationException(message);
2621         }
2622 
2623         if (code == ERROR_CODE_INVALID_RESPONSE) {
2624             return new AuthenticatorException(message);
2625         }
2626 
2627         if (code == ERROR_CODE_BAD_ARGUMENTS) {
2628             return new IllegalArgumentException(message);
2629         }
2630 
2631         return new AuthenticatorException(message);
2632     }
2633 
2634     private void getAccountByTypeAndFeatures(String accountType, String[] features,
2635         AccountManagerCallback<Bundle> callback, Handler handler) {
2636         (new AmsTask(null, handler, callback) {
2637             @Override
2638             public void doWork() throws RemoteException {
2639                 mService.getAccountByTypeAndFeatures(mResponse, accountType, features,
2640                     mContext.getOpPackageName());
2641             }
2642 
2643         }).start();
2644     }
2645 
2646     private class GetAuthTokenByTypeAndFeaturesTask
2647             extends AmsTask implements AccountManagerCallback<Bundle> {
2648         GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
2649                 final String[] features, Activity activityForPrompting,
2650                 final Bundle addAccountOptions, final Bundle loginOptions,
2651                 AccountManagerCallback<Bundle> callback, Handler handler) {
2652             super(activityForPrompting, handler, callback);
2653             if (accountType == null) throw new IllegalArgumentException("account type is null");
2654             mAccountType = accountType;
2655             mAuthTokenType = authTokenType;
2656             mFeatures = features;
2657             mAddAccountOptions = addAccountOptions;
2658             mLoginOptions = loginOptions;
2659             mMyCallback = this;
2660         }
2661         volatile AccountManagerFuture<Bundle> mFuture = null;
2662         final String mAccountType;
2663         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
2664         final String mAuthTokenType;
2665         final String[] mFeatures;
2666         final Bundle mAddAccountOptions;
2667         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
2668         final Bundle mLoginOptions;
2669         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
2670         final AccountManagerCallback<Bundle> mMyCallback;
2671         private volatile int mNumAccounts = 0;
2672 
2673         @Override
2674         public void doWork() throws RemoteException {
2675             getAccountByTypeAndFeatures(mAccountType, mFeatures,
2676                     new AccountManagerCallback<Bundle>() {
2677                         @Override
2678                         public void run(AccountManagerFuture<Bundle> future) {
2679                             String accountName = null;
2680                             String accountType = null;
2681                             try {
2682                                 Bundle result = future.getResult();
2683                                 accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
2684                                 accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
2685                             } catch (OperationCanceledException e) {
2686                                 setException(e);
2687                                 return;
2688                             } catch (IOException e) {
2689                                 setException(e);
2690                                 return;
2691                             } catch (AuthenticatorException e) {
2692                                 setException(e);
2693                                 return;
2694                             }
2695 
2696                             if (accountName == null) {
2697                                 if (mActivity != null) {
2698                                     // no accounts, add one now. pretend that the user directly
2699                                     // made this request
2700                                     mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures,
2701                                             mAddAccountOptions, mActivity, mMyCallback, mHandler);
2702                                 } else {
2703                                     // send result since we can't prompt to add an account
2704                                     Bundle result = new Bundle();
2705                                     result.putString(KEY_ACCOUNT_NAME, null);
2706                                     result.putString(KEY_ACCOUNT_TYPE, null);
2707                                     result.putString(KEY_AUTHTOKEN, null);
2708                                     result.putBinder(KEY_ACCOUNT_ACCESS_ID, null);
2709                                     try {
2710                                         mResponse.onResult(result);
2711                                     } catch (RemoteException e) {
2712                                         // this will never happen
2713                                     }
2714                                     // we are done
2715                                 }
2716                             } else {
2717                                 mNumAccounts = 1;
2718                                 Account account = new Account(accountName, accountType);
2719                                 // have a single account, return an authtoken for it
2720                                 if (mActivity == null) {
2721                                     mFuture = getAuthToken(account, mAuthTokenType,
2722                                             false /* notifyAuthFailure */, mMyCallback, mHandler);
2723                                 } else {
2724                                     mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
2725                                             mActivity, mMyCallback, mHandler);
2726                                 }
2727                             }
2728                         }}, mHandler);
2729         }
2730 
2731         @Override
2732         public void run(AccountManagerFuture<Bundle> future) {
2733             try {
2734                 final Bundle result = future.getResult();
2735                 if (mNumAccounts == 0) {
2736                     final String accountName = result.getString(KEY_ACCOUNT_NAME);
2737                     final String accountType = result.getString(KEY_ACCOUNT_TYPE);
2738                     if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
2739                         setException(new AuthenticatorException("account not in result"));
2740                         return;
2741                     }
2742                     final String accessId = result.getString(KEY_ACCOUNT_ACCESS_ID);
2743                     final Account account = new Account(accountName, accountType, accessId);
2744                     mNumAccounts = 1;
2745                     getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
2746                             mMyCallback, mHandler);
2747                     return;
2748                 }
2749                 set(result);
2750             } catch (OperationCanceledException e) {
2751                 cancel(true /* mayInterruptIfRUnning */);
2752             } catch (IOException e) {
2753                 setException(e);
2754             } catch (AuthenticatorException e) {
2755                 setException(e);
2756             }
2757         }
2758     }
2759 
2760     /**
2761      * This convenience helper combines the functionality of {@link #getAccountsByTypeAndFeatures},
2762      * {@link #getAuthToken}, and {@link #addAccount}.
2763      *
2764      * <p>
2765      * This method gets a list of the accounts matching specific type and feature set which are
2766      * visible to the caller (see {@link #getAccountsByType} for details);
2767      * if there is exactly one already visible account, it is used; if there are some
2768      * accounts for which user grant visibility, the user is prompted to pick one; if there are
2769      * none, the user is prompted to add one. Finally, an auth token is acquired for the chosen
2770      * account.
2771      *
2772      * <p>
2773      * This method may be called from any thread, but the returned {@link AccountManagerFuture} must
2774      * not be used on the main thread.
2775      *
2776      * <p>
2777      * <b>NOTE:</b> If targeting your app to work on API level 22 and before, MANAGE_ACCOUNTS
2778      * permission is needed for those platforms. See docs for this function in API level 22.
2779      *
2780      * @param accountType The account type required (see {@link #getAccountsByType}), must not be
2781      *        null
2782      * @param authTokenType The desired auth token type (see {@link #getAuthToken}), must not be
2783      *        null
2784      * @param features Required features for the account (see
2785      *        {@link #getAccountsByTypeAndFeatures}), may be null or empty
2786      * @param activity The {@link Activity} context to use for launching new sub-Activities to
2787      *        prompt to add an account, select an account, and/or enter a password, as necessary;
2788      *        used only to call startActivity(); should not be null
2789      * @param addAccountOptions Authenticator-specific options to use for adding new accounts; may
2790      *        be null or empty
2791      * @param getAuthTokenOptions Authenticator-specific options to use for getting auth tokens; may
2792      *        be null or empty
2793      * @param callback Callback to invoke when the request completes, null for no callback
2794      * @param handler {@link Handler} identifying the callback thread, null for the main thread
2795      * @return An {@link AccountManagerFuture} which resolves to a Bundle with at least the
2796      *         following fields:
2797      *         <ul>
2798      *         <li>{@link #KEY_ACCOUNT_NAME} - the name of the account
2799      *         <li>{@link #KEY_ACCOUNT_TYPE} - the type of the account
2800      *         <li>{@link #KEY_AUTHTOKEN} - the auth token you wanted
2801      *         </ul>
2802      *
2803      *         If an error occurred, {@link AccountManagerFuture#getResult()} throws:
2804      *         <ul>
2805      *         <li>{@link AuthenticatorException} if no authenticator was registered for this
2806      *         account type or the authenticator failed to respond
2807      *         <li>{@link OperationCanceledException} if the operation was canceled for any reason,
2808      *         including the user canceling any operation
2809      *         <li>{@link IOException} if the authenticator experienced an I/O problem updating
2810      *         settings, usually because of network trouble
2811      *         </ul>
2812      */
2813     public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
2814             final String accountType, final String authTokenType, final String[] features,
2815             final Activity activity, final Bundle addAccountOptions,
2816             final Bundle getAuthTokenOptions, final AccountManagerCallback<Bundle> callback,
2817             final Handler handler) {
2818         if (accountType == null) throw new IllegalArgumentException("account type is null");
2819         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
2820         final GetAuthTokenByTypeAndFeaturesTask task =
2821                 new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features,
2822                 activity, addAccountOptions, getAuthTokenOptions, callback, handler);
2823         task.start();
2824         return task;
2825     }
2826 
2827     /**
2828      * Deprecated in favor of {@link #newChooseAccountIntent(Account, List, String[], String,
2829      * String, String[], Bundle)}.
2830      *
2831      * Returns an intent to an {@link Activity} that prompts the user to choose from a list of
2832      * accounts.
2833      * The caller will then typically start the activity by calling
2834      * <code>startActivityForResult(intent, ...);</code>.
2835      * <p>
2836      * On success the activity returns a Bundle with the account name and type specified using
2837      * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
2838      * Chosen account is marked as {@link #VISIBILITY_USER_MANAGED_VISIBLE} to the caller
2839      * (see {@link #setAccountVisibility}) and will be returned to it in consequent
2840      * {@link #getAccountsByType}) calls.
2841      * <p>
2842      * The most common case is to call this with one account type, e.g.:
2843      * <p>
2844      * <pre>  newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null,
2845      * null, null, null);</pre>
2846      * @param selectedAccount if specified, indicates that the {@link Account} is the currently
2847      * selected one, according to the caller's definition of selected.
2848      * @param allowableAccounts an optional {@link List} of accounts that are allowed to be
2849      * shown. If not specified then this field will not limit the displayed accounts.
2850      * @param allowableAccountTypes an optional string array of account types. These are used
2851      * both to filter the shown accounts and to filter the list of account types that are shown
2852      * when adding an account. If not specified then this field will not limit the displayed
2853      * account types when adding an account.
2854      * @param alwaysPromptForAccount boolean that is ignored.
2855      * @param descriptionOverrideText if non-null this string is used as the description in the
2856      * accounts chooser screen rather than the default
2857      * @param addAccountAuthTokenType this string is passed as the {@link #addAccount}
2858      * authTokenType parameter
2859      * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount}
2860      * requiredFeatures parameter
2861      * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options
2862      * parameter
2863      * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow.
2864      */
2865     @Deprecated
2866     static public Intent newChooseAccountIntent(
2867             Account selectedAccount,
2868             ArrayList<Account> allowableAccounts,
2869             String[] allowableAccountTypes,
2870             boolean alwaysPromptForAccount,
2871             String descriptionOverrideText,
2872             String addAccountAuthTokenType,
2873             String[] addAccountRequiredFeatures,
2874             Bundle addAccountOptions) {
2875         return newChooseAccountIntent(
2876                 selectedAccount,
2877                 allowableAccounts,
2878                 allowableAccountTypes,
2879                 descriptionOverrideText,
2880                 addAccountAuthTokenType,
2881                 addAccountRequiredFeatures,
2882                 addAccountOptions);
2883     }
2884 
2885     /**
2886      * Returns an intent to an {@link Activity} that prompts the user to choose from a list of
2887      * accounts.
2888      * The caller will then typically start the activity by calling
2889      * <code>startActivityForResult(intent, ...);</code>.
2890      * <p>
2891      * On success the activity returns a Bundle with the account name and type specified using
2892      * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
2893      * Chosen account is marked as {@link #VISIBILITY_USER_MANAGED_VISIBLE} to the caller
2894      * (see {@link #setAccountVisibility}) and will be returned to it in consequent
2895      * {@link #getAccountsByType}) calls.
2896      * <p>
2897      * The most common case is to call this with one account type, e.g.:
2898      * <p>
2899      * <pre>  newChooseAccountIntent(null, null, new String[]{"com.google"}, null, null, null,
2900      * null);</pre>
2901      * @param selectedAccount if specified, indicates that the {@link Account} is the currently
2902      * selected one, according to the caller's definition of selected.
2903      * @param allowableAccounts an optional {@link List} of accounts that are allowed to be
2904      * shown. If not specified then this field will not limit the displayed accounts.
2905      * @param allowableAccountTypes an optional string array of account types. These are used
2906      * both to filter the shown accounts and to filter the list of account types that are shown
2907      * when adding an account. If not specified then this field will not limit the displayed
2908      * account types when adding an account.
2909      * @param descriptionOverrideText if non-null this string is used as the description in the
2910      * accounts chooser screen rather than the default
2911      * @param addAccountAuthTokenType this string is passed as the {@link #addAccount}
2912      * authTokenType parameter
2913      * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount}
2914      * requiredFeatures parameter
2915      * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options
2916      * parameter
2917      * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow.
2918      */
2919     static public Intent newChooseAccountIntent(
2920             Account selectedAccount,
2921             List<Account> allowableAccounts,
2922             String[] allowableAccountTypes,
2923             String descriptionOverrideText,
2924             String addAccountAuthTokenType,
2925             String[] addAccountRequiredFeatures,
2926             Bundle addAccountOptions) {
2927         Intent intent = new Intent();
2928         ComponentName componentName = ComponentName.unflattenFromString(
2929                 Resources.getSystem().getString(R.string.config_chooseTypeAndAccountActivity));
2930         intent.setClassName(componentName.getPackageName(),
2931                 componentName.getClassName());
2932         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST,
2933                 allowableAccounts == null ? null : new ArrayList<Account>(allowableAccounts));
2934         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
2935                 allowableAccountTypes);
2936         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
2937                 addAccountOptions);
2938         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_SELECTED_ACCOUNT, selectedAccount);
2939         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_DESCRIPTION_TEXT_OVERRIDE,
2940                 descriptionOverrideText);
2941         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,
2942                 addAccountAuthTokenType);
2943         intent.putExtra(
2944                 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,
2945                 addAccountRequiredFeatures);
2946         return intent;
2947     }
2948 
2949     private final HashMap<OnAccountsUpdateListener, Handler> mAccountsUpdatedListeners =
2950             Maps.newHashMap();
2951 
2952     private final HashMap<OnAccountsUpdateListener, Set<String> > mAccountsUpdatedListenersTypes =
2953             Maps.newHashMap();
2954 
2955     /**
2956      * BroadcastReceiver that listens for the ACTION_VISIBLE_ACCOUNTS_CHANGED intent
2957      * so that it can read the updated list of accounts and send them to the listener
2958      * in mAccountsUpdatedListeners.
2959      */
2960     private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
2961         @Override
2962         public void onReceive(final Context context, final Intent intent) {
2963             final Account[] accounts = getAccounts();
2964             // send the result to the listeners
2965             synchronized (mAccountsUpdatedListeners) {
2966                 for (Map.Entry<OnAccountsUpdateListener, Handler> entry :
2967                         mAccountsUpdatedListeners.entrySet()) {
2968                     postToHandler(entry.getValue(), entry.getKey(), accounts);
2969                 }
2970             }
2971         }
2972     };
2973 
2974     /**
2975      * Adds an {@link OnAccountsUpdateListener} to this instance of the {@link AccountManager}. This
2976      * listener will be notified whenever user or AbstractAccountAuthenticator made changes to
2977      * accounts of any type related to the caller. This method is equivalent to
2978      * addOnAccountsUpdatedListener(listener, handler, updateImmediately, null)
2979      *
2980      * @see #addOnAccountsUpdatedListener(OnAccountsUpdateListener, Handler, boolean,
2981      *      String[])
2982      */
2983     public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
2984             Handler handler, boolean updateImmediately) {
2985         addOnAccountsUpdatedListener(listener, handler,updateImmediately, null);
2986     }
2987 
2988     /**
2989      * Adds an {@link OnAccountsUpdateListener} to this instance of the {@link AccountManager}. This
2990      * listener will be notified whenever user or AbstractAccountAuthenticator made changes to
2991      * accounts of given types related to the caller -
2992      * either list of accounts returned by {@link #getAccounts()}
2993      * was changed, or new account was added for which user can grant access to the caller.
2994      * <p>
2995      * As long as this listener is present, the AccountManager instance will not be
2996      * garbage-collected, and neither will the {@link Context} used to retrieve it, which may be a
2997      * large Activity instance. To avoid memory leaks, you must remove this listener before then.
2998      * Normally listeners are added in an Activity or Service's {@link Activity#onCreate} and
2999      * removed in {@link Activity#onDestroy}.
3000      * <p>
3001      * It is safe to call this method from the main thread.
3002      *
3003      * @param listener The listener to send notifications to
3004      * @param handler {@link Handler} identifying the thread to use for notifications, null for the
3005      *        main thread
3006      * @param updateImmediately If true, the listener will be invoked (on the handler thread) right
3007      *        away with the current account list
3008      * @param accountTypes If set, only changes to accounts of given types will be reported.
3009      * @throws IllegalArgumentException if listener is null
3010      * @throws IllegalStateException if listener was already added
3011      */
3012     public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
3013             Handler handler, boolean updateImmediately, String[] accountTypes) {
3014         if (listener == null) {
3015             throw new IllegalArgumentException("the listener is null");
3016         }
3017         synchronized (mAccountsUpdatedListeners) {
3018             if (mAccountsUpdatedListeners.containsKey(listener)) {
3019                 throw new IllegalStateException("this listener is already added");
3020             }
3021             final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
3022 
3023             mAccountsUpdatedListeners.put(listener, handler);
3024             if (accountTypes != null) {
3025                 mAccountsUpdatedListenersTypes.put(listener,
3026                     new HashSet<String>(Arrays.asList(accountTypes)));
3027             } else {
3028                 mAccountsUpdatedListenersTypes.put(listener, null);
3029             }
3030 
3031             if (wasEmpty) {
3032                 // Register a broadcast receiver to monitor account changes
3033                 IntentFilter intentFilter = new IntentFilter();
3034                 intentFilter.addAction(ACTION_VISIBLE_ACCOUNTS_CHANGED);
3035                 // To recover from disk-full.
3036                 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
3037                 mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
3038             }
3039 
3040             try {
3041                 // Notify AccountManagedService about new receiver.
3042                 // The receiver must be unregistered later exactly one time
3043                 mService.registerAccountListener(accountTypes, mContext.getOpPackageName());
3044             } catch (RemoteException e) {
3045                 throw e.rethrowFromSystemServer();
3046             }
3047         }
3048         if (updateImmediately) {
3049             postToHandler(handler, listener, getAccounts());
3050         }
3051     }
3052 
3053     /**
3054      * Removes an {@link OnAccountsUpdateListener} previously registered with
3055      * {@link #addOnAccountsUpdatedListener}.  The listener will no longer
3056      * receive notifications of account changes.
3057      *
3058      * <p>It is safe to call this method from the main thread.
3059      *
3060      * <p>No permission is required to call this method.
3061      *
3062      * @param listener The previously added listener to remove
3063      * @throws IllegalArgumentException if listener is null
3064      * @throws IllegalStateException if listener was not already added
3065      */
3066     public void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) {
3067         if (listener == null) throw new IllegalArgumentException("listener is null");
3068         synchronized (mAccountsUpdatedListeners) {
3069             if (!mAccountsUpdatedListeners.containsKey(listener)) {
3070                 Log.e(TAG, "Listener was not previously added");
3071                 return;
3072             }
3073             Set<String> accountTypes = mAccountsUpdatedListenersTypes.get(listener);
3074             String[] accountsArray;
3075             if (accountTypes != null) {
3076                 accountsArray = accountTypes.toArray(new String[accountTypes.size()]);
3077             } else {
3078                 accountsArray = null;
3079             }
3080             mAccountsUpdatedListeners.remove(listener);
3081             mAccountsUpdatedListenersTypes.remove(listener);
3082             if (mAccountsUpdatedListeners.isEmpty()) {
3083                 mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
3084             }
3085             try {
3086                 mService.unregisterAccountListener(accountsArray, mContext.getOpPackageName());
3087             } catch (RemoteException e) {
3088                 throw e.rethrowFromSystemServer();
3089             }
3090         }
3091     }
3092 
3093     /**
3094      * Asks the user to authenticate with an account of a specified type. The
3095      * authenticator for this account type processes this request with the
3096      * appropriate user interface. If the user does elect to authenticate with a
3097      * new account, a bundle of session data for installing the account later is
3098      * returned with optional account password and account status token.
3099      * <p>
3100      * This method may be called from any thread, but the returned
3101      * {@link AccountManagerFuture} must not be used on the main thread.
3102      * <p>
3103      * <p>
3104      * <b>NOTE:</b> The account will not be installed to the device by calling
3105      * this api alone. #finishSession should be called after this to install the
3106      * account on device.
3107      *
3108      * @param accountType The type of account to add; must not be null
3109      * @param authTokenType The type of auth token (see {@link #getAuthToken})
3110      *            this account will need to be able to generate, null for none
3111      * @param requiredFeatures The features (see {@link #hasFeatures}) this
3112      *            account must have, null for none
3113      * @param options Authenticator-specific options for the request, may be
3114      *            null or empty
3115      * @param activity The {@link Activity} context to use for launching a new
3116      *            authenticator-defined sub-Activity to prompt the user to
3117      *            create an account; used only to call startActivity(); if null,
3118      *            the prompt will not be launched directly, but the necessary
3119      *            {@link Intent} will be returned to the caller instead
3120      * @param callback Callback to invoke when the request completes, null for
3121      *            no callback
3122      * @param handler {@link Handler} identifying the callback thread, null for
3123      *            the main thread
3124      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
3125      *         these fields if activity was specified and user was authenticated
3126      *         with an account:
3127      *         <ul>
3128      *         <li>{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for
3129      *         adding the the to the device later.
3130      *         <li>{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
3131      *         status of the account
3132      *         </ul>
3133      *         If no activity was specified, the returned Bundle contains only
3134      *         {@link #KEY_INTENT} with the {@link Intent} needed to launch the
3135      *         actual account creation process. If authenticator doesn't support
3136      *         this method, the returned Bundle contains only
3137      *         {@link #KEY_ACCOUNT_SESSION_BUNDLE} with encrypted
3138      *         {@code options} needed to add account later. If an error
3139      *         occurred, {@link AccountManagerFuture#getResult()} throws:
3140      *         <ul>
3141      *         <li>{@link AuthenticatorException} if no authenticator was
3142      *         registered for this account type or the authenticator failed to
3143      *         respond
3144      *         <li>{@link OperationCanceledException} if the operation was
3145      *         canceled for any reason, including the user canceling the
3146      *         creation process or adding accounts (of this type) has been
3147      *         disabled by policy
3148      *         <li>{@link IOException} if the authenticator experienced an I/O
3149      *         problem creating a new account, usually because of network
3150      *         trouble
3151      *         </ul>
3152      * @see #finishSession
3153      */
3154     public AccountManagerFuture<Bundle> startAddAccountSession(
3155             final String accountType,
3156             final String authTokenType,
3157             final String[] requiredFeatures,
3158             final Bundle options,
3159             final Activity activity,
3160             AccountManagerCallback<Bundle> callback,
3161             Handler handler) {
3162         if (accountType == null) throw new IllegalArgumentException("accountType is null");
3163         final Bundle optionsIn = new Bundle();
3164         if (options != null) {
3165             optionsIn.putAll(options);
3166         }
3167         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
3168 
3169         return new AmsTask(activity, handler, callback) {
3170             @Override
3171             public void doWork() throws RemoteException {
3172                 mService.startAddAccountSession(
3173                         mResponse,
3174                         accountType,
3175                         authTokenType,
3176                         requiredFeatures,
3177                         activity != null,
3178                         optionsIn);
3179             }
3180         }.start();
3181     }
3182 
3183     /**
3184      * Asks the user to enter a new password for the account but not updating the
3185      * saved credentials for the account until {@link #finishSession} is called.
3186      * <p>
3187      * This method may be called from any thread, but the returned
3188      * {@link AccountManagerFuture} must not be used on the main thread.
3189      * <p>
3190      * <b>NOTE:</b> The saved credentials for the account alone will not be
3191      * updated by calling this API alone. #finishSession should be called after
3192      * this to update local credentials
3193      *
3194      * @param account The account to update credentials for
3195      * @param authTokenType The credentials entered must allow an auth token of
3196      *            this type to be created (but no actual auth token is
3197      *            returned); may be null
3198      * @param options Authenticator-specific options for the request; may be
3199      *            null or empty
3200      * @param activity The {@link Activity} context to use for launching a new
3201      *            authenticator-defined sub-Activity to prompt the user to enter
3202      *            a password; used only to call startActivity(); if null, the
3203      *            prompt will not be launched directly, but the necessary
3204      *            {@link Intent} will be returned to the caller instead
3205      * @param callback Callback to invoke when the request completes, null for
3206      *            no callback
3207      * @param handler {@link Handler} identifying the callback thread, null for
3208      *            the main thread
3209      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
3210      *         these fields if an activity was supplied and user was
3211      *         successfully re-authenticated to the account:
3212      *         <ul>
3213      *         <li>{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for
3214      *         updating the local credentials on device later.
3215      *         <li>{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
3216      *         status of the account
3217      *         </ul>
3218      *         If no activity was specified, the returned Bundle contains
3219      *         {@link #KEY_INTENT} with the {@link Intent} needed to launch the
3220      *         password prompt. If an error occurred,
3221      *         {@link AccountManagerFuture#getResult()} throws:
3222      *         <ul>
3223      *         <li>{@link AuthenticatorException} if the authenticator failed to
3224      *         respond
3225      *         <li>{@link OperationCanceledException} if the operation was
3226      *         canceled for any reason, including the user canceling the
3227      *         password prompt
3228      *         <li>{@link IOException} if the authenticator experienced an I/O
3229      *         problem verifying the password, usually because of network
3230      *         trouble
3231      *         </ul>
3232      * @see #finishSession
3233      */
3234     public AccountManagerFuture<Bundle> startUpdateCredentialsSession(
3235             final Account account,
3236             final String authTokenType,
3237             final Bundle options,
3238             final Activity activity,
3239             final AccountManagerCallback<Bundle> callback,
3240             final Handler handler) {
3241         if (account == null) {
3242             throw new IllegalArgumentException("account is null");
3243         }
3244 
3245         // Always include the calling package name. This just makes life easier
3246         // down stream.
3247         final Bundle optionsIn = new Bundle();
3248         if (options != null) {
3249             optionsIn.putAll(options);
3250         }
3251         optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
3252 
3253         return new AmsTask(activity, handler, callback) {
3254             @Override
3255             public void doWork() throws RemoteException {
3256                 mService.startUpdateCredentialsSession(
3257                         mResponse,
3258                         account,
3259                         authTokenType,
3260                         activity != null,
3261                         optionsIn);
3262             }
3263         }.start();
3264     }
3265 
3266     /**
3267      * Finishes the session started by {@link #startAddAccountSession} or
3268      * {@link #startUpdateCredentialsSession}. This will either add the account
3269      * to AccountManager or update the local credentials stored.
3270      * <p>
3271      * This method may be called from any thread, but the returned
3272      * {@link AccountManagerFuture} must not be used on the main thread.
3273      *
3274      * @param sessionBundle a {@link Bundle} created by {@link #startAddAccountSession} or
3275      *            {@link #startUpdateCredentialsSession}
3276      * @param activity The {@link Activity} context to use for launching a new
3277      *            authenticator-defined sub-Activity to prompt the user to
3278      *            create an account or reauthenticate existing account; used
3279      *            only to call startActivity(); if null, the prompt will not
3280      *            be launched directly, but the necessary {@link Intent} will
3281      *            be returned to the caller instead
3282      * @param callback Callback to invoke when the request completes, null for
3283      *            no callback
3284      * @param handler {@link Handler} identifying the callback thread, null for
3285      *            the main thread
3286      * @return An {@link AccountManagerFuture} which resolves to a Bundle with
3287      *         these fields if an activity was supplied and an account was added
3288      *         to device or local credentials were updated::
3289      *         <ul>
3290      *         <li>{@link #KEY_ACCOUNT_NAME} - the name of the account created
3291      *         <li>{@link #KEY_ACCOUNT_TYPE} - the type of the account
3292      *         <li>{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
3293      *         status of the account
3294      *         </ul>
3295      *         If no activity was specified and additional information is needed
3296      *         from user, the returned Bundle may only contain
3297      *         {@link #KEY_INTENT} with the {@link Intent} needed to launch the
3298      *         actual account creation process. If an error occurred,
3299      *         {@link AccountManagerFuture#getResult()} throws:
3300      *         <ul>
3301      *         <li>{@link AuthenticatorException} if no authenticator was
3302      *         registered for this account type or the authenticator failed to
3303      *         respond
3304      *         <li>{@link OperationCanceledException} if the operation was
3305      *         canceled for any reason, including the user canceling the
3306      *         creation process or adding accounts (of this type) has been
3307      *         disabled by policy
3308      *         <li>{@link IOException} if the authenticator experienced an I/O
3309      *         problem creating a new account, usually because of network
3310      *         trouble
3311      *         </ul>
3312      * @see #startAddAccountSession and #startUpdateCredentialsSession
3313      */
3314     @UserHandleAware
3315     public AccountManagerFuture<Bundle> finishSession(
3316             final Bundle sessionBundle,
3317             final Activity activity,
3318             AccountManagerCallback<Bundle> callback,
3319             Handler handler) {
3320         return finishSessionAsUser(
3321                 sessionBundle,
3322                 activity,
3323                 mContext.getUser(),
3324                 callback,
3325                 handler);
3326     }
3327 
3328     /**
3329      * @see #finishSession
3330      * @hide
3331      */
3332     @SystemApi
3333     @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
3334     public AccountManagerFuture<Bundle> finishSessionAsUser(
3335             final Bundle sessionBundle,
3336             final Activity activity,
3337             final UserHandle userHandle,
3338             AccountManagerCallback<Bundle> callback,
3339             Handler handler) {
3340         if (sessionBundle == null) {
3341             throw new IllegalArgumentException("sessionBundle is null");
3342         }
3343 
3344         /* Add information required by add account flow */
3345         final Bundle appInfo = new Bundle();
3346         appInfo.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
3347 
3348         return new AmsTask(activity, handler, callback) {
3349             @Override
3350             public void doWork() throws RemoteException {
3351                 mService.finishSessionAsUser(
3352                         mResponse,
3353                         sessionBundle,
3354                         activity != null,
3355                         appInfo,
3356                         userHandle.getIdentifier());
3357             }
3358         }.start();
3359     }
3360 
3361     /**
3362      * Checks whether {@link #updateCredentials} or {@link #startUpdateCredentialsSession} should be
3363      * called with respect to the specified account.
3364      * <p>
3365      * This method may be called from any thread, but the returned {@link AccountManagerFuture} must
3366      * not be used on the main thread.
3367      *
3368      * @param account The {@link Account} to be checked whether {@link #updateCredentials} or
3369      * {@link #startUpdateCredentialsSession} should be called
3370      * @param statusToken a String of token to check account staus
3371      * @param callback Callback to invoke when the request completes, null for no callback
3372      * @param handler {@link Handler} identifying the callback thread, null for the main thread
3373      * @return An {@link AccountManagerFuture} which resolves to a Boolean, true if the credentials
3374      *         of the account should be updated.
3375      */
3376     public AccountManagerFuture<Boolean> isCredentialsUpdateSuggested(
3377             final Account account,
3378             final String statusToken,
3379             AccountManagerCallback<Boolean> callback,
3380             Handler handler) {
3381         if (account == null) {
3382             throw new IllegalArgumentException("account is null");
3383         }
3384 
3385         if (TextUtils.isEmpty(statusToken)) {
3386             throw new IllegalArgumentException("status token is empty");
3387         }
3388 
3389         return new Future2Task<Boolean>(handler, callback) {
3390             @Override
3391             public void doWork() throws RemoteException {
3392                 mService.isCredentialsUpdateSuggested(
3393                         mResponse,
3394                         account,
3395                         statusToken);
3396             }
3397             @Override
3398             public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
3399                 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
3400                     throw new AuthenticatorException("no result in response");
3401                 }
3402                 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
3403             }
3404         }.start();
3405     }
3406 
3407     /**
3408      * Gets whether a given package under a user has access to an account.
3409      * Can be called only from the system UID.
3410      *
3411      * @param account The account for which to check.
3412      * @param packageName The package for which to check.
3413      * @param userHandle The user for which to check.
3414      * @return True if the package can access the account.
3415      *
3416      * @hide
3417      */
3418     public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
3419             @NonNull UserHandle userHandle) {
3420         try {
3421             return mService.hasAccountAccess(account, packageName, userHandle);
3422         } catch (RemoteException e) {
3423             throw e.rethrowFromSystemServer();
3424         }
3425     }
3426 
3427     /**
3428      * Creates an intent to request access to a given account for a UID.
3429      * The returned intent should be stated for a result where {@link
3430      * Activity#RESULT_OK} result means access was granted whereas {@link
3431      * Activity#RESULT_CANCELED} result means access wasn't granted. Can
3432      * be called only from the system UID.
3433      *
3434      * @param account The account for which to request.
3435      * @param packageName The package name which to request.
3436      * @param userHandle The user for which to request.
3437      * @return The intent to request account access or null if the package
3438      *     doesn't exist.
3439      *
3440      * @hide
3441      */
3442     public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
3443             @NonNull String packageName, @NonNull UserHandle userHandle) {
3444         try {
3445             return mService.createRequestAccountAccessIntentSenderAsUser(account, packageName,
3446                     userHandle);
3447         } catch (RemoteException e) {
3448             throw e.rethrowFromSystemServer();
3449         }
3450     }
3451 
3452     /**
3453      * @hide
3454      * Calling this will invalidate Local Accounts Data Cache which
3455      * forces the next query in any process to recompute the cache
3456     */
3457     public static void invalidateLocalAccountsDataCaches() {
3458         PropertyInvalidatedCache.invalidateCache(CACHE_KEY_ACCOUNTS_DATA_PROPERTY);
3459     }
3460 
3461     /**
3462      * @hide
3463      * Calling this will disable account data caching.
3464     */
3465     public void disableLocalAccountCaches() {
3466         mAccountsForUserCache.disableLocal();
3467     }
3468 
3469     /**
3470      * @hide
3471      * Calling this will invalidate Local Account User Data Cache which
3472      * forces the next query in any process to recompute the cache
3473     */
3474     public static void invalidateLocalAccountUserDataCaches() {
3475         PropertyInvalidatedCache.invalidateCache(CACHE_KEY_USER_DATA_PROPERTY);
3476     }
3477 
3478     /**
3479      * @hide
3480      * Calling this will disable user info caching.
3481     */
3482     public void disableLocalUserInfoCaches() {
3483         mUserDataCache.disableLocal();
3484     }
3485 }
3486