blob: ada1ac268fc04aa67d5ee58595319354784e8930 [file] [log] [blame]
Fred Quintana60307342009-03-24 22:48:12 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.accounts;
18
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -070019import android.annotation.NonNull;
Tor Norbye80b530a2015-04-23 16:36:09 -070020import android.annotation.RequiresPermission;
21import android.annotation.Size;
Fred Quintana60307342009-03-24 22:48:12 -070022import android.app.Activity;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080023import android.content.BroadcastReceiver;
Amith Yamasani12b8e132013-03-14 10:48:07 -070024import android.content.ComponentName;
Fred Quintana60307342009-03-24 22:48:12 -070025import android.content.Context;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080026import android.content.Intent;
Fred Quintanad9d2f112009-04-23 13:36:27 -070027import android.content.IntentFilter;
Amith Yamasani12b8e132013-03-14 10:48:07 -070028import android.content.res.Resources;
Costin Manolacheb6437242009-09-10 16:14:12 -070029import android.database.SQLException;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080030import android.os.Build;
Fred Quintanaa698f422009-04-08 19:14:54 -070031import android.os.Bundle;
32import android.os.Handler;
33import android.os.Looper;
Fred Quintana33269202009-04-20 16:05:10 -070034import android.os.Parcelable;
Amith Yamasani2c7bc262012-11-05 16:46:02 -080035import android.os.Process;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080036import android.os.RemoteException;
Amith Yamasani2c7bc262012-11-05 16:46:02 -080037import android.os.UserHandle;
Fred Quintanaf0fd8432010-03-08 12:48:05 -080038import android.text.TextUtils;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080039import android.util.Log;
40
41import com.android.internal.R;
42import com.google.android.collect.Maps;
Fred Quintana60307342009-03-24 22:48:12 -070043
Fred Quintanaa698f422009-04-08 19:14:54 -070044import java.io.IOException;
Fred Quintana1121bb52011-09-14 23:19:35 -070045import java.util.ArrayList;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080046import java.util.HashMap;
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -070047import java.util.List;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080048import java.util.Map;
Fred Quintanaa698f422009-04-08 19:14:54 -070049import java.util.concurrent.Callable;
50import java.util.concurrent.CancellationException;
51import java.util.concurrent.ExecutionException;
52import java.util.concurrent.FutureTask;
Fred Quintanaa698f422009-04-08 19:14:54 -070053import java.util.concurrent.TimeUnit;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080054import java.util.concurrent.TimeoutException;
Fred Quintana60307342009-03-24 22:48:12 -070055
Tor Norbye80b530a2015-04-23 16:36:09 -070056import static android.Manifest.permission.GET_ACCOUNTS;
Tor Norbye80b530a2015-04-23 16:36:09 -070057
Fred Quintana60307342009-03-24 22:48:12 -070058/**
Dan Egnor661f0132010-02-19 11:23:00 -080059 * This class provides access to a centralized registry of the user's
Dan Egnor8e4378b2010-08-02 18:22:09 -070060 * online accounts. The user enters credentials (username and password) once
61 * per account, granting applications access to online resources with
62 * "one-click" approval.
Fred Quintana60307342009-03-24 22:48:12 -070063 *
Dan Egnor661f0132010-02-19 11:23:00 -080064 * <p>Different online services have different ways of handling accounts and
65 * authentication, so the account manager uses pluggable <em>authenticator</em>
Dan Egnor8e4378b2010-08-02 18:22:09 -070066 * modules for different <em>account types</em>. Authenticators (which may be
67 * written by third parties) handle the actual details of validating account
68 * credentials and storing account information. For example, Google, Facebook,
69 * and Microsoft Exchange each have their own authenticator.
Dan Egnor661f0132010-02-19 11:23:00 -080070 *
71 * <p>Many servers support some notion of an <em>authentication token</em>,
72 * which can be used to authenticate a request to the server without sending
73 * the user's actual password. (Auth tokens are normally created with a
74 * separate request which does include the user's credentials.) AccountManager
Dan Egnor8e4378b2010-08-02 18:22:09 -070075 * can generate auth tokens for applications, so the application doesn't need to
76 * handle passwords directly. Auth tokens are normally reusable and cached by
77 * AccountManager, but must be refreshed periodically. It's the responsibility
78 * of applications to <em>invalidate</em> auth tokens when they stop working so
79 * the AccountManager knows it needs to regenerate them.
Dan Egnor661f0132010-02-19 11:23:00 -080080 *
81 * <p>Applications accessing a server normally go through these steps:
82 *
83 * <ul>
84 * <li>Get an instance of AccountManager using {@link #get(Context)}.
85 *
86 * <li>List the available accounts using {@link #getAccountsByType} or
87 * {@link #getAccountsByTypeAndFeatures}. Normally applications will only
88 * be interested in accounts with one particular <em>type</em>, which
89 * identifies the authenticator. Account <em>features</em> are used to
90 * identify particular account subtypes and capabilities. Both the account
91 * type and features are authenticator-specific strings, and must be known by
92 * the application in coordination with its preferred authenticators.
93 *
94 * <li>Select one or more of the available accounts, possibly by asking the
95 * user for their preference. If no suitable accounts are available,
96 * {@link #addAccount} may be called to prompt the user to create an
97 * account of the appropriate type.
98 *
Dan Egnor8e4378b2010-08-02 18:22:09 -070099 * <li><b>Important:</b> If the application is using a previously remembered
100 * account selection, it must make sure the account is still in the list
101 * of accounts returned by {@link #getAccountsByType}. Requesting an auth token
102 * for an account no longer on the device results in an undefined failure.
103 *
Dan Egnor661f0132010-02-19 11:23:00 -0800104 * <li>Request an auth token for the selected account(s) using one of the
105 * {@link #getAuthToken} methods or related helpers. Refer to the description
106 * of each method for exact usage and error handling details.
107 *
108 * <li>Make the request using the auth token. The form of the auth token,
109 * the format of the request, and the protocol used are all specific to the
Dan Egnor8e4378b2010-08-02 18:22:09 -0700110 * service you are accessing. The application may use whatever network and
111 * protocol libraries are useful.
Dan Egnor661f0132010-02-19 11:23:00 -0800112 *
113 * <li><b>Important:</b> If the request fails with an authentication error,
114 * it could be that a cached auth token is stale and no longer honored by
115 * the server. The application must call {@link #invalidateAuthToken} to remove
116 * the token from the cache, otherwise requests will continue failing! After
117 * invalidating the auth token, immediately go back to the "Request an auth
118 * token" step above. If the process fails the second time, then it can be
119 * treated as a "genuine" authentication failure and the user notified or other
120 * appropriate actions taken.
121 * </ul>
122 *
Dan Egnor8e4378b2010-08-02 18:22:09 -0700123 * <p>Some AccountManager methods may need to interact with the user to
Dan Egnor661f0132010-02-19 11:23:00 -0800124 * prompt for credentials, present options, or ask the user to add an account.
125 * The caller may choose whether to allow AccountManager to directly launch the
126 * necessary user interface and wait for the user, or to return an Intent which
127 * the caller may use to launch the interface, or (in some cases) to install a
128 * notification which the user can select at any time to launch the interface.
129 * To have AccountManager launch the interface directly, the caller must supply
130 * the current foreground {@link Activity} context.
131 *
132 * <p>Many AccountManager methods take {@link AccountManagerCallback} and
Dan Egnor8e4378b2010-08-02 18:22:09 -0700133 * {@link Handler} as parameters. These methods return immediately and
Dan Egnor661f0132010-02-19 11:23:00 -0800134 * run asynchronously. If a callback is provided then
135 * {@link AccountManagerCallback#run} will be invoked on the Handler's
136 * thread when the request completes, successfully or not.
Dan Egnor8e4378b2010-08-02 18:22:09 -0700137 * The result is retrieved by calling {@link AccountManagerFuture#getResult()}
138 * on the {@link AccountManagerFuture} returned by the method (and also passed
139 * to the callback). This method waits for the operation to complete (if
140 * necessary) and either returns the result or throws an exception if an error
141 * occurred during the operation. To make the request synchronously, call
Dan Egnor661f0132010-02-19 11:23:00 -0800142 * {@link AccountManagerFuture#getResult()} immediately on receiving the
Dan Egnor8e4378b2010-08-02 18:22:09 -0700143 * future from the method; no callback need be supplied.
Dan Egnor661f0132010-02-19 11:23:00 -0800144 *
145 * <p>Requests which may block, including
146 * {@link AccountManagerFuture#getResult()}, must never be called on
147 * the application's main event thread. These operations throw
148 * {@link IllegalStateException} if they are used on the main thread.
Fred Quintana60307342009-03-24 22:48:12 -0700149 */
150public class AccountManager {
151 private static final String TAG = "AccountManager";
152
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700153 public static final int ERROR_CODE_REMOTE_EXCEPTION = 1;
154 public static final int ERROR_CODE_NETWORK_ERROR = 3;
155 public static final int ERROR_CODE_CANCELED = 4;
156 public static final int ERROR_CODE_INVALID_RESPONSE = 5;
157 public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6;
158 public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
159 public static final int ERROR_CODE_BAD_REQUEST = 8;
Jatin Lodhia3df7d692013-03-27 10:57:23 -0700160 public static final int ERROR_CODE_BAD_AUTHENTICATION = 9;
Fred Quintana756b7352009-10-21 13:43:10 -0700161
Amith Yamasanidf2e92a2013-03-01 17:04:38 -0800162 /** @hide */
163 public static final int ERROR_CODE_USER_RESTRICTED = 100;
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100164 /** @hide */
165 public static final int ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE = 101;
Amith Yamasanidf2e92a2013-03-01 17:04:38 -0800166
Dan Egnor661f0132010-02-19 11:23:00 -0800167 /**
Dan Egnor8e4378b2010-08-02 18:22:09 -0700168 * Bundle key used for the {@link String} account name in results
Dan Egnor661f0132010-02-19 11:23:00 -0800169 * from methods which return information about a particular account.
170 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700171 public static final String KEY_ACCOUNT_NAME = "authAccount";
Dan Egnor661f0132010-02-19 11:23:00 -0800172
173 /**
Dan Egnor8e4378b2010-08-02 18:22:09 -0700174 * Bundle key used for the {@link String} account type in results
Dan Egnor661f0132010-02-19 11:23:00 -0800175 * from methods which return information about a particular account.
176 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700177 public static final String KEY_ACCOUNT_TYPE = "accountType";
Dan Egnor661f0132010-02-19 11:23:00 -0800178
179 /**
Dan Egnor8e4378b2010-08-02 18:22:09 -0700180 * Bundle key used for the auth token value in results
Dan Egnor661f0132010-02-19 11:23:00 -0800181 * from {@link #getAuthToken} and friends.
182 */
183 public static final String KEY_AUTHTOKEN = "authtoken";
184
185 /**
Dan Egnor8e4378b2010-08-02 18:22:09 -0700186 * Bundle key used for an {@link Intent} in results from methods that
Dan Egnor661f0132010-02-19 11:23:00 -0800187 * may require the caller to interact with the user. The Intent can
188 * be used to start the corresponding user interface activity.
189 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700190 public static final String KEY_INTENT = "intent";
Dan Egnor661f0132010-02-19 11:23:00 -0800191
192 /**
Dan Egnor8e4378b2010-08-02 18:22:09 -0700193 * Bundle key used to supply the password directly in options to
Dan Egnor661f0132010-02-19 11:23:00 -0800194 * {@link #confirmCredentials}, rather than prompting the user with
195 * the standard password prompt.
196 */
197 public static final String KEY_PASSWORD = "password";
198
199 public static final String KEY_ACCOUNTS = "accounts";
Brian Carlstrom46703b02011-04-06 15:41:29 -0700200
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700201 public static final String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
202 public static final String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
Dan Egnor661f0132010-02-19 11:23:00 -0800203 public static final String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700204 public static final String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage";
205 public static final String KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey";
Dan Egnor661f0132010-02-19 11:23:00 -0800206 public static final String KEY_BOOLEAN_RESULT = "booleanResult";
207 public static final String KEY_ERROR_CODE = "errorCode";
208 public static final String KEY_ERROR_MESSAGE = "errorMessage";
209 public static final String KEY_USERDATA = "userdata";
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700210
Costin Manolachea40c6302010-12-13 14:50:45 -0800211 /**
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800212 * Bundle key used to supply the last time the credentials of the account
213 * were authenticated successfully. Time is specified in milliseconds since
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -0700214 * epoch. Associated time is updated on successful authentication of account
215 * on adding account, confirming credentials, or updating credentials.
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800216 */
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -0700217 public static final String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800218
219 /**
Costin Manolachea40c6302010-12-13 14:50:45 -0800220 * Authenticators using 'customTokens' option will also get the UID of the
221 * caller
222 */
223 public static final String KEY_CALLER_UID = "callerUid";
224 public static final String KEY_CALLER_PID = "callerPid";
Dan Egnor661f0132010-02-19 11:23:00 -0800225
Costin Manolached6060452011-01-24 16:11:36 -0800226 /**
Fred Quintanaad93a322011-09-08 13:21:01 -0700227 * The Android package of the caller will be set in the options bundle by the
228 * {@link AccountManager} and will be passed to the AccountManagerService and
229 * to the AccountAuthenticators. The uid of the caller will be known by the
230 * AccountManagerService as well as the AccountAuthenticators so they will be able to
231 * verify that the package is consistent with the uid (a uid might be shared by many
232 * packages).
233 */
234 public static final String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
235
236 /**
Costin Manolached6060452011-01-24 16:11:36 -0800237 * Boolean, if set and 'customTokens' the authenticator is responsible for
238 * notifications.
239 * @hide
240 */
241 public static final String KEY_NOTIFY_ON_FAILURE = "notifyOnAuthFailure";
242
Sandra Kwan78812282015-11-04 11:19:47 -0800243 /**
244 * Bundle key used for a {@link Bundle} in result from
245 * {@link #startAddAccountSession} and friends which returns session data
246 * for installing an account later.
247 */
248 public static final String KEY_ACCOUNT_SESSION_BUNDLE = "accountSessionBundle";
249
250 /**
251 * Bundle key used for the {@link String} account status token in result
252 * from {@link #startAddAccountSession} and friends which returns
253 * information about a particular account.
254 */
255 public static final String KEY_ACCOUNT_STATUS_TOKEN = "accountStatusToken";
256
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700257 public static final String ACTION_AUTHENTICATOR_INTENT =
258 "android.accounts.AccountAuthenticator";
259 public static final String AUTHENTICATOR_META_DATA_NAME =
Dan Egnor661f0132010-02-19 11:23:00 -0800260 "android.accounts.AccountAuthenticator";
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700261 public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
262
Fred Quintana60307342009-03-24 22:48:12 -0700263 private final Context mContext;
264 private final IAccountManager mService;
Fred Quintanad9d2f112009-04-23 13:36:27 -0700265 private final Handler mMainHandler;
Dan Egnor661f0132010-02-19 11:23:00 -0800266
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700267 /**
268 * Action sent as a broadcast Intent by the AccountsService
Dan Egnor661f0132010-02-19 11:23:00 -0800269 * when accounts are added, accounts are removed, or an
270 * account's credentials (saved password, etc) are changed.
271 *
272 * @see #addOnAccountsUpdatedListener
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700273 */
274 public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
275 "android.accounts.LOGIN_ACCOUNTS_CHANGED";
Fred Quintana60307342009-03-24 22:48:12 -0700276
Fred Quintana33269202009-04-20 16:05:10 -0700277 /**
278 * @hide
279 */
Fred Quintana60307342009-03-24 22:48:12 -0700280 public AccountManager(Context context, IAccountManager service) {
281 mContext = context;
282 mService = service;
Fred Quintanad9d2f112009-04-23 13:36:27 -0700283 mMainHandler = new Handler(mContext.getMainLooper());
Fred Quintana60307342009-03-24 22:48:12 -0700284 }
285
Fred Quintana0eabf022009-04-27 15:08:17 -0700286 /**
287 * @hide used for testing only
288 */
289 public AccountManager(Context context, IAccountManager service, Handler handler) {
290 mContext = context;
291 mService = service;
292 mMainHandler = handler;
293 }
294
Fred Quintana756b7352009-10-21 13:43:10 -0700295 /**
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800296 * @hide for internal use only
297 */
298 public static Bundle sanitizeResult(Bundle result) {
Fred Quintana382601f2010-03-25 12:25:10 -0700299 if (result != null) {
300 if (result.containsKey(KEY_AUTHTOKEN)
301 && !TextUtils.isEmpty(result.getString(KEY_AUTHTOKEN))) {
302 final Bundle newResult = new Bundle(result);
303 newResult.putString(KEY_AUTHTOKEN, "<omitted for logging purposes>");
304 return newResult;
305 }
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800306 }
307 return result;
308 }
309
310 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800311 * Gets an AccountManager instance associated with a Context.
312 * The {@link Context} will be used as long as the AccountManager is
313 * active, so make sure to use a {@link Context} whose lifetime is
314 * commensurate with any listeners registered to
315 * {@link #addOnAccountsUpdatedListener} or similar methods.
316 *
317 * <p>It is safe to call this method from the main thread.
318 *
319 * <p>No permission is required to call this method.
320 *
Fred Quintana756b7352009-10-21 13:43:10 -0700321 * @param context The {@link Context} to use when necessary
Dan Egnor661f0132010-02-19 11:23:00 -0800322 * @return An {@link AccountManager} instance
Fred Quintana756b7352009-10-21 13:43:10 -0700323 */
Fred Quintanaa698f422009-04-08 19:14:54 -0700324 public static AccountManager get(Context context) {
Fred Quintana382601f2010-03-25 12:25:10 -0700325 if (context == null) throw new IllegalArgumentException("context is null");
Fred Quintanaa698f422009-04-08 19:14:54 -0700326 return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
327 }
328
Fred Quintana756b7352009-10-21 13:43:10 -0700329 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800330 * Gets the saved password associated with the account.
331 * This is intended for authenticators and related code; applications
332 * should get an auth token instead.
333 *
334 * <p>It is safe to call this method from the main thread.
335 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700336 * <p>This method requires the caller to have a signature match with the
337 * authenticator that owns the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -0800338 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700339 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
340 * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs for
341 * this function in API level 22.
342 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700343 * @param account The account to query for a password. Must not be {@code null}.
Dan Egnor661f0132010-02-19 11:23:00 -0800344 * @return The account's password, null if none or if the account doesn't exist
Fred Quintana756b7352009-10-21 13:43:10 -0700345 */
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700346 public String getPassword(final Account account) {
Fred Quintana382601f2010-03-25 12:25:10 -0700347 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana60307342009-03-24 22:48:12 -0700348 try {
349 return mService.getPassword(account);
350 } catch (RemoteException e) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000351 // won't ever happen
Fred Quintana60307342009-03-24 22:48:12 -0700352 throw new RuntimeException(e);
353 }
354 }
355
Fred Quintana756b7352009-10-21 13:43:10 -0700356 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800357 * Gets the user data named by "key" associated with the account.
358 * This is intended for authenticators and related code to store
359 * arbitrary metadata along with accounts. The meaning of the keys
360 * and values is up to the authenticator for the account.
361 *
362 * <p>It is safe to call this method from the main thread.
363 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700364 * <p>This method requires the caller to have a signature match with the
365 * authenticator that owns the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -0800366 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700367 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
368 * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs
369 * for this function in API level 22.
370 *
Dan Egnor661f0132010-02-19 11:23:00 -0800371 * @param account The account to query for user data
372 * @return The user data, null if the account or key doesn't exist
Fred Quintana756b7352009-10-21 13:43:10 -0700373 */
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700374 public String getUserData(final Account account, final String key) {
Fred Quintana382601f2010-03-25 12:25:10 -0700375 if (account == null) throw new IllegalArgumentException("account is null");
376 if (key == null) throw new IllegalArgumentException("key is null");
Fred Quintana60307342009-03-24 22:48:12 -0700377 try {
378 return mService.getUserData(account, key);
379 } catch (RemoteException e) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000380 // won't ever happen
Fred Quintana60307342009-03-24 22:48:12 -0700381 throw new RuntimeException(e);
382 }
383 }
384
Fred Quintana756b7352009-10-21 13:43:10 -0700385 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800386 * Lists the currently registered authenticators.
387 *
388 * <p>It is safe to call this method from the main thread.
389 *
390 * <p>No permission is required to call this method.
391 *
392 * @return An array of {@link AuthenticatorDescription} for every
393 * authenticator known to the AccountManager service. Empty (never
394 * null) if no authenticators are known.
Fred Quintana756b7352009-10-21 13:43:10 -0700395 */
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700396 public AuthenticatorDescription[] getAuthenticatorTypes() {
Fred Quintanaa698f422009-04-08 19:14:54 -0700397 try {
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100398 return mService.getAuthenticatorTypes(UserHandle.getCallingUserId());
399 } catch (RemoteException e) {
400 // will never happen
401 throw new RuntimeException(e);
402 }
403 }
404
405 /**
406 * @hide
407 * Lists the currently registered authenticators for a given user id.
408 *
409 * <p>It is safe to call this method from the main thread.
410 *
411 * <p>The caller has to be in the same user or have the permission
412 * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
413 *
414 * @return An array of {@link AuthenticatorDescription} for every
415 * authenticator known to the AccountManager service. Empty (never
416 * null) if no authenticators are known.
417 */
418 public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) {
419 try {
420 return mService.getAuthenticatorTypes(userId);
Fred Quintanaa698f422009-04-08 19:14:54 -0700421 } catch (RemoteException e) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700422 // will never happen
Fred Quintanaa698f422009-04-08 19:14:54 -0700423 throw new RuntimeException(e);
424 }
425 }
426
Fred Quintana756b7352009-10-21 13:43:10 -0700427 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800428 * Lists all accounts of any type registered on the device.
429 * Equivalent to getAccountsByType(null).
430 *
431 * <p>It is safe to call this method from the main thread.
432 *
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000433 * <p>Clients of this method that have not been granted the
434 * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
435 * will only see those accounts managed by AbstractAccountAuthenticators whose
436 * signature matches the client.
Dan Egnor661f0132010-02-19 11:23:00 -0800437 *
438 * @return An array of {@link Account}, one for each account. Empty
439 * (never null) if no accounts have been added.
Fred Quintana756b7352009-10-21 13:43:10 -0700440 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -0700441 @NonNull
Tor Norbye80b530a2015-04-23 16:36:09 -0700442 @RequiresPermission(GET_ACCOUNTS)
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700443 public Account[] getAccounts() {
Fred Quintana60307342009-03-24 22:48:12 -0700444 try {
Svetoslavf3f02ac2015-09-08 14:36:35 -0700445 return mService.getAccounts(null, mContext.getOpPackageName());
Fred Quintana60307342009-03-24 22:48:12 -0700446 } catch (RemoteException e) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700447 // won't ever happen
Fred Quintana60307342009-03-24 22:48:12 -0700448 throw new RuntimeException(e);
449 }
450 }
451
Fred Quintana756b7352009-10-21 13:43:10 -0700452 /**
Amith Yamasani27db4682013-03-30 17:07:47 -0700453 * @hide
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100454 * Lists all accounts of any type registered on the device for a given
455 * user id. Equivalent to getAccountsByType(null).
456 *
457 * <p>It is safe to call this method from the main thread.
458 *
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000459 * <p>Clients of this method that have not been granted the
460 * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
461 * will only see those accounts managed by AbstractAccountAuthenticators whose
462 * signature matches the client.
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100463 *
464 * @return An array of {@link Account}, one for each account. Empty
465 * (never null) if no accounts have been added.
466 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -0700467 @NonNull
Tor Norbye80b530a2015-04-23 16:36:09 -0700468 @RequiresPermission(GET_ACCOUNTS)
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100469 public Account[] getAccountsAsUser(int userId) {
470 try {
Svetoslavf3f02ac2015-09-08 14:36:35 -0700471 return mService.getAccountsAsUser(null, userId, mContext.getOpPackageName());
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100472 } catch (RemoteException e) {
473 // won't ever happen
474 throw new RuntimeException(e);
475 }
476 }
477
478 /**
479 * @hide
Amith Yamasani27db4682013-03-30 17:07:47 -0700480 * For use by internal activities. Returns the list of accounts that the calling package
481 * is authorized to use, particularly for shared accounts.
482 * @param packageName package name of the calling app.
483 * @param uid the uid of the calling app.
484 * @return the accounts that are available to this package and user.
485 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -0700486 @NonNull
Amith Yamasani27db4682013-03-30 17:07:47 -0700487 public Account[] getAccountsForPackage(String packageName, int uid) {
488 try {
Svetoslavf3f02ac2015-09-08 14:36:35 -0700489 return mService.getAccountsForPackage(packageName, uid, mContext.getOpPackageName());
Amith Yamasani27db4682013-03-30 17:07:47 -0700490 } catch (RemoteException re) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000491 // won't ever happen
Amith Yamasani27db4682013-03-30 17:07:47 -0700492 throw new RuntimeException(re);
493 }
494 }
495
496 /**
Amith Yamasani3b458ad2013-04-18 18:40:07 -0700497 * Returns the accounts visible to the specified package, in an environment where some apps
498 * are not authorized to view all accounts. This method can only be called by system apps.
499 * @param type The type of accounts to return, null to retrieve all accounts
500 * @param packageName The package name of the app for which the accounts are to be returned
501 * @return An array of {@link Account}, one per matching account. Empty
502 * (never null) if no accounts of the specified type have been added.
503 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -0700504 @NonNull
Amith Yamasani3b458ad2013-04-18 18:40:07 -0700505 public Account[] getAccountsByTypeForPackage(String type, String packageName) {
506 try {
Svetoslavf3f02ac2015-09-08 14:36:35 -0700507 return mService.getAccountsByTypeForPackage(type, packageName,
508 mContext.getOpPackageName());
Amith Yamasani3b458ad2013-04-18 18:40:07 -0700509 } catch (RemoteException re) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000510 // won't ever happen
Amith Yamasani3b458ad2013-04-18 18:40:07 -0700511 throw new RuntimeException(re);
512 }
513 }
514
515 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800516 * Lists all accounts of a particular type. The account type is a
517 * string token corresponding to the authenticator and useful domain
518 * of the account. For example, there are types corresponding to Google
519 * and Facebook. The exact string token to use will be published somewhere
520 * associated with the authenticator in question.
521 *
522 * <p>It is safe to call this method from the main thread.
523 *
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000524 * <p>Clients of this method that have not been granted the
525 * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
526 * will only see those accounts managed by AbstractAccountAuthenticators whose
527 * signature matches the client.
Dan Egnor661f0132010-02-19 11:23:00 -0800528 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700529 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
530 * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
531 * or signature match. See docs for this function in API level 22.
532 *
Dan Egnor661f0132010-02-19 11:23:00 -0800533 * @param type The type of accounts to return, null to retrieve all accounts
534 * @return An array of {@link Account}, one per matching account. Empty
535 * (never null) if no accounts of the specified type have been added.
Fred Quintana756b7352009-10-21 13:43:10 -0700536 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -0700537 @NonNull
Tor Norbye80b530a2015-04-23 16:36:09 -0700538 @RequiresPermission(GET_ACCOUNTS)
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700539 public Account[] getAccountsByType(String type) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -0800540 return getAccountsByTypeAsUser(type, Process.myUserHandle());
541 }
542
543 /** @hide Same as {@link #getAccountsByType(String)} but for a specific user. */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -0700544 @NonNull
Amith Yamasani2c7bc262012-11-05 16:46:02 -0800545 public Account[] getAccountsByTypeAsUser(String type, UserHandle userHandle) {
Fred Quintana60307342009-03-24 22:48:12 -0700546 try {
Svetoslavf3f02ac2015-09-08 14:36:35 -0700547 return mService.getAccountsAsUser(type, userHandle.getIdentifier(),
548 mContext.getOpPackageName());
Fred Quintana60307342009-03-24 22:48:12 -0700549 } catch (RemoteException e) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700550 // won't ever happen
Fred Quintana60307342009-03-24 22:48:12 -0700551 throw new RuntimeException(e);
552 }
553 }
554
Fred Quintana756b7352009-10-21 13:43:10 -0700555 /**
Fred Quintanad9640ec2012-05-23 12:37:00 -0700556 * Change whether or not an app (identified by its uid) is allowed to retrieve an authToken
557 * for an account.
558 * <p>
559 * This is only meant to be used by system activities and is not in the SDK.
560 * @param account The account whose permissions are being modified
561 * @param authTokenType The type of token whose permissions are being modified
562 * @param uid The uid that identifies the app which is being granted or revoked permission.
563 * @param value true is permission is being granted, false for revoked
564 * @hide
565 */
566 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) {
567 try {
568 mService.updateAppPermission(account, authTokenType, uid, value);
569 } catch (RemoteException e) {
570 // won't ever happen
571 throw new RuntimeException(e);
572 }
573 }
574
575 /**
576 * Get the user-friendly label associated with an authenticator's auth token.
577 * @param accountType the type of the authenticator. must not be null.
578 * @param authTokenType the token type. must not be null.
579 * @param callback callback to invoke when the result is available. may be null.
580 * @param handler the handler on which to invoke the callback, or null for the main thread
581 * @return a future containing the label string
582 * @hide
583 */
584 public AccountManagerFuture<String> getAuthTokenLabel(
585 final String accountType, final String authTokenType,
586 AccountManagerCallback<String> callback, Handler handler) {
587 if (accountType == null) throw new IllegalArgumentException("accountType is null");
588 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
589 return new Future2Task<String>(handler, callback) {
590 public void doWork() throws RemoteException {
591 mService.getAuthTokenLabel(mResponse, accountType, authTokenType);
592 }
593
594 @Override
595 public String bundleToResult(Bundle bundle) throws AuthenticatorException {
596 if (!bundle.containsKey(KEY_AUTH_TOKEN_LABEL)) {
597 throw new AuthenticatorException("no result in response");
598 }
599 return bundle.getString(KEY_AUTH_TOKEN_LABEL);
600 }
601 }.start();
602 }
603
604 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800605 * Finds out whether a particular account has all the specified features.
606 * Account features are authenticator-specific string tokens identifying
607 * boolean account properties. For example, features are used to tell
608 * whether Google accounts have a particular service (such as Google
609 * Calendar or Google Talk) enabled. The feature names and their meanings
610 * are published somewhere associated with the authenticator in question.
611 *
612 * <p>This method may be called from any thread, but the returned
613 * {@link AccountManagerFuture} must not be used on the main thread.
614 *
615 * <p>This method requires the caller to hold the permission
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000616 * {@link android.Manifest.permission#GET_ACCOUNTS} or be a signature
617 * match with the AbstractAccountAuthenticator that manages the account.
Fred Quintanabb68a4f2010-01-13 17:28:39 -0800618 *
619 * @param account The {@link Account} to test
Dan Egnor661f0132010-02-19 11:23:00 -0800620 * @param features An array of the account features to check
621 * @param callback Callback to invoke when the request completes,
622 * null for no callback
623 * @param handler {@link Handler} identifying the callback thread,
624 * null for the main thread
625 * @return An {@link AccountManagerFuture} which resolves to a Boolean,
626 * true if the account exists and has all of the specified features.
Fred Quintanabb68a4f2010-01-13 17:28:39 -0800627 */
Tor Norbye80b530a2015-04-23 16:36:09 -0700628 @RequiresPermission(GET_ACCOUNTS)
Fred Quintana3084a6f2010-01-14 18:02:03 -0800629 public AccountManagerFuture<Boolean> hasFeatures(final Account account,
Fred Quintanabb68a4f2010-01-13 17:28:39 -0800630 final String[] features,
631 AccountManagerCallback<Boolean> callback, Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -0700632 if (account == null) throw new IllegalArgumentException("account is null");
633 if (features == null) throw new IllegalArgumentException("features is null");
Fred Quintanabb68a4f2010-01-13 17:28:39 -0800634 return new Future2Task<Boolean>(handler, callback) {
635 public void doWork() throws RemoteException {
Svetoslavf3f02ac2015-09-08 14:36:35 -0700636 mService.hasFeatures(mResponse, account, features, mContext.getOpPackageName());
Fred Quintanabb68a4f2010-01-13 17:28:39 -0800637 }
638 public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
639 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
640 throw new AuthenticatorException("no result in response");
641 }
642 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
643 }
644 }.start();
645 }
646
647 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800648 * Lists all accounts of a type which have certain features. The account
649 * type identifies the authenticator (see {@link #getAccountsByType}).
650 * Account features are authenticator-specific string tokens identifying
651 * boolean account properties (see {@link #hasFeatures}).
Fred Quintana756b7352009-10-21 13:43:10 -0700652 *
Dan Egnor661f0132010-02-19 11:23:00 -0800653 * <p>Unlike {@link #getAccountsByType}, this method calls the authenticator,
654 * which may contact the server or do other work to check account features,
655 * so the method returns an {@link AccountManagerFuture}.
Fred Quintanaa698f422009-04-08 19:14:54 -0700656 *
Dan Egnor661f0132010-02-19 11:23:00 -0800657 * <p>This method may be called from any thread, but the returned
658 * {@link AccountManagerFuture} must not be used on the main thread.
Fred Quintana756b7352009-10-21 13:43:10 -0700659 *
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000660 * <p>Clients of this method that have not been granted the
661 * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
662 * will only see those accounts managed by AbstractAccountAuthenticators whose
663 * signature matches the client.
Fred Quintana756b7352009-10-21 13:43:10 -0700664 *
Dan Egnor661f0132010-02-19 11:23:00 -0800665 * @param type The type of accounts to return, must not be null
666 * @param features An array of the account features to require,
667 * may be null or empty
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700668 *
669 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
670 * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
671 * or signature match. See docs for this function in API level 22.
672 *
Dan Egnor661f0132010-02-19 11:23:00 -0800673 * @param callback Callback to invoke when the request completes,
674 * null for no callback
675 * @param handler {@link Handler} identifying the callback thread,
676 * null for the main thread
677 * @return An {@link AccountManagerFuture} which resolves to an array of
678 * {@link Account}, one per account of the specified type which
679 * matches the requested features.
Fred Quintana8570f742010-02-18 10:32:54 -0800680 */
Tor Norbye80b530a2015-04-23 16:36:09 -0700681 @RequiresPermission(GET_ACCOUNTS)
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700682 public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
683 final String type, final String[] features,
684 AccountManagerCallback<Account[]> callback, Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -0700685 if (type == null) throw new IllegalArgumentException("type is null");
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700686 return new Future2Task<Account[]>(handler, callback) {
687 public void doWork() throws RemoteException {
Svetoslavf3f02ac2015-09-08 14:36:35 -0700688 mService.getAccountsByFeatures(mResponse, type, features,
689 mContext.getOpPackageName());
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700690 }
691 public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700692 if (!bundle.containsKey(KEY_ACCOUNTS)) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700693 throw new AuthenticatorException("no result in response");
694 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700695 final Parcelable[] parcelables = bundle.getParcelableArray(KEY_ACCOUNTS);
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700696 Account[] descs = new Account[parcelables.length];
697 for (int i = 0; i < parcelables.length; i++) {
698 descs[i] = (Account) parcelables[i];
699 }
700 return descs;
701 }
702 }.start();
703 }
704
Fred Quintana756b7352009-10-21 13:43:10 -0700705 /**
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -0700706 * Adds an account directly to the AccountManager. Normally used by sign-up
Dan Egnor661f0132010-02-19 11:23:00 -0800707 * wizards associated with authenticators, not directly by applications.
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -0700708 * <p>Calling this method does not update the last authenticated timestamp,
709 * referred by {@link #KEY_LAST_AUTHENTICATED_TIME}. To update it, call
710 * {@link #notifyAccountAuthenticated(Account)} after getting success.
711 * However, if this method is called when it is triggered by addAccount() or
712 * addAccountAsUser() or similar functions, then there is no need to update
713 * timestamp manually as it is updated automatically by framework on
714 * successful completion of the mentioned functions.
Dan Egnor661f0132010-02-19 11:23:00 -0800715 * <p>It is safe to call this method from the main thread.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700716 * <p>This method requires the caller to have a signature match with the
717 * authenticator that owns the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -0800718 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700719 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
720 * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs
721 * for this function in API level 22.
722 *
Dan Egnor661f0132010-02-19 11:23:00 -0800723 * @param account The {@link Account} to add
724 * @param password The password to associate with the account, null for none
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -0700725 * @param userdata String values to use for the account's userdata, null for
726 * none
Dan Egnor8e4378b2010-08-02 18:22:09 -0700727 * @return True if the account was successfully added, false if the account
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -0700728 * already exists, the account is null, or another error occurs.
Dan Egnor661f0132010-02-19 11:23:00 -0800729 */
730 public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
Fred Quintana382601f2010-03-25 12:25:10 -0700731 if (account == null) throw new IllegalArgumentException("account is null");
Dan Egnor661f0132010-02-19 11:23:00 -0800732 try {
Amith Yamasani27db4682013-03-30 17:07:47 -0700733 return mService.addAccountExplicitly(account, password, userdata);
Dan Egnor661f0132010-02-19 11:23:00 -0800734 } catch (RemoteException e) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000735 // Can happen if there was a SecurityException was thrown.
Dan Egnor661f0132010-02-19 11:23:00 -0800736 throw new RuntimeException(e);
737 }
738 }
739
740 /**
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -0700741 * Notifies the system that the account has just been authenticated. This
742 * information may be used by other applications to verify the account. This
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800743 * should be called only when the user has entered correct credentials for
744 * the account.
745 * <p>
746 * It is not safe to call this method from the main thread. As such, call it
747 * from another thread.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700748 * <p>This method requires the caller to have a signature match with the
749 * authenticator that owns the specified account.
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800750 *
751 * @param account The {@link Account} to be updated.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700752 * @return boolean {@code true} if the authentication of the account has been successfully
753 * acknowledged. Otherwise {@code false}.
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800754 */
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -0700755 public boolean notifyAccountAuthenticated(Account account) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800756 if (account == null)
757 throw new IllegalArgumentException("account is null");
758 try {
759 return mService.accountAuthenticated(account);
760 } catch (RemoteException e) {
761 throw new RuntimeException(e);
762 }
763 }
764
765 /**
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700766 * Rename the specified {@link Account}. This is equivalent to removing
767 * the existing account and adding a new renamed account with the old
768 * account's user data.
769 *
770 * <p>It is safe to call this method from the main thread.
771 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700772 * <p>This method requires the caller to have a signature match with the
773 * authenticator that manages the specified account.
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700774 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700775 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
776 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
777 * is needed for those platforms. See docs for this function in API level 22.
778 *
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700779 * @param account The {@link Account} to rename
780 * @param newName String name to be associated with the account.
781 * @param callback Callback to invoke when the request completes, null for
782 * no callback
783 * @param handler {@link Handler} identifying the callback thread, null for
784 * the main thread
785 * @return An {@link AccountManagerFuture} which resolves to the Account
786 * after the name change. If successful the account's name will be the
787 * specified new name.
788 */
789 public AccountManagerFuture<Account> renameAccount(
790 final Account account,
Tor Norbye80b530a2015-04-23 16:36:09 -0700791 @Size(min = 1) final String newName,
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700792 AccountManagerCallback<Account> callback,
793 Handler handler) {
794 if (account == null) throw new IllegalArgumentException("account is null.");
795 if (TextUtils.isEmpty(newName)) {
796 throw new IllegalArgumentException("newName is empty or null.");
797 }
798 return new Future2Task<Account>(handler, callback) {
799 @Override
800 public void doWork() throws RemoteException {
801 mService.renameAccount(mResponse, account, newName);
802 }
803 @Override
804 public Account bundleToResult(Bundle bundle) throws AuthenticatorException {
805 String name = bundle.getString(KEY_ACCOUNT_NAME);
806 String type = bundle.getString(KEY_ACCOUNT_TYPE);
807 return new Account(name, type);
808 }
809 }.start();
810 }
811
812 /**
813 * Gets the previous name associated with the account or {@code null}, if
814 * none. This is intended so that clients of {@link
815 * #LOGIN_ACCOUNTS_CHANGED_ACTION} broadcasts can determine if an
816 * authenticator has renamed an account.
817 *
818 * <p>It is safe to call this method from the main thread.
819 *
820 * @param account The account to query for a previous name.
821 * @return The account's previous name, null if the account has never been
822 * renamed.
823 */
824 public String getPreviousName(final Account account) {
825 if (account == null) throw new IllegalArgumentException("account is null");
826 try {
827 return mService.getPreviousName(account);
828 } catch (RemoteException e) {
829 // will never happen
830 throw new RuntimeException(e);
831 }
832 }
833
834 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800835 * Removes an account from the AccountManager. Does nothing if the account
836 * does not exist. Does not delete the account from the server.
837 * The authenticator may have its own policies preventing account
838 * deletion, in which case the account will not be deleted.
839 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700840 * <p>This method requires the caller to have a signature match with the
841 * authenticator that manages the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -0800842 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700843 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
844 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
845 * this function in API level 22.
846 *
Dan Egnor661f0132010-02-19 11:23:00 -0800847 * @param account The {@link Account} to remove
848 * @param callback Callback to invoke when the request completes,
849 * null for no callback
850 * @param handler {@link Handler} identifying the callback thread,
851 * null for the main thread
852 * @return An {@link AccountManagerFuture} which resolves to a Boolean,
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100853 * true if the account has been successfully removed
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800854 * @deprecated use
855 * {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)}
856 * instead
Dan Egnor661f0132010-02-19 11:23:00 -0800857 */
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800858 @Deprecated
Dan Egnor661f0132010-02-19 11:23:00 -0800859 public AccountManagerFuture<Boolean> removeAccount(final Account account,
860 AccountManagerCallback<Boolean> callback, Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -0700861 if (account == null) throw new IllegalArgumentException("account is null");
Dan Egnor661f0132010-02-19 11:23:00 -0800862 return new Future2Task<Boolean>(handler, callback) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700863 @Override
Dan Egnor661f0132010-02-19 11:23:00 -0800864 public void doWork() throws RemoteException {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800865 mService.removeAccount(mResponse, account, false);
Dan Egnor661f0132010-02-19 11:23:00 -0800866 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700867 @Override
Dan Egnor661f0132010-02-19 11:23:00 -0800868 public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
869 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
870 throw new AuthenticatorException("no result in response");
871 }
872 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
873 }
874 }.start();
875 }
876
877 /**
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800878 * Removes an account from the AccountManager. Does nothing if the account
879 * does not exist. Does not delete the account from the server.
880 * The authenticator may have its own policies preventing account
881 * deletion, in which case the account will not be deleted.
882 *
883 * <p>This method may be called from any thread, but the returned
884 * {@link AccountManagerFuture} must not be used on the main thread.
885 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700886 * <p>This method requires the caller to have a signature match with the
887 * authenticator that manages the specified account.
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800888 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700889 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
890 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
891 * this function in API level 22.
892 *
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800893 * @param account The {@link Account} to remove
894 * @param activity The {@link Activity} context to use for launching a new
895 * authenticator-defined sub-Activity to prompt the user to delete an
896 * account; used only to call startActivity(); if null, the prompt
897 * will not be launched directly, but the {@link Intent} may be
898 * returned to the caller instead
899 * @param callback Callback to invoke when the request completes,
900 * null for no callback
901 * @param handler {@link Handler} identifying the callback thread,
902 * null for the main thread
903 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
904 * {@link #KEY_BOOLEAN_RESULT} if activity was specified and an account
905 * was removed or if active. If no activity was specified, the returned
906 * Bundle contains only {@link #KEY_INTENT} with the {@link Intent}
907 * needed to launch the actual account removal process, if authenticator
908 * needs the activity launch. If an error occurred,
909 * {@link AccountManagerFuture#getResult()} throws:
910 * <ul>
911 * <li> {@link AuthenticatorException} if no authenticator was registered for
912 * this account type or the authenticator failed to respond
913 * <li> {@link OperationCanceledException} if the operation was canceled for
914 * any reason, including the user canceling the creation process or
915 * adding accounts (of this type) has been disabled by policy
916 * </ul>
917 */
918 public AccountManagerFuture<Bundle> removeAccount(final Account account,
919 final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
920 if (account == null) throw new IllegalArgumentException("account is null");
921 return new AmsTask(activity, handler, callback) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700922 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800923 public void doWork() throws RemoteException {
924 mService.removeAccount(mResponse, account, activity != null);
925 }
926 }.start();
927 }
928
929 /**
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100930 * @see #removeAccount(Account, AccountManagerCallback, Handler)
931 * @hide
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800932 * @deprecated use
933 * {@link #removeAccountAsUser(Account, Activity, AccountManagerCallback, Handler)}
934 * instead
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100935 */
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800936 @Deprecated
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100937 public AccountManagerFuture<Boolean> removeAccountAsUser(final Account account,
938 AccountManagerCallback<Boolean> callback, Handler handler,
939 final UserHandle userHandle) {
940 if (account == null) throw new IllegalArgumentException("account is null");
941 if (userHandle == null) throw new IllegalArgumentException("userHandle is null");
942 return new Future2Task<Boolean>(handler, callback) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700943 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100944 public void doWork() throws RemoteException {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800945 mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier());
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100946 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700947 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100948 public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
949 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
950 throw new AuthenticatorException("no result in response");
951 }
952 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
953 }
954 }.start();
955 }
956
957 /**
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800958 * @see #removeAccount(Account, Activity, AccountManagerCallback, Handler)
959 * @hide
960 */
961 public AccountManagerFuture<Bundle> removeAccountAsUser(final Account account,
962 final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler,
963 final UserHandle userHandle) {
964 if (account == null)
965 throw new IllegalArgumentException("account is null");
966 if (userHandle == null)
967 throw new IllegalArgumentException("userHandle is null");
968 return new AmsTask(activity, handler, callback) {
969 public void doWork() throws RemoteException {
970 mService.removeAccountAsUser(mResponse, account, activity != null,
971 userHandle.getIdentifier());
972 }
973 }.start();
974 }
975
976 /**
977 * Removes an account directly. Normally used by authenticators, not
978 * directly by applications. Does not delete the account from the server.
979 * The authenticator may have its own policies preventing account deletion,
980 * in which case the account will not be deleted.
981 * <p>
982 * It is safe to call this method from the main thread.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700983 * <p>This method requires the caller to have a signature match with the
984 * authenticator that manages the specified account.
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800985 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700986 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
987 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
988 * is needed for those platforms. See docs for this function in API level 22.
989 *
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800990 * @param account The {@link Account} to delete.
991 * @return True if the account was successfully deleted, false if the
992 * account did not exist, the account is null, or another error
993 * occurs.
994 */
995 public boolean removeAccountExplicitly(Account account) {
996 if (account == null) throw new IllegalArgumentException("account is null");
997 try {
998 return mService.removeAccountExplicitly(account);
999 } catch (RemoteException e) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001000 // May happen if the caller doesn't match the signature of the authenticator.
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -08001001 throw new RuntimeException(e);
1002 }
1003 }
1004
1005 /**
Dan Egnor661f0132010-02-19 11:23:00 -08001006 * Removes an auth token from the AccountManager's cache. Does nothing if
1007 * the auth token is not currently in the cache. Applications must call this
1008 * method when the auth token is found to have expired or otherwise become
1009 * invalid for authenticating requests. The AccountManager does not validate
1010 * or expire cached auth tokens otherwise.
1011 *
1012 * <p>It is safe to call this method from the main thread.
1013 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001014 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1015 * MANAGE_ACCOUNTS or USE_CREDENTIALS permission is needed for those
1016 * platforms. See docs for this function in API level 22.
1017 *
Fred Quintanaf35b68f2010-04-01 11:36:00 -07001018 * @param accountType The account type of the auth token to invalidate, must not be null
1019 * @param authToken The auth token to invalidate, may be null
Dan Egnor661f0132010-02-19 11:23:00 -08001020 */
1021 public void invalidateAuthToken(final String accountType, final String authToken) {
Fred Quintana382601f2010-03-25 12:25:10 -07001022 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001023 try {
Fred Quintanaf35b68f2010-04-01 11:36:00 -07001024 if (authToken != null) {
1025 mService.invalidateAuthToken(accountType, authToken);
1026 }
Dan Egnor661f0132010-02-19 11:23:00 -08001027 } catch (RemoteException e) {
1028 // won't ever happen
1029 throw new RuntimeException(e);
1030 }
1031 }
1032
1033 /**
1034 * Gets an auth token from the AccountManager's cache. If no auth
1035 * token is cached for this account, null will be returned -- a new
1036 * auth token will not be generated, and the server will not be contacted.
1037 * Intended for use by the authenticator, not directly by applications.
1038 *
1039 * <p>It is safe to call this method from the main thread.
1040 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001041 * <p>This method requires the caller to have a signature match with the
1042 * authenticator that manages the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -08001043 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001044 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1045 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
1046 * is needed for those platforms. See docs for this function in API level 22.
1047 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001048 * @param account The account for which an auth token is to be fetched. Cannot be {@code null}.
1049 * @param authTokenType The type of auth token to fetch. Cannot be {@code null}.
Dan Egnor661f0132010-02-19 11:23:00 -08001050 * @return The cached auth token for this account and type, or null if
1051 * no auth token is cached or the account does not exist.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001052 * @see #getAuthToken
Dan Egnor661f0132010-02-19 11:23:00 -08001053 */
1054 public String peekAuthToken(final Account account, final String authTokenType) {
Fred Quintana382601f2010-03-25 12:25:10 -07001055 if (account == null) throw new IllegalArgumentException("account is null");
1056 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001057 try {
1058 return mService.peekAuthToken(account, authTokenType);
1059 } catch (RemoteException e) {
1060 // won't ever happen
1061 throw new RuntimeException(e);
1062 }
1063 }
1064
1065 /**
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07001066 * Sets or forgets a saved password. This modifies the local copy of the
1067 * password used to automatically authenticate the user; it does not change
1068 * the user's account password on the server. Intended for use by the
1069 * authenticator, not directly by applications.
1070 * <p>Calling this method does not update the last authenticated timestamp,
1071 * referred by {@link #KEY_LAST_AUTHENTICATED_TIME}. To update it, call
1072 * {@link #notifyAccountAuthenticated(Account)} after getting success.
Dan Egnor661f0132010-02-19 11:23:00 -08001073 * <p>It is safe to call this method from the main thread.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001074 * <p>This method requires the caller to have a signature match with the
1075 * authenticator that manages the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -08001076 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001077 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1078 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
1079 * is needed for those platforms. See docs for this function in API level 22.
1080 *
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07001081 * @param account The account whose password is to be set. Cannot be
1082 * {@code null}.
Dan Egnor661f0132010-02-19 11:23:00 -08001083 * @param password The password to set, null to clear the password
1084 */
1085 public void setPassword(final Account account, final String password) {
Fred Quintana382601f2010-03-25 12:25:10 -07001086 if (account == null) throw new IllegalArgumentException("account is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001087 try {
1088 mService.setPassword(account, password);
1089 } catch (RemoteException e) {
1090 // won't ever happen
1091 throw new RuntimeException(e);
1092 }
1093 }
1094
1095 /**
1096 * Forgets a saved password. This erases the local copy of the password;
1097 * it does not change the user's account password on the server.
1098 * Has the same effect as setPassword(account, null) but requires fewer
1099 * permissions, and may be used by applications or management interfaces
1100 * to "sign out" from an account.
1101 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001102 * <p>This method only successfully clear the account's password when the
1103 * caller has the same signature as the authenticator that owns the
1104 * specified account. Otherwise, this method will silently fail.
Dan Egnor661f0132010-02-19 11:23:00 -08001105 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001106 * <p>It is safe to call this method from the main thread.
Carlos Valdiviadcddc472015-06-11 20:04:04 +00001107 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001108 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1109 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
1110 * this function in API level 22.
1111 *
Dan Egnor661f0132010-02-19 11:23:00 -08001112 * @param account The account whose password to clear
1113 */
1114 public void clearPassword(final Account account) {
Fred Quintana382601f2010-03-25 12:25:10 -07001115 if (account == null) throw new IllegalArgumentException("account is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001116 try {
1117 mService.clearPassword(account);
1118 } catch (RemoteException e) {
1119 // won't ever happen
1120 throw new RuntimeException(e);
1121 }
1122 }
1123
1124 /**
1125 * Sets one userdata key for an account. Intended by use for the
1126 * authenticator to stash state for itself, not directly by applications.
1127 * The meaning of the keys and values is up to the authenticator.
1128 *
1129 * <p>It is safe to call this method from the main thread.
1130 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001131 * <p>This method requires the caller to have a signature match with the
1132 * authenticator that manages the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -08001133 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001134 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1135 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
1136 * is needed for those platforms. See docs for this function in API level 22.
1137 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001138 * @param account Account whose user data is to be set. Must not be {@code null}.
1139 * @param key String user data key to set. Must not be null
1140 * @param value String value to set, {@code null} to clear this user data key
Dan Egnor661f0132010-02-19 11:23:00 -08001141 */
1142 public void setUserData(final Account account, final String key, final String value) {
Fred Quintana382601f2010-03-25 12:25:10 -07001143 if (account == null) throw new IllegalArgumentException("account is null");
1144 if (key == null) throw new IllegalArgumentException("key is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001145 try {
1146 mService.setUserData(account, key, value);
1147 } catch (RemoteException e) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001148 // Will happen if there is not signature match.
Dan Egnor661f0132010-02-19 11:23:00 -08001149 throw new RuntimeException(e);
1150 }
1151 }
1152
1153 /**
1154 * Adds an auth token to the AccountManager cache for an account.
1155 * If the account does not exist then this call has no effect.
1156 * Replaces any previous auth token for this account and auth token type.
1157 * Intended for use by the authenticator, not directly by applications.
1158 *
1159 * <p>It is safe to call this method from the main thread.
1160 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001161 * <p>This method requires the caller to have a signature match with the
1162 * authenticator that manages the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -08001163 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001164 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1165 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
1166 * is needed for those platforms. See docs for this function in API level 22.
1167 *
Dan Egnor661f0132010-02-19 11:23:00 -08001168 * @param account The account to set an auth token for
1169 * @param authTokenType The type of the auth token, see {#getAuthToken}
1170 * @param authToken The auth token to add to the cache
1171 */
1172 public void setAuthToken(Account account, final String authTokenType, final String authToken) {
Fred Quintana382601f2010-03-25 12:25:10 -07001173 if (account == null) throw new IllegalArgumentException("account is null");
1174 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001175 try {
1176 mService.setAuthToken(account, authTokenType, authToken);
1177 } catch (RemoteException e) {
1178 // won't ever happen
1179 throw new RuntimeException(e);
1180 }
1181 }
1182
1183 /**
1184 * This convenience helper synchronously gets an auth token with
1185 * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, Handler)}.
1186 *
1187 * <p>This method may block while a network request completes, and must
1188 * never be made from the main thread.
1189 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001190 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1191 * USE_CREDENTIALS permission is needed for those platforms. See docs for
1192 * this function in API level 22.
1193 *
Dan Egnor661f0132010-02-19 11:23:00 -08001194 * @param account The account to fetch an auth token for
Joe Malinb6a35262013-06-03 09:49:04 -07001195 * @param authTokenType The auth token type, see {@link #getAuthToken getAuthToken()}
Dan Egnor661f0132010-02-19 11:23:00 -08001196 * @param notifyAuthFailure If true, display a notification and return null
1197 * if authentication fails; if false, prompt and wait for the user to
1198 * re-enter correct credentials before returning
1199 * @return An auth token of the specified type for this account, or null
1200 * if authentication fails or none can be fetched.
1201 * @throws AuthenticatorException if the authenticator failed to respond
1202 * @throws OperationCanceledException if the request was canceled for any
1203 * reason, including the user canceling a credential request
1204 * @throws java.io.IOException if the authenticator experienced an I/O problem
1205 * creating a new auth token, usually because of network trouble
1206 */
1207 public String blockingGetAuthToken(Account account, String authTokenType,
1208 boolean notifyAuthFailure)
1209 throws OperationCanceledException, IOException, AuthenticatorException {
Fred Quintana382601f2010-03-25 12:25:10 -07001210 if (account == null) throw new IllegalArgumentException("account is null");
1211 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001212 Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */,
1213 null /* handler */).getResult();
Fred Quintana96580e02010-03-04 13:42:42 -08001214 if (bundle == null) {
1215 // This should never happen, but it does, occasionally. If it does return null to
1216 // signify that we were not able to get the authtoken.
1217 // TODO: remove this when the bug is found that sometimes causes a null bundle to be
1218 // returned
1219 Log.e(TAG, "blockingGetAuthToken: null was returned from getResult() for "
1220 + account + ", authTokenType " + authTokenType);
1221 return null;
1222 }
Dan Egnor661f0132010-02-19 11:23:00 -08001223 return bundle.getString(KEY_AUTHTOKEN);
1224 }
1225
1226 /**
1227 * Gets an auth token of the specified type for a particular account,
1228 * prompting the user for credentials if necessary. This method is
1229 * intended for applications running in the foreground where it makes
1230 * sense to ask the user directly for a password.
1231 *
1232 * <p>If a previously generated auth token is cached for this account and
Dan Egnor8e4378b2010-08-02 18:22:09 -07001233 * type, then it is returned. Otherwise, if a saved password is
1234 * available, it is sent to the server to generate a new auth token.
1235 * Otherwise, the user is prompted to enter a password.
Dan Egnor661f0132010-02-19 11:23:00 -08001236 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07001237 * <p>Some authenticators have auth token <em>types</em>, whose value
1238 * is authenticator-dependent. Some services use different token types to
1239 * access different functionality -- for example, Google uses different auth
1240 * tokens to access Gmail and Google Calendar for the same account.
Dan Egnor661f0132010-02-19 11:23:00 -08001241 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001242 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1243 * USE_CREDENTIALS permission is needed for those platforms. See docs for
1244 * this function in API level 22.
1245 *
Dan Egnor661f0132010-02-19 11:23:00 -08001246 * <p>This method may be called from any thread, but the returned
1247 * {@link AccountManagerFuture} must not be used on the main thread.
1248 *
Dan Egnor661f0132010-02-19 11:23:00 -08001249 * @param account The account to fetch an auth token for
1250 * @param authTokenType The auth token type, an authenticator-dependent
1251 * string token, must not be null
1252 * @param options Authenticator-specific options for the request,
1253 * may be null or empty
1254 * @param activity The {@link Activity} context to use for launching a new
1255 * authenticator-defined sub-Activity to prompt the user for a password
1256 * if necessary; used only to call startActivity(); must not be null.
1257 * @param callback Callback to invoke when the request completes,
1258 * null for no callback
1259 * @param handler {@link Handler} identifying the callback thread,
1260 * null for the main thread
1261 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
1262 * at least the following fields:
Fred Quintana756b7352009-10-21 13:43:10 -07001263 * <ul>
Dan Egnor661f0132010-02-19 11:23:00 -08001264 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
1265 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1266 * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
Fred Quintana756b7352009-10-21 13:43:10 -07001267 * </ul>
Dan Egnor661f0132010-02-19 11:23:00 -08001268 *
1269 * (Other authenticator-specific values may be returned.) If an auth token
1270 * could not be fetched, {@link AccountManagerFuture#getResult()} throws:
1271 * <ul>
1272 * <li> {@link AuthenticatorException} if the authenticator failed to respond
1273 * <li> {@link OperationCanceledException} if the operation is canceled for
1274 * any reason, incluidng the user canceling a credential request
1275 * <li> {@link IOException} if the authenticator experienced an I/O problem
1276 * creating a new auth token, usually because of network trouble
1277 * </ul>
Dan Egnor8e4378b2010-08-02 18:22:09 -07001278 * If the account is no longer present on the device, the return value is
1279 * authenticator-dependent. The caller should verify the validity of the
1280 * account before requesting an auth token.
Dan Egnor661f0132010-02-19 11:23:00 -08001281 */
1282 public AccountManagerFuture<Bundle> getAuthToken(
1283 final Account account, final String authTokenType, final Bundle options,
1284 final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -07001285 if (account == null) throw new IllegalArgumentException("account is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001286 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Costin Manolachee5847ad2011-09-14 12:52:19 -07001287 final Bundle optionsIn = new Bundle();
1288 if (options != null) {
1289 optionsIn.putAll(options);
1290 }
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001291 optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
Dan Egnor661f0132010-02-19 11:23:00 -08001292 return new AmsTask(activity, handler, callback) {
1293 public void doWork() throws RemoteException {
1294 mService.getAuthToken(mResponse, account, authTokenType,
1295 false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001296 optionsIn);
Dan Egnor661f0132010-02-19 11:23:00 -08001297 }
1298 }.start();
1299 }
1300
1301 /**
1302 * Gets an auth token of the specified type for a particular account,
1303 * optionally raising a notification if the user must enter credentials.
1304 * This method is intended for background tasks and services where the
1305 * user should not be immediately interrupted with a password prompt.
1306 *
1307 * <p>If a previously generated auth token is cached for this account and
Dan Egnor8e4378b2010-08-02 18:22:09 -07001308 * type, then it is returned. Otherwise, if a saved password is
1309 * available, it is sent to the server to generate a new auth token.
1310 * Otherwise, an {@link Intent} is returned which, when started, will
1311 * prompt the user for a password. If the notifyAuthFailure parameter is
1312 * set, a status bar notification is also created with the same Intent,
Dan Egnor661f0132010-02-19 11:23:00 -08001313 * alerting the user that they need to enter a password at some point.
1314 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07001315 * <p>In that case, you may need to wait until the user responds, which
1316 * could take hours or days or forever. When the user does respond and
1317 * supply a new password, the account manager will broadcast the
1318 * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
1319 * use to try again.
Dan Egnor661f0132010-02-19 11:23:00 -08001320 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07001321 * <p>If notifyAuthFailure is not set, it is the application's
1322 * responsibility to launch the returned Intent at some point.
1323 * Either way, the result from this call will not wait for user action.
Dan Egnor661f0132010-02-19 11:23:00 -08001324 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07001325 * <p>Some authenticators have auth token <em>types</em>, whose value
1326 * is authenticator-dependent. Some services use different token types to
1327 * access different functionality -- for example, Google uses different auth
1328 * tokens to access Gmail and Google Calendar for the same account.
Dan Egnor661f0132010-02-19 11:23:00 -08001329 *
1330 * <p>This method may be called from any thread, but the returned
1331 * {@link AccountManagerFuture} must not be used on the main thread.
1332 *
Dan Egnor661f0132010-02-19 11:23:00 -08001333 * @param account The account to fetch an auth token for
1334 * @param authTokenType The auth token type, an authenticator-dependent
1335 * string token, must not be null
Dan Egnor661f0132010-02-19 11:23:00 -08001336 * @param notifyAuthFailure True to add a notification to prompt the
1337 * user for a password if necessary, false to leave that to the caller
1338 * @param callback Callback to invoke when the request completes,
1339 * null for no callback
1340 * @param handler {@link Handler} identifying the callback thread,
1341 * null for the main thread
1342 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
1343 * at least the following fields on success:
1344 * <ul>
1345 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
1346 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1347 * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
1348 * </ul>
1349 *
1350 * (Other authenticator-specific values may be returned.) If the user
1351 * must enter credentials, the returned Bundle contains only
1352 * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
1353 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07001354 * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
Dan Egnor661f0132010-02-19 11:23:00 -08001355 * <ul>
1356 * <li> {@link AuthenticatorException} if the authenticator failed to respond
1357 * <li> {@link OperationCanceledException} if the operation is canceled for
1358 * any reason, incluidng the user canceling a credential request
1359 * <li> {@link IOException} if the authenticator experienced an I/O problem
1360 * creating a new auth token, usually because of network trouble
1361 * </ul>
Dan Egnor8e4378b2010-08-02 18:22:09 -07001362 * If the account is no longer present on the device, the return value is
1363 * authenticator-dependent. The caller should verify the validity of the
1364 * account before requesting an auth token.
Fred Quintanaad93a322011-09-08 13:21:01 -07001365 * @deprecated use {@link #getAuthToken(Account, String, android.os.Bundle,
1366 * boolean, AccountManagerCallback, android.os.Handler)} instead
Dan Egnor661f0132010-02-19 11:23:00 -08001367 */
Fred Quintanaad93a322011-09-08 13:21:01 -07001368 @Deprecated
Dan Egnor661f0132010-02-19 11:23:00 -08001369 public AccountManagerFuture<Bundle> getAuthToken(
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001370 final Account account, final String authTokenType,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001371 final boolean notifyAuthFailure,
Dan Egnor661f0132010-02-19 11:23:00 -08001372 AccountManagerCallback<Bundle> callback, Handler handler) {
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001373 return getAuthToken(account, authTokenType, null, notifyAuthFailure, callback,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001374 handler);
Dan Egnor661f0132010-02-19 11:23:00 -08001375 }
1376
1377 /**
Fred Quintanaad93a322011-09-08 13:21:01 -07001378 * Gets an auth token of the specified type for a particular account,
1379 * optionally raising a notification if the user must enter credentials.
1380 * This method is intended for background tasks and services where the
1381 * user should not be immediately interrupted with a password prompt.
1382 *
1383 * <p>If a previously generated auth token is cached for this account and
1384 * type, then it is returned. Otherwise, if a saved password is
1385 * available, it is sent to the server to generate a new auth token.
1386 * Otherwise, an {@link Intent} is returned which, when started, will
1387 * prompt the user for a password. If the notifyAuthFailure parameter is
1388 * set, a status bar notification is also created with the same Intent,
1389 * alerting the user that they need to enter a password at some point.
1390 *
1391 * <p>In that case, you may need to wait until the user responds, which
1392 * could take hours or days or forever. When the user does respond and
1393 * supply a new password, the account manager will broadcast the
1394 * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
1395 * use to try again.
1396 *
1397 * <p>If notifyAuthFailure is not set, it is the application's
1398 * responsibility to launch the returned Intent at some point.
1399 * Either way, the result from this call will not wait for user action.
1400 *
1401 * <p>Some authenticators have auth token <em>types</em>, whose value
1402 * is authenticator-dependent. Some services use different token types to
1403 * access different functionality -- for example, Google uses different auth
1404 * tokens to access Gmail and Google Calendar for the same account.
1405 *
1406 * <p>This method may be called from any thread, but the returned
1407 * {@link AccountManagerFuture} must not be used on the main thread.
1408 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001409 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1410 * USE_CREDENTIALS permission is needed for those platforms. See docs for
1411 * this function in API level 22.
1412 *
Fred Quintanaad93a322011-09-08 13:21:01 -07001413 * @param account The account to fetch an auth token for
1414 * @param authTokenType The auth token type, an authenticator-dependent
1415 * string token, must not be null
1416 * @param options Authenticator-specific options for the request,
1417 * may be null or empty
1418 * @param notifyAuthFailure True to add a notification to prompt the
1419 * user for a password if necessary, false to leave that to the caller
1420 * @param callback Callback to invoke when the request completes,
1421 * null for no callback
1422 * @param handler {@link Handler} identifying the callback thread,
1423 * null for the main thread
1424 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
1425 * at least the following fields on success:
1426 * <ul>
1427 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
1428 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1429 * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
1430 * </ul>
1431 *
1432 * (Other authenticator-specific values may be returned.) If the user
1433 * must enter credentials, the returned Bundle contains only
1434 * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
1435 *
1436 * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
1437 * <ul>
1438 * <li> {@link AuthenticatorException} if the authenticator failed to respond
1439 * <li> {@link OperationCanceledException} if the operation is canceled for
1440 * any reason, incluidng the user canceling a credential request
1441 * <li> {@link IOException} if the authenticator experienced an I/O problem
1442 * creating a new auth token, usually because of network trouble
1443 * </ul>
1444 * If the account is no longer present on the device, the return value is
1445 * authenticator-dependent. The caller should verify the validity of the
1446 * account before requesting an auth token.
1447 */
1448 public AccountManagerFuture<Bundle> getAuthToken(
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001449 final Account account, final String authTokenType, final Bundle options,
1450 final boolean notifyAuthFailure,
Fred Quintanaad93a322011-09-08 13:21:01 -07001451 AccountManagerCallback<Bundle> callback, Handler handler) {
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001452
Fred Quintanaad93a322011-09-08 13:21:01 -07001453 if (account == null) throw new IllegalArgumentException("account is null");
1454 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Costin Manolachee5847ad2011-09-14 12:52:19 -07001455 final Bundle optionsIn = new Bundle();
1456 if (options != null) {
1457 optionsIn.putAll(options);
1458 }
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001459 optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
Fred Quintanaad93a322011-09-08 13:21:01 -07001460 return new AmsTask(null, handler, callback) {
1461 public void doWork() throws RemoteException {
1462 mService.getAuthToken(mResponse, account, authTokenType,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001463 notifyAuthFailure, false /* expectActivityLaunch */, optionsIn);
Fred Quintanaad93a322011-09-08 13:21:01 -07001464 }
1465 }.start();
1466 }
1467
1468 /**
Dan Egnor661f0132010-02-19 11:23:00 -08001469 * Asks the user to add an account of a specified type. The authenticator
1470 * for this account type processes this request with the appropriate user
1471 * interface. If the user does elect to create a new account, the account
1472 * name is returned.
1473 *
1474 * <p>This method may be called from any thread, but the returned
1475 * {@link AccountManagerFuture} must not be used on the main thread.
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001476 *
1477 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1478 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
1479 * this function in API level 22.
Dan Egnor661f0132010-02-19 11:23:00 -08001480 *
Dan Egnor661f0132010-02-19 11:23:00 -08001481 * @param accountType The type of account to add; must not be null
1482 * @param authTokenType The type of auth token (see {@link #getAuthToken})
1483 * this account will need to be able to generate, null for none
1484 * @param requiredFeatures The features (see {@link #hasFeatures}) this
1485 * account must have, null for none
1486 * @param addAccountOptions Authenticator-specific options for the request,
1487 * may be null or empty
1488 * @param activity The {@link Activity} context to use for launching a new
1489 * authenticator-defined sub-Activity to prompt the user to create an
1490 * account; used only to call startActivity(); if null, the prompt
1491 * will not be launched directly, but the necessary {@link Intent}
1492 * will be returned to the caller instead
1493 * @param callback Callback to invoke when the request completes,
1494 * null for no callback
1495 * @param handler {@link Handler} identifying the callback thread,
1496 * null for the main thread
Doug Zongkerff592dc2010-02-23 12:26:33 -08001497 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
Dan Egnor661f0132010-02-19 11:23:00 -08001498 * these fields if activity was specified and an account was created:
1499 * <ul>
1500 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
1501 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1502 * </ul>
1503 *
1504 * If no activity was specified, the returned Bundle contains only
1505 * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
Dan Egnor8e4378b2010-08-02 18:22:09 -07001506 * actual account creation process. If an error occurred,
1507 * {@link AccountManagerFuture#getResult()} throws:
Dan Egnor661f0132010-02-19 11:23:00 -08001508 * <ul>
1509 * <li> {@link AuthenticatorException} if no authenticator was registered for
1510 * this account type or the authenticator failed to respond
1511 * <li> {@link OperationCanceledException} if the operation was canceled for
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001512 * any reason, including the user canceling the creation process or adding accounts
1513 * (of this type) has been disabled by policy
Dan Egnor661f0132010-02-19 11:23:00 -08001514 * <li> {@link IOException} if the authenticator experienced an I/O problem
1515 * creating a new account, usually because of network trouble
1516 * </ul>
1517 */
1518 public AccountManagerFuture<Bundle> addAccount(final String accountType,
1519 final String authTokenType, final String[] requiredFeatures,
1520 final Bundle addAccountOptions,
1521 final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -07001522 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolachee5847ad2011-09-14 12:52:19 -07001523 final Bundle optionsIn = new Bundle();
1524 if (addAccountOptions != null) {
1525 optionsIn.putAll(addAccountOptions);
1526 }
1527 optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001528
Dan Egnor661f0132010-02-19 11:23:00 -08001529 return new AmsTask(activity, handler, callback) {
1530 public void doWork() throws RemoteException {
Amith Yamasani27db4682013-03-30 17:07:47 -07001531 mService.addAccount(mResponse, accountType, authTokenType,
Costin Manolachee5847ad2011-09-14 12:52:19 -07001532 requiredFeatures, activity != null, optionsIn);
Dan Egnor661f0132010-02-19 11:23:00 -08001533 }
1534 }.start();
1535 }
1536
1537 /**
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001538 * @see #addAccount(String, String, String[], Bundle, Activity, AccountManagerCallback, Handler)
1539 * @hide
1540 */
1541 public AccountManagerFuture<Bundle> addAccountAsUser(final String accountType,
1542 final String authTokenType, final String[] requiredFeatures,
1543 final Bundle addAccountOptions, final Activity activity,
1544 AccountManagerCallback<Bundle> callback, Handler handler, final UserHandle userHandle) {
1545 if (accountType == null) throw new IllegalArgumentException("accountType is null");
1546 if (userHandle == null) throw new IllegalArgumentException("userHandle is null");
1547 final Bundle optionsIn = new Bundle();
1548 if (addAccountOptions != null) {
1549 optionsIn.putAll(addAccountOptions);
1550 }
1551 optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
1552
1553 return new AmsTask(activity, handler, callback) {
1554 public void doWork() throws RemoteException {
1555 mService.addAccountAsUser(mResponse, accountType, authTokenType,
1556 requiredFeatures, activity != null, optionsIn, userHandle.getIdentifier());
1557 }
1558 }.start();
1559 }
1560
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07001561
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001562 /**
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07001563 * Adds shared accounts from a parent user to a secondary user. Adding the shared account
Amith Yamasani67df64b2012-12-14 12:09:36 -08001564 * doesn't take effect immediately. When the target user starts up, any pending shared accounts
1565 * are attempted to be copied to the target user from the primary via calls to the
1566 * authenticator.
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07001567 * @param parentUser parent user
1568 * @param user target user
Amith Yamasani67df64b2012-12-14 12:09:36 -08001569 * @hide
1570 */
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07001571 public void addSharedAccountsFromParentUser(UserHandle parentUser, UserHandle user) {
Amith Yamasani67df64b2012-12-14 12:09:36 -08001572 try {
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07001573 mService.addSharedAccountsFromParentUser(parentUser.getIdentifier(),
1574 user.getIdentifier());
Amith Yamasani67df64b2012-12-14 12:09:36 -08001575 } catch (RemoteException re) {
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07001576 throw new IllegalStateException(re);
Amith Yamasani67df64b2012-12-14 12:09:36 -08001577 }
1578 }
1579
1580 /**
Xiaohui Chen75f68ce2015-08-14 09:28:07 -07001581 * Copies an account from one user to another user.
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001582 * @param account the account to copy
Xiaohui Chen75f68ce2015-08-14 09:28:07 -07001583 * @param fromUser the user to copy the account from
1584 * @param toUser the target user
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001585 * @param callback Callback to invoke when the request completes,
1586 * null for no callback
1587 * @param handler {@link Handler} identifying the callback thread,
1588 * null for the main thread
1589 * @return An {@link AccountManagerFuture} which resolves to a Boolean indicated wether it
1590 * succeeded.
1591 * @hide
1592 */
1593 public AccountManagerFuture<Boolean> copyAccountToUser(
Xiaohui Chen75f68ce2015-08-14 09:28:07 -07001594 final Account account, final UserHandle fromUser, final UserHandle toUser,
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001595 AccountManagerCallback<Boolean> callback, Handler handler) {
1596 if (account == null) throw new IllegalArgumentException("account is null");
Xiaohui Chen75f68ce2015-08-14 09:28:07 -07001597 if (toUser == null || fromUser == null) {
1598 throw new IllegalArgumentException("fromUser and toUser cannot be null");
1599 }
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001600
1601 return new Future2Task<Boolean>(handler, callback) {
1602 @Override
1603 public void doWork() throws RemoteException {
1604 mService.copyAccountToUser(
Xiaohui Chen75f68ce2015-08-14 09:28:07 -07001605 mResponse, account, fromUser.getIdentifier(), toUser.getIdentifier());
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001606 }
1607 @Override
1608 public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
1609 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
1610 throw new AuthenticatorException("no result in response");
1611 }
1612 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
1613 }
1614 }.start();
1615 }
1616
1617 /**
Amith Yamasani67df64b2012-12-14 12:09:36 -08001618 * @hide
1619 * Removes the shared account.
1620 * @param account the account to remove
1621 * @param user the user to remove the account from
1622 * @return
1623 */
1624 public boolean removeSharedAccount(final Account account, UserHandle user) {
1625 try {
1626 boolean val = mService.removeSharedAccountAsUser(account, user.getIdentifier());
1627 return val;
1628 } catch (RemoteException re) {
1629 // won't ever happen
1630 throw new RuntimeException(re);
1631 }
1632 }
1633
1634 /**
1635 * @hide
1636 * @param user
1637 * @return
1638 */
1639 public Account[] getSharedAccounts(UserHandle user) {
1640 try {
1641 return mService.getSharedAccountsAsUser(user.getIdentifier());
1642 } catch (RemoteException re) {
1643 // won't ever happen
1644 throw new RuntimeException(re);
1645 }
1646 }
1647
1648 /**
Dan Egnor661f0132010-02-19 11:23:00 -08001649 * Confirms that the user knows the password for an account to make extra
1650 * sure they are the owner of the account. The user-entered password can
1651 * be supplied directly, otherwise the authenticator for this account type
1652 * prompts the user with the appropriate interface. This method is
1653 * intended for applications which want extra assurance; for example, the
1654 * phone lock screen uses this to let the user unlock the phone with an
1655 * account password if they forget the lock pattern.
1656 *
1657 * <p>If the user-entered password matches a saved password for this
1658 * account, the request is considered valid; otherwise the authenticator
1659 * verifies the password (usually by contacting the server).
1660 *
1661 * <p>This method may be called from any thread, but the returned
1662 * {@link AccountManagerFuture} must not be used on the main thread.
1663 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001664 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1665 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs
1666 * for this function in API level 22.
1667 *
Dan Egnor661f0132010-02-19 11:23:00 -08001668 * @param account The account to confirm password knowledge for
1669 * @param options Authenticator-specific options for the request;
1670 * if the {@link #KEY_PASSWORD} string field is present, the
1671 * authenticator may use it directly rather than prompting the user;
1672 * may be null or empty
1673 * @param activity The {@link Activity} context to use for launching a new
1674 * authenticator-defined sub-Activity to prompt the user to enter a
1675 * password; used only to call startActivity(); if null, the prompt
1676 * will not be launched directly, but the necessary {@link Intent}
1677 * will be returned to the caller instead
1678 * @param callback Callback to invoke when the request completes,
1679 * null for no callback
1680 * @param handler {@link Handler} identifying the callback thread,
1681 * null for the main thread
1682 * @return An {@link AccountManagerFuture} which resolves to a Bundle
1683 * with these fields if activity or password was supplied and
1684 * the account was successfully verified:
1685 * <ul>
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001686 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account verified
Dan Egnor661f0132010-02-19 11:23:00 -08001687 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1688 * <li> {@link #KEY_BOOLEAN_RESULT} - true to indicate success
1689 * </ul>
1690 *
1691 * If no activity or password was specified, the returned Bundle contains
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001692 * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
1693 * password prompt.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001694 *
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001695 * <p>Also the returning Bundle may contain {@link
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07001696 * #KEY_LAST_AUTHENTICATED_TIME} indicating the last time the
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001697 * credential was validated/created.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001698 *
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001699 * If an error occurred,{@link AccountManagerFuture#getResult()} throws:
Dan Egnor661f0132010-02-19 11:23:00 -08001700 * <ul>
1701 * <li> {@link AuthenticatorException} if the authenticator failed to respond
1702 * <li> {@link OperationCanceledException} if the operation was canceled for
1703 * any reason, including the user canceling the password prompt
1704 * <li> {@link IOException} if the authenticator experienced an I/O problem
1705 * verifying the password, usually because of network trouble
1706 * </ul>
Fred Quintana756b7352009-10-21 13:43:10 -07001707 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001708 public AccountManagerFuture<Bundle> confirmCredentials(final Account account,
1709 final Bundle options,
1710 final Activity activity,
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001711 final AccountManagerCallback<Bundle> callback,
Fred Quintanaa698f422009-04-08 19:14:54 -07001712 final Handler handler) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08001713 return confirmCredentialsAsUser(account, options, activity, callback, handler,
1714 Process.myUserHandle());
1715 }
1716
1717 /**
1718 * @hide
1719 * Same as {@link #confirmCredentials(Account, Bundle, Activity, AccountManagerCallback, Handler)}
1720 * but for the specified user.
1721 */
1722 public AccountManagerFuture<Bundle> confirmCredentialsAsUser(final Account account,
1723 final Bundle options,
1724 final Activity activity,
1725 final AccountManagerCallback<Bundle> callback,
1726 final Handler handler, UserHandle userHandle) {
Fred Quintana382601f2010-03-25 12:25:10 -07001727 if (account == null) throw new IllegalArgumentException("account is null");
Amith Yamasani2c7bc262012-11-05 16:46:02 -08001728 final int userId = userHandle.getIdentifier();
Fred Quintanaa698f422009-04-08 19:14:54 -07001729 return new AmsTask(activity, handler, callback) {
1730 public void doWork() throws RemoteException {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08001731 mService.confirmCredentialsAsUser(mResponse, account, options, activity != null,
1732 userId);
Fred Quintanaa698f422009-04-08 19:14:54 -07001733 }
Fred Quintana33269202009-04-20 16:05:10 -07001734 }.start();
Fred Quintanaa698f422009-04-08 19:14:54 -07001735 }
1736
Fred Quintana756b7352009-10-21 13:43:10 -07001737 /**
Dan Egnor661f0132010-02-19 11:23:00 -08001738 * Asks the user to enter a new password for an account, updating the
1739 * saved credentials for the account. Normally this happens automatically
1740 * when the server rejects credentials during an auth token fetch, but this
1741 * can be invoked directly to ensure we have the correct credentials stored.
Fred Quintana756b7352009-10-21 13:43:10 -07001742 *
Dan Egnor661f0132010-02-19 11:23:00 -08001743 * <p>This method may be called from any thread, but the returned
1744 * {@link AccountManagerFuture} must not be used on the main thread.
1745 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001746 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1747 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
1748 * this function in API level 22.
1749 *
Dan Egnor661f0132010-02-19 11:23:00 -08001750 * @param account The account to update credentials for
1751 * @param authTokenType The credentials entered must allow an auth token
1752 * of this type to be created (but no actual auth token is returned);
1753 * may be null
1754 * @param options Authenticator-specific options for the request;
1755 * may be null or empty
1756 * @param activity The {@link Activity} context to use for launching a new
1757 * authenticator-defined sub-Activity to prompt the user to enter a
1758 * password; used only to call startActivity(); if null, the prompt
1759 * will not be launched directly, but the necessary {@link Intent}
1760 * will be returned to the caller instead
1761 * @param callback Callback to invoke when the request completes,
1762 * null for no callback
1763 * @param handler {@link Handler} identifying the callback thread,
1764 * null for the main thread
1765 * @return An {@link AccountManagerFuture} which resolves to a Bundle
1766 * with these fields if an activity was supplied and the account
1767 * credentials were successfully updated:
Fred Quintana756b7352009-10-21 13:43:10 -07001768 * <ul>
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00001769 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account
Dan Egnor661f0132010-02-19 11:23:00 -08001770 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
Fred Quintana756b7352009-10-21 13:43:10 -07001771 * </ul>
Dan Egnor661f0132010-02-19 11:23:00 -08001772 *
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001773 * If no activity was specified, the returned Bundle contains
Dan Egnor661f0132010-02-19 11:23:00 -08001774 * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001775 * password prompt. If an error occurred,
Dan Egnor8e4378b2010-08-02 18:22:09 -07001776 * {@link AccountManagerFuture#getResult()} throws:
Dan Egnor661f0132010-02-19 11:23:00 -08001777 * <ul>
1778 * <li> {@link AuthenticatorException} if the authenticator failed to respond
1779 * <li> {@link OperationCanceledException} if the operation was canceled for
1780 * any reason, including the user canceling the password prompt
1781 * <li> {@link IOException} if the authenticator experienced an I/O problem
1782 * verifying the password, usually because of network trouble
1783 * </ul>
Fred Quintana756b7352009-10-21 13:43:10 -07001784 */
1785 public AccountManagerFuture<Bundle> updateCredentials(final Account account,
1786 final String authTokenType,
Fred Quintana31957f12009-10-21 13:43:10 -07001787 final Bundle options, final Activity activity,
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001788 final AccountManagerCallback<Bundle> callback,
Fred Quintanaa698f422009-04-08 19:14:54 -07001789 final Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -07001790 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintanaa698f422009-04-08 19:14:54 -07001791 return new AmsTask(activity, handler, callback) {
1792 public void doWork() throws RemoteException {
1793 mService.updateCredentials(mResponse, account, authTokenType, activity != null,
Fred Quintana31957f12009-10-21 13:43:10 -07001794 options);
Fred Quintanaa698f422009-04-08 19:14:54 -07001795 }
Fred Quintana33269202009-04-20 16:05:10 -07001796 }.start();
Fred Quintanaa698f422009-04-08 19:14:54 -07001797 }
1798
Fred Quintana756b7352009-10-21 13:43:10 -07001799 /**
Dan Egnor661f0132010-02-19 11:23:00 -08001800 * Offers the user an opportunity to change an authenticator's settings.
1801 * These properties are for the authenticator in general, not a particular
1802 * account. Not all authenticators support this method.
Fred Quintana756b7352009-10-21 13:43:10 -07001803 *
Dan Egnor661f0132010-02-19 11:23:00 -08001804 * <p>This method may be called from any thread, but the returned
1805 * {@link AccountManagerFuture} must not be used on the main thread.
1806 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001807 * <p>This method requires the caller to have the same signature as the
1808 * authenticator associated with the specified account type.
Dan Egnor661f0132010-02-19 11:23:00 -08001809 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001810 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1811 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs
1812 * for this function in API level 22.
1813 *
Dan Egnor661f0132010-02-19 11:23:00 -08001814 * @param accountType The account type associated with the authenticator
1815 * to adjust
1816 * @param activity The {@link Activity} context to use for launching a new
1817 * authenticator-defined sub-Activity to adjust authenticator settings;
1818 * used only to call startActivity(); if null, the settings dialog will
1819 * not be launched directly, but the necessary {@link Intent} will be
1820 * returned to the caller instead
1821 * @param callback Callback to invoke when the request completes,
1822 * null for no callback
1823 * @param handler {@link Handler} identifying the callback thread,
1824 * null for the main thread
1825 * @return An {@link AccountManagerFuture} which resolves to a Bundle
1826 * which is empty if properties were edited successfully, or
1827 * if no activity was specified, contains only {@link #KEY_INTENT}
1828 * needed to launch the authenticator's settings dialog.
Dan Egnor8e4378b2010-08-02 18:22:09 -07001829 * If an error occurred, {@link AccountManagerFuture#getResult()}
1830 * throws:
Fred Quintana756b7352009-10-21 13:43:10 -07001831 * <ul>
Dan Egnor661f0132010-02-19 11:23:00 -08001832 * <li> {@link AuthenticatorException} if no authenticator was registered for
1833 * this account type or the authenticator failed to respond
1834 * <li> {@link OperationCanceledException} if the operation was canceled for
1835 * any reason, including the user canceling the settings dialog
1836 * <li> {@link IOException} if the authenticator experienced an I/O problem
1837 * updating settings, usually because of network trouble
Fred Quintana756b7352009-10-21 13:43:10 -07001838 * </ul>
Fred Quintana756b7352009-10-21 13:43:10 -07001839 */
1840 public AccountManagerFuture<Bundle> editProperties(final String accountType,
1841 final Activity activity, final AccountManagerCallback<Bundle> callback,
Fred Quintanaa698f422009-04-08 19:14:54 -07001842 final Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -07001843 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Fred Quintanaa698f422009-04-08 19:14:54 -07001844 return new AmsTask(activity, handler, callback) {
1845 public void doWork() throws RemoteException {
1846 mService.editProperties(mResponse, accountType, activity != null);
1847 }
Fred Quintana33269202009-04-20 16:05:10 -07001848 }.start();
Fred Quintanaa698f422009-04-08 19:14:54 -07001849 }
1850
1851 private void ensureNotOnMainThread() {
1852 final Looper looper = Looper.myLooper();
1853 if (looper != null && looper == mContext.getMainLooper()) {
Fred Quintana53bd2522010-02-05 15:28:12 -08001854 final IllegalStateException exception = new IllegalStateException(
1855 "calling this from your main thread can lead to deadlock");
1856 Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs",
1857 exception);
Fred Quintana751fdc02010-02-09 14:13:18 -08001858 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.FROYO) {
1859 throw exception;
1860 }
Fred Quintana60307342009-03-24 22:48:12 -07001861 }
1862 }
1863
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001864 private void postToHandler(Handler handler, final AccountManagerCallback<Bundle> callback,
1865 final AccountManagerFuture<Bundle> future) {
Fred Quintanad9d2f112009-04-23 13:36:27 -07001866 handler = handler == null ? mMainHandler : handler;
1867 handler.post(new Runnable() {
Fred Quintanaa698f422009-04-08 19:14:54 -07001868 public void run() {
1869 callback.run(future);
1870 }
1871 });
1872 }
Fred Quintana60307342009-03-24 22:48:12 -07001873
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001874 private void postToHandler(Handler handler, final OnAccountsUpdateListener listener,
Fred Quintanad9d2f112009-04-23 13:36:27 -07001875 final Account[] accounts) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001876 final Account[] accountsCopy = new Account[accounts.length];
1877 // send a copy to make sure that one doesn't
1878 // change what another sees
1879 System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
1880 handler = (handler == null) ? mMainHandler : handler;
Fred Quintanad9d2f112009-04-23 13:36:27 -07001881 handler.post(new Runnable() {
1882 public void run() {
Costin Manolacheb6437242009-09-10 16:14:12 -07001883 try {
1884 listener.onAccountsUpdated(accountsCopy);
1885 } catch (SQLException e) {
1886 // Better luck next time. If the problem was disk-full,
1887 // the STORAGE_OK intent will re-trigger the update.
1888 Log.e(TAG, "Can't update accounts", e);
1889 }
Fred Quintanad9d2f112009-04-23 13:36:27 -07001890 }
1891 });
1892 }
1893
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001894 private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> {
Fred Quintanaa698f422009-04-08 19:14:54 -07001895 final IAccountManagerResponse mResponse;
1896 final Handler mHandler;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001897 final AccountManagerCallback<Bundle> mCallback;
Fred Quintanaa698f422009-04-08 19:14:54 -07001898 final Activity mActivity;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001899 public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) {
Fred Quintanaa698f422009-04-08 19:14:54 -07001900 super(new Callable<Bundle>() {
1901 public Bundle call() throws Exception {
1902 throw new IllegalStateException("this should never be called");
1903 }
1904 });
1905
1906 mHandler = handler;
1907 mCallback = callback;
1908 mActivity = activity;
1909 mResponse = new Response();
Fred Quintana33269202009-04-20 16:05:10 -07001910 }
1911
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001912 public final AccountManagerFuture<Bundle> start() {
1913 try {
1914 doWork();
1915 } catch (RemoteException e) {
1916 setException(e);
1917 }
Fred Quintana33269202009-04-20 16:05:10 -07001918 return this;
Fred Quintana60307342009-03-24 22:48:12 -07001919 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001920
Fred Quintana96580e02010-03-04 13:42:42 -08001921 protected void set(Bundle bundle) {
1922 // TODO: somehow a null is being set as the result of the Future. Log this
1923 // case to help debug where this is occurring. When this bug is fixed this
1924 // condition statement should be removed.
1925 if (bundle == null) {
1926 Log.e(TAG, "the bundle must not be null", new Exception());
1927 }
1928 super.set(bundle);
1929 }
1930
Fred Quintanaa698f422009-04-08 19:14:54 -07001931 public abstract void doWork() throws RemoteException;
1932
1933 private Bundle internalGetResult(Long timeout, TimeUnit unit)
1934 throws OperationCanceledException, IOException, AuthenticatorException {
Fred Quintana53bd2522010-02-05 15:28:12 -08001935 if (!isDone()) {
1936 ensureNotOnMainThread();
1937 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001938 try {
1939 if (timeout == null) {
1940 return get();
1941 } else {
1942 return get(timeout, unit);
1943 }
1944 } catch (CancellationException e) {
1945 throw new OperationCanceledException();
1946 } catch (TimeoutException e) {
1947 // fall through and cancel
1948 } catch (InterruptedException e) {
1949 // fall through and cancel
1950 } catch (ExecutionException e) {
1951 final Throwable cause = e.getCause();
1952 if (cause instanceof IOException) {
1953 throw (IOException) cause;
1954 } else if (cause instanceof UnsupportedOperationException) {
1955 throw new AuthenticatorException(cause);
1956 } else if (cause instanceof AuthenticatorException) {
1957 throw (AuthenticatorException) cause;
1958 } else if (cause instanceof RuntimeException) {
1959 throw (RuntimeException) cause;
1960 } else if (cause instanceof Error) {
1961 throw (Error) cause;
1962 } else {
1963 throw new IllegalStateException(cause);
1964 }
1965 } finally {
1966 cancel(true /* interrupt if running */);
1967 }
1968 throw new OperationCanceledException();
1969 }
1970
1971 public Bundle getResult()
1972 throws OperationCanceledException, IOException, AuthenticatorException {
1973 return internalGetResult(null, null);
1974 }
1975
1976 public Bundle getResult(long timeout, TimeUnit unit)
1977 throws OperationCanceledException, IOException, AuthenticatorException {
1978 return internalGetResult(timeout, unit);
1979 }
1980
1981 protected void done() {
1982 if (mCallback != null) {
1983 postToHandler(mHandler, mCallback, this);
1984 }
1985 }
1986
1987 /** Handles the responses from the AccountManager */
1988 private class Response extends IAccountManagerResponse.Stub {
1989 public void onResult(Bundle bundle) {
Brian Carlstrom46703b02011-04-06 15:41:29 -07001990 Intent intent = bundle.getParcelable(KEY_INTENT);
Fred Quintanaa698f422009-04-08 19:14:54 -07001991 if (intent != null && mActivity != null) {
1992 // since the user provided an Activity we will silently start intents
1993 // that we see
1994 mActivity.startActivity(intent);
1995 // leave the Future running to wait for the real response to this request
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07001996 } else if (bundle.getBoolean("retry")) {
1997 try {
1998 doWork();
1999 } catch (RemoteException e) {
2000 // this will only happen if the system process is dead, which means
2001 // we will be dying ourselves
2002 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002003 } else {
2004 set(bundle);
2005 }
2006 }
2007
2008 public void onError(int code, String message) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002009 if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
2010 || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
2011 // the authenticator indicated that this request was canceled or we were
2012 // forbidden to fulfill; cancel now
Fred Quintanaa698f422009-04-08 19:14:54 -07002013 cancel(true /* mayInterruptIfRunning */);
2014 return;
2015 }
2016 setException(convertErrorToException(code, message));
2017 }
2018 }
2019
Fred Quintana60307342009-03-24 22:48:12 -07002020 }
2021
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002022 private abstract class BaseFutureTask<T> extends FutureTask<T> {
2023 final public IAccountManagerResponse mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07002024 final Handler mHandler;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002025
2026 public BaseFutureTask(Handler handler) {
2027 super(new Callable<T>() {
2028 public T call() throws Exception {
Fred Quintanaa698f422009-04-08 19:14:54 -07002029 throw new IllegalStateException("this should never be called");
2030 }
2031 });
Fred Quintanaa698f422009-04-08 19:14:54 -07002032 mHandler = handler;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002033 mResponse = new Response();
Fred Quintana60307342009-03-24 22:48:12 -07002034 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002035
2036 public abstract void doWork() throws RemoteException;
2037
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002038 public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException;
Fred Quintanaa698f422009-04-08 19:14:54 -07002039
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002040 protected void postRunnableToHandler(Runnable runnable) {
2041 Handler handler = (mHandler == null) ? mMainHandler : mHandler;
2042 handler.post(runnable);
Fred Quintanaa698f422009-04-08 19:14:54 -07002043 }
2044
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002045 protected void startTask() {
Fred Quintanaa698f422009-04-08 19:14:54 -07002046 try {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002047 doWork();
2048 } catch (RemoteException e) {
2049 setException(e);
Fred Quintanaa698f422009-04-08 19:14:54 -07002050 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002051 }
2052
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002053 protected class Response extends IAccountManagerResponse.Stub {
Fred Quintanaa698f422009-04-08 19:14:54 -07002054 public void onResult(Bundle bundle) {
2055 try {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002056 T result = bundleToResult(bundle);
2057 if (result == null) {
Fred Quintanaa698f422009-04-08 19:14:54 -07002058 return;
2059 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002060 set(result);
2061 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002062 } catch (ClassCastException e) {
2063 // we will set the exception below
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002064 } catch (AuthenticatorException e) {
2065 // we will set the exception below
Fred Quintanaa698f422009-04-08 19:14:54 -07002066 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002067 onError(ERROR_CODE_INVALID_RESPONSE, "no result in response");
Fred Quintanaa698f422009-04-08 19:14:54 -07002068 }
2069
2070 public void onError(int code, String message) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002071 if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
2072 || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
2073 // the authenticator indicated that this request was canceled or we were
2074 // forbidden to fulfill; cancel now
Fred Quintanaa698f422009-04-08 19:14:54 -07002075 cancel(true /* mayInterruptIfRunning */);
2076 return;
2077 }
2078 setException(convertErrorToException(code, message));
2079 }
2080 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002081 }
2082
2083 private abstract class Future2Task<T>
2084 extends BaseFutureTask<T> implements AccountManagerFuture<T> {
2085 final AccountManagerCallback<T> mCallback;
2086 public Future2Task(Handler handler, AccountManagerCallback<T> callback) {
2087 super(handler);
2088 mCallback = callback;
2089 }
2090
2091 protected void done() {
2092 if (mCallback != null) {
2093 postRunnableToHandler(new Runnable() {
2094 public void run() {
2095 mCallback.run(Future2Task.this);
2096 }
2097 });
2098 }
2099 }
2100
2101 public Future2Task<T> start() {
2102 startTask();
2103 return this;
2104 }
2105
2106 private T internalGetResult(Long timeout, TimeUnit unit)
2107 throws OperationCanceledException, IOException, AuthenticatorException {
Fred Quintana53bd2522010-02-05 15:28:12 -08002108 if (!isDone()) {
2109 ensureNotOnMainThread();
2110 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002111 try {
2112 if (timeout == null) {
2113 return get();
2114 } else {
2115 return get(timeout, unit);
2116 }
2117 } catch (InterruptedException e) {
2118 // fall through and cancel
2119 } catch (TimeoutException e) {
2120 // fall through and cancel
2121 } catch (CancellationException e) {
2122 // fall through and cancel
2123 } catch (ExecutionException e) {
2124 final Throwable cause = e.getCause();
2125 if (cause instanceof IOException) {
2126 throw (IOException) cause;
2127 } else if (cause instanceof UnsupportedOperationException) {
2128 throw new AuthenticatorException(cause);
2129 } else if (cause instanceof AuthenticatorException) {
2130 throw (AuthenticatorException) cause;
2131 } else if (cause instanceof RuntimeException) {
2132 throw (RuntimeException) cause;
2133 } else if (cause instanceof Error) {
2134 throw (Error) cause;
2135 } else {
2136 throw new IllegalStateException(cause);
2137 }
2138 } finally {
2139 cancel(true /* interrupt if running */);
2140 }
2141 throw new OperationCanceledException();
2142 }
2143
2144 public T getResult()
2145 throws OperationCanceledException, IOException, AuthenticatorException {
2146 return internalGetResult(null, null);
2147 }
2148
2149 public T getResult(long timeout, TimeUnit unit)
2150 throws OperationCanceledException, IOException, AuthenticatorException {
2151 return internalGetResult(timeout, unit);
2152 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002153
Fred Quintana60307342009-03-24 22:48:12 -07002154 }
2155
Fred Quintanaa698f422009-04-08 19:14:54 -07002156 private Exception convertErrorToException(int code, String message) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002157 if (code == ERROR_CODE_NETWORK_ERROR) {
Fred Quintanaa698f422009-04-08 19:14:54 -07002158 return new IOException(message);
Fred Quintana60307342009-03-24 22:48:12 -07002159 }
Fred Quintana60307342009-03-24 22:48:12 -07002160
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002161 if (code == ERROR_CODE_UNSUPPORTED_OPERATION) {
Fred Quintana33269202009-04-20 16:05:10 -07002162 return new UnsupportedOperationException(message);
Fred Quintana60307342009-03-24 22:48:12 -07002163 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002164
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002165 if (code == ERROR_CODE_INVALID_RESPONSE) {
Fred Quintana33269202009-04-20 16:05:10 -07002166 return new AuthenticatorException(message);
Fred Quintanaa698f422009-04-08 19:14:54 -07002167 }
2168
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002169 if (code == ERROR_CODE_BAD_ARGUMENTS) {
Fred Quintana33269202009-04-20 16:05:10 -07002170 return new IllegalArgumentException(message);
2171 }
2172
2173 return new AuthenticatorException(message);
2174 }
2175
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002176 private class GetAuthTokenByTypeAndFeaturesTask
2177 extends AmsTask implements AccountManagerCallback<Bundle> {
Fred Quintana33269202009-04-20 16:05:10 -07002178 GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
2179 final String[] features, Activity activityForPrompting,
2180 final Bundle addAccountOptions, final Bundle loginOptions,
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002181 AccountManagerCallback<Bundle> callback, Handler handler) {
Fred Quintana33269202009-04-20 16:05:10 -07002182 super(activityForPrompting, handler, callback);
2183 if (accountType == null) throw new IllegalArgumentException("account type is null");
2184 mAccountType = accountType;
2185 mAuthTokenType = authTokenType;
2186 mFeatures = features;
2187 mAddAccountOptions = addAccountOptions;
2188 mLoginOptions = loginOptions;
2189 mMyCallback = this;
2190 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002191 volatile AccountManagerFuture<Bundle> mFuture = null;
Fred Quintana33269202009-04-20 16:05:10 -07002192 final String mAccountType;
2193 final String mAuthTokenType;
2194 final String[] mFeatures;
2195 final Bundle mAddAccountOptions;
2196 final Bundle mLoginOptions;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002197 final AccountManagerCallback<Bundle> mMyCallback;
Fred Quintanaf0fd8432010-03-08 12:48:05 -08002198 private volatile int mNumAccounts = 0;
Fred Quintana33269202009-04-20 16:05:10 -07002199
2200 public void doWork() throws RemoteException {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002201 getAccountsByTypeAndFeatures(mAccountType, mFeatures,
2202 new AccountManagerCallback<Account[]>() {
2203 public void run(AccountManagerFuture<Account[]> future) {
2204 Account[] accounts;
Fred Quintana33269202009-04-20 16:05:10 -07002205 try {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002206 accounts = future.getResult();
2207 } catch (OperationCanceledException e) {
2208 setException(e);
2209 return;
2210 } catch (IOException e) {
2211 setException(e);
2212 return;
2213 } catch (AuthenticatorException e) {
2214 setException(e);
2215 return;
Fred Quintana33269202009-04-20 16:05:10 -07002216 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002217
Fred Quintanaf0fd8432010-03-08 12:48:05 -08002218 mNumAccounts = accounts.length;
2219
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002220 if (accounts.length == 0) {
2221 if (mActivity != null) {
2222 // no accounts, add one now. pretend that the user directly
2223 // made this request
2224 mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures,
2225 mAddAccountOptions, mActivity, mMyCallback, mHandler);
2226 } else {
2227 // send result since we can't prompt to add an account
2228 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002229 result.putString(KEY_ACCOUNT_NAME, null);
2230 result.putString(KEY_ACCOUNT_TYPE, null);
2231 result.putString(KEY_AUTHTOKEN, null);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002232 try {
2233 mResponse.onResult(result);
2234 } catch (RemoteException e) {
2235 // this will never happen
2236 }
2237 // we are done
2238 }
2239 } else if (accounts.length == 1) {
2240 // have a single account, return an authtoken for it
2241 if (mActivity == null) {
2242 mFuture = getAuthToken(accounts[0], mAuthTokenType,
2243 false /* notifyAuthFailure */, mMyCallback, mHandler);
2244 } else {
2245 mFuture = getAuthToken(accounts[0],
2246 mAuthTokenType, mLoginOptions,
Fred Quintana33269202009-04-20 16:05:10 -07002247 mActivity, mMyCallback, mHandler);
2248 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002249 } else {
2250 if (mActivity != null) {
2251 IAccountManagerResponse chooseResponse =
2252 new IAccountManagerResponse.Stub() {
2253 public void onResult(Bundle value) throws RemoteException {
2254 Account account = new Account(
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002255 value.getString(KEY_ACCOUNT_NAME),
2256 value.getString(KEY_ACCOUNT_TYPE));
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002257 mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
2258 mActivity, mMyCallback, mHandler);
2259 }
Fred Quintana33269202009-04-20 16:05:10 -07002260
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002261 public void onError(int errorCode, String errorMessage)
2262 throws RemoteException {
2263 mResponse.onError(errorCode, errorMessage);
2264 }
2265 };
2266 // have many accounts, launch the chooser
2267 Intent intent = new Intent();
Amith Yamasani12b8e132013-03-14 10:48:07 -07002268 ComponentName componentName = ComponentName.unflattenFromString(
2269 Resources.getSystem().getString(
2270 R.string.config_chooseAccountActivity));
2271 intent.setClassName(componentName.getPackageName(),
2272 componentName.getClassName());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002273 intent.putExtra(KEY_ACCOUNTS, accounts);
2274 intent.putExtra(KEY_ACCOUNT_MANAGER_RESPONSE,
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002275 new AccountManagerResponse(chooseResponse));
2276 mActivity.startActivity(intent);
2277 // the result will arrive via the IAccountManagerResponse
2278 } else {
2279 // send result since we can't prompt to select an account
2280 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002281 result.putString(KEY_ACCOUNTS, null);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002282 try {
2283 mResponse.onResult(result);
2284 } catch (RemoteException e) {
2285 // this will never happen
2286 }
2287 // we are done
Fred Quintana33269202009-04-20 16:05:10 -07002288 }
Fred Quintana33269202009-04-20 16:05:10 -07002289 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002290 }}, mHandler);
Fred Quintana33269202009-04-20 16:05:10 -07002291 }
2292
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002293 public void run(AccountManagerFuture<Bundle> future) {
Fred Quintana33269202009-04-20 16:05:10 -07002294 try {
Fred Quintanaf0fd8432010-03-08 12:48:05 -08002295 final Bundle result = future.getResult();
2296 if (mNumAccounts == 0) {
2297 final String accountName = result.getString(KEY_ACCOUNT_NAME);
2298 final String accountType = result.getString(KEY_ACCOUNT_TYPE);
2299 if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
2300 setException(new AuthenticatorException("account not in result"));
2301 return;
2302 }
2303 final Account account = new Account(accountName, accountType);
2304 mNumAccounts = 1;
2305 getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
2306 mMyCallback, mHandler);
2307 return;
2308 }
2309 set(result);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002310 } catch (OperationCanceledException e) {
2311 cancel(true /* mayInterruptIfRUnning */);
2312 } catch (IOException e) {
2313 setException(e);
2314 } catch (AuthenticatorException e) {
2315 setException(e);
Fred Quintana33269202009-04-20 16:05:10 -07002316 }
2317 }
2318 }
2319
Fred Quintana756b7352009-10-21 13:43:10 -07002320 /**
Dan Egnor661f0132010-02-19 11:23:00 -08002321 * This convenience helper combines the functionality of
2322 * {@link #getAccountsByTypeAndFeatures}, {@link #getAuthToken}, and
2323 * {@link #addAccount}.
Fred Quintana756b7352009-10-21 13:43:10 -07002324 *
Dan Egnor661f0132010-02-19 11:23:00 -08002325 * <p>This method gets a list of the accounts matching the
2326 * specified type and feature set; if there is exactly one, it is
2327 * used; if there are more than one, the user is prompted to pick one;
2328 * if there are none, the user is prompted to add one. Finally,
2329 * an auth token is acquired for the chosen account.
2330 *
2331 * <p>This method may be called from any thread, but the returned
2332 * {@link AccountManagerFuture} must not be used on the main thread.
2333 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07002334 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
2335 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
2336 * this function in API level 22.
2337 *
Dan Egnor661f0132010-02-19 11:23:00 -08002338 * @param accountType The account type required
Doug Zongkerff592dc2010-02-23 12:26:33 -08002339 * (see {@link #getAccountsByType}), must not be null
Dan Egnor661f0132010-02-19 11:23:00 -08002340 * @param authTokenType The desired auth token type
2341 * (see {@link #getAuthToken}), must not be null
2342 * @param features Required features for the account
2343 * (see {@link #getAccountsByTypeAndFeatures}), may be null or empty
2344 * @param activity The {@link Activity} context to use for launching new
2345 * sub-Activities to prompt to add an account, select an account,
2346 * and/or enter a password, as necessary; used only to call
2347 * startActivity(); should not be null
2348 * @param addAccountOptions Authenticator-specific options to use for
2349 * adding new accounts; may be null or empty
2350 * @param getAuthTokenOptions Authenticator-specific options to use for
2351 * getting auth tokens; may be null or empty
2352 * @param callback Callback to invoke when the request completes,
2353 * null for no callback
2354 * @param handler {@link Handler} identifying the callback thread,
2355 * null for the main thread
2356 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
2357 * at least the following fields:
Fred Quintana756b7352009-10-21 13:43:10 -07002358 * <ul>
Dan Egnor661f0132010-02-19 11:23:00 -08002359 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account
2360 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
2361 * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
Fred Quintana756b7352009-10-21 13:43:10 -07002362 * </ul>
Dan Egnor661f0132010-02-19 11:23:00 -08002363 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07002364 * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
Dan Egnor661f0132010-02-19 11:23:00 -08002365 * <ul>
2366 * <li> {@link AuthenticatorException} if no authenticator was registered for
2367 * this account type or the authenticator failed to respond
2368 * <li> {@link OperationCanceledException} if the operation was canceled for
2369 * any reason, including the user canceling any operation
2370 * <li> {@link IOException} if the authenticator experienced an I/O problem
2371 * updating settings, usually because of network trouble
2372 * </ul>
Fred Quintana756b7352009-10-21 13:43:10 -07002373 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002374 public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
Fred Quintana33269202009-04-20 16:05:10 -07002375 final String accountType, final String authTokenType, final String[] features,
Dan Egnor661f0132010-02-19 11:23:00 -08002376 final Activity activity, final Bundle addAccountOptions,
Fred Quintana31957f12009-10-21 13:43:10 -07002377 final Bundle getAuthTokenOptions,
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002378 final AccountManagerCallback<Bundle> callback, final Handler handler) {
Fred Quintana33269202009-04-20 16:05:10 -07002379 if (accountType == null) throw new IllegalArgumentException("account type is null");
2380 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002381 final GetAuthTokenByTypeAndFeaturesTask task =
2382 new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features,
Dan Egnor661f0132010-02-19 11:23:00 -08002383 activity, addAccountOptions, getAuthTokenOptions, callback, handler);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002384 task.start();
2385 return task;
Fred Quintana60307342009-03-24 22:48:12 -07002386 }
Fred Quintanad9d2f112009-04-23 13:36:27 -07002387
Fred Quintana1121bb52011-09-14 23:19:35 -07002388 /**
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -07002389 * Deprecated in favor of {@link #newChooseAccountIntent(Account, List, String[], String,
2390 * String, String[], Bundle)}.
2391 *
Fred Quintana1121bb52011-09-14 23:19:35 -07002392 * Returns an intent to an {@link Activity} that prompts the user to choose from a list of
2393 * accounts.
2394 * The caller will then typically start the activity by calling
Mark Fickettab249e02012-09-05 09:45:47 -04002395 * <code>startActivityForResult(intent, ...);</code>.
Fred Quintana1121bb52011-09-14 23:19:35 -07002396 * <p>
2397 * On success the activity returns a Bundle with the account name and type specified using
2398 * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
2399 * <p>
2400 * The most common case is to call this with one account type, e.g.:
2401 * <p>
kmccormickf783ce52013-03-29 14:31:54 -07002402 * <pre> newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null,
Fred Quintanad88324d2011-09-19 11:43:05 -07002403 * null, null, null);</pre>
Fred Quintana1121bb52011-09-14 23:19:35 -07002404 * @param selectedAccount if specified, indicates that the {@link Account} is the currently
2405 * selected one, according to the caller's definition of selected.
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -07002406 * @param allowableAccounts an optional {@link List} of accounts that are allowed to be
Fred Quintana1121bb52011-09-14 23:19:35 -07002407 * shown. If not specified then this field will not limit the displayed accounts.
2408 * @param allowableAccountTypes an optional string array of account types. These are used
2409 * both to filter the shown accounts and to filter the list of account types that are shown
Simranjit Singh Kohli734f8fb2015-05-22 14:00:32 -07002410 * when adding an account. If not specified then this field will not limit the displayed
2411 * account types when adding an account.
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -07002412 * @param alwaysPromptForAccount boolean that is ignored.
Fred Quintanad88324d2011-09-19 11:43:05 -07002413 * @param descriptionOverrideText if non-null this string is used as the description in the
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002414 * accounts chooser screen rather than the default
Fred Quintanad88324d2011-09-19 11:43:05 -07002415 * @param addAccountAuthTokenType this string is passed as the {@link #addAccount}
2416 * authTokenType parameter
2417 * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount}
2418 * requiredFeatures parameter
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002419 * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options
Fred Quintanad88324d2011-09-19 11:43:05 -07002420 * parameter
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002421 * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow.
Fred Quintana1121bb52011-09-14 23:19:35 -07002422 */
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -07002423 @Deprecated
2424 static public Intent newChooseAccountIntent(
2425 Account selectedAccount,
Baligh Uddinf2d248d2015-07-10 03:01:47 +00002426 ArrayList<Account> allowableAccounts,
Fred Quintana1121bb52011-09-14 23:19:35 -07002427 String[] allowableAccountTypes,
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002428 boolean alwaysPromptForAccount,
2429 String descriptionOverrideText,
2430 String addAccountAuthTokenType,
2431 String[] addAccountRequiredFeatures,
Fred Quintana1121bb52011-09-14 23:19:35 -07002432 Bundle addAccountOptions) {
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -07002433 return newChooseAccountIntent(
2434 selectedAccount,
2435 allowableAccounts,
2436 allowableAccountTypes,
2437 descriptionOverrideText,
2438 addAccountAuthTokenType,
2439 addAccountRequiredFeatures,
2440 addAccountOptions);
2441 }
2442
2443 /**
2444 * Returns an intent to an {@link Activity} that prompts the user to choose from a list of
2445 * accounts.
2446 * The caller will then typically start the activity by calling
2447 * <code>startActivityForResult(intent, ...);</code>.
2448 * <p>
2449 * On success the activity returns a Bundle with the account name and type specified using
2450 * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
2451 * <p>
2452 * The most common case is to call this with one account type, e.g.:
2453 * <p>
2454 * <pre> newChooseAccountIntent(null, null, new String[]{"com.google"}, null, null, null,
2455 * null);</pre>
2456 * @param selectedAccount if specified, indicates that the {@link Account} is the currently
2457 * selected one, according to the caller's definition of selected.
2458 * @param allowableAccounts an optional {@link List} of accounts that are allowed to be
2459 * shown. If not specified then this field will not limit the displayed accounts.
2460 * @param allowableAccountTypes an optional string array of account types. These are used
2461 * both to filter the shown accounts and to filter the list of account types that are shown
2462 * when adding an account. If not specified then this field will not limit the displayed
2463 * account types when adding an account.
2464 * @param descriptionOverrideText if non-null this string is used as the description in the
2465 * accounts chooser screen rather than the default
2466 * @param addAccountAuthTokenType this string is passed as the {@link #addAccount}
2467 * authTokenType parameter
2468 * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount}
2469 * requiredFeatures parameter
2470 * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options
2471 * parameter
2472 * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow.
2473 */
2474 static public Intent newChooseAccountIntent(
2475 Account selectedAccount,
2476 List<Account> allowableAccounts,
2477 String[] allowableAccountTypes,
2478 String descriptionOverrideText,
2479 String addAccountAuthTokenType,
2480 String[] addAccountRequiredFeatures,
2481 Bundle addAccountOptions) {
Fred Quintana1121bb52011-09-14 23:19:35 -07002482 Intent intent = new Intent();
Amith Yamasani12b8e132013-03-14 10:48:07 -07002483 ComponentName componentName = ComponentName.unflattenFromString(
2484 Resources.getSystem().getString(R.string.config_chooseTypeAndAccountActivity));
2485 intent.setClassName(componentName.getPackageName(),
2486 componentName.getClassName());
Fred Quintana1121bb52011-09-14 23:19:35 -07002487 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST,
Craig Lafayette3c9c71d2015-07-14 10:48:46 -04002488 allowableAccounts == null ? null : new ArrayList<Account>(allowableAccounts));
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002489 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
2490 allowableAccountTypes);
Fred Quintana1121bb52011-09-14 23:19:35 -07002491 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
2492 addAccountOptions);
2493 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_SELECTED_ACCOUNT, selectedAccount);
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002494 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_DESCRIPTION_TEXT_OVERRIDE,
2495 descriptionOverrideText);
2496 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,
2497 addAccountAuthTokenType);
2498 intent.putExtra(
2499 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,
2500 addAccountRequiredFeatures);
Fred Quintana1121bb52011-09-14 23:19:35 -07002501 return intent;
2502 }
2503
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002504 private final HashMap<OnAccountsUpdateListener, Handler> mAccountsUpdatedListeners =
Fred Quintanad9d2f112009-04-23 13:36:27 -07002505 Maps.newHashMap();
2506
Fred Quintanad9d2f112009-04-23 13:36:27 -07002507 /**
2508 * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
2509 * so that it can read the updated list of accounts and send them to the listener
2510 * in mAccountsUpdatedListeners.
2511 */
2512 private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
2513 public void onReceive(final Context context, final Intent intent) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002514 final Account[] accounts = getAccounts();
2515 // send the result to the listeners
2516 synchronized (mAccountsUpdatedListeners) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002517 for (Map.Entry<OnAccountsUpdateListener, Handler> entry :
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002518 mAccountsUpdatedListeners.entrySet()) {
2519 postToHandler(entry.getValue(), entry.getKey(), accounts);
Fred Quintanad9d2f112009-04-23 13:36:27 -07002520 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002521 }
Fred Quintanad9d2f112009-04-23 13:36:27 -07002522 }
2523 };
2524
2525 /**
Dan Egnor661f0132010-02-19 11:23:00 -08002526 * Adds an {@link OnAccountsUpdateListener} to this instance of the
2527 * {@link AccountManager}. This listener will be notified whenever the
2528 * list of accounts on the device changes.
2529 *
2530 * <p>As long as this listener is present, the AccountManager instance
2531 * will not be garbage-collected, and neither will the {@link Context}
2532 * used to retrieve it, which may be a large Activity instance. To avoid
2533 * memory leaks, you must remove this listener before then. Normally
2534 * listeners are added in an Activity or Service's {@link Activity#onCreate}
2535 * and removed in {@link Activity#onDestroy}.
2536 *
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002537 * <p>The listener will only be informed of accounts that would be returned
2538 * to the caller via {@link #getAccounts()}. Typically this means that to
2539 * get any accounts, the caller will need to be grated the GET_ACCOUNTS
2540 * permission.
Dan Egnor661f0132010-02-19 11:23:00 -08002541 *
Ian Pedowitz6cc066d2015-08-05 14:23:43 +00002542 * <p>It is safe to call this method from the main thread.
Ian Pedowitz845d14d2015-08-04 07:47:37 -07002543 *
Dan Egnor661f0132010-02-19 11:23:00 -08002544 * @param listener The listener to send notifications to
2545 * @param handler {@link Handler} identifying the thread to use
2546 * for notifications, null for the main thread
2547 * @param updateImmediately If true, the listener will be invoked
2548 * (on the handler thread) right away with the current account list
Fred Quintanad9d2f112009-04-23 13:36:27 -07002549 * @throws IllegalArgumentException if listener is null
2550 * @throws IllegalStateException if listener was already added
2551 */
Tor Norbye80b530a2015-04-23 16:36:09 -07002552 @RequiresPermission(GET_ACCOUNTS)
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002553 public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
Fred Quintanad9d2f112009-04-23 13:36:27 -07002554 Handler handler, boolean updateImmediately) {
2555 if (listener == null) {
2556 throw new IllegalArgumentException("the listener is null");
2557 }
2558 synchronized (mAccountsUpdatedListeners) {
2559 if (mAccountsUpdatedListeners.containsKey(listener)) {
2560 throw new IllegalStateException("this listener is already added");
2561 }
2562 final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
2563
2564 mAccountsUpdatedListeners.put(listener, handler);
2565
2566 if (wasEmpty) {
2567 // Register a broadcast receiver to monitor account changes
2568 IntentFilter intentFilter = new IntentFilter();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002569 intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
Costin Manolacheb6437242009-09-10 16:14:12 -07002570 // To recover from disk-full.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002571 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
Fred Quintanad9d2f112009-04-23 13:36:27 -07002572 mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
2573 }
2574 }
2575
2576 if (updateImmediately) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002577 postToHandler(handler, listener, getAccounts());
Fred Quintanad9d2f112009-04-23 13:36:27 -07002578 }
2579 }
2580
2581 /**
Dan Egnor661f0132010-02-19 11:23:00 -08002582 * Removes an {@link OnAccountsUpdateListener} previously registered with
2583 * {@link #addOnAccountsUpdatedListener}. The listener will no longer
2584 * receive notifications of account changes.
2585 *
2586 * <p>It is safe to call this method from the main thread.
2587 *
2588 * <p>No permission is required to call this method.
2589 *
2590 * @param listener The previously added listener to remove
Fred Quintanad9d2f112009-04-23 13:36:27 -07002591 * @throws IllegalArgumentException if listener is null
2592 * @throws IllegalStateException if listener was not already added
2593 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002594 public void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) {
Fred Quintana382601f2010-03-25 12:25:10 -07002595 if (listener == null) throw new IllegalArgumentException("listener is null");
Fred Quintanad9d2f112009-04-23 13:36:27 -07002596 synchronized (mAccountsUpdatedListeners) {
Bryan Mawhinney5be61f52009-09-24 14:50:25 +01002597 if (!mAccountsUpdatedListeners.containsKey(listener)) {
Costin Manolache88a211b2009-10-29 11:30:11 -07002598 Log.e(TAG, "Listener was not previously added");
2599 return;
Fred Quintanad9d2f112009-04-23 13:36:27 -07002600 }
Bryan Mawhinney5be61f52009-09-24 14:50:25 +01002601 mAccountsUpdatedListeners.remove(listener);
Fred Quintanad9d2f112009-04-23 13:36:27 -07002602 if (mAccountsUpdatedListeners.isEmpty()) {
2603 mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
2604 }
2605 }
2606 }
Sandra Kwan78812282015-11-04 11:19:47 -08002607
2608 /**
2609 * Asks the user to authenticate with an account of a specified type. The
2610 * authenticator for this account type processes this request with the
2611 * appropriate user interface. If the user does elect to authenticate with a
2612 * new account, a bundle of session data for installing the account later is
2613 * returned with optional account password and account status token.
2614 * <p>
2615 * This method may be called from any thread, but the returned
2616 * {@link AccountManagerFuture} must not be used on the main thread.
2617 * <p>
2618 * <p>
2619 * <b>NOTE:</b> The account will not be installed to the device by calling
Sandra Kwan920f6ef2015-11-10 14:13:29 -08002620 * this api alone. #finishSession should be called after this to install the
2621 * account on device.
Sandra Kwan78812282015-11-04 11:19:47 -08002622 *
2623 * @param accountType The type of account to add; must not be null
2624 * @param authTokenType The type of auth token (see {@link #getAuthToken})
2625 * this account will need to be able to generate, null for none
2626 * @param requiredFeatures The features (see {@link #hasFeatures}) this
2627 * account must have, null for none
2628 * @param options Authenticator-specific options for the request, may be
2629 * null or empty
2630 * @param activity The {@link Activity} context to use for launching a new
2631 * authenticator-defined sub-Activity to prompt the user to
2632 * create an account; used only to call startActivity(); if null,
2633 * the prompt will not be launched directly, but the necessary
2634 * {@link Intent} will be returned to the caller instead
2635 * @param callback Callback to invoke when the request completes, null for
2636 * no callback
2637 * @param handler {@link Handler} identifying the callback thread, null for
2638 * the main thread
2639 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
2640 * these fields if activity was specified and user was authenticated
2641 * with an account:
2642 * <ul>
2643 * <li>{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for
2644 * adding the the to the device later.
2645 * <li>{@link #KEY_PASSWORD} - optional, the password or password
2646 * hash of the account.
2647 * <li>{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
2648 * status of the account
2649 * </ul>
2650 * If no activity was specified, the returned Bundle contains only
2651 * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
2652 * actual account creation process. If authenticator doesn't support
2653 * this method, the returned Bundle contains only
2654 * {@link #KEY_ACCOUNT_SESSION_BUNDLE} with encrypted
2655 * {@code options} needed to add account later. If an error
2656 * occurred, {@link AccountManagerFuture#getResult()} throws:
2657 * <ul>
2658 * <li>{@link AuthenticatorException} if no authenticator was
2659 * registered for this account type or the authenticator failed to
2660 * respond
2661 * <li>{@link OperationCanceledException} if the operation was
2662 * canceled for any reason, including the user canceling the
2663 * creation process or adding accounts (of this type) has been
2664 * disabled by policy
2665 * <li>{@link IOException} if the authenticator experienced an I/O
2666 * problem creating a new account, usually because of network
2667 * trouble
2668 * </ul>
Sandra Kwan920f6ef2015-11-10 14:13:29 -08002669 * @see #finishSession
Sandra Kwan78812282015-11-04 11:19:47 -08002670 */
Sandra Kwane68c37e2015-11-12 17:11:49 -08002671 public AccountManagerFuture<Bundle> startAddAccountSession(
2672 final String accountType,
2673 final String authTokenType,
2674 final String[] requiredFeatures,
2675 final Bundle options,
2676 final Activity activity,
2677 AccountManagerCallback<Bundle> callback,
2678 Handler handler) {
Sandra Kwan78812282015-11-04 11:19:47 -08002679 if (accountType == null) throw new IllegalArgumentException("accountType is null");
2680 final Bundle optionsIn = new Bundle();
2681 if (options != null) {
2682 optionsIn.putAll(options);
2683 }
2684 optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
2685
2686 return new AmsTask(activity, handler, callback) {
2687 @Override
2688 public void doWork() throws RemoteException {
Sandra Kwane68c37e2015-11-12 17:11:49 -08002689 mService.startAddAccountSession(
2690 mResponse,
2691 accountType,
2692 authTokenType,
2693 requiredFeatures,
2694 activity != null,
2695 optionsIn);
2696 }
2697 }.start();
2698 }
2699
2700 /**
2701 * Asks the user to enter a new password for an account but not updating the
Sandra Kwan920f6ef2015-11-10 14:13:29 -08002702 * saved credentials for the account until {@link #finishSession} is called.
Sandra Kwane68c37e2015-11-12 17:11:49 -08002703 * <p>
2704 * This method may be called from any thread, but the returned
2705 * {@link AccountManagerFuture} must not be used on the main thread.
2706 * <p>
2707 * <b>NOTE:</b> The saved credentials for the account alone will not be
Sandra Kwan920f6ef2015-11-10 14:13:29 -08002708 * updated by calling this API alone. #finishSession should be called after
2709 * this to update local credentials
Sandra Kwane68c37e2015-11-12 17:11:49 -08002710 *
2711 * @param account The account to update credentials for
2712 * @param authTokenType The credentials entered must allow an auth token of
2713 * this type to be created (but no actual auth token is
2714 * returned); may be null
2715 * @param options Authenticator-specific options for the request; may be
2716 * null or empty
2717 * @param activity The {@link Activity} context to use for launching a new
2718 * authenticator-defined sub-Activity to prompt the user to enter
2719 * a password; used only to call startActivity(); if null, the
2720 * prompt will not be launched directly, but the necessary
2721 * {@link Intent} will be returned to the caller instead
2722 * @param callback Callback to invoke when the request completes, null for
2723 * no callback
2724 * @param handler {@link Handler} identifying the callback thread, null for
2725 * the main thread
2726 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
2727 * these fields if an activity was supplied and user was
Sandra Kwan920f6ef2015-11-10 14:13:29 -08002728 * successfully re-authenticated to the account:
Sandra Kwane68c37e2015-11-12 17:11:49 -08002729 * <ul>
2730 * <li>{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for
2731 * updating the local credentials on device later.
Sandra Kwan920f6ef2015-11-10 14:13:29 -08002732 * <li>{@link #KEY_PASSWORD} - optional, the password or password
2733 * hash of the account
2734 * <li>{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
2735 * status of the account
Sandra Kwane68c37e2015-11-12 17:11:49 -08002736 * </ul>
2737 * If no activity was specified, the returned Bundle contains
2738 * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
2739 * password prompt. If an error occurred,
2740 * {@link AccountManagerFuture#getResult()} throws:
2741 * <ul>
2742 * <li>{@link AuthenticatorException} if the authenticator failed to
2743 * respond
2744 * <li>{@link OperationCanceledException} if the operation was
2745 * canceled for any reason, including the user canceling the
2746 * password prompt
2747 * <li>{@link IOException} if the authenticator experienced an I/O
2748 * problem verifying the password, usually because of network
2749 * trouble
2750 * </ul>
Sandra Kwan920f6ef2015-11-10 14:13:29 -08002751 * @see #finishSession
Sandra Kwane68c37e2015-11-12 17:11:49 -08002752 */
2753 public AccountManagerFuture<Bundle> startUpdateCredentialsSession(
2754 final Account account,
2755 final String authTokenType,
2756 final Bundle options,
2757 final Activity activity,
2758 final AccountManagerCallback<Bundle> callback,
2759 final Handler handler) {
2760 if (account == null) {
2761 throw new IllegalArgumentException("account is null");
2762 }
2763 return new AmsTask(activity, handler, callback) {
2764 @Override
2765 public void doWork() throws RemoteException {
2766 mService.startUpdateCredentialsSession(
2767 mResponse,
2768 account,
2769 authTokenType,
2770 activity != null,
2771 options);
Sandra Kwan78812282015-11-04 11:19:47 -08002772 }
2773 }.start();
2774 }
Sandra Kwan920f6ef2015-11-10 14:13:29 -08002775
2776 /**
2777 * Finishes the session started by {@link #startAddAccountSession} or
2778 * {@link #startUpdateCredentialsSession}. This will either add the account
2779 * to AccountManager or update the local credentials stored.
2780 * <p>
2781 * This method may be called from any thread, but the returned
2782 * {@link AccountManagerFuture} must not be used on the main thread.
2783 *
2784 * @param sessionBundle a {@link Bundle} created by {@link #startAddAccountSession} or
2785 * {@link #startUpdateCredentialsSession}
2786 * @param activity The {@link Activity} context to use for launching a new
2787 * authenticator-defined sub-Activity to prompt the user to
2788 * create an account or reauthenticate existing account; used
2789 * only to call startActivity(); if null, the prompt will not
2790 * be launched directly, but the necessary {@link Intent} will
2791 * be returned to the caller instead
2792 * @param callback Callback to invoke when the request completes, null for
2793 * no callback
2794 * @param handler {@link Handler} identifying the callback thread, null for
2795 * the main thread
2796 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
2797 * these fields if an activity was supplied and an account was added
2798 * to device or local credentials were updated::
2799 * <ul>
2800 * <li>{@link #KEY_ACCOUNT_NAME} - the name of the account created
2801 * <li>{@link #KEY_ACCOUNT_TYPE} - the type of the account
2802 * </ul>
2803 * If no activity was specified and additional information is needed
2804 * from user, the returned Bundle may contains only
2805 * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
2806 * actual account creation process. If an error occurred,
2807 * {@link AccountManagerFuture#getResult()} throws:
2808 * <ul>
2809 * <li>{@link AuthenticatorException} if no authenticator was
2810 * registered for this account type or the authenticator failed to
2811 * respond
2812 * <li>{@link OperationCanceledException} if the operation was
2813 * canceled for any reason, including the user canceling the
2814 * creation process or adding accounts (of this type) has been
2815 * disabled by policy
2816 * <li>{@link IOException} if the authenticator experienced an I/O
2817 * problem creating a new account, usually because of network
2818 * trouble
2819 * </ul>
2820 * @see #startAddAccountSession and #startUpdateCredentialsSession
2821 */
2822 public AccountManagerFuture<Bundle> finishSession(
2823 final Bundle sessionBundle,
2824 final Activity activity,
2825 AccountManagerCallback<Bundle> callback,
2826 Handler handler) {
2827 if (sessionBundle == null) {
2828 throw new IllegalArgumentException("sessionBundle is null");
2829 }
2830
2831 /* Add information required by add account flow */
2832 final Bundle appInfo = new Bundle();
2833 appInfo.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
2834
2835 return new AmsTask(activity, handler, callback) {
2836 @Override
2837 public void doWork() throws RemoteException {
2838 mService.finishSession(mResponse, sessionBundle, activity != null, appInfo);
2839 }
2840 }.start();
2841 }
Fred Quintana60307342009-03-24 22:48:12 -07002842}