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