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