blob: 9394d2c05a2e046db16c2a48d626f3bb71e7ee5d [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
Tor Norbye80b530a2015-04-23 16:36:09 -070019import android.annotation.RequiresPermission;
20import android.annotation.Size;
Fred Quintana60307342009-03-24 22:48:12 -070021import android.app.Activity;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080022import android.content.BroadcastReceiver;
Amith Yamasani12b8e132013-03-14 10:48:07 -070023import android.content.ComponentName;
Fred Quintana60307342009-03-24 22:48:12 -070024import android.content.Context;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080025import android.content.Intent;
Fred Quintanad9d2f112009-04-23 13:36:27 -070026import android.content.IntentFilter;
Amith Yamasani12b8e132013-03-14 10:48:07 -070027import android.content.res.Resources;
Costin Manolacheb6437242009-09-10 16:14:12 -070028import android.database.SQLException;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080029import android.os.Build;
Fred Quintanaa698f422009-04-08 19:14:54 -070030import android.os.Bundle;
31import android.os.Handler;
32import android.os.Looper;
Fred Quintana33269202009-04-20 16:05:10 -070033import android.os.Parcelable;
Amith Yamasani2c7bc262012-11-05 16:46:02 -080034import android.os.Process;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080035import android.os.RemoteException;
Amith Yamasani2c7bc262012-11-05 16:46:02 -080036import android.os.UserHandle;
Fred Quintanaf0fd8432010-03-08 12:48:05 -080037import android.text.TextUtils;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080038import android.util.Log;
39
40import com.android.internal.R;
41import com.google.android.collect.Maps;
Fred Quintana60307342009-03-24 22:48:12 -070042
Fred Quintanaa698f422009-04-08 19:14:54 -070043import java.io.IOException;
Fred Quintana1121bb52011-09-14 23:19:35 -070044import java.util.ArrayList;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080045import java.util.HashMap;
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -070046import java.util.List;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080047import java.util.Map;
Fred Quintanaa698f422009-04-08 19:14:54 -070048import java.util.concurrent.Callable;
49import java.util.concurrent.CancellationException;
50import java.util.concurrent.ExecutionException;
51import java.util.concurrent.FutureTask;
Fred Quintanaa698f422009-04-08 19:14:54 -070052import java.util.concurrent.TimeUnit;
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -080053import java.util.concurrent.TimeoutException;
Fred Quintana60307342009-03-24 22:48:12 -070054
Tor Norbye80b530a2015-04-23 16:36:09 -070055import static android.Manifest.permission.GET_ACCOUNTS;
Tor Norbye80b530a2015-04-23 16:36:09 -070056
Fred Quintana60307342009-03-24 22:48:12 -070057/**
Dan Egnor661f0132010-02-19 11:23:00 -080058 * This class provides access to a centralized registry of the user's
Dan Egnor8e4378b2010-08-02 18:22:09 -070059 * online accounts. The user enters credentials (username and password) once
60 * per account, granting applications access to online resources with
61 * "one-click" approval.
Fred Quintana60307342009-03-24 22:48:12 -070062 *
Dan Egnor661f0132010-02-19 11:23:00 -080063 * <p>Different online services have different ways of handling accounts and
64 * authentication, so the account manager uses pluggable <em>authenticator</em>
Dan Egnor8e4378b2010-08-02 18:22:09 -070065 * modules for different <em>account types</em>. Authenticators (which may be
66 * written by third parties) handle the actual details of validating account
67 * credentials and storing account information. For example, Google, Facebook,
68 * and Microsoft Exchange each have their own authenticator.
Dan Egnor661f0132010-02-19 11:23:00 -080069 *
70 * <p>Many servers support some notion of an <em>authentication token</em>,
71 * which can be used to authenticate a request to the server without sending
72 * the user's actual password. (Auth tokens are normally created with a
73 * separate request which does include the user's credentials.) AccountManager
Dan Egnor8e4378b2010-08-02 18:22:09 -070074 * can generate auth tokens for applications, so the application doesn't need to
75 * handle passwords directly. Auth tokens are normally reusable and cached by
76 * AccountManager, but must be refreshed periodically. It's the responsibility
77 * of applications to <em>invalidate</em> auth tokens when they stop working so
78 * the AccountManager knows it needs to regenerate them.
Dan Egnor661f0132010-02-19 11:23:00 -080079 *
80 * <p>Applications accessing a server normally go through these steps:
81 *
82 * <ul>
83 * <li>Get an instance of AccountManager using {@link #get(Context)}.
84 *
85 * <li>List the available accounts using {@link #getAccountsByType} or
86 * {@link #getAccountsByTypeAndFeatures}. Normally applications will only
87 * be interested in accounts with one particular <em>type</em>, which
88 * identifies the authenticator. Account <em>features</em> are used to
89 * identify particular account subtypes and capabilities. Both the account
90 * type and features are authenticator-specific strings, and must be known by
91 * the application in coordination with its preferred authenticators.
92 *
93 * <li>Select one or more of the available accounts, possibly by asking the
94 * user for their preference. If no suitable accounts are available,
95 * {@link #addAccount} may be called to prompt the user to create an
96 * account of the appropriate type.
97 *
Dan Egnor8e4378b2010-08-02 18:22:09 -070098 * <li><b>Important:</b> If the application is using a previously remembered
99 * account selection, it must make sure the account is still in the list
100 * of accounts returned by {@link #getAccountsByType}. Requesting an auth token
101 * for an account no longer on the device results in an undefined failure.
102 *
Dan Egnor661f0132010-02-19 11:23:00 -0800103 * <li>Request an auth token for the selected account(s) using one of the
104 * {@link #getAuthToken} methods or related helpers. Refer to the description
105 * of each method for exact usage and error handling details.
106 *
107 * <li>Make the request using the auth token. The form of the auth token,
108 * the format of the request, and the protocol used are all specific to the
Dan Egnor8e4378b2010-08-02 18:22:09 -0700109 * service you are accessing. The application may use whatever network and
110 * protocol libraries are useful.
Dan Egnor661f0132010-02-19 11:23:00 -0800111 *
112 * <li><b>Important:</b> If the request fails with an authentication error,
113 * it could be that a cached auth token is stale and no longer honored by
114 * the server. The application must call {@link #invalidateAuthToken} to remove
115 * the token from the cache, otherwise requests will continue failing! After
116 * invalidating the auth token, immediately go back to the "Request an auth
117 * token" step above. If the process fails the second time, then it can be
118 * treated as a "genuine" authentication failure and the user notified or other
119 * appropriate actions taken.
120 * </ul>
121 *
Dan Egnor8e4378b2010-08-02 18:22:09 -0700122 * <p>Some AccountManager methods may need to interact with the user to
Dan Egnor661f0132010-02-19 11:23:00 -0800123 * prompt for credentials, present options, or ask the user to add an account.
124 * The caller may choose whether to allow AccountManager to directly launch the
125 * necessary user interface and wait for the user, or to return an Intent which
126 * the caller may use to launch the interface, or (in some cases) to install a
127 * notification which the user can select at any time to launch the interface.
128 * To have AccountManager launch the interface directly, the caller must supply
129 * the current foreground {@link Activity} context.
130 *
131 * <p>Many AccountManager methods take {@link AccountManagerCallback} and
Dan Egnor8e4378b2010-08-02 18:22:09 -0700132 * {@link Handler} as parameters. These methods return immediately and
Dan Egnor661f0132010-02-19 11:23:00 -0800133 * run asynchronously. If a callback is provided then
134 * {@link AccountManagerCallback#run} will be invoked on the Handler's
135 * thread when the request completes, successfully or not.
Dan Egnor8e4378b2010-08-02 18:22:09 -0700136 * The result is retrieved by calling {@link AccountManagerFuture#getResult()}
137 * on the {@link AccountManagerFuture} returned by the method (and also passed
138 * to the callback). This method waits for the operation to complete (if
139 * necessary) and either returns the result or throws an exception if an error
140 * occurred during the operation. To make the request synchronously, call
Dan Egnor661f0132010-02-19 11:23:00 -0800141 * {@link AccountManagerFuture#getResult()} immediately on receiving the
Dan Egnor8e4378b2010-08-02 18:22:09 -0700142 * future from the method; no callback need be supplied.
Dan Egnor661f0132010-02-19 11:23:00 -0800143 *
144 * <p>Requests which may block, including
145 * {@link AccountManagerFuture#getResult()}, must never be called on
146 * the application's main event thread. These operations throw
147 * {@link IllegalStateException} if they are used on the main thread.
Fred Quintana60307342009-03-24 22:48:12 -0700148 */
149public class AccountManager {
150 private static final String TAG = "AccountManager";
151
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700152 public static final int ERROR_CODE_REMOTE_EXCEPTION = 1;
153 public static final int ERROR_CODE_NETWORK_ERROR = 3;
154 public static final int ERROR_CODE_CANCELED = 4;
155 public static final int ERROR_CODE_INVALID_RESPONSE = 5;
156 public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6;
157 public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
158 public static final int ERROR_CODE_BAD_REQUEST = 8;
Jatin Lodhia3df7d692013-03-27 10:57:23 -0700159 public static final int ERROR_CODE_BAD_AUTHENTICATION = 9;
Fred Quintana756b7352009-10-21 13:43:10 -0700160
Amith Yamasanidf2e92a2013-03-01 17:04:38 -0800161 /** @hide */
162 public static final int ERROR_CODE_USER_RESTRICTED = 100;
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100163 /** @hide */
164 public static final int ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE = 101;
Amith Yamasanidf2e92a2013-03-01 17:04:38 -0800165
Dan Egnor661f0132010-02-19 11:23:00 -0800166 /**
Dan Egnor8e4378b2010-08-02 18:22:09 -0700167 * Bundle key used for the {@link String} account name in results
Dan Egnor661f0132010-02-19 11:23:00 -0800168 * from methods which return information about a particular account.
169 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700170 public static final String KEY_ACCOUNT_NAME = "authAccount";
Dan Egnor661f0132010-02-19 11:23:00 -0800171
172 /**
Dan Egnor8e4378b2010-08-02 18:22:09 -0700173 * Bundle key used for the {@link String} account type in results
Dan Egnor661f0132010-02-19 11:23:00 -0800174 * from methods which return information about a particular account.
175 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700176 public static final String KEY_ACCOUNT_TYPE = "accountType";
Dan Egnor661f0132010-02-19 11:23:00 -0800177
178 /**
Dan Egnor8e4378b2010-08-02 18:22:09 -0700179 * Bundle key used for the auth token value in results
Dan Egnor661f0132010-02-19 11:23:00 -0800180 * from {@link #getAuthToken} and friends.
181 */
182 public static final String KEY_AUTHTOKEN = "authtoken";
183
184 /**
Dan Egnor8e4378b2010-08-02 18:22:09 -0700185 * Bundle key used for an {@link Intent} in results from methods that
Dan Egnor661f0132010-02-19 11:23:00 -0800186 * may require the caller to interact with the user. The Intent can
187 * be used to start the corresponding user interface activity.
188 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700189 public static final String KEY_INTENT = "intent";
Dan Egnor661f0132010-02-19 11:23:00 -0800190
191 /**
Dan Egnor8e4378b2010-08-02 18:22:09 -0700192 * Bundle key used to supply the password directly in options to
Dan Egnor661f0132010-02-19 11:23:00 -0800193 * {@link #confirmCredentials}, rather than prompting the user with
194 * the standard password prompt.
195 */
196 public static final String KEY_PASSWORD = "password";
197
198 public static final String KEY_ACCOUNTS = "accounts";
Brian Carlstrom46703b02011-04-06 15:41:29 -0700199
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700200 public static final String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
201 public static final String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
Dan Egnor661f0132010-02-19 11:23:00 -0800202 public static final String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700203 public static final String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage";
204 public static final String KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey";
Dan Egnor661f0132010-02-19 11:23:00 -0800205 public static final String KEY_BOOLEAN_RESULT = "booleanResult";
206 public static final String KEY_ERROR_CODE = "errorCode";
207 public static final String KEY_ERROR_MESSAGE = "errorMessage";
208 public static final String KEY_USERDATA = "userdata";
Costin Manolacheb61e8fb2011-09-08 11:26:09 -0700209
Costin Manolachea40c6302010-12-13 14:50:45 -0800210 /**
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800211 * Bundle key used to supply the last time the credentials of the account
212 * were authenticated successfully. Time is specified in milliseconds since
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -0700213 * epoch. Associated time is updated on successful authentication of account
214 * on adding account, confirming credentials, or updating credentials.
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800215 */
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -0700216 public static final String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800217
218 /**
Costin Manolachea40c6302010-12-13 14:50:45 -0800219 * Authenticators using 'customTokens' option will also get the UID of the
220 * caller
221 */
222 public static final String KEY_CALLER_UID = "callerUid";
223 public static final String KEY_CALLER_PID = "callerPid";
Dan Egnor661f0132010-02-19 11:23:00 -0800224
Costin Manolached6060452011-01-24 16:11:36 -0800225 /**
Fred Quintanaad93a322011-09-08 13:21:01 -0700226 * The Android package of the caller will be set in the options bundle by the
227 * {@link AccountManager} and will be passed to the AccountManagerService and
228 * to the AccountAuthenticators. The uid of the caller will be known by the
229 * AccountManagerService as well as the AccountAuthenticators so they will be able to
230 * verify that the package is consistent with the uid (a uid might be shared by many
231 * packages).
232 */
233 public static final String KEY_ANDROID_PACKAGE_NAME = "androidPackageName";
234
235 /**
Costin Manolached6060452011-01-24 16:11:36 -0800236 * Boolean, if set and 'customTokens' the authenticator is responsible for
237 * notifications.
238 * @hide
239 */
240 public static final String KEY_NOTIFY_ON_FAILURE = "notifyOnAuthFailure";
241
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700242 public static final String ACTION_AUTHENTICATOR_INTENT =
243 "android.accounts.AccountAuthenticator";
244 public static final String AUTHENTICATOR_META_DATA_NAME =
Dan Egnor661f0132010-02-19 11:23:00 -0800245 "android.accounts.AccountAuthenticator";
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700246 public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
247
Fred Quintana60307342009-03-24 22:48:12 -0700248 private final Context mContext;
249 private final IAccountManager mService;
Fred Quintanad9d2f112009-04-23 13:36:27 -0700250 private final Handler mMainHandler;
Dan Egnor661f0132010-02-19 11:23:00 -0800251
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700252 /**
253 * Action sent as a broadcast Intent by the AccountsService
Dan Egnor661f0132010-02-19 11:23:00 -0800254 * when accounts are added, accounts are removed, or an
255 * account's credentials (saved password, etc) are changed.
256 *
257 * @see #addOnAccountsUpdatedListener
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700258 */
259 public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
260 "android.accounts.LOGIN_ACCOUNTS_CHANGED";
Fred Quintana60307342009-03-24 22:48:12 -0700261
Fred Quintana33269202009-04-20 16:05:10 -0700262 /**
263 * @hide
264 */
Fred Quintana60307342009-03-24 22:48:12 -0700265 public AccountManager(Context context, IAccountManager service) {
266 mContext = context;
267 mService = service;
Fred Quintanad9d2f112009-04-23 13:36:27 -0700268 mMainHandler = new Handler(mContext.getMainLooper());
Fred Quintana60307342009-03-24 22:48:12 -0700269 }
270
Fred Quintana0eabf022009-04-27 15:08:17 -0700271 /**
272 * @hide used for testing only
273 */
274 public AccountManager(Context context, IAccountManager service, Handler handler) {
275 mContext = context;
276 mService = service;
277 mMainHandler = handler;
278 }
279
Fred Quintana756b7352009-10-21 13:43:10 -0700280 /**
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800281 * @hide for internal use only
282 */
283 public static Bundle sanitizeResult(Bundle result) {
Fred Quintana382601f2010-03-25 12:25:10 -0700284 if (result != null) {
285 if (result.containsKey(KEY_AUTHTOKEN)
286 && !TextUtils.isEmpty(result.getString(KEY_AUTHTOKEN))) {
287 final Bundle newResult = new Bundle(result);
288 newResult.putString(KEY_AUTHTOKEN, "<omitted for logging purposes>");
289 return newResult;
290 }
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800291 }
292 return result;
293 }
294
295 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800296 * Gets an AccountManager instance associated with a Context.
297 * The {@link Context} will be used as long as the AccountManager is
298 * active, so make sure to use a {@link Context} whose lifetime is
299 * commensurate with any listeners registered to
300 * {@link #addOnAccountsUpdatedListener} or similar methods.
301 *
302 * <p>It is safe to call this method from the main thread.
303 *
304 * <p>No permission is required to call this method.
305 *
Fred Quintana756b7352009-10-21 13:43:10 -0700306 * @param context The {@link Context} to use when necessary
Dan Egnor661f0132010-02-19 11:23:00 -0800307 * @return An {@link AccountManager} instance
Fred Quintana756b7352009-10-21 13:43:10 -0700308 */
Fred Quintanaa698f422009-04-08 19:14:54 -0700309 public static AccountManager get(Context context) {
Fred Quintana382601f2010-03-25 12:25:10 -0700310 if (context == null) throw new IllegalArgumentException("context is null");
Fred Quintanaa698f422009-04-08 19:14:54 -0700311 return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
312 }
313
Fred Quintana756b7352009-10-21 13:43:10 -0700314 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800315 * Gets the saved password associated with the account.
316 * This is intended for authenticators and related code; applications
317 * should get an auth token instead.
318 *
319 * <p>It is safe to call this method from the main thread.
320 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700321 * <p>This method requires the caller to have a signature match with the
322 * authenticator that owns the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -0800323 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700324 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
325 * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs for
326 * this function in API level 22.
327 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700328 * @param account The account to query for a password. Must not be {@code null}.
Dan Egnor661f0132010-02-19 11:23:00 -0800329 * @return The account's password, null if none or if the account doesn't exist
Fred Quintana756b7352009-10-21 13:43:10 -0700330 */
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700331 public String getPassword(final Account account) {
Fred Quintana382601f2010-03-25 12:25:10 -0700332 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintana60307342009-03-24 22:48:12 -0700333 try {
334 return mService.getPassword(account);
335 } catch (RemoteException e) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700336 // will never happen
Fred Quintana60307342009-03-24 22:48:12 -0700337 throw new RuntimeException(e);
338 }
339 }
340
Fred Quintana756b7352009-10-21 13:43:10 -0700341 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800342 * Gets the user data named by "key" associated with the account.
343 * This is intended for authenticators and related code to store
344 * arbitrary metadata along with accounts. The meaning of the keys
345 * and values is up to the authenticator for the account.
346 *
347 * <p>It is safe to call this method from the main thread.
348 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700349 * <p>This method requires the caller to have a signature match with the
350 * authenticator that owns the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -0800351 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700352 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
353 * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs
354 * for this function in API level 22.
355 *
Dan Egnor661f0132010-02-19 11:23:00 -0800356 * @param account The account to query for user data
357 * @return The user data, null if the account or key doesn't exist
Fred Quintana756b7352009-10-21 13:43:10 -0700358 */
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700359 public String getUserData(final Account account, final String key) {
Fred Quintana382601f2010-03-25 12:25:10 -0700360 if (account == null) throw new IllegalArgumentException("account is null");
361 if (key == null) throw new IllegalArgumentException("key is null");
Fred Quintana60307342009-03-24 22:48:12 -0700362 try {
363 return mService.getUserData(account, key);
364 } catch (RemoteException e) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700365 // will never happen
Fred Quintana60307342009-03-24 22:48:12 -0700366 throw new RuntimeException(e);
367 }
368 }
369
Fred Quintana756b7352009-10-21 13:43:10 -0700370 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800371 * Lists the currently registered authenticators.
372 *
373 * <p>It is safe to call this method from the main thread.
374 *
375 * <p>No permission is required to call this method.
376 *
377 * @return An array of {@link AuthenticatorDescription} for every
378 * authenticator known to the AccountManager service. Empty (never
379 * null) if no authenticators are known.
Fred Quintana756b7352009-10-21 13:43:10 -0700380 */
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700381 public AuthenticatorDescription[] getAuthenticatorTypes() {
Fred Quintanaa698f422009-04-08 19:14:54 -0700382 try {
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100383 return mService.getAuthenticatorTypes(UserHandle.getCallingUserId());
384 } catch (RemoteException e) {
385 // will never happen
386 throw new RuntimeException(e);
387 }
388 }
389
390 /**
391 * @hide
392 * Lists the currently registered authenticators for a given user id.
393 *
394 * <p>It is safe to call this method from the main thread.
395 *
396 * <p>The caller has to be in the same user or have the permission
397 * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
398 *
399 * @return An array of {@link AuthenticatorDescription} for every
400 * authenticator known to the AccountManager service. Empty (never
401 * null) if no authenticators are known.
402 */
403 public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) {
404 try {
405 return mService.getAuthenticatorTypes(userId);
Fred Quintanaa698f422009-04-08 19:14:54 -0700406 } catch (RemoteException e) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700407 // will never happen
Fred Quintanaa698f422009-04-08 19:14:54 -0700408 throw new RuntimeException(e);
409 }
410 }
411
Fred Quintana756b7352009-10-21 13:43:10 -0700412 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800413 * Lists all accounts of any type registered on the device.
414 * Equivalent to getAccountsByType(null).
415 *
416 * <p>It is safe to call this method from the main thread.
417 *
418 * <p>This method requires the caller to hold the permission
419 * {@link android.Manifest.permission#GET_ACCOUNTS}.
420 *
421 * @return An array of {@link Account}, one for each account. Empty
422 * (never null) if no accounts have been added.
Fred Quintana756b7352009-10-21 13:43:10 -0700423 */
Tor Norbye80b530a2015-04-23 16:36:09 -0700424 @RequiresPermission(GET_ACCOUNTS)
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700425 public Account[] getAccounts() {
Fred Quintana60307342009-03-24 22:48:12 -0700426 try {
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700427 return mService.getAccounts(null);
Fred Quintana60307342009-03-24 22:48:12 -0700428 } catch (RemoteException e) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700429 // won't ever happen
Fred Quintana60307342009-03-24 22:48:12 -0700430 throw new RuntimeException(e);
431 }
432 }
433
Fred Quintana756b7352009-10-21 13:43:10 -0700434 /**
Amith Yamasani27db4682013-03-30 17:07:47 -0700435 * @hide
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100436 * Lists all accounts of any type registered on the device for a given
437 * user id. Equivalent to getAccountsByType(null).
438 *
439 * <p>It is safe to call this method from the main thread.
440 *
441 * <p>This method requires the caller to hold the permission
442 * {@link android.Manifest.permission#GET_ACCOUNTS}.
443 *
444 * @return An array of {@link Account}, one for each account. Empty
445 * (never null) if no accounts have been added.
446 */
Tor Norbye80b530a2015-04-23 16:36:09 -0700447 @RequiresPermission(GET_ACCOUNTS)
Alexandra Gherghinac1cf1612014-06-05 10:49:14 +0100448 public Account[] getAccountsAsUser(int userId) {
449 try {
450 return mService.getAccountsAsUser(null, userId);
451 } catch (RemoteException e) {
452 // won't ever happen
453 throw new RuntimeException(e);
454 }
455 }
456
457 /**
458 * @hide
Amith Yamasani27db4682013-03-30 17:07:47 -0700459 * For use by internal activities. Returns the list of accounts that the calling package
460 * is authorized to use, particularly for shared accounts.
461 * @param packageName package name of the calling app.
462 * @param uid the uid of the calling app.
463 * @return the accounts that are available to this package and user.
464 */
465 public Account[] getAccountsForPackage(String packageName, int uid) {
466 try {
467 return mService.getAccountsForPackage(packageName, uid);
468 } catch (RemoteException re) {
469 // possible security exception
470 throw new RuntimeException(re);
471 }
472 }
473
474 /**
Amith Yamasani3b458ad2013-04-18 18:40:07 -0700475 * Returns the accounts visible to the specified package, in an environment where some apps
476 * are not authorized to view all accounts. This method can only be called by system apps.
477 * @param type The type of accounts to return, null to retrieve all accounts
478 * @param packageName The package name of the app for which the accounts are to be returned
479 * @return An array of {@link Account}, one per matching account. Empty
480 * (never null) if no accounts of the specified type have been added.
481 */
482 public Account[] getAccountsByTypeForPackage(String type, String packageName) {
483 try {
484 return mService.getAccountsByTypeForPackage(type, packageName);
485 } catch (RemoteException re) {
486 // possible security exception
487 throw new RuntimeException(re);
488 }
489 }
490
491 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800492 * Lists all accounts of a particular type. The account type is a
493 * string token corresponding to the authenticator and useful domain
494 * of the account. For example, there are types corresponding to Google
495 * and Facebook. The exact string token to use will be published somewhere
496 * associated with the authenticator in question.
497 *
498 * <p>It is safe to call this method from the main thread.
499 *
500 * <p>This method requires the caller to hold the permission
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700501 * {@link android.Manifest.permission#GET_ACCOUNTS} or share a uid with the
502 * authenticator that owns the account type.
Dan Egnor661f0132010-02-19 11:23:00 -0800503 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700504 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
505 * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
506 * or signature match. See docs for this function in API level 22.
507 *
Dan Egnor661f0132010-02-19 11:23:00 -0800508 * @param type The type of accounts to return, null to retrieve all accounts
509 * @return An array of {@link Account}, one per matching account. Empty
510 * (never null) if no accounts of the specified type have been added.
Fred Quintana756b7352009-10-21 13:43:10 -0700511 */
Tor Norbye80b530a2015-04-23 16:36:09 -0700512 @RequiresPermission(GET_ACCOUNTS)
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700513 public Account[] getAccountsByType(String type) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -0800514 return getAccountsByTypeAsUser(type, Process.myUserHandle());
515 }
516
517 /** @hide Same as {@link #getAccountsByType(String)} but for a specific user. */
518 public Account[] getAccountsByTypeAsUser(String type, UserHandle userHandle) {
Fred Quintana60307342009-03-24 22:48:12 -0700519 try {
Amith Yamasani2c7bc262012-11-05 16:46:02 -0800520 return mService.getAccountsAsUser(type, userHandle.getIdentifier());
Fred Quintana60307342009-03-24 22:48:12 -0700521 } catch (RemoteException e) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700522 // won't ever happen
Fred Quintana60307342009-03-24 22:48:12 -0700523 throw new RuntimeException(e);
524 }
525 }
526
Fred Quintana756b7352009-10-21 13:43:10 -0700527 /**
Fred Quintanad9640ec2012-05-23 12:37:00 -0700528 * Change whether or not an app (identified by its uid) is allowed to retrieve an authToken
529 * for an account.
530 * <p>
531 * This is only meant to be used by system activities and is not in the SDK.
532 * @param account The account whose permissions are being modified
533 * @param authTokenType The type of token whose permissions are being modified
534 * @param uid The uid that identifies the app which is being granted or revoked permission.
535 * @param value true is permission is being granted, false for revoked
536 * @hide
537 */
538 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) {
539 try {
540 mService.updateAppPermission(account, authTokenType, uid, value);
541 } catch (RemoteException e) {
542 // won't ever happen
543 throw new RuntimeException(e);
544 }
545 }
546
547 /**
548 * Get the user-friendly label associated with an authenticator's auth token.
549 * @param accountType the type of the authenticator. must not be null.
550 * @param authTokenType the token type. must not be null.
551 * @param callback callback to invoke when the result is available. may be null.
552 * @param handler the handler on which to invoke the callback, or null for the main thread
553 * @return a future containing the label string
554 * @hide
555 */
556 public AccountManagerFuture<String> getAuthTokenLabel(
557 final String accountType, final String authTokenType,
558 AccountManagerCallback<String> callback, Handler handler) {
559 if (accountType == null) throw new IllegalArgumentException("accountType is null");
560 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
561 return new Future2Task<String>(handler, callback) {
562 public void doWork() throws RemoteException {
563 mService.getAuthTokenLabel(mResponse, accountType, authTokenType);
564 }
565
566 @Override
567 public String bundleToResult(Bundle bundle) throws AuthenticatorException {
568 if (!bundle.containsKey(KEY_AUTH_TOKEN_LABEL)) {
569 throw new AuthenticatorException("no result in response");
570 }
571 return bundle.getString(KEY_AUTH_TOKEN_LABEL);
572 }
573 }.start();
574 }
575
576 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800577 * Finds out whether a particular account has all the specified features.
578 * Account features are authenticator-specific string tokens identifying
579 * boolean account properties. For example, features are used to tell
580 * whether Google accounts have a particular service (such as Google
581 * Calendar or Google Talk) enabled. The feature names and their meanings
582 * are published somewhere associated with the authenticator in question.
583 *
584 * <p>This method may be called from any thread, but the returned
585 * {@link AccountManagerFuture} must not be used on the main thread.
586 *
587 * <p>This method requires the caller to hold the permission
588 * {@link android.Manifest.permission#GET_ACCOUNTS}.
Fred Quintanabb68a4f2010-01-13 17:28:39 -0800589 *
590 * @param account The {@link Account} to test
Dan Egnor661f0132010-02-19 11:23:00 -0800591 * @param features An array of the account features to check
592 * @param callback Callback to invoke when the request completes,
593 * null for no callback
594 * @param handler {@link Handler} identifying the callback thread,
595 * null for the main thread
596 * @return An {@link AccountManagerFuture} which resolves to a Boolean,
597 * true if the account exists and has all of the specified features.
Fred Quintanabb68a4f2010-01-13 17:28:39 -0800598 */
Tor Norbye80b530a2015-04-23 16:36:09 -0700599 @RequiresPermission(GET_ACCOUNTS)
Fred Quintana3084a6f2010-01-14 18:02:03 -0800600 public AccountManagerFuture<Boolean> hasFeatures(final Account account,
Fred Quintanabb68a4f2010-01-13 17:28:39 -0800601 final String[] features,
602 AccountManagerCallback<Boolean> callback, Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -0700603 if (account == null) throw new IllegalArgumentException("account is null");
604 if (features == null) throw new IllegalArgumentException("features is null");
Fred Quintanabb68a4f2010-01-13 17:28:39 -0800605 return new Future2Task<Boolean>(handler, callback) {
606 public void doWork() throws RemoteException {
Fred Quintana3084a6f2010-01-14 18:02:03 -0800607 mService.hasFeatures(mResponse, account, features);
Fred Quintanabb68a4f2010-01-13 17:28:39 -0800608 }
609 public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
610 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
611 throw new AuthenticatorException("no result in response");
612 }
613 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
614 }
615 }.start();
616 }
617
618 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800619 * Lists all accounts of a type which have certain features. The account
620 * type identifies the authenticator (see {@link #getAccountsByType}).
621 * Account features are authenticator-specific string tokens identifying
622 * boolean account properties (see {@link #hasFeatures}).
Fred Quintana756b7352009-10-21 13:43:10 -0700623 *
Dan Egnor661f0132010-02-19 11:23:00 -0800624 * <p>Unlike {@link #getAccountsByType}, this method calls the authenticator,
625 * which may contact the server or do other work to check account features,
626 * so the method returns an {@link AccountManagerFuture}.
Fred Quintanaa698f422009-04-08 19:14:54 -0700627 *
Dan Egnor661f0132010-02-19 11:23:00 -0800628 * <p>This method may be called from any thread, but the returned
629 * {@link AccountManagerFuture} must not be used on the main thread.
Fred Quintana756b7352009-10-21 13:43:10 -0700630 *
Dan Egnor661f0132010-02-19 11:23:00 -0800631 * <p>This method requires the caller to hold the permission
Carlos Valdiviac37ee222015-06-17 20:17:37 -0700632 * {@link android.Manifest.permission#GET_ACCOUNTS} or share a uid with the
633 * authenticator that owns the account type.
Fred Quintana756b7352009-10-21 13:43:10 -0700634 *
Dan Egnor661f0132010-02-19 11:23:00 -0800635 * @param type The type of accounts to return, must not be null
636 * @param features An array of the account features to require,
637 * may be null or empty
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700638 *
639 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
640 * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
641 * or signature match. See docs for this function in API level 22.
642 *
Dan Egnor661f0132010-02-19 11:23:00 -0800643 * @param callback Callback to invoke when the request completes,
644 * null for no callback
645 * @param handler {@link Handler} identifying the callback thread,
646 * null for the main thread
647 * @return An {@link AccountManagerFuture} which resolves to an array of
648 * {@link Account}, one per account of the specified type which
649 * matches the requested features.
Fred Quintana8570f742010-02-18 10:32:54 -0800650 */
Tor Norbye80b530a2015-04-23 16:36:09 -0700651 @RequiresPermission(GET_ACCOUNTS)
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700652 public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
653 final String type, final String[] features,
654 AccountManagerCallback<Account[]> callback, Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -0700655 if (type == null) throw new IllegalArgumentException("type is null");
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700656 return new Future2Task<Account[]>(handler, callback) {
657 public void doWork() throws RemoteException {
658 mService.getAccountsByFeatures(mResponse, type, features);
659 }
660 public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700661 if (!bundle.containsKey(KEY_ACCOUNTS)) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700662 throw new AuthenticatorException("no result in response");
663 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700664 final Parcelable[] parcelables = bundle.getParcelableArray(KEY_ACCOUNTS);
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700665 Account[] descs = new Account[parcelables.length];
666 for (int i = 0; i < parcelables.length; i++) {
667 descs[i] = (Account) parcelables[i];
668 }
669 return descs;
670 }
671 }.start();
672 }
673
Fred Quintana756b7352009-10-21 13:43:10 -0700674 /**
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -0700675 * Adds an account directly to the AccountManager. Normally used by sign-up
Dan Egnor661f0132010-02-19 11:23:00 -0800676 * wizards associated with authenticators, not directly by applications.
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -0700677 * <p>Calling this method does not update the last authenticated timestamp,
678 * referred by {@link #KEY_LAST_AUTHENTICATED_TIME}. To update it, call
679 * {@link #notifyAccountAuthenticated(Account)} after getting success.
680 * However, if this method is called when it is triggered by addAccount() or
681 * addAccountAsUser() or similar functions, then there is no need to update
682 * timestamp manually as it is updated automatically by framework on
683 * successful completion of the mentioned functions.
Dan Egnor661f0132010-02-19 11:23:00 -0800684 * <p>It is safe to call this method from the main thread.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700685 * <p>This method requires the caller to have a signature match with the
686 * authenticator that owns the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -0800687 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700688 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
689 * AUTHENTICATE_ACCOUNTS permission is needed for those platforms. See docs
690 * for this function in API level 22.
691 *
Dan Egnor661f0132010-02-19 11:23:00 -0800692 * @param account The {@link Account} to add
693 * @param password The password to associate with the account, null for none
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -0700694 * @param userdata String values to use for the account's userdata, null for
695 * none
Dan Egnor8e4378b2010-08-02 18:22:09 -0700696 * @return True if the account was successfully added, false if the account
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -0700697 * already exists, the account is null, or another error occurs.
Dan Egnor661f0132010-02-19 11:23:00 -0800698 */
699 public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
Fred Quintana382601f2010-03-25 12:25:10 -0700700 if (account == null) throw new IllegalArgumentException("account is null");
Dan Egnor661f0132010-02-19 11:23:00 -0800701 try {
Amith Yamasani27db4682013-03-30 17:07:47 -0700702 return mService.addAccountExplicitly(account, password, userdata);
Dan Egnor661f0132010-02-19 11:23:00 -0800703 } catch (RemoteException e) {
704 // won't ever happen
705 throw new RuntimeException(e);
706 }
707 }
708
709 /**
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -0700710 * Notifies the system that the account has just been authenticated. This
711 * information may be used by other applications to verify the account. This
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800712 * should be called only when the user has entered correct credentials for
713 * the account.
714 * <p>
715 * It is not safe to call this method from the main thread. As such, call it
716 * from another thread.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700717 * <p>This method requires the caller to have a signature match with the
718 * authenticator that owns the specified account.
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800719 *
720 * @param account The {@link Account} to be updated.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700721 * @return boolean {@code true} if the authentication of the account has been successfully
722 * acknowledged. Otherwise {@code false}.
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800723 */
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -0700724 public boolean notifyAccountAuthenticated(Account account) {
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -0800725 if (account == null)
726 throw new IllegalArgumentException("account is null");
727 try {
728 return mService.accountAuthenticated(account);
729 } catch (RemoteException e) {
730 throw new RuntimeException(e);
731 }
732 }
733
734 /**
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700735 * Rename the specified {@link Account}. This is equivalent to removing
736 * the existing account and adding a new renamed account with the old
737 * account's user data.
738 *
739 * <p>It is safe to call this method from the main thread.
740 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700741 * <p>This method requires the caller to have a signature match with the
742 * authenticator that manages the specified account.
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700743 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700744 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
745 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
746 * is needed for those platforms. See docs for this function in API level 22.
747 *
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700748 * @param account The {@link Account} to rename
749 * @param newName String name to be associated with the account.
750 * @param callback Callback to invoke when the request completes, null for
751 * no callback
752 * @param handler {@link Handler} identifying the callback thread, null for
753 * the main thread
754 * @return An {@link AccountManagerFuture} which resolves to the Account
755 * after the name change. If successful the account's name will be the
756 * specified new name.
757 */
758 public AccountManagerFuture<Account> renameAccount(
759 final Account account,
Tor Norbye80b530a2015-04-23 16:36:09 -0700760 @Size(min = 1) final String newName,
Carlos Valdiviaf193b9a2014-07-18 01:34:57 -0700761 AccountManagerCallback<Account> callback,
762 Handler handler) {
763 if (account == null) throw new IllegalArgumentException("account is null.");
764 if (TextUtils.isEmpty(newName)) {
765 throw new IllegalArgumentException("newName is empty or null.");
766 }
767 return new Future2Task<Account>(handler, callback) {
768 @Override
769 public void doWork() throws RemoteException {
770 mService.renameAccount(mResponse, account, newName);
771 }
772 @Override
773 public Account bundleToResult(Bundle bundle) throws AuthenticatorException {
774 String name = bundle.getString(KEY_ACCOUNT_NAME);
775 String type = bundle.getString(KEY_ACCOUNT_TYPE);
776 return new Account(name, type);
777 }
778 }.start();
779 }
780
781 /**
782 * Gets the previous name associated with the account or {@code null}, if
783 * none. This is intended so that clients of {@link
784 * #LOGIN_ACCOUNTS_CHANGED_ACTION} broadcasts can determine if an
785 * authenticator has renamed an account.
786 *
787 * <p>It is safe to call this method from the main thread.
788 *
789 * @param account The account to query for a previous name.
790 * @return The account's previous name, null if the account has never been
791 * renamed.
792 */
793 public String getPreviousName(final Account account) {
794 if (account == null) throw new IllegalArgumentException("account is null");
795 try {
796 return mService.getPreviousName(account);
797 } catch (RemoteException e) {
798 // will never happen
799 throw new RuntimeException(e);
800 }
801 }
802
803 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800804 * Removes an account from the AccountManager. Does nothing if the account
805 * does not exist. Does not delete the account from the server.
806 * The authenticator may have its own policies preventing account
807 * deletion, in which case the account will not be deleted.
808 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700809 * <p>This method requires the caller to have a signature match with the
810 * authenticator that manages the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -0800811 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700812 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
813 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
814 * this function in API level 22.
815 *
Dan Egnor661f0132010-02-19 11:23:00 -0800816 * @param account The {@link Account} to remove
817 * @param callback Callback to invoke when the request completes,
818 * null for no callback
819 * @param handler {@link Handler} identifying the callback thread,
820 * null for the main thread
821 * @return An {@link AccountManagerFuture} which resolves to a Boolean,
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100822 * true if the account has been successfully removed
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800823 * @deprecated use
824 * {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)}
825 * instead
Dan Egnor661f0132010-02-19 11:23:00 -0800826 */
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800827 @Deprecated
Dan Egnor661f0132010-02-19 11:23:00 -0800828 public AccountManagerFuture<Boolean> removeAccount(final Account account,
829 AccountManagerCallback<Boolean> callback, Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -0700830 if (account == null) throw new IllegalArgumentException("account is null");
Dan Egnor661f0132010-02-19 11:23:00 -0800831 return new Future2Task<Boolean>(handler, callback) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700832 @Override
Dan Egnor661f0132010-02-19 11:23:00 -0800833 public void doWork() throws RemoteException {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800834 mService.removeAccount(mResponse, account, false);
Dan Egnor661f0132010-02-19 11:23:00 -0800835 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700836 @Override
Dan Egnor661f0132010-02-19 11:23:00 -0800837 public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
838 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
839 throw new AuthenticatorException("no result in response");
840 }
841 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
842 }
843 }.start();
844 }
845
846 /**
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800847 * Removes an account from the AccountManager. Does nothing if the account
848 * does not exist. Does not delete the account from the server.
849 * The authenticator may have its own policies preventing account
850 * deletion, in which case the account will not be deleted.
851 *
852 * <p>This method may be called from any thread, but the returned
853 * {@link AccountManagerFuture} must not be used on the main thread.
854 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700855 * <p>This method requires the caller to have a signature match with the
856 * authenticator that manages the specified account.
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800857 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700858 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
859 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
860 * this function in API level 22.
861 *
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800862 * @param account The {@link Account} to remove
863 * @param activity The {@link Activity} context to use for launching a new
864 * authenticator-defined sub-Activity to prompt the user to delete an
865 * account; used only to call startActivity(); if null, the prompt
866 * will not be launched directly, but the {@link Intent} may be
867 * returned to the caller instead
868 * @param callback Callback to invoke when the request completes,
869 * null for no callback
870 * @param handler {@link Handler} identifying the callback thread,
871 * null for the main thread
872 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
873 * {@link #KEY_BOOLEAN_RESULT} if activity was specified and an account
874 * was removed or if active. If no activity was specified, the returned
875 * Bundle contains only {@link #KEY_INTENT} with the {@link Intent}
876 * needed to launch the actual account removal process, if authenticator
877 * needs the activity launch. If an error occurred,
878 * {@link AccountManagerFuture#getResult()} throws:
879 * <ul>
880 * <li> {@link AuthenticatorException} if no authenticator was registered for
881 * this account type or the authenticator failed to respond
882 * <li> {@link OperationCanceledException} if the operation was canceled for
883 * any reason, including the user canceling the creation process or
884 * adding accounts (of this type) has been disabled by policy
885 * </ul>
886 */
887 public AccountManagerFuture<Bundle> removeAccount(final Account account,
888 final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
889 if (account == null) throw new IllegalArgumentException("account is null");
890 return new AmsTask(activity, handler, callback) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700891 @Override
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800892 public void doWork() throws RemoteException {
893 mService.removeAccount(mResponse, account, activity != null);
894 }
895 }.start();
896 }
897
898 /**
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100899 * @see #removeAccount(Account, AccountManagerCallback, Handler)
900 * @hide
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800901 * @deprecated use
902 * {@link #removeAccountAsUser(Account, Activity, AccountManagerCallback, Handler)}
903 * instead
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100904 */
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800905 @Deprecated
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100906 public AccountManagerFuture<Boolean> removeAccountAsUser(final Account account,
907 AccountManagerCallback<Boolean> callback, Handler handler,
908 final UserHandle userHandle) {
909 if (account == null) throw new IllegalArgumentException("account is null");
910 if (userHandle == null) throw new IllegalArgumentException("userHandle is null");
911 return new Future2Task<Boolean>(handler, callback) {
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700912 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100913 public void doWork() throws RemoteException {
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800914 mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier());
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100915 }
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700916 @Override
Alexandra Gherghina999d3942014-07-03 11:40:08 +0100917 public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
918 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
919 throw new AuthenticatorException("no result in response");
920 }
921 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
922 }
923 }.start();
924 }
925
926 /**
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800927 * @see #removeAccount(Account, Activity, AccountManagerCallback, Handler)
928 * @hide
929 */
930 public AccountManagerFuture<Bundle> removeAccountAsUser(final Account account,
931 final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler,
932 final UserHandle userHandle) {
933 if (account == null)
934 throw new IllegalArgumentException("account is null");
935 if (userHandle == null)
936 throw new IllegalArgumentException("userHandle is null");
937 return new AmsTask(activity, handler, callback) {
938 public void doWork() throws RemoteException {
939 mService.removeAccountAsUser(mResponse, account, activity != null,
940 userHandle.getIdentifier());
941 }
942 }.start();
943 }
944
945 /**
946 * Removes an account directly. Normally used by authenticators, not
947 * directly by applications. Does not delete the account from the server.
948 * The authenticator may have its own policies preventing account deletion,
949 * in which case the account will not be deleted.
950 * <p>
951 * It is safe to call this method from the main thread.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -0700952 * <p>This method requires the caller to have a signature match with the
953 * authenticator that manages the specified account.
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800954 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700955 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
956 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
957 * is needed for those platforms. See docs for this function in API level 22.
958 *
Simranjit Singh Kohli8778f992014-11-05 21:33:55 -0800959 * @param account The {@link Account} to delete.
960 * @return True if the account was successfully deleted, false if the
961 * account did not exist, the account is null, or another error
962 * occurs.
963 */
964 public boolean removeAccountExplicitly(Account account) {
965 if (account == null) throw new IllegalArgumentException("account is null");
966 try {
967 return mService.removeAccountExplicitly(account);
968 } catch (RemoteException e) {
969 // won't ever happen
970 throw new RuntimeException(e);
971 }
972 }
973
974 /**
Dan Egnor661f0132010-02-19 11:23:00 -0800975 * Removes an auth token from the AccountManager's cache. Does nothing if
976 * the auth token is not currently in the cache. Applications must call this
977 * method when the auth token is found to have expired or otherwise become
978 * invalid for authenticating requests. The AccountManager does not validate
979 * or expire cached auth tokens otherwise.
980 *
981 * <p>It is safe to call this method from the main thread.
982 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -0700983 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
984 * MANAGE_ACCOUNTS or USE_CREDENTIALS permission is needed for those
985 * platforms. See docs for this function in API level 22.
986 *
Fred Quintanaf35b68f2010-04-01 11:36:00 -0700987 * @param accountType The account type of the auth token to invalidate, must not be null
988 * @param authToken The auth token to invalidate, may be null
Dan Egnor661f0132010-02-19 11:23:00 -0800989 */
990 public void invalidateAuthToken(final String accountType, final String authToken) {
Fred Quintana382601f2010-03-25 12:25:10 -0700991 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Dan Egnor661f0132010-02-19 11:23:00 -0800992 try {
Fred Quintanaf35b68f2010-04-01 11:36:00 -0700993 if (authToken != null) {
994 mService.invalidateAuthToken(accountType, authToken);
995 }
Dan Egnor661f0132010-02-19 11:23:00 -0800996 } catch (RemoteException e) {
997 // won't ever happen
998 throw new RuntimeException(e);
999 }
1000 }
1001
1002 /**
1003 * Gets an auth token from the AccountManager's cache. If no auth
1004 * token is cached for this account, null will be returned -- a new
1005 * auth token will not be generated, and the server will not be contacted.
1006 * Intended for use by the authenticator, not directly by applications.
1007 *
1008 * <p>It is safe to call this method from the main thread.
1009 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001010 * <p>This method requires the caller to have a signature match with the
1011 * authenticator that manages the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -08001012 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001013 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1014 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
1015 * is needed for those platforms. See docs for this function in API level 22.
1016 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001017 * @param account The account for which an auth token is to be fetched. Cannot be {@code null}.
1018 * @param authTokenType The type of auth token to fetch. Cannot be {@code null}.
Dan Egnor661f0132010-02-19 11:23:00 -08001019 * @return The cached auth token for this account and type, or null if
1020 * no auth token is cached or the account does not exist.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001021 * @see #getAuthToken
Dan Egnor661f0132010-02-19 11:23:00 -08001022 */
1023 public String peekAuthToken(final Account account, final String authTokenType) {
Fred Quintana382601f2010-03-25 12:25:10 -07001024 if (account == null) throw new IllegalArgumentException("account is null");
1025 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001026 try {
1027 return mService.peekAuthToken(account, authTokenType);
1028 } catch (RemoteException e) {
1029 // won't ever happen
1030 throw new RuntimeException(e);
1031 }
1032 }
1033
1034 /**
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07001035 * Sets or forgets a saved password. This modifies the local copy of the
1036 * password used to automatically authenticate the user; it does not change
1037 * the user's account password on the server. Intended for use by the
1038 * authenticator, not directly by applications.
1039 * <p>Calling this method does not update the last authenticated timestamp,
1040 * referred by {@link #KEY_LAST_AUTHENTICATED_TIME}. To update it, call
1041 * {@link #notifyAccountAuthenticated(Account)} after getting success.
Dan Egnor661f0132010-02-19 11:23:00 -08001042 * <p>It is safe to call this method from the main thread.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001043 * <p>This method requires the caller to have a signature match with the
1044 * authenticator that manages the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -08001045 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001046 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1047 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
1048 * is needed for those platforms. See docs for this function in API level 22.
1049 *
Simranjit Singh Kohli0b8a7c02015-06-19 12:45:27 -07001050 * @param account The account whose password is to be set. Cannot be
1051 * {@code null}.
Dan Egnor661f0132010-02-19 11:23:00 -08001052 * @param password The password to set, null to clear the password
1053 */
1054 public void setPassword(final Account account, final String password) {
Fred Quintana382601f2010-03-25 12:25:10 -07001055 if (account == null) throw new IllegalArgumentException("account is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001056 try {
1057 mService.setPassword(account, password);
1058 } catch (RemoteException e) {
1059 // won't ever happen
1060 throw new RuntimeException(e);
1061 }
1062 }
1063
1064 /**
1065 * Forgets a saved password. This erases the local copy of the password;
1066 * it does not change the user's account password on the server.
1067 * Has the same effect as setPassword(account, null) but requires fewer
1068 * permissions, and may be used by applications or management interfaces
1069 * to "sign out" from an account.
1070 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001071 * <p>This method only successfully clear the account's password when the
1072 * caller has the same signature as the authenticator that owns the
1073 * specified account. Otherwise, this method will silently fail.
Dan Egnor661f0132010-02-19 11:23:00 -08001074 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001075 * <p>It is safe to call this method from the main thread.
Carlos Valdiviadcddc472015-06-11 20:04:04 +00001076 *
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 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
1079 * this function in API level 22.
1080 *
Dan Egnor661f0132010-02-19 11:23:00 -08001081 * @param account The account whose password to clear
1082 */
1083 public void clearPassword(final Account account) {
Fred Quintana382601f2010-03-25 12:25:10 -07001084 if (account == null) throw new IllegalArgumentException("account is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001085 try {
1086 mService.clearPassword(account);
1087 } catch (RemoteException e) {
1088 // won't ever happen
1089 throw new RuntimeException(e);
1090 }
1091 }
1092
1093 /**
1094 * Sets one userdata key for an account. Intended by use for the
1095 * authenticator to stash state for itself, not directly by applications.
1096 * The meaning of the keys and values is up to the authenticator.
1097 *
1098 * <p>It is safe to call this method from the main thread.
1099 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001100 * <p>This method requires the caller to have a signature match with the
1101 * authenticator that manages the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -08001102 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001103 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1104 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
1105 * is needed for those platforms. See docs for this function in API level 22.
1106 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001107 * @param account Account whose user data is to be set. Must not be {@code null}.
1108 * @param key String user data key to set. Must not be null
1109 * @param value String value to set, {@code null} to clear this user data key
Dan Egnor661f0132010-02-19 11:23:00 -08001110 */
1111 public void setUserData(final Account account, final String key, final String value) {
Fred Quintana382601f2010-03-25 12:25:10 -07001112 if (account == null) throw new IllegalArgumentException("account is null");
1113 if (key == null) throw new IllegalArgumentException("key is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001114 try {
1115 mService.setUserData(account, key, value);
1116 } catch (RemoteException e) {
1117 // won't ever happen
1118 throw new RuntimeException(e);
1119 }
1120 }
1121
1122 /**
1123 * Adds an auth token to the AccountManager cache for an account.
1124 * If the account does not exist then this call has no effect.
1125 * Replaces any previous auth token for this account and auth token type.
1126 * Intended for use by the authenticator, not directly by applications.
1127 *
1128 * <p>It is safe to call this method from the main thread.
1129 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001130 * <p>This method requires the caller to have a signature match with the
1131 * authenticator that manages the specified account.
Dan Egnor661f0132010-02-19 11:23:00 -08001132 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001133 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1134 * AUTHENTICATE_ACCOUNTS permission and same UID as account's authenticator
1135 * is needed for those platforms. See docs for this function in API level 22.
1136 *
Dan Egnor661f0132010-02-19 11:23:00 -08001137 * @param account The account to set an auth token for
1138 * @param authTokenType The type of the auth token, see {#getAuthToken}
1139 * @param authToken The auth token to add to the cache
1140 */
1141 public void setAuthToken(Account account, final String authTokenType, final String authToken) {
Fred Quintana382601f2010-03-25 12:25:10 -07001142 if (account == null) throw new IllegalArgumentException("account is null");
1143 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001144 try {
1145 mService.setAuthToken(account, authTokenType, authToken);
1146 } catch (RemoteException e) {
1147 // won't ever happen
1148 throw new RuntimeException(e);
1149 }
1150 }
1151
1152 /**
1153 * This convenience helper synchronously gets an auth token with
1154 * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, Handler)}.
1155 *
1156 * <p>This method may block while a network request completes, and must
1157 * never be made from the main thread.
1158 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001159 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1160 * USE_CREDENTIALS permission is needed for those platforms. See docs for
1161 * this function in API level 22.
1162 *
Dan Egnor661f0132010-02-19 11:23:00 -08001163 * @param account The account to fetch an auth token for
Joe Malinb6a35262013-06-03 09:49:04 -07001164 * @param authTokenType The auth token type, see {@link #getAuthToken getAuthToken()}
Dan Egnor661f0132010-02-19 11:23:00 -08001165 * @param notifyAuthFailure If true, display a notification and return null
1166 * if authentication fails; if false, prompt and wait for the user to
1167 * re-enter correct credentials before returning
1168 * @return An auth token of the specified type for this account, or null
1169 * if authentication fails or none can be fetched.
1170 * @throws AuthenticatorException if the authenticator failed to respond
1171 * @throws OperationCanceledException if the request was canceled for any
1172 * reason, including the user canceling a credential request
1173 * @throws java.io.IOException if the authenticator experienced an I/O problem
1174 * creating a new auth token, usually because of network trouble
1175 */
1176 public String blockingGetAuthToken(Account account, String authTokenType,
1177 boolean notifyAuthFailure)
1178 throws OperationCanceledException, IOException, AuthenticatorException {
Fred Quintana382601f2010-03-25 12:25:10 -07001179 if (account == null) throw new IllegalArgumentException("account is null");
1180 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001181 Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */,
1182 null /* handler */).getResult();
Fred Quintana96580e02010-03-04 13:42:42 -08001183 if (bundle == null) {
1184 // This should never happen, but it does, occasionally. If it does return null to
1185 // signify that we were not able to get the authtoken.
1186 // TODO: remove this when the bug is found that sometimes causes a null bundle to be
1187 // returned
1188 Log.e(TAG, "blockingGetAuthToken: null was returned from getResult() for "
1189 + account + ", authTokenType " + authTokenType);
1190 return null;
1191 }
Dan Egnor661f0132010-02-19 11:23:00 -08001192 return bundle.getString(KEY_AUTHTOKEN);
1193 }
1194
1195 /**
1196 * Gets an auth token of the specified type for a particular account,
1197 * prompting the user for credentials if necessary. This method is
1198 * intended for applications running in the foreground where it makes
1199 * sense to ask the user directly for a password.
1200 *
1201 * <p>If a previously generated auth token is cached for this account and
Dan Egnor8e4378b2010-08-02 18:22:09 -07001202 * type, then it is returned. Otherwise, if a saved password is
1203 * available, it is sent to the server to generate a new auth token.
1204 * Otherwise, the user is prompted to enter a password.
Dan Egnor661f0132010-02-19 11:23:00 -08001205 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07001206 * <p>Some authenticators have auth token <em>types</em>, whose value
1207 * is authenticator-dependent. Some services use different token types to
1208 * access different functionality -- for example, Google uses different auth
1209 * tokens to access Gmail and Google Calendar for the same account.
Dan Egnor661f0132010-02-19 11:23:00 -08001210 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001211 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1212 * USE_CREDENTIALS permission is needed for those platforms. See docs for
1213 * this function in API level 22.
1214 *
Dan Egnor661f0132010-02-19 11:23:00 -08001215 * <p>This method may be called from any thread, but the returned
1216 * {@link AccountManagerFuture} must not be used on the main thread.
1217 *
Dan Egnor661f0132010-02-19 11:23:00 -08001218 * @param account The account to fetch an auth token for
1219 * @param authTokenType The auth token type, an authenticator-dependent
1220 * string token, must not be null
1221 * @param options Authenticator-specific options for the request,
1222 * may be null or empty
1223 * @param activity The {@link Activity} context to use for launching a new
1224 * authenticator-defined sub-Activity to prompt the user for a password
1225 * if necessary; used only to call startActivity(); must not be null.
1226 * @param callback Callback to invoke when the request completes,
1227 * null for no callback
1228 * @param handler {@link Handler} identifying the callback thread,
1229 * null for the main thread
1230 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
1231 * at least the following fields:
Fred Quintana756b7352009-10-21 13:43:10 -07001232 * <ul>
Dan Egnor661f0132010-02-19 11:23:00 -08001233 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
1234 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1235 * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
Fred Quintana756b7352009-10-21 13:43:10 -07001236 * </ul>
Dan Egnor661f0132010-02-19 11:23:00 -08001237 *
1238 * (Other authenticator-specific values may be returned.) If an auth token
1239 * could not be fetched, {@link AccountManagerFuture#getResult()} throws:
1240 * <ul>
1241 * <li> {@link AuthenticatorException} if the authenticator failed to respond
1242 * <li> {@link OperationCanceledException} if the operation is canceled for
1243 * any reason, incluidng the user canceling a credential request
1244 * <li> {@link IOException} if the authenticator experienced an I/O problem
1245 * creating a new auth token, usually because of network trouble
1246 * </ul>
Dan Egnor8e4378b2010-08-02 18:22:09 -07001247 * If the account is no longer present on the device, the return value is
1248 * authenticator-dependent. The caller should verify the validity of the
1249 * account before requesting an auth token.
Dan Egnor661f0132010-02-19 11:23:00 -08001250 */
1251 public AccountManagerFuture<Bundle> getAuthToken(
1252 final Account account, final String authTokenType, final Bundle options,
1253 final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -07001254 if (account == null) throw new IllegalArgumentException("account is null");
Dan Egnor661f0132010-02-19 11:23:00 -08001255 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Costin Manolachee5847ad2011-09-14 12:52:19 -07001256 final Bundle optionsIn = new Bundle();
1257 if (options != null) {
1258 optionsIn.putAll(options);
1259 }
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001260 optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
Dan Egnor661f0132010-02-19 11:23:00 -08001261 return new AmsTask(activity, handler, callback) {
1262 public void doWork() throws RemoteException {
1263 mService.getAuthToken(mResponse, account, authTokenType,
1264 false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001265 optionsIn);
Dan Egnor661f0132010-02-19 11:23:00 -08001266 }
1267 }.start();
1268 }
1269
1270 /**
1271 * Gets an auth token of the specified type for a particular account,
1272 * optionally raising a notification if the user must enter credentials.
1273 * This method is intended for background tasks and services where the
1274 * user should not be immediately interrupted with a password prompt.
1275 *
1276 * <p>If a previously generated auth token is cached for this account and
Dan Egnor8e4378b2010-08-02 18:22:09 -07001277 * type, then it is returned. Otherwise, if a saved password is
1278 * available, it is sent to the server to generate a new auth token.
1279 * Otherwise, an {@link Intent} is returned which, when started, will
1280 * prompt the user for a password. If the notifyAuthFailure parameter is
1281 * set, a status bar notification is also created with the same Intent,
Dan Egnor661f0132010-02-19 11:23:00 -08001282 * alerting the user that they need to enter a password at some point.
1283 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07001284 * <p>In that case, you may need to wait until the user responds, which
1285 * could take hours or days or forever. When the user does respond and
1286 * supply a new password, the account manager will broadcast the
1287 * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
1288 * use to try again.
Dan Egnor661f0132010-02-19 11:23:00 -08001289 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07001290 * <p>If notifyAuthFailure is not set, it is the application's
1291 * responsibility to launch the returned Intent at some point.
1292 * Either way, the result from this call will not wait for user action.
Dan Egnor661f0132010-02-19 11:23:00 -08001293 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07001294 * <p>Some authenticators have auth token <em>types</em>, whose value
1295 * is authenticator-dependent. Some services use different token types to
1296 * access different functionality -- for example, Google uses different auth
1297 * tokens to access Gmail and Google Calendar for the same account.
Dan Egnor661f0132010-02-19 11:23:00 -08001298 *
1299 * <p>This method may be called from any thread, but the returned
1300 * {@link AccountManagerFuture} must not be used on the main thread.
1301 *
Dan Egnor661f0132010-02-19 11:23:00 -08001302 * @param account The account to fetch an auth token for
1303 * @param authTokenType The auth token type, an authenticator-dependent
1304 * string token, must not be null
Dan Egnor661f0132010-02-19 11:23:00 -08001305 * @param notifyAuthFailure True to add a notification to prompt the
1306 * user for a password if necessary, false to leave that to the caller
1307 * @param callback Callback to invoke when the request completes,
1308 * null for no callback
1309 * @param handler {@link Handler} identifying the callback thread,
1310 * null for the main thread
1311 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
1312 * at least the following fields on success:
1313 * <ul>
1314 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
1315 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1316 * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
1317 * </ul>
1318 *
1319 * (Other authenticator-specific values may be returned.) If the user
1320 * must enter credentials, the returned Bundle contains only
1321 * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
1322 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07001323 * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
Dan Egnor661f0132010-02-19 11:23:00 -08001324 * <ul>
1325 * <li> {@link AuthenticatorException} if the authenticator failed to respond
1326 * <li> {@link OperationCanceledException} if the operation is canceled for
1327 * any reason, incluidng the user canceling a credential request
1328 * <li> {@link IOException} if the authenticator experienced an I/O problem
1329 * creating a new auth token, usually because of network trouble
1330 * </ul>
Dan Egnor8e4378b2010-08-02 18:22:09 -07001331 * If the account is no longer present on the device, the return value is
1332 * authenticator-dependent. The caller should verify the validity of the
1333 * account before requesting an auth token.
Fred Quintanaad93a322011-09-08 13:21:01 -07001334 * @deprecated use {@link #getAuthToken(Account, String, android.os.Bundle,
1335 * boolean, AccountManagerCallback, android.os.Handler)} instead
Dan Egnor661f0132010-02-19 11:23:00 -08001336 */
Fred Quintanaad93a322011-09-08 13:21:01 -07001337 @Deprecated
Dan Egnor661f0132010-02-19 11:23:00 -08001338 public AccountManagerFuture<Bundle> getAuthToken(
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001339 final Account account, final String authTokenType,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001340 final boolean notifyAuthFailure,
Dan Egnor661f0132010-02-19 11:23:00 -08001341 AccountManagerCallback<Bundle> callback, Handler handler) {
Jatin Lodhia3df7d692013-03-27 10:57:23 -07001342 return getAuthToken(account, authTokenType, null, notifyAuthFailure, callback,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001343 handler);
Dan Egnor661f0132010-02-19 11:23:00 -08001344 }
1345
1346 /**
Fred Quintanaad93a322011-09-08 13:21:01 -07001347 * Gets an auth token of the specified type for a particular account,
1348 * optionally raising a notification if the user must enter credentials.
1349 * This method is intended for background tasks and services where the
1350 * user should not be immediately interrupted with a password prompt.
1351 *
1352 * <p>If a previously generated auth token is cached for this account and
1353 * type, then it is returned. Otherwise, if a saved password is
1354 * available, it is sent to the server to generate a new auth token.
1355 * Otherwise, an {@link Intent} is returned which, when started, will
1356 * prompt the user for a password. If the notifyAuthFailure parameter is
1357 * set, a status bar notification is also created with the same Intent,
1358 * alerting the user that they need to enter a password at some point.
1359 *
1360 * <p>In that case, you may need to wait until the user responds, which
1361 * could take hours or days or forever. When the user does respond and
1362 * supply a new password, the account manager will broadcast the
1363 * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
1364 * use to try again.
1365 *
1366 * <p>If notifyAuthFailure is not set, it is the application's
1367 * responsibility to launch the returned Intent at some point.
1368 * Either way, the result from this call will not wait for user action.
1369 *
1370 * <p>Some authenticators have auth token <em>types</em>, whose value
1371 * is authenticator-dependent. Some services use different token types to
1372 * access different functionality -- for example, Google uses different auth
1373 * tokens to access Gmail and Google Calendar for the same account.
1374 *
1375 * <p>This method may be called from any thread, but the returned
1376 * {@link AccountManagerFuture} must not be used on the main thread.
1377 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001378 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1379 * USE_CREDENTIALS permission is needed for those platforms. See docs for
1380 * this function in API level 22.
1381 *
Fred Quintanaad93a322011-09-08 13:21:01 -07001382 * @param account The account to fetch an auth token for
1383 * @param authTokenType The auth token type, an authenticator-dependent
1384 * string token, must not be null
1385 * @param options Authenticator-specific options for the request,
1386 * may be null or empty
1387 * @param notifyAuthFailure True to add a notification to prompt the
1388 * user for a password if necessary, false to leave that to the caller
1389 * @param callback Callback to invoke when the request completes,
1390 * null for no callback
1391 * @param handler {@link Handler} identifying the callback thread,
1392 * null for the main thread
1393 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
1394 * at least the following fields on success:
1395 * <ul>
1396 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
1397 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1398 * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
1399 * </ul>
1400 *
1401 * (Other authenticator-specific values may be returned.) If the user
1402 * must enter credentials, the returned Bundle contains only
1403 * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
1404 *
1405 * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
1406 * <ul>
1407 * <li> {@link AuthenticatorException} if the authenticator failed to respond
1408 * <li> {@link OperationCanceledException} if the operation is canceled for
1409 * any reason, incluidng the user canceling a credential request
1410 * <li> {@link IOException} if the authenticator experienced an I/O problem
1411 * creating a new auth token, usually because of network trouble
1412 * </ul>
1413 * If the account is no longer present on the device, the return value is
1414 * authenticator-dependent. The caller should verify the validity of the
1415 * account before requesting an auth token.
1416 */
1417 public AccountManagerFuture<Bundle> getAuthToken(
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001418 final Account account, final String authTokenType, final Bundle options,
1419 final boolean notifyAuthFailure,
Fred Quintanaad93a322011-09-08 13:21:01 -07001420 AccountManagerCallback<Bundle> callback, Handler handler) {
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001421
Fred Quintanaad93a322011-09-08 13:21:01 -07001422 if (account == null) throw new IllegalArgumentException("account is null");
1423 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Costin Manolachee5847ad2011-09-14 12:52:19 -07001424 final Bundle optionsIn = new Bundle();
1425 if (options != null) {
1426 optionsIn.putAll(options);
1427 }
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001428 optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
Fred Quintanaad93a322011-09-08 13:21:01 -07001429 return new AmsTask(null, handler, callback) {
1430 public void doWork() throws RemoteException {
1431 mService.getAuthToken(mResponse, account, authTokenType,
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001432 notifyAuthFailure, false /* expectActivityLaunch */, optionsIn);
Fred Quintanaad93a322011-09-08 13:21:01 -07001433 }
1434 }.start();
1435 }
1436
1437 /**
Dan Egnor661f0132010-02-19 11:23:00 -08001438 * Asks the user to add an account of a specified type. The authenticator
1439 * for this account type processes this request with the appropriate user
1440 * interface. If the user does elect to create a new account, the account
1441 * name is returned.
1442 *
1443 * <p>This method may be called from any thread, but the returned
1444 * {@link AccountManagerFuture} must not be used on the main thread.
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001445 *
1446 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1447 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
1448 * this function in API level 22.
Dan Egnor661f0132010-02-19 11:23:00 -08001449 *
Dan Egnor661f0132010-02-19 11:23:00 -08001450 * @param accountType The type of account to add; must not be null
1451 * @param authTokenType The type of auth token (see {@link #getAuthToken})
1452 * this account will need to be able to generate, null for none
1453 * @param requiredFeatures The features (see {@link #hasFeatures}) this
1454 * account must have, null for none
1455 * @param addAccountOptions Authenticator-specific options for the request,
1456 * may be null or empty
1457 * @param activity The {@link Activity} context to use for launching a new
1458 * authenticator-defined sub-Activity to prompt the user to create an
1459 * account; used only to call startActivity(); if null, the prompt
1460 * will not be launched directly, but the necessary {@link Intent}
1461 * will be returned to the caller instead
1462 * @param callback Callback to invoke when the request completes,
1463 * null for no callback
1464 * @param handler {@link Handler} identifying the callback thread,
1465 * null for the main thread
Doug Zongkerff592dc2010-02-23 12:26:33 -08001466 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
Dan Egnor661f0132010-02-19 11:23:00 -08001467 * these fields if activity was specified and an account was created:
1468 * <ul>
1469 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
1470 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1471 * </ul>
1472 *
1473 * If no activity was specified, the returned Bundle contains only
1474 * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
Dan Egnor8e4378b2010-08-02 18:22:09 -07001475 * actual account creation process. If an error occurred,
1476 * {@link AccountManagerFuture#getResult()} throws:
Dan Egnor661f0132010-02-19 11:23:00 -08001477 * <ul>
1478 * <li> {@link AuthenticatorException} if no authenticator was registered for
1479 * this account type or the authenticator failed to respond
1480 * <li> {@link OperationCanceledException} if the operation was canceled for
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001481 * any reason, including the user canceling the creation process or adding accounts
1482 * (of this type) has been disabled by policy
Dan Egnor661f0132010-02-19 11:23:00 -08001483 * <li> {@link IOException} if the authenticator experienced an I/O problem
1484 * creating a new account, usually because of network trouble
1485 * </ul>
1486 */
1487 public AccountManagerFuture<Bundle> addAccount(final String accountType,
1488 final String authTokenType, final String[] requiredFeatures,
1489 final Bundle addAccountOptions,
1490 final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -07001491 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Costin Manolachee5847ad2011-09-14 12:52:19 -07001492 final Bundle optionsIn = new Bundle();
1493 if (addAccountOptions != null) {
1494 optionsIn.putAll(addAccountOptions);
1495 }
1496 optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
Costin Manolacheb61e8fb2011-09-08 11:26:09 -07001497
Dan Egnor661f0132010-02-19 11:23:00 -08001498 return new AmsTask(activity, handler, callback) {
1499 public void doWork() throws RemoteException {
Amith Yamasani27db4682013-03-30 17:07:47 -07001500 mService.addAccount(mResponse, accountType, authTokenType,
Costin Manolachee5847ad2011-09-14 12:52:19 -07001501 requiredFeatures, activity != null, optionsIn);
Dan Egnor661f0132010-02-19 11:23:00 -08001502 }
1503 }.start();
1504 }
1505
1506 /**
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001507 * @see #addAccount(String, String, String[], Bundle, Activity, AccountManagerCallback, Handler)
1508 * @hide
1509 */
1510 public AccountManagerFuture<Bundle> addAccountAsUser(final String accountType,
1511 final String authTokenType, final String[] requiredFeatures,
1512 final Bundle addAccountOptions, final Activity activity,
1513 AccountManagerCallback<Bundle> callback, Handler handler, final UserHandle userHandle) {
1514 if (accountType == null) throw new IllegalArgumentException("accountType is null");
1515 if (userHandle == null) throw new IllegalArgumentException("userHandle is null");
1516 final Bundle optionsIn = new Bundle();
1517 if (addAccountOptions != null) {
1518 optionsIn.putAll(addAccountOptions);
1519 }
1520 optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
1521
1522 return new AmsTask(activity, handler, callback) {
1523 public void doWork() throws RemoteException {
1524 mService.addAccountAsUser(mResponse, accountType, authTokenType,
1525 requiredFeatures, activity != null, optionsIn, userHandle.getIdentifier());
1526 }
1527 }.start();
1528 }
1529
1530 /**
Amith Yamasani67df64b2012-12-14 12:09:36 -08001531 * Adds a shared account from the primary user to a secondary user. Adding the shared account
1532 * doesn't take effect immediately. When the target user starts up, any pending shared accounts
1533 * are attempted to be copied to the target user from the primary via calls to the
1534 * authenticator.
1535 * @param account the account to share
1536 * @param user the target user
1537 * @return
1538 * @hide
1539 */
1540 public boolean addSharedAccount(final Account account, UserHandle user) {
1541 try {
1542 boolean val = mService.addSharedAccountAsUser(account, user.getIdentifier());
1543 return val;
1544 } catch (RemoteException re) {
1545 // won't ever happen
1546 throw new RuntimeException(re);
1547 }
1548 }
1549
1550 /**
Esteban Talavera22dc3b72014-10-31 15:41:12 +00001551 * Copies an account from the primary user to another user.
1552 * @param account the account to copy
1553 * @param user the target user
1554 * @param callback Callback to invoke when the request completes,
1555 * null for no callback
1556 * @param handler {@link Handler} identifying the callback thread,
1557 * null for the main thread
1558 * @return An {@link AccountManagerFuture} which resolves to a Boolean indicated wether it
1559 * succeeded.
1560 * @hide
1561 */
1562 public AccountManagerFuture<Boolean> copyAccountToUser(
1563 final Account account, final UserHandle user,
1564 AccountManagerCallback<Boolean> callback, Handler handler) {
1565 if (account == null) throw new IllegalArgumentException("account is null");
1566 if (user == null) throw new IllegalArgumentException("user is null");
1567
1568 return new Future2Task<Boolean>(handler, callback) {
1569 @Override
1570 public void doWork() throws RemoteException {
1571 mService.copyAccountToUser(
1572 mResponse, account, UserHandle.USER_OWNER, user.getIdentifier());
1573 }
1574 @Override
1575 public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
1576 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
1577 throw new AuthenticatorException("no result in response");
1578 }
1579 return bundle.getBoolean(KEY_BOOLEAN_RESULT);
1580 }
1581 }.start();
1582 }
1583
1584 /**
Amith Yamasani67df64b2012-12-14 12:09:36 -08001585 * @hide
1586 * Removes the shared account.
1587 * @param account the account to remove
1588 * @param user the user to remove the account from
1589 * @return
1590 */
1591 public boolean removeSharedAccount(final Account account, UserHandle user) {
1592 try {
1593 boolean val = mService.removeSharedAccountAsUser(account, user.getIdentifier());
1594 return val;
1595 } catch (RemoteException re) {
1596 // won't ever happen
1597 throw new RuntimeException(re);
1598 }
1599 }
1600
1601 /**
1602 * @hide
1603 * @param user
1604 * @return
1605 */
1606 public Account[] getSharedAccounts(UserHandle user) {
1607 try {
1608 return mService.getSharedAccountsAsUser(user.getIdentifier());
1609 } catch (RemoteException re) {
1610 // won't ever happen
1611 throw new RuntimeException(re);
1612 }
1613 }
1614
1615 /**
Dan Egnor661f0132010-02-19 11:23:00 -08001616 * Confirms that the user knows the password for an account to make extra
1617 * sure they are the owner of the account. The user-entered password can
1618 * be supplied directly, otherwise the authenticator for this account type
1619 * prompts the user with the appropriate interface. This method is
1620 * intended for applications which want extra assurance; for example, the
1621 * phone lock screen uses this to let the user unlock the phone with an
1622 * account password if they forget the lock pattern.
1623 *
1624 * <p>If the user-entered password matches a saved password for this
1625 * account, the request is considered valid; otherwise the authenticator
1626 * verifies the password (usually by contacting the server).
1627 *
1628 * <p>This method may be called from any thread, but the returned
1629 * {@link AccountManagerFuture} must not be used on the main thread.
1630 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001631 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1632 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs
1633 * for this function in API level 22.
1634 *
Dan Egnor661f0132010-02-19 11:23:00 -08001635 * @param account The account to confirm password knowledge for
1636 * @param options Authenticator-specific options for the request;
1637 * if the {@link #KEY_PASSWORD} string field is present, the
1638 * authenticator may use it directly rather than prompting the user;
1639 * may be null or empty
1640 * @param activity The {@link Activity} context to use for launching a new
1641 * authenticator-defined sub-Activity to prompt the user to enter a
1642 * password; used only to call startActivity(); if null, the prompt
1643 * will not be launched directly, but the necessary {@link Intent}
1644 * will be returned to the caller instead
1645 * @param callback Callback to invoke when the request completes,
1646 * null for no callback
1647 * @param handler {@link Handler} identifying the callback thread,
1648 * null for the main thread
1649 * @return An {@link AccountManagerFuture} which resolves to a Bundle
1650 * with these fields if activity or password was supplied and
1651 * the account was successfully verified:
1652 * <ul>
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001653 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account verified
Dan Egnor661f0132010-02-19 11:23:00 -08001654 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
1655 * <li> {@link #KEY_BOOLEAN_RESULT} - true to indicate success
1656 * </ul>
1657 *
1658 * If no activity or password was specified, the returned Bundle contains
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001659 * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
1660 * password prompt.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001661 *
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001662 * <p>Also the returning Bundle may contain {@link
Simranjit Singh Kohli1663b442015-04-28 11:11:12 -07001663 * #KEY_LAST_AUTHENTICATED_TIME} indicating the last time the
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001664 * credential was validated/created.
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001665 *
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001666 * If an error occurred,{@link AccountManagerFuture#getResult()} throws:
Dan Egnor661f0132010-02-19 11:23:00 -08001667 * <ul>
1668 * <li> {@link AuthenticatorException} if the authenticator failed to respond
1669 * <li> {@link OperationCanceledException} if the operation was canceled for
1670 * any reason, including the user canceling the password prompt
1671 * <li> {@link IOException} if the authenticator experienced an I/O problem
1672 * verifying the password, usually because of network trouble
1673 * </ul>
Fred Quintana756b7352009-10-21 13:43:10 -07001674 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001675 public AccountManagerFuture<Bundle> confirmCredentials(final Account account,
1676 final Bundle options,
1677 final Activity activity,
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001678 final AccountManagerCallback<Bundle> callback,
Fred Quintanaa698f422009-04-08 19:14:54 -07001679 final Handler handler) {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08001680 return confirmCredentialsAsUser(account, options, activity, callback, handler,
1681 Process.myUserHandle());
1682 }
1683
1684 /**
1685 * @hide
1686 * Same as {@link #confirmCredentials(Account, Bundle, Activity, AccountManagerCallback, Handler)}
1687 * but for the specified user.
1688 */
1689 public AccountManagerFuture<Bundle> confirmCredentialsAsUser(final Account account,
1690 final Bundle options,
1691 final Activity activity,
1692 final AccountManagerCallback<Bundle> callback,
1693 final Handler handler, UserHandle userHandle) {
Fred Quintana382601f2010-03-25 12:25:10 -07001694 if (account == null) throw new IllegalArgumentException("account is null");
Amith Yamasani2c7bc262012-11-05 16:46:02 -08001695 final int userId = userHandle.getIdentifier();
Fred Quintanaa698f422009-04-08 19:14:54 -07001696 return new AmsTask(activity, handler, callback) {
1697 public void doWork() throws RemoteException {
Amith Yamasani2c7bc262012-11-05 16:46:02 -08001698 mService.confirmCredentialsAsUser(mResponse, account, options, activity != null,
1699 userId);
Fred Quintanaa698f422009-04-08 19:14:54 -07001700 }
Fred Quintana33269202009-04-20 16:05:10 -07001701 }.start();
Fred Quintanaa698f422009-04-08 19:14:54 -07001702 }
1703
Fred Quintana756b7352009-10-21 13:43:10 -07001704 /**
Dan Egnor661f0132010-02-19 11:23:00 -08001705 * Asks the user to enter a new password for an account, updating the
1706 * saved credentials for the account. Normally this happens automatically
1707 * when the server rejects credentials during an auth token fetch, but this
1708 * can be invoked directly to ensure we have the correct credentials stored.
Fred Quintana756b7352009-10-21 13:43:10 -07001709 *
Dan Egnor661f0132010-02-19 11:23:00 -08001710 * <p>This method may be called from any thread, but the returned
1711 * {@link AccountManagerFuture} must not be used on the main thread.
1712 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001713 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1714 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
1715 * this function in API level 22.
1716 *
Dan Egnor661f0132010-02-19 11:23:00 -08001717 * @param account The account to update credentials for
1718 * @param authTokenType The credentials entered must allow an auth token
1719 * of this type to be created (but no actual auth token is returned);
1720 * may be null
1721 * @param options Authenticator-specific options for the request;
1722 * may be null or empty
1723 * @param activity The {@link Activity} context to use for launching a new
1724 * authenticator-defined sub-Activity to prompt the user to enter a
1725 * password; used only to call startActivity(); if null, the prompt
1726 * will not be launched directly, but the necessary {@link Intent}
1727 * will be returned to the caller instead
1728 * @param callback Callback to invoke when the request completes,
1729 * null for no callback
1730 * @param handler {@link Handler} identifying the callback thread,
1731 * null for the main thread
1732 * @return An {@link AccountManagerFuture} which resolves to a Bundle
1733 * with these fields if an activity was supplied and the account
1734 * credentials were successfully updated:
Fred Quintana756b7352009-10-21 13:43:10 -07001735 * <ul>
Dan Egnor661f0132010-02-19 11:23:00 -08001736 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
1737 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
Fred Quintana756b7352009-10-21 13:43:10 -07001738 * </ul>
Dan Egnor661f0132010-02-19 11:23:00 -08001739 *
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001740 * If no activity was specified, the returned Bundle contains
Dan Egnor661f0132010-02-19 11:23:00 -08001741 * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
Simranjit Singh Kohli6c7c4ad2015-02-23 18:11:14 -08001742 * password prompt. If an error occurred,
Dan Egnor8e4378b2010-08-02 18:22:09 -07001743 * {@link AccountManagerFuture#getResult()} throws:
Dan Egnor661f0132010-02-19 11:23:00 -08001744 * <ul>
1745 * <li> {@link AuthenticatorException} if the authenticator failed to respond
1746 * <li> {@link OperationCanceledException} if the operation was canceled for
1747 * any reason, including the user canceling the password prompt
1748 * <li> {@link IOException} if the authenticator experienced an I/O problem
1749 * verifying the password, usually because of network trouble
1750 * </ul>
Fred Quintana756b7352009-10-21 13:43:10 -07001751 */
1752 public AccountManagerFuture<Bundle> updateCredentials(final Account account,
1753 final String authTokenType,
Fred Quintana31957f12009-10-21 13:43:10 -07001754 final Bundle options, final Activity activity,
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001755 final AccountManagerCallback<Bundle> callback,
Fred Quintanaa698f422009-04-08 19:14:54 -07001756 final Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -07001757 if (account == null) throw new IllegalArgumentException("account is null");
Fred Quintanaa698f422009-04-08 19:14:54 -07001758 return new AmsTask(activity, handler, callback) {
1759 public void doWork() throws RemoteException {
1760 mService.updateCredentials(mResponse, account, authTokenType, activity != null,
Fred Quintana31957f12009-10-21 13:43:10 -07001761 options);
Fred Quintanaa698f422009-04-08 19:14:54 -07001762 }
Fred Quintana33269202009-04-20 16:05:10 -07001763 }.start();
Fred Quintanaa698f422009-04-08 19:14:54 -07001764 }
1765
Fred Quintana756b7352009-10-21 13:43:10 -07001766 /**
Dan Egnor661f0132010-02-19 11:23:00 -08001767 * Offers the user an opportunity to change an authenticator's settings.
1768 * These properties are for the authenticator in general, not a particular
1769 * account. Not all authenticators support this method.
Fred Quintana756b7352009-10-21 13:43:10 -07001770 *
Dan Egnor661f0132010-02-19 11:23:00 -08001771 * <p>This method may be called from any thread, but the returned
1772 * {@link AccountManagerFuture} must not be used on the main thread.
1773 *
Carlos Valdivia6eb73a52015-06-11 13:07:11 -07001774 * <p>This method requires the caller to have the same signature as the
1775 * authenticator associated with the specified account type.
Dan Egnor661f0132010-02-19 11:23:00 -08001776 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07001777 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
1778 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs
1779 * for this function in API level 22.
1780 *
Dan Egnor661f0132010-02-19 11:23:00 -08001781 * @param accountType The account type associated with the authenticator
1782 * to adjust
1783 * @param activity The {@link Activity} context to use for launching a new
1784 * authenticator-defined sub-Activity to adjust authenticator settings;
1785 * used only to call startActivity(); if null, the settings dialog will
1786 * not be launched directly, but the necessary {@link Intent} will be
1787 * returned to the caller instead
1788 * @param callback Callback to invoke when the request completes,
1789 * null for no callback
1790 * @param handler {@link Handler} identifying the callback thread,
1791 * null for the main thread
1792 * @return An {@link AccountManagerFuture} which resolves to a Bundle
1793 * which is empty if properties were edited successfully, or
1794 * if no activity was specified, contains only {@link #KEY_INTENT}
1795 * needed to launch the authenticator's settings dialog.
Dan Egnor8e4378b2010-08-02 18:22:09 -07001796 * If an error occurred, {@link AccountManagerFuture#getResult()}
1797 * throws:
Fred Quintana756b7352009-10-21 13:43:10 -07001798 * <ul>
Dan Egnor661f0132010-02-19 11:23:00 -08001799 * <li> {@link AuthenticatorException} if no authenticator was registered for
1800 * this account type or the authenticator failed to respond
1801 * <li> {@link OperationCanceledException} if the operation was canceled for
1802 * any reason, including the user canceling the settings dialog
1803 * <li> {@link IOException} if the authenticator experienced an I/O problem
1804 * updating settings, usually because of network trouble
Fred Quintana756b7352009-10-21 13:43:10 -07001805 * </ul>
Fred Quintana756b7352009-10-21 13:43:10 -07001806 */
1807 public AccountManagerFuture<Bundle> editProperties(final String accountType,
1808 final Activity activity, final AccountManagerCallback<Bundle> callback,
Fred Quintanaa698f422009-04-08 19:14:54 -07001809 final Handler handler) {
Fred Quintana382601f2010-03-25 12:25:10 -07001810 if (accountType == null) throw new IllegalArgumentException("accountType is null");
Fred Quintanaa698f422009-04-08 19:14:54 -07001811 return new AmsTask(activity, handler, callback) {
1812 public void doWork() throws RemoteException {
1813 mService.editProperties(mResponse, accountType, activity != null);
1814 }
Fred Quintana33269202009-04-20 16:05:10 -07001815 }.start();
Fred Quintanaa698f422009-04-08 19:14:54 -07001816 }
1817
1818 private void ensureNotOnMainThread() {
1819 final Looper looper = Looper.myLooper();
1820 if (looper != null && looper == mContext.getMainLooper()) {
Fred Quintana53bd2522010-02-05 15:28:12 -08001821 final IllegalStateException exception = new IllegalStateException(
1822 "calling this from your main thread can lead to deadlock");
1823 Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs",
1824 exception);
Fred Quintana751fdc02010-02-09 14:13:18 -08001825 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.FROYO) {
1826 throw exception;
1827 }
Fred Quintana60307342009-03-24 22:48:12 -07001828 }
1829 }
1830
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001831 private void postToHandler(Handler handler, final AccountManagerCallback<Bundle> callback,
1832 final AccountManagerFuture<Bundle> future) {
Fred Quintanad9d2f112009-04-23 13:36:27 -07001833 handler = handler == null ? mMainHandler : handler;
1834 handler.post(new Runnable() {
Fred Quintanaa698f422009-04-08 19:14:54 -07001835 public void run() {
1836 callback.run(future);
1837 }
1838 });
1839 }
Fred Quintana60307342009-03-24 22:48:12 -07001840
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07001841 private void postToHandler(Handler handler, final OnAccountsUpdateListener listener,
Fred Quintanad9d2f112009-04-23 13:36:27 -07001842 final Account[] accounts) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001843 final Account[] accountsCopy = new Account[accounts.length];
1844 // send a copy to make sure that one doesn't
1845 // change what another sees
1846 System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
1847 handler = (handler == null) ? mMainHandler : handler;
Fred Quintanad9d2f112009-04-23 13:36:27 -07001848 handler.post(new Runnable() {
1849 public void run() {
Costin Manolacheb6437242009-09-10 16:14:12 -07001850 try {
1851 listener.onAccountsUpdated(accountsCopy);
1852 } catch (SQLException e) {
1853 // Better luck next time. If the problem was disk-full,
1854 // the STORAGE_OK intent will re-trigger the update.
1855 Log.e(TAG, "Can't update accounts", e);
1856 }
Fred Quintanad9d2f112009-04-23 13:36:27 -07001857 }
1858 });
1859 }
1860
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001861 private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> {
Fred Quintanaa698f422009-04-08 19:14:54 -07001862 final IAccountManagerResponse mResponse;
1863 final Handler mHandler;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001864 final AccountManagerCallback<Bundle> mCallback;
Fred Quintanaa698f422009-04-08 19:14:54 -07001865 final Activity mActivity;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001866 public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) {
Fred Quintanaa698f422009-04-08 19:14:54 -07001867 super(new Callable<Bundle>() {
1868 public Bundle call() throws Exception {
1869 throw new IllegalStateException("this should never be called");
1870 }
1871 });
1872
1873 mHandler = handler;
1874 mCallback = callback;
1875 mActivity = activity;
1876 mResponse = new Response();
Fred Quintana33269202009-04-20 16:05:10 -07001877 }
1878
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001879 public final AccountManagerFuture<Bundle> start() {
1880 try {
1881 doWork();
1882 } catch (RemoteException e) {
1883 setException(e);
1884 }
Fred Quintana33269202009-04-20 16:05:10 -07001885 return this;
Fred Quintana60307342009-03-24 22:48:12 -07001886 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001887
Fred Quintana96580e02010-03-04 13:42:42 -08001888 protected void set(Bundle bundle) {
1889 // TODO: somehow a null is being set as the result of the Future. Log this
1890 // case to help debug where this is occurring. When this bug is fixed this
1891 // condition statement should be removed.
1892 if (bundle == null) {
1893 Log.e(TAG, "the bundle must not be null", new Exception());
1894 }
1895 super.set(bundle);
1896 }
1897
Fred Quintanaa698f422009-04-08 19:14:54 -07001898 public abstract void doWork() throws RemoteException;
1899
1900 private Bundle internalGetResult(Long timeout, TimeUnit unit)
1901 throws OperationCanceledException, IOException, AuthenticatorException {
Fred Quintana53bd2522010-02-05 15:28:12 -08001902 if (!isDone()) {
1903 ensureNotOnMainThread();
1904 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001905 try {
1906 if (timeout == null) {
1907 return get();
1908 } else {
1909 return get(timeout, unit);
1910 }
1911 } catch (CancellationException e) {
1912 throw new OperationCanceledException();
1913 } catch (TimeoutException e) {
1914 // fall through and cancel
1915 } catch (InterruptedException e) {
1916 // fall through and cancel
1917 } catch (ExecutionException e) {
1918 final Throwable cause = e.getCause();
1919 if (cause instanceof IOException) {
1920 throw (IOException) cause;
1921 } else if (cause instanceof UnsupportedOperationException) {
1922 throw new AuthenticatorException(cause);
1923 } else if (cause instanceof AuthenticatorException) {
1924 throw (AuthenticatorException) cause;
1925 } else if (cause instanceof RuntimeException) {
1926 throw (RuntimeException) cause;
1927 } else if (cause instanceof Error) {
1928 throw (Error) cause;
1929 } else {
1930 throw new IllegalStateException(cause);
1931 }
1932 } finally {
1933 cancel(true /* interrupt if running */);
1934 }
1935 throw new OperationCanceledException();
1936 }
1937
1938 public Bundle getResult()
1939 throws OperationCanceledException, IOException, AuthenticatorException {
1940 return internalGetResult(null, null);
1941 }
1942
1943 public Bundle getResult(long timeout, TimeUnit unit)
1944 throws OperationCanceledException, IOException, AuthenticatorException {
1945 return internalGetResult(timeout, unit);
1946 }
1947
1948 protected void done() {
1949 if (mCallback != null) {
1950 postToHandler(mHandler, mCallback, this);
1951 }
1952 }
1953
1954 /** Handles the responses from the AccountManager */
1955 private class Response extends IAccountManagerResponse.Stub {
1956 public void onResult(Bundle bundle) {
Brian Carlstrom46703b02011-04-06 15:41:29 -07001957 Intent intent = bundle.getParcelable(KEY_INTENT);
Fred Quintanaa698f422009-04-08 19:14:54 -07001958 if (intent != null && mActivity != null) {
1959 // since the user provided an Activity we will silently start intents
1960 // that we see
1961 mActivity.startActivity(intent);
1962 // leave the Future running to wait for the real response to this request
Fred Quintanad4a1d2e2009-07-16 16:36:38 -07001963 } else if (bundle.getBoolean("retry")) {
1964 try {
1965 doWork();
1966 } catch (RemoteException e) {
1967 // this will only happen if the system process is dead, which means
1968 // we will be dying ourselves
1969 }
Fred Quintanaa698f422009-04-08 19:14:54 -07001970 } else {
1971 set(bundle);
1972 }
1973 }
1974
1975 public void onError(int code, String message) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01001976 if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
1977 || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
1978 // the authenticator indicated that this request was canceled or we were
1979 // forbidden to fulfill; cancel now
Fred Quintanaa698f422009-04-08 19:14:54 -07001980 cancel(true /* mayInterruptIfRunning */);
1981 return;
1982 }
1983 setException(convertErrorToException(code, message));
1984 }
1985 }
1986
Fred Quintana60307342009-03-24 22:48:12 -07001987 }
1988
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001989 private abstract class BaseFutureTask<T> extends FutureTask<T> {
1990 final public IAccountManagerResponse mResponse;
Fred Quintanaa698f422009-04-08 19:14:54 -07001991 final Handler mHandler;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07001992
1993 public BaseFutureTask(Handler handler) {
1994 super(new Callable<T>() {
1995 public T call() throws Exception {
Fred Quintanaa698f422009-04-08 19:14:54 -07001996 throw new IllegalStateException("this should never be called");
1997 }
1998 });
Fred Quintanaa698f422009-04-08 19:14:54 -07001999 mHandler = handler;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002000 mResponse = new Response();
Fred Quintana60307342009-03-24 22:48:12 -07002001 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002002
2003 public abstract void doWork() throws RemoteException;
2004
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002005 public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException;
Fred Quintanaa698f422009-04-08 19:14:54 -07002006
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002007 protected void postRunnableToHandler(Runnable runnable) {
2008 Handler handler = (mHandler == null) ? mMainHandler : mHandler;
2009 handler.post(runnable);
Fred Quintanaa698f422009-04-08 19:14:54 -07002010 }
2011
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002012 protected void startTask() {
Fred Quintanaa698f422009-04-08 19:14:54 -07002013 try {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002014 doWork();
2015 } catch (RemoteException e) {
2016 setException(e);
Fred Quintanaa698f422009-04-08 19:14:54 -07002017 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002018 }
2019
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002020 protected class Response extends IAccountManagerResponse.Stub {
Fred Quintanaa698f422009-04-08 19:14:54 -07002021 public void onResult(Bundle bundle) {
2022 try {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002023 T result = bundleToResult(bundle);
2024 if (result == null) {
Fred Quintanaa698f422009-04-08 19:14:54 -07002025 return;
2026 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002027 set(result);
2028 return;
Fred Quintanaa698f422009-04-08 19:14:54 -07002029 } catch (ClassCastException e) {
2030 // we will set the exception below
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002031 } catch (AuthenticatorException e) {
2032 // we will set the exception below
Fred Quintanaa698f422009-04-08 19:14:54 -07002033 }
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002034 onError(ERROR_CODE_INVALID_RESPONSE, "no result in response");
Fred Quintanaa698f422009-04-08 19:14:54 -07002035 }
2036
2037 public void onError(int code, String message) {
Alexandra Gherghina999d3942014-07-03 11:40:08 +01002038 if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
2039 || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
2040 // the authenticator indicated that this request was canceled or we were
2041 // forbidden to fulfill; cancel now
Fred Quintanaa698f422009-04-08 19:14:54 -07002042 cancel(true /* mayInterruptIfRunning */);
2043 return;
2044 }
2045 setException(convertErrorToException(code, message));
2046 }
2047 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002048 }
2049
2050 private abstract class Future2Task<T>
2051 extends BaseFutureTask<T> implements AccountManagerFuture<T> {
2052 final AccountManagerCallback<T> mCallback;
2053 public Future2Task(Handler handler, AccountManagerCallback<T> callback) {
2054 super(handler);
2055 mCallback = callback;
2056 }
2057
2058 protected void done() {
2059 if (mCallback != null) {
2060 postRunnableToHandler(new Runnable() {
2061 public void run() {
2062 mCallback.run(Future2Task.this);
2063 }
2064 });
2065 }
2066 }
2067
2068 public Future2Task<T> start() {
2069 startTask();
2070 return this;
2071 }
2072
2073 private T internalGetResult(Long timeout, TimeUnit unit)
2074 throws OperationCanceledException, IOException, AuthenticatorException {
Fred Quintana53bd2522010-02-05 15:28:12 -08002075 if (!isDone()) {
2076 ensureNotOnMainThread();
2077 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002078 try {
2079 if (timeout == null) {
2080 return get();
2081 } else {
2082 return get(timeout, unit);
2083 }
2084 } catch (InterruptedException e) {
2085 // fall through and cancel
2086 } catch (TimeoutException e) {
2087 // fall through and cancel
2088 } catch (CancellationException e) {
2089 // fall through and cancel
2090 } catch (ExecutionException e) {
2091 final Throwable cause = e.getCause();
2092 if (cause instanceof IOException) {
2093 throw (IOException) cause;
2094 } else if (cause instanceof UnsupportedOperationException) {
2095 throw new AuthenticatorException(cause);
2096 } else if (cause instanceof AuthenticatorException) {
2097 throw (AuthenticatorException) cause;
2098 } else if (cause instanceof RuntimeException) {
2099 throw (RuntimeException) cause;
2100 } else if (cause instanceof Error) {
2101 throw (Error) cause;
2102 } else {
2103 throw new IllegalStateException(cause);
2104 }
2105 } finally {
2106 cancel(true /* interrupt if running */);
2107 }
2108 throw new OperationCanceledException();
2109 }
2110
2111 public T getResult()
2112 throws OperationCanceledException, IOException, AuthenticatorException {
2113 return internalGetResult(null, null);
2114 }
2115
2116 public T getResult(long timeout, TimeUnit unit)
2117 throws OperationCanceledException, IOException, AuthenticatorException {
2118 return internalGetResult(timeout, unit);
2119 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002120
Fred Quintana60307342009-03-24 22:48:12 -07002121 }
2122
Fred Quintanaa698f422009-04-08 19:14:54 -07002123 private Exception convertErrorToException(int code, String message) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002124 if (code == ERROR_CODE_NETWORK_ERROR) {
Fred Quintanaa698f422009-04-08 19:14:54 -07002125 return new IOException(message);
Fred Quintana60307342009-03-24 22:48:12 -07002126 }
Fred Quintana60307342009-03-24 22:48:12 -07002127
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002128 if (code == ERROR_CODE_UNSUPPORTED_OPERATION) {
Fred Quintana33269202009-04-20 16:05:10 -07002129 return new UnsupportedOperationException(message);
Fred Quintana60307342009-03-24 22:48:12 -07002130 }
Fred Quintanaa698f422009-04-08 19:14:54 -07002131
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002132 if (code == ERROR_CODE_INVALID_RESPONSE) {
Fred Quintana33269202009-04-20 16:05:10 -07002133 return new AuthenticatorException(message);
Fred Quintanaa698f422009-04-08 19:14:54 -07002134 }
2135
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002136 if (code == ERROR_CODE_BAD_ARGUMENTS) {
Fred Quintana33269202009-04-20 16:05:10 -07002137 return new IllegalArgumentException(message);
2138 }
2139
2140 return new AuthenticatorException(message);
2141 }
2142
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002143 private class GetAuthTokenByTypeAndFeaturesTask
2144 extends AmsTask implements AccountManagerCallback<Bundle> {
Fred Quintana33269202009-04-20 16:05:10 -07002145 GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
2146 final String[] features, Activity activityForPrompting,
2147 final Bundle addAccountOptions, final Bundle loginOptions,
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002148 AccountManagerCallback<Bundle> callback, Handler handler) {
Fred Quintana33269202009-04-20 16:05:10 -07002149 super(activityForPrompting, handler, callback);
2150 if (accountType == null) throw new IllegalArgumentException("account type is null");
2151 mAccountType = accountType;
2152 mAuthTokenType = authTokenType;
2153 mFeatures = features;
2154 mAddAccountOptions = addAccountOptions;
2155 mLoginOptions = loginOptions;
2156 mMyCallback = this;
2157 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002158 volatile AccountManagerFuture<Bundle> mFuture = null;
Fred Quintana33269202009-04-20 16:05:10 -07002159 final String mAccountType;
2160 final String mAuthTokenType;
2161 final String[] mFeatures;
2162 final Bundle mAddAccountOptions;
2163 final Bundle mLoginOptions;
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002164 final AccountManagerCallback<Bundle> mMyCallback;
Fred Quintanaf0fd8432010-03-08 12:48:05 -08002165 private volatile int mNumAccounts = 0;
Fred Quintana33269202009-04-20 16:05:10 -07002166
2167 public void doWork() throws RemoteException {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002168 getAccountsByTypeAndFeatures(mAccountType, mFeatures,
2169 new AccountManagerCallback<Account[]>() {
2170 public void run(AccountManagerFuture<Account[]> future) {
2171 Account[] accounts;
Fred Quintana33269202009-04-20 16:05:10 -07002172 try {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002173 accounts = future.getResult();
2174 } catch (OperationCanceledException e) {
2175 setException(e);
2176 return;
2177 } catch (IOException e) {
2178 setException(e);
2179 return;
2180 } catch (AuthenticatorException e) {
2181 setException(e);
2182 return;
Fred Quintana33269202009-04-20 16:05:10 -07002183 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002184
Fred Quintanaf0fd8432010-03-08 12:48:05 -08002185 mNumAccounts = accounts.length;
2186
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002187 if (accounts.length == 0) {
2188 if (mActivity != null) {
2189 // no accounts, add one now. pretend that the user directly
2190 // made this request
2191 mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures,
2192 mAddAccountOptions, mActivity, mMyCallback, mHandler);
2193 } else {
2194 // send result since we can't prompt to add an account
2195 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002196 result.putString(KEY_ACCOUNT_NAME, null);
2197 result.putString(KEY_ACCOUNT_TYPE, null);
2198 result.putString(KEY_AUTHTOKEN, null);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002199 try {
2200 mResponse.onResult(result);
2201 } catch (RemoteException e) {
2202 // this will never happen
2203 }
2204 // we are done
2205 }
2206 } else if (accounts.length == 1) {
2207 // have a single account, return an authtoken for it
2208 if (mActivity == null) {
2209 mFuture = getAuthToken(accounts[0], mAuthTokenType,
2210 false /* notifyAuthFailure */, mMyCallback, mHandler);
2211 } else {
2212 mFuture = getAuthToken(accounts[0],
2213 mAuthTokenType, mLoginOptions,
Fred Quintana33269202009-04-20 16:05:10 -07002214 mActivity, mMyCallback, mHandler);
2215 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002216 } else {
2217 if (mActivity != null) {
2218 IAccountManagerResponse chooseResponse =
2219 new IAccountManagerResponse.Stub() {
2220 public void onResult(Bundle value) throws RemoteException {
2221 Account account = new Account(
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002222 value.getString(KEY_ACCOUNT_NAME),
2223 value.getString(KEY_ACCOUNT_TYPE));
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002224 mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
2225 mActivity, mMyCallback, mHandler);
2226 }
Fred Quintana33269202009-04-20 16:05:10 -07002227
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002228 public void onError(int errorCode, String errorMessage)
2229 throws RemoteException {
2230 mResponse.onError(errorCode, errorMessage);
2231 }
2232 };
2233 // have many accounts, launch the chooser
2234 Intent intent = new Intent();
Amith Yamasani12b8e132013-03-14 10:48:07 -07002235 ComponentName componentName = ComponentName.unflattenFromString(
2236 Resources.getSystem().getString(
2237 R.string.config_chooseAccountActivity));
2238 intent.setClassName(componentName.getPackageName(),
2239 componentName.getClassName());
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002240 intent.putExtra(KEY_ACCOUNTS, accounts);
2241 intent.putExtra(KEY_ACCOUNT_MANAGER_RESPONSE,
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002242 new AccountManagerResponse(chooseResponse));
2243 mActivity.startActivity(intent);
2244 // the result will arrive via the IAccountManagerResponse
2245 } else {
2246 // send result since we can't prompt to select an account
2247 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002248 result.putString(KEY_ACCOUNTS, null);
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002249 try {
2250 mResponse.onResult(result);
2251 } catch (RemoteException e) {
2252 // this will never happen
2253 }
2254 // we are done
Fred Quintana33269202009-04-20 16:05:10 -07002255 }
Fred Quintana33269202009-04-20 16:05:10 -07002256 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002257 }}, mHandler);
Fred Quintana33269202009-04-20 16:05:10 -07002258 }
2259
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002260 public void run(AccountManagerFuture<Bundle> future) {
Fred Quintana33269202009-04-20 16:05:10 -07002261 try {
Fred Quintanaf0fd8432010-03-08 12:48:05 -08002262 final Bundle result = future.getResult();
2263 if (mNumAccounts == 0) {
2264 final String accountName = result.getString(KEY_ACCOUNT_NAME);
2265 final String accountType = result.getString(KEY_ACCOUNT_TYPE);
2266 if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
2267 setException(new AuthenticatorException("account not in result"));
2268 return;
2269 }
2270 final Account account = new Account(accountName, accountType);
2271 mNumAccounts = 1;
2272 getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
2273 mMyCallback, mHandler);
2274 return;
2275 }
2276 set(result);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002277 } catch (OperationCanceledException e) {
2278 cancel(true /* mayInterruptIfRUnning */);
2279 } catch (IOException e) {
2280 setException(e);
2281 } catch (AuthenticatorException e) {
2282 setException(e);
Fred Quintana33269202009-04-20 16:05:10 -07002283 }
2284 }
2285 }
2286
Fred Quintana756b7352009-10-21 13:43:10 -07002287 /**
Dan Egnor661f0132010-02-19 11:23:00 -08002288 * This convenience helper combines the functionality of
2289 * {@link #getAccountsByTypeAndFeatures}, {@link #getAuthToken}, and
2290 * {@link #addAccount}.
Fred Quintana756b7352009-10-21 13:43:10 -07002291 *
Dan Egnor661f0132010-02-19 11:23:00 -08002292 * <p>This method gets a list of the accounts matching the
2293 * specified type and feature set; if there is exactly one, it is
2294 * used; if there are more than one, the user is prompted to pick one;
2295 * if there are none, the user is prompted to add one. Finally,
2296 * an auth token is acquired for the chosen account.
2297 *
2298 * <p>This method may be called from any thread, but the returned
2299 * {@link AccountManagerFuture} must not be used on the main thread.
2300 *
Simranjit Singh Kohli210bace2015-07-29 16:34:49 -07002301 * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
2302 * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
2303 * this function in API level 22.
2304 *
Dan Egnor661f0132010-02-19 11:23:00 -08002305 * @param accountType The account type required
Doug Zongkerff592dc2010-02-23 12:26:33 -08002306 * (see {@link #getAccountsByType}), must not be null
Dan Egnor661f0132010-02-19 11:23:00 -08002307 * @param authTokenType The desired auth token type
2308 * (see {@link #getAuthToken}), must not be null
2309 * @param features Required features for the account
2310 * (see {@link #getAccountsByTypeAndFeatures}), may be null or empty
2311 * @param activity The {@link Activity} context to use for launching new
2312 * sub-Activities to prompt to add an account, select an account,
2313 * and/or enter a password, as necessary; used only to call
2314 * startActivity(); should not be null
2315 * @param addAccountOptions Authenticator-specific options to use for
2316 * adding new accounts; may be null or empty
2317 * @param getAuthTokenOptions Authenticator-specific options to use for
2318 * getting auth tokens; may be null or empty
2319 * @param callback Callback to invoke when the request completes,
2320 * null for no callback
2321 * @param handler {@link Handler} identifying the callback thread,
2322 * null for the main thread
2323 * @return An {@link AccountManagerFuture} which resolves to a Bundle with
2324 * at least the following fields:
Fred Quintana756b7352009-10-21 13:43:10 -07002325 * <ul>
Dan Egnor661f0132010-02-19 11:23:00 -08002326 * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account
2327 * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
2328 * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
Fred Quintana756b7352009-10-21 13:43:10 -07002329 * </ul>
Dan Egnor661f0132010-02-19 11:23:00 -08002330 *
Dan Egnor8e4378b2010-08-02 18:22:09 -07002331 * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
Dan Egnor661f0132010-02-19 11:23:00 -08002332 * <ul>
2333 * <li> {@link AuthenticatorException} if no authenticator was registered for
2334 * this account type or the authenticator failed to respond
2335 * <li> {@link OperationCanceledException} if the operation was canceled for
2336 * any reason, including the user canceling any operation
2337 * <li> {@link IOException} if the authenticator experienced an I/O problem
2338 * updating settings, usually because of network trouble
2339 * </ul>
Fred Quintana756b7352009-10-21 13:43:10 -07002340 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002341 public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
Fred Quintana33269202009-04-20 16:05:10 -07002342 final String accountType, final String authTokenType, final String[] features,
Dan Egnor661f0132010-02-19 11:23:00 -08002343 final Activity activity, final Bundle addAccountOptions,
Fred Quintana31957f12009-10-21 13:43:10 -07002344 final Bundle getAuthTokenOptions,
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002345 final AccountManagerCallback<Bundle> callback, final Handler handler) {
Fred Quintana33269202009-04-20 16:05:10 -07002346 if (accountType == null) throw new IllegalArgumentException("account type is null");
2347 if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002348 final GetAuthTokenByTypeAndFeaturesTask task =
2349 new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features,
Dan Egnor661f0132010-02-19 11:23:00 -08002350 activity, addAccountOptions, getAuthTokenOptions, callback, handler);
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002351 task.start();
2352 return task;
Fred Quintana60307342009-03-24 22:48:12 -07002353 }
Fred Quintanad9d2f112009-04-23 13:36:27 -07002354
Fred Quintana1121bb52011-09-14 23:19:35 -07002355 /**
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -07002356 * Deprecated in favor of {@link #newChooseAccountIntent(Account, List, String[], String,
2357 * String, String[], Bundle)}.
2358 *
Fred Quintana1121bb52011-09-14 23:19:35 -07002359 * Returns an intent to an {@link Activity} that prompts the user to choose from a list of
2360 * accounts.
2361 * The caller will then typically start the activity by calling
Mark Fickettab249e02012-09-05 09:45:47 -04002362 * <code>startActivityForResult(intent, ...);</code>.
Fred Quintana1121bb52011-09-14 23:19:35 -07002363 * <p>
2364 * On success the activity returns a Bundle with the account name and type specified using
2365 * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
2366 * <p>
2367 * The most common case is to call this with one account type, e.g.:
2368 * <p>
kmccormickf783ce52013-03-29 14:31:54 -07002369 * <pre> newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null,
Fred Quintanad88324d2011-09-19 11:43:05 -07002370 * null, null, null);</pre>
Fred Quintana1121bb52011-09-14 23:19:35 -07002371 * @param selectedAccount if specified, indicates that the {@link Account} is the currently
2372 * selected one, according to the caller's definition of selected.
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -07002373 * @param allowableAccounts an optional {@link List} of accounts that are allowed to be
Fred Quintana1121bb52011-09-14 23:19:35 -07002374 * shown. If not specified then this field will not limit the displayed accounts.
2375 * @param allowableAccountTypes an optional string array of account types. These are used
2376 * 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 -07002377 * when adding an account. If not specified then this field will not limit the displayed
2378 * account types when adding an account.
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -07002379 * @param alwaysPromptForAccount boolean that is ignored.
Fred Quintanad88324d2011-09-19 11:43:05 -07002380 * @param descriptionOverrideText if non-null this string is used as the description in the
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002381 * accounts chooser screen rather than the default
Fred Quintanad88324d2011-09-19 11:43:05 -07002382 * @param addAccountAuthTokenType this string is passed as the {@link #addAccount}
2383 * authTokenType parameter
2384 * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount}
2385 * requiredFeatures parameter
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002386 * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options
Fred Quintanad88324d2011-09-19 11:43:05 -07002387 * parameter
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002388 * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow.
Fred Quintana1121bb52011-09-14 23:19:35 -07002389 */
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -07002390 @Deprecated
2391 static public Intent newChooseAccountIntent(
2392 Account selectedAccount,
Baligh Uddinf2d248d2015-07-10 03:01:47 +00002393 ArrayList<Account> allowableAccounts,
Fred Quintana1121bb52011-09-14 23:19:35 -07002394 String[] allowableAccountTypes,
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002395 boolean alwaysPromptForAccount,
2396 String descriptionOverrideText,
2397 String addAccountAuthTokenType,
2398 String[] addAccountRequiredFeatures,
Fred Quintana1121bb52011-09-14 23:19:35 -07002399 Bundle addAccountOptions) {
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -07002400 return newChooseAccountIntent(
2401 selectedAccount,
2402 allowableAccounts,
2403 allowableAccountTypes,
2404 descriptionOverrideText,
2405 addAccountAuthTokenType,
2406 addAccountRequiredFeatures,
2407 addAccountOptions);
2408 }
2409
2410 /**
2411 * Returns an intent to an {@link Activity} that prompts the user to choose from a list of
2412 * accounts.
2413 * The caller will then typically start the activity by calling
2414 * <code>startActivityForResult(intent, ...);</code>.
2415 * <p>
2416 * On success the activity returns a Bundle with the account name and type specified using
2417 * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
2418 * <p>
2419 * The most common case is to call this with one account type, e.g.:
2420 * <p>
2421 * <pre> newChooseAccountIntent(null, null, new String[]{"com.google"}, null, null, null,
2422 * null);</pre>
2423 * @param selectedAccount if specified, indicates that the {@link Account} is the currently
2424 * selected one, according to the caller's definition of selected.
2425 * @param allowableAccounts an optional {@link List} of accounts that are allowed to be
2426 * shown. If not specified then this field will not limit the displayed accounts.
2427 * @param allowableAccountTypes an optional string array of account types. These are used
2428 * both to filter the shown accounts and to filter the list of account types that are shown
2429 * when adding an account. If not specified then this field will not limit the displayed
2430 * account types when adding an account.
2431 * @param descriptionOverrideText if non-null this string is used as the description in the
2432 * accounts chooser screen rather than the default
2433 * @param addAccountAuthTokenType this string is passed as the {@link #addAccount}
2434 * authTokenType parameter
2435 * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount}
2436 * requiredFeatures parameter
2437 * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options
2438 * parameter
2439 * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow.
2440 */
2441 static public Intent newChooseAccountIntent(
2442 Account selectedAccount,
2443 List<Account> allowableAccounts,
2444 String[] allowableAccountTypes,
2445 String descriptionOverrideText,
2446 String addAccountAuthTokenType,
2447 String[] addAccountRequiredFeatures,
2448 Bundle addAccountOptions) {
Fred Quintana1121bb52011-09-14 23:19:35 -07002449 Intent intent = new Intent();
Amith Yamasani12b8e132013-03-14 10:48:07 -07002450 ComponentName componentName = ComponentName.unflattenFromString(
2451 Resources.getSystem().getString(R.string.config_chooseTypeAndAccountActivity));
2452 intent.setClassName(componentName.getPackageName(),
2453 componentName.getClassName());
Fred Quintana1121bb52011-09-14 23:19:35 -07002454 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST,
Craig Lafayette3c9c71d2015-07-14 10:48:46 -04002455 allowableAccounts == null ? null : new ArrayList<Account>(allowableAccounts));
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002456 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
2457 allowableAccountTypes);
Fred Quintana1121bb52011-09-14 23:19:35 -07002458 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
2459 addAccountOptions);
2460 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_SELECTED_ACCOUNT, selectedAccount);
Fred Quintanab04fe4e2011-09-16 21:17:21 -07002461 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_DESCRIPTION_TEXT_OVERRIDE,
2462 descriptionOverrideText);
2463 intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,
2464 addAccountAuthTokenType);
2465 intent.putExtra(
2466 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,
2467 addAccountRequiredFeatures);
Fred Quintana1121bb52011-09-14 23:19:35 -07002468 return intent;
2469 }
2470
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002471 private final HashMap<OnAccountsUpdateListener, Handler> mAccountsUpdatedListeners =
Fred Quintanad9d2f112009-04-23 13:36:27 -07002472 Maps.newHashMap();
2473
Fred Quintanad9d2f112009-04-23 13:36:27 -07002474 /**
2475 * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
2476 * so that it can read the updated list of accounts and send them to the listener
2477 * in mAccountsUpdatedListeners.
2478 */
2479 private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
2480 public void onReceive(final Context context, final Intent intent) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002481 final Account[] accounts = getAccounts();
2482 // send the result to the listeners
2483 synchronized (mAccountsUpdatedListeners) {
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002484 for (Map.Entry<OnAccountsUpdateListener, Handler> entry :
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002485 mAccountsUpdatedListeners.entrySet()) {
2486 postToHandler(entry.getValue(), entry.getKey(), accounts);
Fred Quintanad9d2f112009-04-23 13:36:27 -07002487 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002488 }
Fred Quintanad9d2f112009-04-23 13:36:27 -07002489 }
2490 };
2491
2492 /**
Dan Egnor661f0132010-02-19 11:23:00 -08002493 * Adds an {@link OnAccountsUpdateListener} to this instance of the
2494 * {@link AccountManager}. This listener will be notified whenever the
2495 * list of accounts on the device changes.
2496 *
2497 * <p>As long as this listener is present, the AccountManager instance
2498 * will not be garbage-collected, and neither will the {@link Context}
2499 * used to retrieve it, which may be a large Activity instance. To avoid
2500 * memory leaks, you must remove this listener before then. Normally
2501 * listeners are added in an Activity or Service's {@link Activity#onCreate}
2502 * and removed in {@link Activity#onDestroy}.
2503 *
2504 * <p>It is safe to call this method from the main thread.
2505 *
Nicolas Falliere9530e3a2012-06-18 17:21:06 -07002506 * <p>This method requires the caller to hold the permission
2507 * {@link android.Manifest.permission#GET_ACCOUNTS}.
Dan Egnor661f0132010-02-19 11:23:00 -08002508 *
2509 * @param listener The listener to send notifications to
2510 * @param handler {@link Handler} identifying the thread to use
2511 * for notifications, null for the main thread
2512 * @param updateImmediately If true, the listener will be invoked
2513 * (on the handler thread) right away with the current account list
Fred Quintanad9d2f112009-04-23 13:36:27 -07002514 * @throws IllegalArgumentException if listener is null
2515 * @throws IllegalStateException if listener was already added
2516 */
Tor Norbye80b530a2015-04-23 16:36:09 -07002517 @RequiresPermission(GET_ACCOUNTS)
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002518 public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
Fred Quintanad9d2f112009-04-23 13:36:27 -07002519 Handler handler, boolean updateImmediately) {
2520 if (listener == null) {
2521 throw new IllegalArgumentException("the listener is null");
2522 }
2523 synchronized (mAccountsUpdatedListeners) {
2524 if (mAccountsUpdatedListeners.containsKey(listener)) {
2525 throw new IllegalStateException("this listener is already added");
2526 }
2527 final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
2528
2529 mAccountsUpdatedListeners.put(listener, handler);
2530
2531 if (wasEmpty) {
2532 // Register a broadcast receiver to monitor account changes
2533 IntentFilter intentFilter = new IntentFilter();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002534 intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
Costin Manolacheb6437242009-09-10 16:14:12 -07002535 // To recover from disk-full.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002536 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
Fred Quintanad9d2f112009-04-23 13:36:27 -07002537 mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
2538 }
2539 }
2540
2541 if (updateImmediately) {
Fred Quintanaffd0cb042009-08-15 21:45:26 -07002542 postToHandler(handler, listener, getAccounts());
Fred Quintanad9d2f112009-04-23 13:36:27 -07002543 }
2544 }
2545
2546 /**
Dan Egnor661f0132010-02-19 11:23:00 -08002547 * Removes an {@link OnAccountsUpdateListener} previously registered with
2548 * {@link #addOnAccountsUpdatedListener}. The listener will no longer
2549 * receive notifications of account changes.
2550 *
2551 * <p>It is safe to call this method from the main thread.
2552 *
2553 * <p>No permission is required to call this method.
2554 *
2555 * @param listener The previously added listener to remove
Fred Quintanad9d2f112009-04-23 13:36:27 -07002556 * @throws IllegalArgumentException if listener is null
2557 * @throws IllegalStateException if listener was not already added
2558 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -07002559 public void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) {
Fred Quintana382601f2010-03-25 12:25:10 -07002560 if (listener == null) throw new IllegalArgumentException("listener is null");
Fred Quintanad9d2f112009-04-23 13:36:27 -07002561 synchronized (mAccountsUpdatedListeners) {
Bryan Mawhinney5be61f52009-09-24 14:50:25 +01002562 if (!mAccountsUpdatedListeners.containsKey(listener)) {
Costin Manolache88a211b2009-10-29 11:30:11 -07002563 Log.e(TAG, "Listener was not previously added");
2564 return;
Fred Quintanad9d2f112009-04-23 13:36:27 -07002565 }
Bryan Mawhinney5be61f52009-09-24 14:50:25 +01002566 mAccountsUpdatedListeners.remove(listener);
Fred Quintanad9d2f112009-04-23 13:36:27 -07002567 if (mAccountsUpdatedListeners.isEmpty()) {
2568 mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
2569 }
2570 }
2571 }
Fred Quintana60307342009-03-24 22:48:12 -07002572}