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