1603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/*
2603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Copyright (C) 2009 The Android Open Source Project
3603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
4603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Licensed under the Apache License, Version 2.0 (the "License");
5603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * you may not use this file except in compliance with the License.
6603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * You may obtain a copy of the License at
7603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
8603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *      http://www.apache.org/licenses/LICENSE-2.0
9603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
10603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Unless required by applicable law or agreed to in writing, software
11603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * distributed under the License is distributed on an "AS IS" BASIS,
12603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * See the License for the specific language governing permissions and
14603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * limitations under the License.
15603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
16603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
17603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapackage android.accounts;
18603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
19603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.app.Activity;
20603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.content.Intent;
21603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.content.Context;
22d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport android.content.IntentFilter;
23d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport android.content.BroadcastReceiver;
24b6437245c280596d0a580b8d67189739cf793250Costin Manolacheimport android.database.SQLException;
25a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Bundle;
26a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Handler;
27a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Looper;
28a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.RemoteException;
293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintanaimport android.os.Parcelable;
30751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintanaimport android.os.Build;
31b6437245c280596d0a580b8d67189739cf793250Costin Manolacheimport android.util.Log;
32f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintanaimport android.text.TextUtils;
33603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
34a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.IOException;
35a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.Callable;
36a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.CancellationException;
37a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.ExecutionException;
38a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.FutureTask;
39a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.TimeoutException;
40a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.TimeUnit;
41d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport java.util.HashMap;
42d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport java.util.Map;
43d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
44d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport com.google.android.collect.Maps;
45603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
46603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/**
47661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * This class provides access to a centralized registry of the user's
488e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * online accounts.  The user enters credentials (username and password) once
498e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * per account, granting applications access to online resources with
508e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * "one-click" approval.
51603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
52661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>Different online services have different ways of handling accounts and
53661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * authentication, so the account manager uses pluggable <em>authenticator</em>
548e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * modules for different <em>account types</em>.  Authenticators (which may be
558e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * written by third parties) handle the actual details of validating account
568e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * credentials and storing account information.  For example, Google, Facebook,
578e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * and Microsoft Exchange each have their own authenticator.
58661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor *
59661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>Many servers support some notion of an <em>authentication token</em>,
60661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * which can be used to authenticate a request to the server without sending
61661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the user's actual password.  (Auth tokens are normally created with a
62661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * separate request which does include the user's credentials.)  AccountManager
638e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * can generate auth tokens for applications, so the application doesn't need to
648e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * handle passwords directly.  Auth tokens are normally reusable and cached by
658e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * AccountManager, but must be refreshed periodically.  It's the responsibility
668e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * of applications to <em>invalidate</em> auth tokens when they stop working so
678e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * the AccountManager knows it needs to regenerate them.
68661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor *
69661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>Applications accessing a server normally go through these steps:
70661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor *
71661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <ul>
72661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li>Get an instance of AccountManager using {@link #get(Context)}.
73661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor *
74661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li>List the available accounts using {@link #getAccountsByType} or
75661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #getAccountsByTypeAndFeatures}.  Normally applications will only
76661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * be interested in accounts with one particular <em>type</em>, which
77661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * identifies the authenticator.  Account <em>features</em> are used to
78661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * identify particular account subtypes and capabilities.  Both the account
79661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * type and features are authenticator-specific strings, and must be known by
80661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the application in coordination with its preferred authenticators.
81661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor *
82661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li>Select one or more of the available accounts, possibly by asking the
83661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * user for their preference.  If no suitable accounts are available,
84661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #addAccount} may be called to prompt the user to create an
85661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * account of the appropriate type.
86661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor *
878e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * <li><b>Important:</b> If the application is using a previously remembered
888e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * account selection, it must make sure the account is still in the list
898e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * of accounts returned by {@link #getAccountsByType}.  Requesting an auth token
908e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * for an account no longer on the device results in an undefined failure.
918e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor *
92661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li>Request an auth token for the selected account(s) using one of the
93661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #getAuthToken} methods or related helpers.  Refer to the description
94661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * of each method for exact usage and error handling details.
95661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor *
96661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li>Make the request using the auth token.  The form of the auth token,
97661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the format of the request, and the protocol used are all specific to the
988e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * service you are accessing.  The application may use whatever network and
998e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * protocol libraries are useful.
100661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor *
101661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li><b>Important:</b> If the request fails with an authentication error,
102661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * it could be that a cached auth token is stale and no longer honored by
103661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the server.  The application must call {@link #invalidateAuthToken} to remove
104661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the token from the cache, otherwise requests will continue failing!  After
105661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * invalidating the auth token, immediately go back to the "Request an auth
106661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * token" step above.  If the process fails the second time, then it can be
107661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * treated as a "genuine" authentication failure and the user notified or other
108661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * appropriate actions taken.
109661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * </ul>
110661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor *
1118e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * <p>Some AccountManager methods may need to interact with the user to
112661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * prompt for credentials, present options, or ask the user to add an account.
113661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * The caller may choose whether to allow AccountManager to directly launch the
114661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * necessary user interface and wait for the user, or to return an Intent which
115661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the caller may use to launch the interface, or (in some cases) to install a
116661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * notification which the user can select at any time to launch the interface.
117661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * To have AccountManager launch the interface directly, the caller must supply
118661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the current foreground {@link Activity} context.
119661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor *
120661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>Many AccountManager methods take {@link AccountManagerCallback} and
1218e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * {@link Handler} as parameters.  These methods return immediately and
122661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * run asynchronously. If a callback is provided then
123661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerCallback#run} will be invoked on the Handler's
124661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * thread when the request completes, successfully or not.
1258e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * The result is retrieved by calling {@link AccountManagerFuture#getResult()}
1268e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * on the {@link AccountManagerFuture} returned by the method (and also passed
1278e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * to the callback).  This method waits for the operation to complete (if
1288e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * necessary) and either returns the result or throws an exception if an error
1298e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * occurred during the operation.  To make the request synchronously, call
130661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture#getResult()} immediately on receiving the
1318e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * future from the method; no callback need be supplied.
132661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor *
133661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>Requests which may block, including
134661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture#getResult()}, must never be called on
135661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the application's main event thread.  These operations throw
136661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link IllegalStateException} if they are used on the main thread.
137603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
138603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapublic class AccountManager {
139603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TAG = "AccountManager";
140603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
141f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_REMOTE_EXCEPTION = 1;
142f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_NETWORK_ERROR = 3;
143f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_CANCELED = 4;
144f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_INVALID_RESPONSE = 5;
145f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6;
146f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
147f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_BAD_REQUEST = 8;
148756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana
149661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    /**
1508e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * Bundle key used for the {@link String} account name in results
151661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * from methods which return information about a particular account.
152661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     */
153f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_ACCOUNT_NAME = "authAccount";
154661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor
155661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    /**
1568e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * Bundle key used for the {@link String} account type in results
157661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * from methods which return information about a particular account.
158661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     */
159f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_ACCOUNT_TYPE = "accountType";
160661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor
161661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    /**
1628e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * Bundle key used for the auth token value in results
163661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * from {@link #getAuthToken} and friends.
164661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     */
165661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    public static final String KEY_AUTHTOKEN = "authtoken";
166661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor
167661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    /**
1688e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * Bundle key used for an {@link Intent} in results from methods that
169661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * may require the caller to interact with the user.  The Intent can
170661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * be used to start the corresponding user interface activity.
171661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     */
172f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_INTENT = "intent";
173661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor
174661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    /**
1758e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * Bundle key used to supply the password directly in options to
176661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link #confirmCredentials}, rather than prompting the user with
177661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * the standard password prompt.
178661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     */
179661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    public static final String KEY_PASSWORD = "password";
180661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor
181661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    public static final String KEY_ACCOUNTS = "accounts";
182f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
183f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
184661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    public static final String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
185f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage";
186f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey";
187661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    public static final String KEY_BOOLEAN_RESULT = "booleanResult";
188661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    public static final String KEY_ERROR_CODE = "errorCode";
189661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    public static final String KEY_ERROR_MESSAGE = "errorMessage";
190661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    public static final String KEY_USERDATA = "userdata";
191ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache    /**
192ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache     * Authenticators using 'customTokens' option will also get the UID of the
193ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache     * caller
194ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache     * @hide
195ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache     */
196ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache    public static final String KEY_CALLER_UID = "callerUid";
197ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache
198ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache    /**
199ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache     * @hide
200ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache     */
201ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache    public static final String KEY_CALLER_PID = "callerPid";
202ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache
203ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache    /**
204ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache     * Boolean, if set and 'customTokens' the authenticator is responsible for
205ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache     * notifications.
206ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache     * @hide
207ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache     */
208ef419b2e14e292bf4200a0281ce9125eda431c12Costin Manolache    public static final String KEY_NOTIFY_ON_FAILURE = "notifyOnAuthFailure";
209661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor
210f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String ACTION_AUTHENTICATOR_INTENT =
211f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            "android.accounts.AccountAuthenticator";
212f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String AUTHENTICATOR_META_DATA_NAME =
213661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor            "android.accounts.AccountAuthenticator";
214f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
215f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana
216603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final Context mContext;
217603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final IAccountManager mService;
218d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    private final Handler mMainHandler;
219661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor
220f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    /**
221f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana     * Action sent as a broadcast Intent by the AccountsService
222661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * when accounts are added, accounts are removed, or an
223661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * account's credentials (saved password, etc) are changed.
224661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
225661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @see #addOnAccountsUpdatedListener
226f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana     */
227f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
228f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        "android.accounts.LOGIN_ACCOUNTS_CHANGED";
229603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
2303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    /**
2313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana     * @hide
2323326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana     */
233603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public AccountManager(Context context, IAccountManager service) {
234603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mContext = context;
235603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mService = service;
236d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        mMainHandler = new Handler(mContext.getMainLooper());
237603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
238603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
2390eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana    /**
2400eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana     * @hide used for testing only
2410eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana     */
2420eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana    public AccountManager(Context context, IAccountManager service, Handler handler) {
2430eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana        mContext = context;
2440eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana        mService = service;
2450eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana        mMainHandler = handler;
2460eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana    }
2470eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana
248756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
249f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana     * @hide for internal use only
250f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana     */
251f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana    public static Bundle sanitizeResult(Bundle result) {
252382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (result != null) {
253382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana            if (result.containsKey(KEY_AUTHTOKEN)
254382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana                    && !TextUtils.isEmpty(result.getString(KEY_AUTHTOKEN))) {
255382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana                final Bundle newResult = new Bundle(result);
256382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana                newResult.putString(KEY_AUTHTOKEN, "<omitted for logging purposes>");
257382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana                return newResult;
258382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana            }
259f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana        }
260f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana        return result;
261f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana    }
262f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana
263f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana    /**
264661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Gets an AccountManager instance associated with a Context.
265661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * The {@link Context} will be used as long as the AccountManager is
266661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * active, so make sure to use a {@link Context} whose lifetime is
267661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * commensurate with any listeners registered to
268661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link #addOnAccountsUpdatedListener} or similar methods.
269661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
270661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
271661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
272661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>No permission is required to call this method.
273661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
274756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param context The {@link Context} to use when necessary
275661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An {@link AccountManager} instance
276756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
277a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public static AccountManager get(Context context) {
278382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (context == null) throw new IllegalArgumentException("context is null");
279a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
280a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
281a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
282756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
283661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Gets the saved password associated with the account.
284661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * This is intended for authenticators and related code; applications
285661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * should get an auth token instead.
286661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
287661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
288661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
289661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
290661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
291661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * and to have the same UID as the account's authenticator.
292661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
293661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account to query for a password
294661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return The account's password, null if none or if the account doesn't exist
295756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
296ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public String getPassword(final Account account) {
297382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
298603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
299603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return mService.getPassword(account);
300603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
301ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // will never happen
302603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
303603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
304603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
305603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
306756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
307661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Gets the user data named by "key" associated with the account.
308661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * This is intended for authenticators and related code to store
309661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * arbitrary metadata along with accounts.  The meaning of the keys
310661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * and values is up to the authenticator for the account.
311661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
312661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
313661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
314661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
315661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
316661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * and to have the same UID as the account's authenticator.
317661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
318661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account to query for user data
319661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return The user data, null if the account or key doesn't exist
320756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
321ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public String getUserData(final Account account, final String key) {
322382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
323382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (key == null) throw new IllegalArgumentException("key is null");
324603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
325603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return mService.getUserData(account, key);
326603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
327ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // will never happen
328603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
329603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
330603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
331603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
332756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
333661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Lists the currently registered authenticators.
334661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
335661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
336661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
337661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>No permission is required to call this method.
338661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
339661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An array of {@link AuthenticatorDescription} for every
340661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     authenticator known to the AccountManager service.  Empty (never
341661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null) if no authenticators are known.
342756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
343ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public AuthenticatorDescription[] getAuthenticatorTypes() {
344603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
345a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return mService.getAuthenticatorTypes();
346603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
347ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // will never happen
348603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
349603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
350603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
351603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
352756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
353661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Lists all accounts of any type registered on the device.
354661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Equivalent to getAccountsByType(null).
355661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
356661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
357661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
358661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
359661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#GET_ACCOUNTS}.
360661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
361661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An array of {@link Account}, one for each account.  Empty
362661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     (never null) if no accounts have been added.
363756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
364ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccounts() {
365a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        try {
366ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return mService.getAccounts(null);
367a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        } catch (RemoteException e) {
368ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
369a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            throw new RuntimeException(e);
370a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
371603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
372603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
373756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
374661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Lists all accounts of a particular type.  The account type is a
375661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * string token corresponding to the authenticator and useful domain
376661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * of the account.  For example, there are types corresponding to Google
377661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * and Facebook.  The exact string token to use will be published somewhere
378661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * associated with the authenticator in question.
379661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
380661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
381661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
382661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
383661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#GET_ACCOUNTS}.
384661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
385661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param type The type of accounts to return, null to retrieve all accounts
386661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An array of {@link Account}, one per matching account.  Empty
387661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     (never null) if no accounts of the specified type have been added.
388756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
389ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccountsByType(String type) {
390603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
391ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return mService.getAccounts(type);
392603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
393ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
394603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
395603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
396603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
397603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
398756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
399661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Finds out whether a particular account has all the specified features.
400661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Account features are authenticator-specific string tokens identifying
401661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * boolean account properties.  For example, features are used to tell
402661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * whether Google accounts have a particular service (such as Google
403661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Calendar or Google Talk) enabled.  The feature names and their meanings
404661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * are published somewhere associated with the authenticator in question.
405661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
406661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method may be called from any thread, but the returned
407661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link AccountManagerFuture} must not be used on the main thread.
408661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
409661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
410661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#GET_ACCOUNTS}.
411bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     *
412bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * @param account The {@link Account} to test
413661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param features An array of the account features to check
414661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param callback Callback to invoke when the request completes,
415661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for no callback
416661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param handler {@link Handler} identifying the callback thread,
417661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for the main thread
418661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An {@link AccountManagerFuture} which resolves to a Boolean,
419661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * true if the account exists and has all of the specified features.
420bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     */
4213084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana    public AccountManagerFuture<Boolean> hasFeatures(final Account account,
422bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            final String[] features,
423bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            AccountManagerCallback<Boolean> callback, Handler handler) {
424382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
425382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (features == null) throw new IllegalArgumentException("features is null");
426bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        return new Future2Task<Boolean>(handler, callback) {
427bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            public void doWork() throws RemoteException {
4283084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana                mService.hasFeatures(mResponse, account, features);
429bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
430bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
431bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
432bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    throw new AuthenticatorException("no result in response");
433bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                }
434bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                return bundle.getBoolean(KEY_BOOLEAN_RESULT);
435bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
436bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }.start();
437bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
438bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
439bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    /**
440661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Lists all accounts of a type which have certain features.  The account
441661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * type identifies the authenticator (see {@link #getAccountsByType}).
442661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Account features are authenticator-specific string tokens identifying
443661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * boolean account properties (see {@link #hasFeatures}).
444661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
445661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>Unlike {@link #getAccountsByType}, this method calls the authenticator,
446661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * which may contact the server or do other work to check account features,
447661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * so the method returns an {@link AccountManagerFuture}.
448661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
449661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method may be called from any thread, but the returned
450661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link AccountManagerFuture} must not be used on the main thread.
451661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
452661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
453661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#GET_ACCOUNTS}.
454661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
455661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param type The type of accounts to return, must not be null
456661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param features An array of the account features to require,
457661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     may be null or empty
458661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param callback Callback to invoke when the request completes,
459661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for no callback
460661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param handler {@link Handler} identifying the callback thread,
461661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for the main thread
462661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An {@link AccountManagerFuture} which resolves to an array of
463661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     {@link Account}, one per account of the specified type which
464661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     matches the requested features.
465661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     */
466661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
467661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor            final String type, final String[] features,
468661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor            AccountManagerCallback<Account[]> callback, Handler handler) {
469382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (type == null) throw new IllegalArgumentException("type is null");
470661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor        return new Future2Task<Account[]>(handler, callback) {
471661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor            public void doWork() throws RemoteException {
472661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor                mService.getAccountsByFeatures(mResponse, type, features);
473661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor            }
474661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor            public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
475661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor                if (!bundle.containsKey(KEY_ACCOUNTS)) {
476661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor                    throw new AuthenticatorException("no result in response");
477661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor                }
478661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor                final Parcelable[] parcelables = bundle.getParcelableArray(KEY_ACCOUNTS);
479661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor                Account[] descs = new Account[parcelables.length];
480661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor                for (int i = 0; i < parcelables.length; i++) {
481661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor                    descs[i] = (Account) parcelables[i];
482661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor                }
483661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor                return descs;
484661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor            }
485661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor        }.start();
486661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    }
487661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor
488661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor    /**
489661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Adds an account directly to the AccountManager.  Normally used by sign-up
490661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * wizards associated with authenticators, not directly by applications.
491661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
492661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
493661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
494661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
495661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
496661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * and to have the same UID as the added account's authenticator.
497661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
498661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The {@link Account} to add
499661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param password The password to associate with the account, null for none
500661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param userdata String values to use for the account's userdata, null for none
5018e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * @return True if the account was successfully added, false if the account
502661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     already exists, the account is null, or another error occurs.
503756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
50431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana    public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
505382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
506603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
50731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return mService.addAccount(account, password, userdata);
508603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
509ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
510603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
511603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
512603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
513603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
514756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
515661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Removes an account from the AccountManager.  Does nothing if the account
516661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * does not exist.  Does not delete the account from the server.
517661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * The authenticator may have its own policies preventing account
518661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * deletion, in which case the account will not be deleted.
519661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
520661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method may be called from any thread, but the returned
521661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link AccountManagerFuture} must not be used on the main thread.
522661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
523661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
524661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
525756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     *
526756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account The {@link Account} to remove
527661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param callback Callback to invoke when the request completes,
528661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for no callback
529661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param handler {@link Handler} identifying the callback thread,
530661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for the main thread
531661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An {@link AccountManagerFuture} which resolves to a Boolean,
532661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     true if the account has been successfully removed,
533661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     false if the authenticator forbids deleting this account.
534756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
535ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public AccountManagerFuture<Boolean> removeAccount(final Account account,
536ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            AccountManagerCallback<Boolean> callback, Handler handler) {
537382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
538ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        return new Future2Task<Boolean>(handler, callback) {
539ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            public void doWork() throws RemoteException {
540ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                mService.removeAccount(mResponse, account);
541a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
542ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
543f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
544ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    throw new AuthenticatorException("no result in response");
545ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
546f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                return bundle.getBoolean(KEY_BOOLEAN_RESULT);
547a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
548ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }.start();
549a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
550a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
551756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
552661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Removes an auth token from the AccountManager's cache.  Does nothing if
553661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * the auth token is not currently in the cache.  Applications must call this
554661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * method when the auth token is found to have expired or otherwise become
555661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * invalid for authenticating requests.  The AccountManager does not validate
556661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * or expire cached auth tokens otherwise.
557661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
558661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
559661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
560661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
561b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana     * {@link android.Manifest.permission#MANAGE_ACCOUNTS} or
562b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana     * {@link android.Manifest.permission#USE_CREDENTIALS}
563661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
564f35b68f2b926021bce407f092cfe3e8f52fa0794Fred Quintana     * @param accountType The account type of the auth token to invalidate, must not be null
565f35b68f2b926021bce407f092cfe3e8f52fa0794Fred Quintana     * @param authToken The auth token to invalidate, may be null
566756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
567ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void invalidateAuthToken(final String accountType, final String authToken) {
568382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
569603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
570f35b68f2b926021bce407f092cfe3e8f52fa0794Fred Quintana            if (authToken != null) {
571f35b68f2b926021bce407f092cfe3e8f52fa0794Fred Quintana                mService.invalidateAuthToken(accountType, authToken);
572f35b68f2b926021bce407f092cfe3e8f52fa0794Fred Quintana            }
573603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
574ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
575ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new RuntimeException(e);
576603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
577603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
578603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
579756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
580661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Gets an auth token from the AccountManager's cache.  If no auth
581661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * token is cached for this account, null will be returned -- a new
582661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * auth token will not be generated, and the server will not be contacted.
583661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Intended for use by the authenticator, not directly by applications.
584661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
585661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
586661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
587661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
588661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
589661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * and to have the same UID as the account's authenticator.
590661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
591661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account to fetch an auth token for
592661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param authTokenType The type of auth token to fetch, see {#getAuthToken}
593661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return The cached auth token for this account and type, or null if
594661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     no auth token is cached or the account does not exist.
595756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
596ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public String peekAuthToken(final Account account, final String authTokenType) {
597382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
598382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
599603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
600603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return mService.peekAuthToken(account, authTokenType);
601603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
602ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
603603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
604603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
605603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
606603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
607756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
608661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Sets or forgets a saved password.  This modifies the local copy of the
609661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * password used to automatically authenticate the user; it does
610661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * not change the user's account password on the server.  Intended for use
611661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * by the authenticator, not directly by applications.
612661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
613661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
614661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
615661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
616661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
617661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * and have the same UID as the account's authenticator.
618661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
619661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account to set a password for
620661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param password The password to set, null to clear the password
621756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
622ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void setPassword(final Account account, final String password) {
623382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
624603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
625603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mService.setPassword(account, password);
626603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
627ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
628ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new RuntimeException(e);
629603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
630603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
631603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
632756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
633661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Forgets a saved password.  This erases the local copy of the password;
634661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * it does not change the user's account password on the server.
635661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Has the same effect as setPassword(account, null) but requires fewer
636661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * permissions, and may be used by applications or management interfaces
637661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * to "sign out" from an account.
638661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
639661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
640661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
641661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
642661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#MANAGE_ACCOUNTS}
643661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
644661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account whose password to clear
645756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
646ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void clearPassword(final Account account) {
647382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
648603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
649603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mService.clearPassword(account);
650603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
651ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
652ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new RuntimeException(e);
653603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
654603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
655603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
656756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
657661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Sets one userdata key for an account.  Intended by use for the
658661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * authenticator to stash state for itself, not directly by applications.
659661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * The meaning of the keys and values is up to the authenticator.
660661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
661661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
662661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
663661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
664661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
665661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * and to have the same UID as the account's authenticator.
666661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
667661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account to set the userdata for
668661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param key The userdata key to set.  Must not be null
669661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param value The value to set, null to clear this userdata key
670756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
671ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void setUserData(final Account account, final String key, final String value) {
672382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
673382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (key == null) throw new IllegalArgumentException("key is null");
674603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
675603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mService.setUserData(account, key, value);
676603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
677ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
678ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new RuntimeException(e);
679603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
680603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
681603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
682756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
683661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Adds an auth token to the AccountManager cache for an account.
684756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * If the account does not exist then this call has no effect.
685661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Replaces any previous auth token for this account and auth token type.
686661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Intended for use by the authenticator, not directly by applications.
687661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
688661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
689661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
690661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
691661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
692661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * and to have the same UID as the account's authenticator.
693661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
694661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account to set an auth token for
695661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param authTokenType The type of the auth token, see {#getAuthToken}
696661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param authToken The auth token to add to the cache
697756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
698ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void setAuthToken(Account account, final String authTokenType, final String authToken) {
699382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
700382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
701603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
702603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mService.setAuthToken(account, authTokenType, authToken);
703603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
704ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
705ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new RuntimeException(e);
706603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
707603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
708603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
709756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
710661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * This convenience helper synchronously gets an auth token with
711661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, Handler)}.
712661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
713661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method may block while a network request completes, and must
714661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * never be made from the main thread.
715661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
716661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
717661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#USE_CREDENTIALS}.
718661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
719661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account to fetch an auth token for
720661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param authTokenType The auth token type, see {#link getAuthToken}
721661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param notifyAuthFailure If true, display a notification and return null
722661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     if authentication fails; if false, prompt and wait for the user to
723661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     re-enter correct credentials before returning
724661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An auth token of the specified type for this account, or null
725661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     if authentication fails or none can be fetched.
726661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @throws AuthenticatorException if the authenticator failed to respond
727661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @throws OperationCanceledException if the request was canceled for any
728661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     reason, including the user canceling a credential request
729661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @throws java.io.IOException if the authenticator experienced an I/O problem
730661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     creating a new auth token, usually because of network trouble
731756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
732a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String blockingGetAuthToken(Account account, String authTokenType,
733a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            boolean notifyAuthFailure)
734a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            throws OperationCanceledException, IOException, AuthenticatorException {
735382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
736382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
737a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */,
738a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                null /* handler */).getResult();
73996580e00654a052a82120c374c6b5961ef349a92Fred Quintana        if (bundle == null) {
74096580e00654a052a82120c374c6b5961ef349a92Fred Quintana            // This should never happen, but it does, occasionally. If it does return null to
74196580e00654a052a82120c374c6b5961ef349a92Fred Quintana            // signify that we were not able to get the authtoken.
74296580e00654a052a82120c374c6b5961ef349a92Fred Quintana            // TODO: remove this when the bug is found that sometimes causes a null bundle to be
74396580e00654a052a82120c374c6b5961ef349a92Fred Quintana            // returned
74496580e00654a052a82120c374c6b5961ef349a92Fred Quintana            Log.e(TAG, "blockingGetAuthToken: null was returned from getResult() for "
74596580e00654a052a82120c374c6b5961ef349a92Fred Quintana                    + account + ", authTokenType " + authTokenType);
74696580e00654a052a82120c374c6b5961ef349a92Fred Quintana            return null;
74796580e00654a052a82120c374c6b5961ef349a92Fred Quintana        }
748f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        return bundle.getString(KEY_AUTHTOKEN);
749a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
750a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
751a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    /**
752661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Gets an auth token of the specified type for a particular account,
753661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * prompting the user for credentials if necessary.  This method is
754661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * intended for applications running in the foreground where it makes
755661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * sense to ask the user directly for a password.
756661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
757661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>If a previously generated auth token is cached for this account and
7588e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * type, then it is returned.  Otherwise, if a saved password is
7598e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * available, it is sent to the server to generate a new auth token.
7608e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * Otherwise, the user is prompted to enter a password.
761661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
7628e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * <p>Some authenticators have auth token <em>types</em>, whose value
7638e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * is authenticator-dependent.  Some services use different token types to
7648e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * access different functionality -- for example, Google uses different auth
7658e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * tokens to access Gmail and Google Calendar for the same account.
766661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
767661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method may be called from any thread, but the returned
768661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link AccountManagerFuture} must not be used on the main thread.
769661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
770661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
771661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#USE_CREDENTIALS}.
772661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
773661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account to fetch an auth token for
774661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param authTokenType The auth token type, an authenticator-dependent
775661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     string token, must not be null
776661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param options Authenticator-specific options for the request,
777661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     may be null or empty
778661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param activity The {@link Activity} context to use for launching a new
779661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     authenticator-defined sub-Activity to prompt the user for a password
780661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     if necessary; used only to call startActivity(); must not be null.
781661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param callback Callback to invoke when the request completes,
782661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for no callback
783661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param handler {@link Handler} identifying the callback thread,
784661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for the main thread
785661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An {@link AccountManagerFuture} which resolves to a Bundle with
786661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     at least the following fields:
787661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <ul>
788661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
789661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
790661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
791661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * </ul>
792661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
793661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * (Other authenticator-specific values may be returned.)  If an auth token
794661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * could not be fetched, {@link AccountManagerFuture#getResult()} throws:
795756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
796661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link AuthenticatorException} if the authenticator failed to respond
797661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link OperationCanceledException} if the operation is canceled for
798661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      any reason, incluidng the user canceling a credential request
799661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link IOException} if the authenticator experienced an I/O problem
800661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      creating a new auth token, usually because of network trouble
801756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
8028e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * If the account is no longer present on the device, the return value is
8038e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * authenticator-dependent.  The caller should verify the validity of the
8048e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * account before requesting an auth token.
805a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana     */
806ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public AccountManagerFuture<Bundle> getAuthToken(
80731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            final Account account, final String authTokenType, final Bundle options,
808ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
809382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
810a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
811a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(activity, handler, callback) {
812a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
813a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mService.getAuthToken(mResponse, account, authTokenType,
814a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
81531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                        options);
816a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
8173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
818a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
819a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
820756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
821661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Gets an auth token of the specified type for a particular account,
822661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * optionally raising a notification if the user must enter credentials.
823661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * This method is intended for background tasks and services where the
824661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * user should not be immediately interrupted with a password prompt.
825661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
826661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>If a previously generated auth token is cached for this account and
8278e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * type, then it is returned.  Otherwise, if a saved password is
8288e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * available, it is sent to the server to generate a new auth token.
8298e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * Otherwise, an {@link Intent} is returned which, when started, will
8308e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * prompt the user for a password.  If the notifyAuthFailure parameter is
8318e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * set, a status bar notification is also created with the same Intent,
832661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * alerting the user that they need to enter a password at some point.
833661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
8348e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * <p>In that case, you may need to wait until the user responds, which
8358e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * could take hours or days or forever.  When the user does respond and
8368e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * supply a new password, the account manager will broadcast the
8378e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
8388e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * use to try again.
839661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
8408e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * <p>If notifyAuthFailure is not set, it is the application's
8418e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * responsibility to launch the returned Intent at some point.
8428e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * Either way, the result from this call will not wait for user action.
843661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
8448e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * <p>Some authenticators have auth token <em>types</em>, whose value
8458e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * is authenticator-dependent.  Some services use different token types to
8468e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * access different functionality -- for example, Google uses different auth
8478e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * tokens to access Gmail and Google Calendar for the same account.
848661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
849661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method may be called from any thread, but the returned
850661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link AccountManagerFuture} must not be used on the main thread.
851661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
852661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
853661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#USE_CREDENTIALS}.
854661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
855661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account to fetch an auth token for
856661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param authTokenType The auth token type, an authenticator-dependent
857661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     string token, must not be null
858661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param notifyAuthFailure True to add a notification to prompt the
859661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     user for a password if necessary, false to leave that to the caller
860661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param callback Callback to invoke when the request completes,
861661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for no callback
862661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param handler {@link Handler} identifying the callback thread,
863661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for the main thread
864661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An {@link AccountManagerFuture} which resolves to a Bundle with
865661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     at least the following fields on success:
866756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
867661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
868661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
869661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
870661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * </ul>
871661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
872661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * (Other authenticator-specific values may be returned.)  If the user
873661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * must enter credentials, the returned Bundle contains only
874661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
875661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
8768e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
877661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <ul>
878661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link AuthenticatorException} if the authenticator failed to respond
879661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link OperationCanceledException} if the operation is canceled for
880661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      any reason, incluidng the user canceling a credential request
881661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link IOException} if the authenticator experienced an I/O problem
882661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      creating a new auth token, usually because of network trouble
883756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
8848e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * If the account is no longer present on the device, the return value is
8858e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * authenticator-dependent.  The caller should verify the validity of the
8868e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * account before requesting an auth token.
887756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
888ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public AccountManagerFuture<Bundle> getAuthToken(
889a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Account account, final String authTokenType, final boolean notifyAuthFailure,
890ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            AccountManagerCallback<Bundle> callback, Handler handler) {
891a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
892a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
893a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(null, handler, callback) {
894a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
895a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mService.getAuthToken(mResponse, account, authTokenType,
896a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        notifyAuthFailure, false /* expectActivityLaunch */, null /* options */);
897a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
8983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
899a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
900a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
901756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
902661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Asks the user to add an account of a specified type.  The authenticator
903661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * for this account type processes this request with the appropriate user
904661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * interface.  If the user does elect to create a new account, the account
905661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * name is returned.
906661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
907661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method may be called from any thread, but the returned
908661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link AccountManagerFuture} must not be used on the main thread.
909661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
910661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
911661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
912661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
913661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param accountType The type of account to add; must not be null
914661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param authTokenType The type of auth token (see {@link #getAuthToken})
915661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     this account will need to be able to generate, null for none
916661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param requiredFeatures The features (see {@link #hasFeatures}) this
917661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     account must have, null for none
918661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param addAccountOptions Authenticator-specific options for the request,
919661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     may be null or empty
920661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param activity The {@link Activity} context to use for launching a new
921661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     authenticator-defined sub-Activity to prompt the user to create an
922661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     account; used only to call startActivity(); if null, the prompt
923661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     will not be launched directly, but the necessary {@link Intent}
924661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     will be returned to the caller instead
925661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param callback Callback to invoke when the request completes,
926661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for no callback
927661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param handler {@link Handler} identifying the callback thread,
928661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for the main thread
929ff592dc2fa53d48e4121d9b8fd70efc19938c4a1Doug Zongker     * @return An {@link AccountManagerFuture} which resolves to a Bundle with
930661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     these fields if activity was specified and an account was created:
931756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
932661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
933661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
934661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * </ul>
935661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
936661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * If no activity was specified, the returned Bundle contains only
937661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
9388e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * actual account creation process.  If an error occurred,
9398e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * {@link AccountManagerFuture#getResult()} throws:
940661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <ul>
941661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link AuthenticatorException} if no authenticator was registered for
942661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      this account type or the authenticator failed to respond
943661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link OperationCanceledException} if the operation was canceled for
944661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      any reason, including the user canceling the creation process
945661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link IOException} if the authenticator experienced an I/O problem
946661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      creating a new account, usually because of network trouble
947756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
948756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
949ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public AccountManagerFuture<Bundle> addAccount(final String accountType,
9503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String authTokenType, final String[] requiredFeatures,
9513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final Bundle addAccountOptions,
952ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
953382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
954a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(activity, handler, callback) {
955a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
956a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mService.addAcount(mResponse, accountType, authTokenType,
9573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        requiredFeatures, activity != null, addAccountOptions);
958a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
9593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
960a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
961a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
9628570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana    /**
963661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Confirms that the user knows the password for an account to make extra
964661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * sure they are the owner of the account.  The user-entered password can
965661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * be supplied directly, otherwise the authenticator for this account type
966661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * prompts the user with the appropriate interface.  This method is
967661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * intended for applications which want extra assurance; for example, the
968661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * phone lock screen uses this to let the user unlock the phone with an
969661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * account password if they forget the lock pattern.
970661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
971661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>If the user-entered password matches a saved password for this
972661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * account, the request is considered valid; otherwise the authenticator
973661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * verifies the password (usually by contacting the server).
974661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
975661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method may be called from any thread, but the returned
976661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link AccountManagerFuture} must not be used on the main thread.
977661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
978661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
979661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
980661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
981661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account to confirm password knowledge for
982661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param options Authenticator-specific options for the request;
983661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     if the {@link #KEY_PASSWORD} string field is present, the
984661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     authenticator may use it directly rather than prompting the user;
985661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     may be null or empty
986661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param activity The {@link Activity} context to use for launching a new
987661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     authenticator-defined sub-Activity to prompt the user to enter a
988661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     password; used only to call startActivity(); if null, the prompt
989661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     will not be launched directly, but the necessary {@link Intent}
990661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     will be returned to the caller instead
991661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param callback Callback to invoke when the request completes,
992661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for no callback
993661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param handler {@link Handler} identifying the callback thread,
994661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for the main thread
995661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An {@link AccountManagerFuture} which resolves to a Bundle
996661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     with these fields if activity or password was supplied and
997661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     the account was successfully verified:
998661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <ul>
999661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
1000661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1001661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_BOOLEAN_RESULT} - true to indicate success
1002661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * </ul>
1003661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1004661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * If no activity or password was specified, the returned Bundle contains
1005661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * only {@link #KEY_INTENT} with the {@link Intent} needed to launch the
10068e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * password prompt.  If an error occurred,
10078e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * {@link AccountManagerFuture#getResult()} throws:
1008756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
1009661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link AuthenticatorException} if the authenticator failed to respond
1010661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link OperationCanceledException} if the operation was canceled for
1011661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      any reason, including the user canceling the password prompt
1012661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link IOException} if the authenticator experienced an I/O problem
1013661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      verifying the password, usually because of network trouble
1014756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
1015756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
1016f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public AccountManagerFuture<Bundle> confirmCredentials(final Account account,
1017f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            final Bundle options,
1018f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            final Activity activity,
1019ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final AccountManagerCallback<Bundle> callback,
1020a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Handler handler) {
1021382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1022a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(activity, handler, callback) {
1023a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
1024f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                mService.confirmCredentials(mResponse, account, options, activity != null);
1025a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
10263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
1027a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1028a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1029756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
1030661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Asks the user to enter a new password for an account, updating the
1031661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * saved credentials for the account.  Normally this happens automatically
1032661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * when the server rejects credentials during an auth token fetch, but this
1033661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * can be invoked directly to ensure we have the correct credentials stored.
1034661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1035661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method may be called from any thread, but the returned
1036661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link AccountManagerFuture} must not be used on the main thread.
1037661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1038661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
1039661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
1040661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1041661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param account The account to update credentials for
1042661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param authTokenType The credentials entered must allow an auth token
1043661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     of this type to be created (but no actual auth token is returned);
1044661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     may be null
1045661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param options Authenticator-specific options for the request;
1046661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     may be null or empty
1047661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param activity The {@link Activity} context to use for launching a new
1048661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     authenticator-defined sub-Activity to prompt the user to enter a
1049661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     password; used only to call startActivity(); if null, the prompt
1050661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     will not be launched directly, but the necessary {@link Intent}
1051661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     will be returned to the caller instead
1052661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param callback Callback to invoke when the request completes,
1053661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for no callback
1054661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param handler {@link Handler} identifying the callback thread,
1055661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for the main thread
1056661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An {@link AccountManagerFuture} which resolves to a Bundle
1057661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     with these fields if an activity was supplied and the account
1058661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     credentials were successfully updated:
1059756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
1060661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
1061661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1062661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * </ul>
1063661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1064661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * If no activity was specified, the returned Bundle contains only
1065661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
10668e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * password prompt.  If an error occurred,
10678e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * {@link AccountManagerFuture#getResult()} throws:
1068661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <ul>
1069661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link AuthenticatorException} if the authenticator failed to respond
1070661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link OperationCanceledException} if the operation was canceled for
1071661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      any reason, including the user canceling the password prompt
1072661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link IOException} if the authenticator experienced an I/O problem
1073661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      verifying the password, usually because of network trouble
1074756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
1075756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
1076756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    public AccountManagerFuture<Bundle> updateCredentials(final Account account,
1077756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana            final String authTokenType,
107831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            final Bundle options, final Activity activity,
1079ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final AccountManagerCallback<Bundle> callback,
1080a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Handler handler) {
1081382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1082a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(activity, handler, callback) {
1083a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
1084a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mService.updateCredentials(mResponse, account, authTokenType, activity != null,
108531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                        options);
1086a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
10873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
1088a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1089a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1090756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
1091661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Offers the user an opportunity to change an authenticator's settings.
1092661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * These properties are for the authenticator in general, not a particular
1093661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * account.  Not all authenticators support this method.
1094661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1095661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method may be called from any thread, but the returned
1096661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link AccountManagerFuture} must not be used on the main thread.
1097661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1098661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
1099661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
1100661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1101661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param accountType The account type associated with the authenticator
1102661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     to adjust
1103661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param activity The {@link Activity} context to use for launching a new
1104661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     authenticator-defined sub-Activity to adjust authenticator settings;
1105661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     used only to call startActivity(); if null, the settings dialog will
1106661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     not be launched directly, but the necessary {@link Intent} will be
1107661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     returned to the caller instead
1108661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param callback Callback to invoke when the request completes,
1109661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for no callback
1110661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param handler {@link Handler} identifying the callback thread,
1111661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for the main thread
1112661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An {@link AccountManagerFuture} which resolves to a Bundle
1113661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     which is empty if properties were edited successfully, or
1114661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     if no activity was specified, contains only {@link #KEY_INTENT}
1115661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     needed to launch the authenticator's settings dialog.
11168e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     *     If an error occurred, {@link AccountManagerFuture#getResult()}
11178e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     *     throws:
1118756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
1119661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link AuthenticatorException} if no authenticator was registered for
1120661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      this account type or the authenticator failed to respond
1121661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link OperationCanceledException} if the operation was canceled for
1122661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      any reason, including the user canceling the settings dialog
1123661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link IOException} if the authenticator experienced an I/O problem
1124661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      updating settings, usually because of network trouble
1125756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
1126756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
1127756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    public AccountManagerFuture<Bundle> editProperties(final String accountType,
1128756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana            final Activity activity, final AccountManagerCallback<Bundle> callback,
1129a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Handler handler) {
1130382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
1131a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(activity, handler, callback) {
1132a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
1133a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mService.editProperties(mResponse, accountType, activity != null);
1134a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
11353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
1136a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1137a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1138a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private void ensureNotOnMainThread() {
1139a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final Looper looper = Looper.myLooper();
1140a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        if (looper != null && looper == mContext.getMainLooper()) {
114153bd2522ca7767f46646606123b6e2689b811850Fred Quintana            final IllegalStateException exception = new IllegalStateException(
114253bd2522ca7767f46646606123b6e2689b811850Fred Quintana                    "calling this from your main thread can lead to deadlock");
114353bd2522ca7767f46646606123b6e2689b811850Fred Quintana            Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs",
114453bd2522ca7767f46646606123b6e2689b811850Fred Quintana                    exception);
1145751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana            if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.FROYO) {
1146751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana                throw exception;
1147751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana            }
1148a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1149a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1150a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1151ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void postToHandler(Handler handler, final AccountManagerCallback<Bundle> callback,
1152ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final AccountManagerFuture<Bundle> future) {
1153d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        handler = handler == null ? mMainHandler : handler;
1154d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        handler.post(new Runnable() {
1155a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void run() {
1156a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                callback.run(future);
1157a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1158a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        });
1159603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1160603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1161f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    private void postToHandler(Handler handler, final OnAccountsUpdateListener listener,
1162d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            final Account[] accounts) {
1163ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final Account[] accountsCopy = new Account[accounts.length];
1164ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        // send a copy to make sure that one doesn't
1165ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        // change what another sees
1166ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
1167ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        handler = (handler == null) ? mMainHandler : handler;
1168d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        handler.post(new Runnable() {
1169a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void run() {
1170b6437245c280596d0a580b8d67189739cf793250Costin Manolache                try {
1171b6437245c280596d0a580b8d67189739cf793250Costin Manolache                    listener.onAccountsUpdated(accountsCopy);
1172b6437245c280596d0a580b8d67189739cf793250Costin Manolache                } catch (SQLException e) {
1173b6437245c280596d0a580b8d67189739cf793250Costin Manolache                    // Better luck next time.  If the problem was disk-full,
1174b6437245c280596d0a580b8d67189739cf793250Costin Manolache                    // the STORAGE_OK intent will re-trigger the update.
1175b6437245c280596d0a580b8d67189739cf793250Costin Manolache                    Log.e(TAG, "Can't update accounts", e);
1176b6437245c280596d0a580b8d67189739cf793250Costin Manolache                }
1177a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1178a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        });
1179a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
1180a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1181ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> {
1182a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final IAccountManagerResponse mResponse;
1183a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final Handler mHandler;
1184ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final AccountManagerCallback<Bundle> mCallback;
1185a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final Activity mActivity;
1186ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) {
1187a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            super(new Callable<Bundle>() {
1188a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                public Bundle call() throws Exception {
1189a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw new IllegalStateException("this should never be called");
1190a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1191a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            });
1192a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1193a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mHandler = handler;
1194a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mCallback = callback;
1195a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mActivity = activity;
1196a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mResponse = new Response();
11973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
11983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1199ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public final AccountManagerFuture<Bundle> start() {
1200ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            try {
1201ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                doWork();
1202ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } catch (RemoteException e) {
1203ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                setException(e);
1204ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
12053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return this;
1206a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1207a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
120896580e00654a052a82120c374c6b5961ef349a92Fred Quintana        protected void set(Bundle bundle) {
120996580e00654a052a82120c374c6b5961ef349a92Fred Quintana            // TODO: somehow a null is being set as the result of the Future. Log this
121096580e00654a052a82120c374c6b5961ef349a92Fred Quintana            // case to help debug where this is occurring. When this bug is fixed this
121196580e00654a052a82120c374c6b5961ef349a92Fred Quintana            // condition statement should be removed.
121296580e00654a052a82120c374c6b5961ef349a92Fred Quintana            if (bundle == null) {
121396580e00654a052a82120c374c6b5961ef349a92Fred Quintana                Log.e(TAG, "the bundle must not be null", new Exception());
121496580e00654a052a82120c374c6b5961ef349a92Fred Quintana            }
121596580e00654a052a82120c374c6b5961ef349a92Fred Quintana            super.set(bundle);
121696580e00654a052a82120c374c6b5961ef349a92Fred Quintana        }
121796580e00654a052a82120c374c6b5961ef349a92Fred Quintana
1218a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public abstract void doWork() throws RemoteException;
1219603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1220a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private Bundle internalGetResult(Long timeout, TimeUnit unit)
1221a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
122253bd2522ca7767f46646606123b6e2689b811850Fred Quintana            if (!isDone()) {
122353bd2522ca7767f46646606123b6e2689b811850Fred Quintana                ensureNotOnMainThread();
122453bd2522ca7767f46646606123b6e2689b811850Fred Quintana            }
1225a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1226a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (timeout == null) {
1227a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return get();
1228a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else {
1229a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return get(timeout, unit);
1230a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1231a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (CancellationException e) {
1232a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                throw new OperationCanceledException();
1233a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (TimeoutException e) {
1234a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // fall through and cancel
1235a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (InterruptedException e) {
1236a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // fall through and cancel
1237a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (ExecutionException e) {
1238a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                final Throwable cause = e.getCause();
1239a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (cause instanceof IOException) {
1240a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (IOException) cause;
1241a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof UnsupportedOperationException) {
1242a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw new AuthenticatorException(cause);
1243a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof AuthenticatorException) {
1244a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (AuthenticatorException) cause;
1245a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof RuntimeException) {
1246a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (RuntimeException) cause;
1247a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof Error) {
1248a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (Error) cause;
1249a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else {
1250a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw new IllegalStateException(cause);
1251a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1252a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } finally {
1253a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                cancel(true /* interrupt if running */);
1254603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1255a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            throw new OperationCanceledException();
1256603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1257603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1258a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public Bundle getResult()
1259a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
1260a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return internalGetResult(null, null);
1261603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1262603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1263a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public Bundle getResult(long timeout, TimeUnit unit)
1264a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
1265a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return internalGetResult(timeout, unit);
1266603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1267603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1268a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected void done() {
1269a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mCallback != null) {
1270a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                postToHandler(mHandler, mCallback, this);
1271a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1272a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1273a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1274a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        /** Handles the responses from the AccountManager */
1275a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private class Response extends IAccountManagerResponse.Stub {
1276a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void onResult(Bundle bundle) {
1277a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Intent intent = bundle.getParcelable("intent");
1278a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (intent != null && mActivity != null) {
1279a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // since the user provided an Activity we will silently start intents
1280a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // that we see
1281a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    mActivity.startActivity(intent);
1282a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // leave the Future running to wait for the real response to this request
1283d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                } else if (bundle.getBoolean("retry")) {
1284d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    try {
1285d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        doWork();
1286d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    } catch (RemoteException e) {
1287d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        // this will only happen if the system process is dead, which means
1288d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        // we will be dying ourselves
1289d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    }
1290a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else {
1291a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    set(bundle);
1292a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1293a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1294a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1295a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void onError(int code, String message) {
1296f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                if (code == ERROR_CODE_CANCELED) {
1297a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // the authenticator indicated that this request was canceled, do so now
1298a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    cancel(true /* mayInterruptIfRunning */);
1299a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return;
1300a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1301a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                setException(convertErrorToException(code, message));
1302a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1303603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1304a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1305603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1306603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1307ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private abstract class BaseFutureTask<T> extends FutureTask<T> {
1308ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final public IAccountManagerResponse mResponse;
1309a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final Handler mHandler;
1310ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1311ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public BaseFutureTask(Handler handler) {
1312ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super(new Callable<T>() {
1313ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                public T call() throws Exception {
1314a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw new IllegalStateException("this should never be called");
1315a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1316a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            });
1317a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mHandler = handler;
1318ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mResponse = new Response();
1319ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1320a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1321ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public abstract void doWork() throws RemoteException;
1322ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1323ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException;
1324ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1325ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected void postRunnableToHandler(Runnable runnable) {
1326ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            Handler handler = (mHandler == null) ? mMainHandler : mHandler;
1327ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            handler.post(runnable);
1328ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1329ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1330ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected void startTask() {
1331ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            try {
1332ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                doWork();
1333ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } catch (RemoteException e) {
1334ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                setException(e);
1335ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
1336ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1337ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1338ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected class Response extends IAccountManagerResponse.Stub {
1339ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            public void onResult(Bundle bundle) {
1340ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                try {
1341ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    T result = bundleToResult(bundle);
1342ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    if (result == null) {
1343ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        return;
1344a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1345ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    set(result);
1346ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
1347ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                } catch (ClassCastException e) {
1348ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    // we will set the exception below
1349ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                } catch (AuthenticatorException e) {
1350ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    // we will set the exception below
1351a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1352f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(ERROR_CODE_INVALID_RESPONSE, "no result in response");
1353ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
1354a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1355ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            public void onError(int code, String message) {
1356f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                if (code == ERROR_CODE_CANCELED) {
1357ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    cancel(true /* mayInterruptIfRunning */);
1358ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
1359ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
1360ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                setException(convertErrorToException(code, message));
1361ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
1362ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1363ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
1364a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1365ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private abstract class Future2Task<T>
1366ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            extends BaseFutureTask<T> implements AccountManagerFuture<T> {
1367ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final AccountManagerCallback<T> mCallback;
1368ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public Future2Task(Handler handler, AccountManagerCallback<T> callback) {
1369ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super(handler);
1370ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mCallback = callback;
1371ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1372a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1373a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected void done() {
1374a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mCallback != null) {
1375ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                postRunnableToHandler(new Runnable() {
1376ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    public void run() {
1377ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        mCallback.run(Future2Task.this);
1378ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    }
1379ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                });
1380a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1381a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1382a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1383ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public Future2Task<T> start() {
1384ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            startTask();
1385ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return this;
1386ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1387ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1388ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        private T internalGetResult(Long timeout, TimeUnit unit)
1389ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
139053bd2522ca7767f46646606123b6e2689b811850Fred Quintana            if (!isDone()) {
139153bd2522ca7767f46646606123b6e2689b811850Fred Quintana                ensureNotOnMainThread();
139253bd2522ca7767f46646606123b6e2689b811850Fred Quintana            }
1393a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1394a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (timeout == null) {
1395a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return get();
1396a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else {
1397a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return get(timeout, unit);
1398a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1399a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (InterruptedException e) {
1400a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // fall through and cancel
1401a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (TimeoutException e) {
1402a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // fall through and cancel
1403a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (CancellationException e) {
1404ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                // fall through and cancel
1405a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (ExecutionException e) {
1406a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                final Throwable cause = e.getCause();
1407a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (cause instanceof IOException) {
1408ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    throw (IOException) cause;
1409a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof UnsupportedOperationException) {
1410ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    throw new AuthenticatorException(cause);
1411a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof AuthenticatorException) {
1412ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    throw (AuthenticatorException) cause;
1413a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof RuntimeException) {
1414a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (RuntimeException) cause;
1415a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof Error) {
1416a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (Error) cause;
1417a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else {
1418a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw new IllegalStateException(cause);
1419a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1420a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } finally {
1421a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                cancel(true /* interrupt if running */);
1422a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1423ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new OperationCanceledException();
1424a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1425a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1426ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public T getResult()
1427ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
1428a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return internalGetResult(null, null);
1429603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1430a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1431ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public T getResult(long timeout, TimeUnit unit)
1432ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
1433a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return internalGetResult(timeout, unit);
1434a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1435a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1436603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1437603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1438a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private Exception convertErrorToException(int code, String message) {
1439f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        if (code == ERROR_CODE_NETWORK_ERROR) {
1440a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return new IOException(message);
1441603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1442a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1443f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        if (code == ERROR_CODE_UNSUPPORTED_OPERATION) {
14443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return new UnsupportedOperationException(message);
1445a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1446a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1447f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        if (code == ERROR_CODE_INVALID_RESPONSE) {
14483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return new AuthenticatorException(message);
14493326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
14503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1451f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        if (code == ERROR_CODE_BAD_ARGUMENTS) {
14523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return new IllegalArgumentException(message);
14533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
14543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        return new AuthenticatorException(message);
14563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
14573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1458ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private class GetAuthTokenByTypeAndFeaturesTask
1459ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            extends AmsTask implements AccountManagerCallback<Bundle> {
14603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
14613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                final String[] features, Activity activityForPrompting,
14623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                final Bundle addAccountOptions, final Bundle loginOptions,
1463ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                AccountManagerCallback<Bundle> callback, Handler handler) {
14643326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            super(activityForPrompting, handler, callback);
14653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountType == null) throw new IllegalArgumentException("account type is null");
14663326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountType = accountType;
14673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAuthTokenType = authTokenType;
14683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mFeatures = features;
14693326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAddAccountOptions = addAccountOptions;
14703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mLoginOptions = loginOptions;
14713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mMyCallback = this;
14723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
1473ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        volatile AccountManagerFuture<Bundle> mFuture = null;
14743326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        final String mAccountType;
14753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        final String mAuthTokenType;
14763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        final String[] mFeatures;
14773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        final Bundle mAddAccountOptions;
14783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        final Bundle mLoginOptions;
1479ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final AccountManagerCallback<Bundle> mMyCallback;
1480f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana        private volatile int mNumAccounts = 0;
14813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void doWork() throws RemoteException {
1483ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            getAccountsByTypeAndFeatures(mAccountType, mFeatures,
1484ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    new AccountManagerCallback<Account[]>() {
1485ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        public void run(AccountManagerFuture<Account[]> future) {
1486ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            Account[] accounts;
14873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            try {
1488ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                accounts = future.getResult();
1489ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            } catch (OperationCanceledException e) {
1490ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                setException(e);
1491ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                return;
1492ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            } catch (IOException e) {
1493ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                setException(e);
1494ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                return;
1495ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            } catch (AuthenticatorException e) {
1496ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                setException(e);
1497ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                return;
14983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            }
1499ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1500f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                            mNumAccounts = accounts.length;
1501f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana
1502ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            if (accounts.length == 0) {
1503ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                if (mActivity != null) {
1504ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // no accounts, add one now. pretend that the user directly
1505ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // made this request
1506ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures,
1507ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            mAddAccountOptions, mActivity, mMyCallback, mHandler);
1508ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                } else {
1509ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // send result since we can't prompt to add an account
1510ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    Bundle result = new Bundle();
1511f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.putString(KEY_ACCOUNT_NAME, null);
1512f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.putString(KEY_ACCOUNT_TYPE, null);
1513f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.putString(KEY_AUTHTOKEN, null);
1514ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    try {
1515ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        mResponse.onResult(result);
1516ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    } catch (RemoteException e) {
1517ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        // this will never happen
1518ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    }
1519ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // we are done
1520ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                }
1521ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            } else if (accounts.length == 1) {
1522ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                // have a single account, return an authtoken for it
1523ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                if (mActivity == null) {
1524ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    mFuture = getAuthToken(accounts[0], mAuthTokenType,
1525ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            false /* notifyAuthFailure */, mMyCallback, mHandler);
1526ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                } else {
1527ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    mFuture = getAuthToken(accounts[0],
1528ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            mAuthTokenType, mLoginOptions,
15293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                                            mActivity, mMyCallback, mHandler);
15303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                                }
1531ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            } else {
1532ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                if (mActivity != null) {
1533ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    IAccountManagerResponse chooseResponse =
1534ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            new IAccountManagerResponse.Stub() {
1535ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        public void onResult(Bundle value) throws RemoteException {
1536ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            Account account = new Account(
1537f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                                    value.getString(KEY_ACCOUNT_NAME),
1538f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                                    value.getString(KEY_ACCOUNT_TYPE));
1539ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
1540ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                                    mActivity, mMyCallback, mHandler);
1541ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        }
1542ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1543ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        public void onError(int errorCode, String errorMessage)
1544ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                                throws RemoteException {
1545ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            mResponse.onError(errorCode, errorMessage);
1546ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        }
1547ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    };
1548ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // have many accounts, launch the chooser
1549ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    Intent intent = new Intent();
1550ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    intent.setClassName("android",
1551ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            "android.accounts.ChooseAccountActivity");
1552f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    intent.putExtra(KEY_ACCOUNTS, accounts);
1553f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    intent.putExtra(KEY_ACCOUNT_MANAGER_RESPONSE,
1554ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            new AccountManagerResponse(chooseResponse));
1555ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    mActivity.startActivity(intent);
1556ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // the result will arrive via the IAccountManagerResponse
1557ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                } else {
1558ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // send result since we can't prompt to select an account
1559ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    Bundle result = new Bundle();
1560f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.putString(KEY_ACCOUNTS, null);
1561ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    try {
1562ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        mResponse.onResult(result);
1563ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    } catch (RemoteException e) {
1564ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        // this will never happen
1565ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    }
1566ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // we are done
15673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                                }
15683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            }
1569ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        }}, mHandler);
15703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
15713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1572ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void run(AccountManagerFuture<Bundle> future) {
15733326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            try {
1574f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                final Bundle result = future.getResult();
1575f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                if (mNumAccounts == 0) {
1576f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                    final String accountName = result.getString(KEY_ACCOUNT_NAME);
1577f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                    final String accountType = result.getString(KEY_ACCOUNT_TYPE);
1578f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                    if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
1579f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                        setException(new AuthenticatorException("account not in result"));
1580f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                        return;
1581f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                    }
1582f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                    final Account account = new Account(accountName, accountType);
1583f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                    mNumAccounts = 1;
1584f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                    getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
1585f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                            mMyCallback, mHandler);
1586f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                    return;
1587f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                }
1588f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana                set(result);
1589f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            } catch (OperationCanceledException e) {
1590f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                cancel(true /* mayInterruptIfRUnning */);
1591f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            } catch (IOException e) {
1592f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                setException(e);
1593f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            } catch (AuthenticatorException e) {
1594f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                setException(e);
15953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
1596a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
15973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
1598a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1599756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
1600661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * This convenience helper combines the functionality of
1601661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link #getAccountsByTypeAndFeatures}, {@link #getAuthToken}, and
1602661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link #addAccount}.
1603661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1604661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method gets a list of the accounts matching the
1605661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * specified type and feature set; if there is exactly one, it is
1606661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * used; if there are more than one, the user is prompted to pick one;
1607661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * if there are none, the user is prompted to add one.  Finally,
1608661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * an auth token is acquired for the chosen account.
1609661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1610661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method may be called from any thread, but the returned
1611661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link AccountManagerFuture} must not be used on the main thread.
1612661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1613661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>This method requires the caller to hold the permission
1614661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
1615661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1616661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param accountType The account type required
1617ff592dc2fa53d48e4121d9b8fd70efc19938c4a1Doug Zongker     *     (see {@link #getAccountsByType}), must not be null
1618661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param authTokenType The desired auth token type
1619661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     (see {@link #getAuthToken}), must not be null
1620661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param features Required features for the account
1621661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     (see {@link #getAccountsByTypeAndFeatures}), may be null or empty
1622661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param activity The {@link Activity} context to use for launching new
1623661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     sub-Activities to prompt to add an account, select an account,
1624661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     and/or enter a password, as necessary; used only to call
1625661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     startActivity(); should not be null
1626661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param addAccountOptions Authenticator-specific options to use for
1627661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     adding new accounts; may be null or empty
1628661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param getAuthTokenOptions Authenticator-specific options to use for
1629661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     getting auth tokens; may be null or empty
1630661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param callback Callback to invoke when the request completes,
1631661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for no callback
1632661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param handler {@link Handler} identifying the callback thread,
1633661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     null for the main thread
1634661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @return An {@link AccountManagerFuture} which resolves to a Bundle with
1635661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     at least the following fields:
1636756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
1637661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account
1638661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1639661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
1640661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * </ul>
1641661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
16428e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor     * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
1643661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <ul>
1644661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link AuthenticatorException} if no authenticator was registered for
1645661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      this account type or the authenticator failed to respond
1646661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link OperationCanceledException} if the operation was canceled for
1647661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      any reason, including the user canceling any operation
1648661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <li> {@link IOException} if the authenticator experienced an I/O problem
1649661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *      updating settings, usually because of network trouble
1650756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
1651756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
1652f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
16533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String accountType, final String authTokenType, final String[] features,
1654661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor            final Activity activity, final Bundle addAccountOptions,
165531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            final Bundle getAuthTokenOptions,
1656ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final AccountManagerCallback<Bundle> callback, final Handler handler) {
16573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        if (accountType == null) throw new IllegalArgumentException("account type is null");
16583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
1659f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        final GetAuthTokenByTypeAndFeaturesTask task =
1660f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features,
1661661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor                activity, addAccountOptions, getAuthTokenOptions, callback, handler);
1662f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        task.start();
1663f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        return task;
1664603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1665d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1666f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    private final HashMap<OnAccountsUpdateListener, Handler> mAccountsUpdatedListeners =
1667d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            Maps.newHashMap();
1668d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1669d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    /**
1670d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
1671d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * so that it can read the updated list of accounts and send them to the listener
1672d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * in mAccountsUpdatedListeners.
1673d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     */
1674d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
1675d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        public void onReceive(final Context context, final Intent intent) {
1676ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final Account[] accounts = getAccounts();
1677ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // send the result to the listeners
1678ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            synchronized (mAccountsUpdatedListeners) {
1679f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                for (Map.Entry<OnAccountsUpdateListener, Handler> entry :
1680ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        mAccountsUpdatedListeners.entrySet()) {
1681ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    postToHandler(entry.getValue(), entry.getKey(), accounts);
1682d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                }
1683ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
1684d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
1685d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    };
1686d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1687d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    /**
1688661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Adds an {@link OnAccountsUpdateListener} to this instance of the
1689661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link AccountManager}.  This listener will be notified whenever the
1690661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * list of accounts on the device changes.
1691661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1692661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>As long as this listener is present, the AccountManager instance
1693661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * will not be garbage-collected, and neither will the {@link Context}
1694661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * used to retrieve it, which may be a large Activity instance.  To avoid
1695661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * memory leaks, you must remove this listener before then.  Normally
1696661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * listeners are added in an Activity or Service's {@link Activity#onCreate}
1697661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * and removed in {@link Activity#onDestroy}.
1698661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1699661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
1700661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1701661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>No permission is required to call this method.
1702661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1703661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param listener The listener to send notifications to
1704661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param handler {@link Handler} identifying the thread to use
1705661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     for notifications, null for the main thread
1706661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param updateImmediately If true, the listener will be invoked
1707661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *     (on the handler thread) right away with the current account list
1708d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @throws IllegalArgumentException if listener is null
1709d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @throws IllegalStateException if listener was already added
1710d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     */
1711f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
1712d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            Handler handler, boolean updateImmediately) {
1713d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        if (listener == null) {
1714d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            throw new IllegalArgumentException("the listener is null");
1715d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
1716d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        synchronized (mAccountsUpdatedListeners) {
1717d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            if (mAccountsUpdatedListeners.containsKey(listener)) {
1718d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                throw new IllegalStateException("this listener is already added");
1719d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            }
1720d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
1721d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1722d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            mAccountsUpdatedListeners.put(listener, handler);
1723d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1724d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            if (wasEmpty) {
1725d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                // Register a broadcast receiver to monitor account changes
1726d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                IntentFilter intentFilter = new IntentFilter();
1727f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
1728b6437245c280596d0a580b8d67189739cf793250Costin Manolache                // To recover from disk-full.
1729c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
1730d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
1731d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            }
1732d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
1733d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1734d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        if (updateImmediately) {
1735ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            postToHandler(handler, listener, getAccounts());
1736d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
1737d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    }
1738d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1739d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    /**
1740661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * Removes an {@link OnAccountsUpdateListener} previously registered with
1741661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * {@link #addOnAccountsUpdatedListener}.  The listener will no longer
1742661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * receive notifications of account changes.
1743661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1744661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>It is safe to call this method from the main thread.
1745661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1746661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * <p>No permission is required to call this method.
1747661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     *
1748661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor     * @param listener The previously added listener to remove
1749d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @throws IllegalArgumentException if listener is null
1750d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @throws IllegalStateException if listener was not already added
1751d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     */
1752f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) {
1753382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (listener == null) throw new IllegalArgumentException("listener is null");
1754d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        synchronized (mAccountsUpdatedListeners) {
17555be61f5b3ad61706b72c1f6b00914ab042dc6bedBryan Mawhinney            if (!mAccountsUpdatedListeners.containsKey(listener)) {
175688a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                Log.e(TAG, "Listener was not previously added");
175788a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                return;
1758d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            }
17595be61f5b3ad61706b72c1f6b00914ab042dc6bedBryan Mawhinney            mAccountsUpdatedListeners.remove(listener);
1760d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            if (mAccountsUpdatedListeners.isEmpty()) {
1761d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
1762d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            }
1763d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
1764d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    }
1765603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
1766