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