1603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/* 2603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Copyright (C) 2009 The Android Open Source Project 3603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * 4603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Licensed under the Apache License, Version 2.0 (the "License"); 5603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * you may not use this file except in compliance with the License. 6603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * You may obtain a copy of the License at 7603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * 8603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * http://www.apache.org/licenses/LICENSE-2.0 9603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * 10603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Unless required by applicable law or agreed to in writing, software 11603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * distributed under the License is distributed on an "AS IS" BASIS, 12603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * See the License for the specific language governing permissions and 14603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * limitations under the License. 15603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */ 16603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 17603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapackage android.accounts; 18603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 19603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.app.Activity; 20603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.content.Intent; 21603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.content.Context; 22d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport android.content.IntentFilter; 23d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport android.content.BroadcastReceiver; 24b6437245c280596d0a580b8d67189739cf793250Costin Manolacheimport android.database.SQLException; 25a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Bundle; 26a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Handler; 27a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Looper; 28a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.RemoteException; 293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintanaimport android.os.Parcelable; 30751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintanaimport android.os.Build; 31b6437245c280596d0a580b8d67189739cf793250Costin Manolacheimport android.util.Log; 32f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintanaimport android.text.TextUtils; 33603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 34a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.IOException; 351121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintanaimport java.util.ArrayList; 36a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.Callable; 37a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.CancellationException; 38a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.ExecutionException; 39a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.FutureTask; 40a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.TimeoutException; 41a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.TimeUnit; 42d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport java.util.HashMap; 43d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport java.util.Map; 44d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana 451121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintanaimport com.google.android.collect.Lists; 46d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport com.google.android.collect.Maps; 47603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 48603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/** 49661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * This class provides access to a centralized registry of the user's 508e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * online accounts. The user enters credentials (username and password) once 518e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * per account, granting applications access to online resources with 528e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * "one-click" approval. 53603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * 54661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>Different online services have different ways of handling accounts and 55661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * authentication, so the account manager uses pluggable <em>authenticator</em> 568e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * modules for different <em>account types</em>. Authenticators (which may be 578e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * written by third parties) handle the actual details of validating account 588e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * credentials and storing account information. For example, Google, Facebook, 598e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * and Microsoft Exchange each have their own authenticator. 60661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 61661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>Many servers support some notion of an <em>authentication token</em>, 62661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * which can be used to authenticate a request to the server without sending 63661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the user's actual password. (Auth tokens are normally created with a 64661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * separate request which does include the user's credentials.) AccountManager 658e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * can generate auth tokens for applications, so the application doesn't need to 668e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * handle passwords directly. Auth tokens are normally reusable and cached by 678e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * AccountManager, but must be refreshed periodically. It's the responsibility 688e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * of applications to <em>invalidate</em> auth tokens when they stop working so 698e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * the AccountManager knows it needs to regenerate them. 70661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 71661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>Applications accessing a server normally go through these steps: 72661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 73661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <ul> 74661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li>Get an instance of AccountManager using {@link #get(Context)}. 75661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 76661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li>List the available accounts using {@link #getAccountsByType} or 77661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #getAccountsByTypeAndFeatures}. Normally applications will only 78661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * be interested in accounts with one particular <em>type</em>, which 79661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * identifies the authenticator. Account <em>features</em> are used to 80661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * identify particular account subtypes and capabilities. Both the account 81661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * type and features are authenticator-specific strings, and must be known by 82661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the application in coordination with its preferred authenticators. 83661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 84661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li>Select one or more of the available accounts, possibly by asking the 85661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * user for their preference. If no suitable accounts are available, 86661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #addAccount} may be called to prompt the user to create an 87661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * account of the appropriate type. 88661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 898e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * <li><b>Important:</b> If the application is using a previously remembered 908e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * account selection, it must make sure the account is still in the list 918e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * of accounts returned by {@link #getAccountsByType}. Requesting an auth token 928e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * for an account no longer on the device results in an undefined failure. 938e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * 94661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li>Request an auth token for the selected account(s) using one of the 95661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #getAuthToken} methods or related helpers. Refer to the description 96661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * of each method for exact usage and error handling details. 97661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 98661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li>Make the request using the auth token. The form of the auth token, 99661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the format of the request, and the protocol used are all specific to the 1008e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * service you are accessing. The application may use whatever network and 1018e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * protocol libraries are useful. 102661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 103661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li><b>Important:</b> If the request fails with an authentication error, 104661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * it could be that a cached auth token is stale and no longer honored by 105661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the server. The application must call {@link #invalidateAuthToken} to remove 106661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the token from the cache, otherwise requests will continue failing! After 107661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * invalidating the auth token, immediately go back to the "Request an auth 108661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * token" step above. If the process fails the second time, then it can be 109661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * treated as a "genuine" authentication failure and the user notified or other 110661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * appropriate actions taken. 111661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * </ul> 112661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1138e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * <p>Some AccountManager methods may need to interact with the user to 114661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * prompt for credentials, present options, or ask the user to add an account. 115661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * The caller may choose whether to allow AccountManager to directly launch the 116661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * necessary user interface and wait for the user, or to return an Intent which 117661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the caller may use to launch the interface, or (in some cases) to install a 118661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * notification which the user can select at any time to launch the interface. 119661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * To have AccountManager launch the interface directly, the caller must supply 120661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the current foreground {@link Activity} context. 121661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 122661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>Many AccountManager methods take {@link AccountManagerCallback} and 1238e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * {@link Handler} as parameters. These methods return immediately and 124661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * run asynchronously. If a callback is provided then 125661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerCallback#run} will be invoked on the Handler's 126661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * thread when the request completes, successfully or not. 1278e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * The result is retrieved by calling {@link AccountManagerFuture#getResult()} 1288e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * on the {@link AccountManagerFuture} returned by the method (and also passed 1298e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * to the callback). This method waits for the operation to complete (if 1308e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * necessary) and either returns the result or throws an exception if an error 1318e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * occurred during the operation. To make the request synchronously, call 132661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture#getResult()} immediately on receiving the 1338e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * future from the method; no callback need be supplied. 134661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 135661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>Requests which may block, including 136661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture#getResult()}, must never be called on 137661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the application's main event thread. These operations throw 138661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link IllegalStateException} if they are used on the main thread. 139603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */ 140603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapublic class AccountManager { 141603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana private static final String TAG = "AccountManager"; 142603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 143f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final int ERROR_CODE_REMOTE_EXCEPTION = 1; 144f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final int ERROR_CODE_NETWORK_ERROR = 3; 145f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final int ERROR_CODE_CANCELED = 4; 146f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final int ERROR_CODE_INVALID_RESPONSE = 5; 147f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6; 148f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final int ERROR_CODE_BAD_ARGUMENTS = 7; 149f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final int ERROR_CODE_BAD_REQUEST = 8; 150756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana 151661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor /** 1528e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * Bundle key used for the {@link String} account name in results 153661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * from methods which return information about a particular account. 154661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor */ 155f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final String KEY_ACCOUNT_NAME = "authAccount"; 156661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor 157661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor /** 1588e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * Bundle key used for the {@link String} account type in results 159661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * from methods which return information about a particular account. 160661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor */ 161f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final String KEY_ACCOUNT_TYPE = "accountType"; 162661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor 163661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor /** 1648e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * Bundle key used for the auth token value in results 165661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * from {@link #getAuthToken} and friends. 166661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor */ 167661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor public static final String KEY_AUTHTOKEN = "authtoken"; 168661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor 169661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor /** 1708e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * Bundle key used for an {@link Intent} in results from methods that 171661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * may require the caller to interact with the user. The Intent can 172661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * be used to start the corresponding user interface activity. 173661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor */ 174f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final String KEY_INTENT = "intent"; 175661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor 176661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor /** 1778e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * Bundle key used to supply the password directly in options to 178661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #confirmCredentials}, rather than prompting the user with 179661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the standard password prompt. 180661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor */ 181661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor public static final String KEY_PASSWORD = "password"; 182661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor 183661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor public static final String KEY_ACCOUNTS = "accounts"; 18446703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom 185f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse"; 186f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse"; 187661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor public static final String KEY_AUTHENTICATOR_TYPES = "authenticator_types"; 188f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage"; 189f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final String KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey"; 190661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor public static final String KEY_BOOLEAN_RESULT = "booleanResult"; 191661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor public static final String KEY_ERROR_CODE = "errorCode"; 192661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor public static final String KEY_ERROR_MESSAGE = "errorMessage"; 193661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor public static final String KEY_USERDATA = "userdata"; 194b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache 195a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache /** 196a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache * Authenticators using 'customTokens' option will also get the UID of the 197a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache * caller 198a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache */ 199a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache public static final String KEY_CALLER_UID = "callerUid"; 200a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache public static final String KEY_CALLER_PID = "callerPid"; 201661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor 202d606045070dcf6a011e49a7711d2f17d8f2de8c1Costin Manolache /** 203ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * The Android package of the caller will be set in the options bundle by the 204ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * {@link AccountManager} and will be passed to the AccountManagerService and 205ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * to the AccountAuthenticators. The uid of the caller will be known by the 206ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * AccountManagerService as well as the AccountAuthenticators so they will be able to 207ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * verify that the package is consistent with the uid (a uid might be shared by many 208ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * packages). 209ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana */ 210ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana public static final String KEY_ANDROID_PACKAGE_NAME = "androidPackageName"; 211ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana 212ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana /** 213d606045070dcf6a011e49a7711d2f17d8f2de8c1Costin Manolache * Boolean, if set and 'customTokens' the authenticator is responsible for 214d606045070dcf6a011e49a7711d2f17d8f2de8c1Costin Manolache * notifications. 215d606045070dcf6a011e49a7711d2f17d8f2de8c1Costin Manolache * @hide 216d606045070dcf6a011e49a7711d2f17d8f2de8c1Costin Manolache */ 217d606045070dcf6a011e49a7711d2f17d8f2de8c1Costin Manolache public static final String KEY_NOTIFY_ON_FAILURE = "notifyOnAuthFailure"; 218d606045070dcf6a011e49a7711d2f17d8f2de8c1Costin Manolache 219f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final String ACTION_AUTHENTICATOR_INTENT = 220f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana "android.accounts.AccountAuthenticator"; 221f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final String AUTHENTICATOR_META_DATA_NAME = 222661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor "android.accounts.AccountAuthenticator"; 223f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator"; 224f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana 225603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana private final Context mContext; 226603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana private final IAccountManager mService; 227d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana private final Handler mMainHandler; 228661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor 229f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana /** 230f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana * Action sent as a broadcast Intent by the AccountsService 231661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * when accounts are added, accounts are removed, or an 232661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * account's credentials (saved password, etc) are changed. 233661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 234661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @see #addOnAccountsUpdatedListener 235f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana */ 236f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public static final String LOGIN_ACCOUNTS_CHANGED_ACTION = 237f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana "android.accounts.LOGIN_ACCOUNTS_CHANGED"; 238603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 2393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana /** 2403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana * @hide 2413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana */ 242603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana public AccountManager(Context context, IAccountManager service) { 243603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana mContext = context; 244603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana mService = service; 245d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana mMainHandler = new Handler(mContext.getMainLooper()); 246603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 247603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 2480eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana /** 2490eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana * @hide used for testing only 2500eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana */ 2510eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana public AccountManager(Context context, IAccountManager service, Handler handler) { 2520eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana mContext = context; 2530eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana mService = service; 2540eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana mMainHandler = handler; 2550eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana } 2560eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana 257756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 258f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana * @hide for internal use only 259f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana */ 260f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana public static Bundle sanitizeResult(Bundle result) { 261382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (result != null) { 262382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (result.containsKey(KEY_AUTHTOKEN) 263382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana && !TextUtils.isEmpty(result.getString(KEY_AUTHTOKEN))) { 264382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana final Bundle newResult = new Bundle(result); 265382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana newResult.putString(KEY_AUTHTOKEN, "<omitted for logging purposes>"); 266382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana return newResult; 267382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana } 268f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana } 269f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana return result; 270f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana } 271f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana 272f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana /** 273661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Gets an AccountManager instance associated with a Context. 274661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * The {@link Context} will be used as long as the AccountManager is 275661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * active, so make sure to use a {@link Context} whose lifetime is 276661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * commensurate with any listeners registered to 277661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #addOnAccountsUpdatedListener} or similar methods. 278661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 279661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 280661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 281661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>No permission is required to call this method. 282661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 283756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * @param context The {@link Context} to use when necessary 284661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An {@link AccountManager} instance 285756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 286a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public static AccountManager get(Context context) { 287382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (context == null) throw new IllegalArgumentException("context is null"); 288a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); 289a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 290a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 291756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 292661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Gets the saved password associated with the account. 293661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * This is intended for authenticators and related code; applications 294661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * should get an auth token instead. 295661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 296661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 297661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 298661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 299661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} 300661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * and to have the same UID as the account's authenticator. 301661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 302661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account to query for a password 303661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return The account's password, null if none or if the account doesn't exist 304756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 305ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public String getPassword(final Account account) { 306382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 307603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana try { 308603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana return mService.getPassword(account); 309603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } catch (RemoteException e) { 310ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // will never happen 311603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana throw new RuntimeException(e); 312603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 313603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 314603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 315756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 316661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Gets the user data named by "key" associated with the account. 317661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * This is intended for authenticators and related code to store 318661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * arbitrary metadata along with accounts. The meaning of the keys 319661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * and values is up to the authenticator for the account. 320661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 321661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 322661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 323661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 324661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} 325661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * and to have the same UID as the account's authenticator. 326661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 327661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account to query for user data 328661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return The user data, null if the account or key doesn't exist 329756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 330ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public String getUserData(final Account account, final String key) { 331382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 332382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (key == null) throw new IllegalArgumentException("key is null"); 333603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana try { 334603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana return mService.getUserData(account, key); 335603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } catch (RemoteException e) { 336ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // will never happen 337603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana throw new RuntimeException(e); 338603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 339603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 340603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 341756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 342661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Lists the currently registered authenticators. 343661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 344661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 345661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 346661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>No permission is required to call this method. 347661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 348661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An array of {@link AuthenticatorDescription} for every 349661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * authenticator known to the AccountManager service. Empty (never 350661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null) if no authenticators are known. 351756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 352ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public AuthenticatorDescription[] getAuthenticatorTypes() { 353603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana try { 354a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return mService.getAuthenticatorTypes(); 355603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } catch (RemoteException e) { 356ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // will never happen 357603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana throw new RuntimeException(e); 358603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 359603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 360603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 361756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 362661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Lists all accounts of any type registered on the device. 363661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Equivalent to getAccountsByType(null). 364661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 365661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 366661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 367661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 368661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#GET_ACCOUNTS}. 369661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 370661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An array of {@link Account}, one for each account. Empty 371661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * (never null) if no accounts have been added. 372756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 373ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public Account[] getAccounts() { 374a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana try { 375ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana return mService.getAccounts(null); 376a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } catch (RemoteException e) { 377ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // won't ever happen 378a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw new RuntimeException(e); 379a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 380603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 381603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 382756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 383661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Lists all accounts of a particular type. The account type is a 384661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * string token corresponding to the authenticator and useful domain 385661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * of the account. For example, there are types corresponding to Google 386661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * and Facebook. The exact string token to use will be published somewhere 387661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * associated with the authenticator in question. 388661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 389661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 390661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 391661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 392661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#GET_ACCOUNTS}. 393661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 394661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param type The type of accounts to return, null to retrieve all accounts 395661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An array of {@link Account}, one per matching account. Empty 396661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * (never null) if no accounts of the specified type have been added. 397756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 398ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public Account[] getAccountsByType(String type) { 399603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana try { 400ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana return mService.getAccounts(type); 401603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } catch (RemoteException e) { 402ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // won't ever happen 403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana throw new RuntimeException(e); 404603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 405603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 406603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 407756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 408661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Finds out whether a particular account has all the specified features. 409661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Account features are authenticator-specific string tokens identifying 410661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * boolean account properties. For example, features are used to tell 411661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * whether Google accounts have a particular service (such as Google 412661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Calendar or Google Talk) enabled. The feature names and their meanings 413661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * are published somewhere associated with the authenticator in question. 414661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 415661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method may be called from any thread, but the returned 416661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture} must not be used on the main thread. 417661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 418661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 419661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#GET_ACCOUNTS}. 420bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana * 421bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana * @param account The {@link Account} to test 422661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param features An array of the account features to check 423661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param callback Callback to invoke when the request completes, 424661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for no callback 425661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param handler {@link Handler} identifying the callback thread, 426661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for the main thread 427661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An {@link AccountManagerFuture} which resolves to a Boolean, 428661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * true if the account exists and has all of the specified features. 429bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana */ 4303084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana public AccountManagerFuture<Boolean> hasFeatures(final Account account, 431bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana final String[] features, 432bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana AccountManagerCallback<Boolean> callback, Handler handler) { 433382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 434382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (features == null) throw new IllegalArgumentException("features is null"); 435bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana return new Future2Task<Boolean>(handler, callback) { 436bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana public void doWork() throws RemoteException { 4373084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana mService.hasFeatures(mResponse, account, features); 438bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana } 439bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { 440bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) { 441bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana throw new AuthenticatorException("no result in response"); 442bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana } 443bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana return bundle.getBoolean(KEY_BOOLEAN_RESULT); 444bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana } 445bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana }.start(); 446bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana } 447bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana 448bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana /** 449661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Lists all accounts of a type which have certain features. The account 450661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * type identifies the authenticator (see {@link #getAccountsByType}). 451661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Account features are authenticator-specific string tokens identifying 452661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * boolean account properties (see {@link #hasFeatures}). 453661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 454661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>Unlike {@link #getAccountsByType}, this method calls the authenticator, 455661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * which may contact the server or do other work to check account features, 456661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * so the method returns an {@link AccountManagerFuture}. 457661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 458661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method may be called from any thread, but the returned 459661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture} must not be used on the main thread. 460661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 461661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 462661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#GET_ACCOUNTS}. 463661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 464661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param type The type of accounts to return, must not be null 465661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param features An array of the account features to require, 466661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * may be null or empty 467661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param callback Callback to invoke when the request completes, 468661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for no callback 469661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param handler {@link Handler} identifying the callback thread, 470661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for the main thread 471661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An {@link AccountManagerFuture} which resolves to an array of 472661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link Account}, one per account of the specified type which 473661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * matches the requested features. 474661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor */ 475661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures( 476661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor final String type, final String[] features, 477661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor AccountManagerCallback<Account[]> callback, Handler handler) { 478382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (type == null) throw new IllegalArgumentException("type is null"); 479661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor return new Future2Task<Account[]>(handler, callback) { 480661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor public void doWork() throws RemoteException { 481661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor mService.getAccountsByFeatures(mResponse, type, features); 482661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor } 483661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException { 484661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor if (!bundle.containsKey(KEY_ACCOUNTS)) { 485661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor throw new AuthenticatorException("no result in response"); 486661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor } 487661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor final Parcelable[] parcelables = bundle.getParcelableArray(KEY_ACCOUNTS); 488661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor Account[] descs = new Account[parcelables.length]; 489661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor for (int i = 0; i < parcelables.length; i++) { 490661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor descs[i] = (Account) parcelables[i]; 491661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor } 492661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor return descs; 493661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor } 494661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor }.start(); 495661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor } 496661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor 497661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor /** 498661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Adds an account directly to the AccountManager. Normally used by sign-up 499661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * wizards associated with authenticators, not directly by applications. 500661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 501661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 502661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 503661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 504661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} 505661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * and to have the same UID as the added account's authenticator. 506661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 507661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The {@link Account} to add 508661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param password The password to associate with the account, null for none 509661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param userdata String values to use for the account's userdata, null for none 5108e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * @return True if the account was successfully added, false if the account 511661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * already exists, the account is null, or another error occurs. 512756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 51331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana public boolean addAccountExplicitly(Account account, String password, Bundle userdata) { 514382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 515603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana try { 51631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana return mService.addAccount(account, password, userdata); 517603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } catch (RemoteException e) { 518ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // won't ever happen 519603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana throw new RuntimeException(e); 520603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 521603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 522603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 523756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 524661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Removes an account from the AccountManager. Does nothing if the account 525661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * does not exist. Does not delete the account from the server. 526661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * The authenticator may have its own policies preventing account 527661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * deletion, in which case the account will not be deleted. 528661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 529661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method may be called from any thread, but the returned 530661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture} must not be used on the main thread. 531661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 532661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 533661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. 534756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * 535756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * @param account The {@link Account} to remove 536661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param callback Callback to invoke when the request completes, 537661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for no callback 538661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param handler {@link Handler} identifying the callback thread, 539661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for the main thread 540661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An {@link AccountManagerFuture} which resolves to a Boolean, 541661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * true if the account has been successfully removed, 542661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * false if the authenticator forbids deleting this account. 543756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 544ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public AccountManagerFuture<Boolean> removeAccount(final Account account, 545ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana AccountManagerCallback<Boolean> callback, Handler handler) { 546382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 547ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana return new Future2Task<Boolean>(handler, callback) { 548ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void doWork() throws RemoteException { 549ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mService.removeAccount(mResponse, account); 550a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 551ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { 552f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) { 553ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throw new AuthenticatorException("no result in response"); 554ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 555f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana return bundle.getBoolean(KEY_BOOLEAN_RESULT); 556a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 557ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana }.start(); 558a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 559a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 560756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 561661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Removes an auth token from the AccountManager's cache. Does nothing if 562661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the auth token is not currently in the cache. Applications must call this 563661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * method when the auth token is found to have expired or otherwise become 564661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * invalid for authenticating requests. The AccountManager does not validate 565661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * or expire cached auth tokens otherwise. 566661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 567661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 568661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 569661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 570b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana * {@link android.Manifest.permission#MANAGE_ACCOUNTS} or 571b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana * {@link android.Manifest.permission#USE_CREDENTIALS} 572661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 573f35b68f2b926021bce407f092cfe3e8f52fa0794Fred Quintana * @param accountType The account type of the auth token to invalidate, must not be null 574f35b68f2b926021bce407f092cfe3e8f52fa0794Fred Quintana * @param authToken The auth token to invalidate, may be null 575756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 576ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void invalidateAuthToken(final String accountType, final String authToken) { 577382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (accountType == null) throw new IllegalArgumentException("accountType is null"); 578603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana try { 579f35b68f2b926021bce407f092cfe3e8f52fa0794Fred Quintana if (authToken != null) { 580f35b68f2b926021bce407f092cfe3e8f52fa0794Fred Quintana mService.invalidateAuthToken(accountType, authToken); 581f35b68f2b926021bce407f092cfe3e8f52fa0794Fred Quintana } 582603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } catch (RemoteException e) { 583ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // won't ever happen 584ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throw new RuntimeException(e); 585603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 586603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 587603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 588756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 589661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Gets an auth token from the AccountManager's cache. If no auth 590661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * token is cached for this account, null will be returned -- a new 591661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * auth token will not be generated, and the server will not be contacted. 592661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Intended for use by the authenticator, not directly by applications. 593661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 594661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 595661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 596661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 597661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} 598661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * and to have the same UID as the account's authenticator. 599661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 600661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account to fetch an auth token for 601661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param authTokenType The type of auth token to fetch, see {#getAuthToken} 602661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return The cached auth token for this account and type, or null if 603661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * no auth token is cached or the account does not exist. 604756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 605ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public String peekAuthToken(final Account account, final String authTokenType) { 606382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 607382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); 608603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana try { 609603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana return mService.peekAuthToken(account, authTokenType); 610603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } catch (RemoteException e) { 611ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // won't ever happen 612603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana throw new RuntimeException(e); 613603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 614603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 615603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 616756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 617661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Sets or forgets a saved password. This modifies the local copy of the 618661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * password used to automatically authenticate the user; it does 619661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * not change the user's account password on the server. Intended for use 620661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * by the authenticator, not directly by applications. 621661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 622661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 623661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 624661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 625661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} 626661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * and have the same UID as the account's authenticator. 627661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 628661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account to set a password for 629661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param password The password to set, null to clear the password 630756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 631ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void setPassword(final Account account, final String password) { 632382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 633603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana try { 634603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana mService.setPassword(account, password); 635603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } catch (RemoteException e) { 636ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // won't ever happen 637ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throw new RuntimeException(e); 638603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 639603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 640603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 641756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 642661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Forgets a saved password. This erases the local copy of the password; 643661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * it does not change the user's account password on the server. 644661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Has the same effect as setPassword(account, null) but requires fewer 645661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * permissions, and may be used by applications or management interfaces 646661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * to "sign out" from an account. 647661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 648661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 649661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 650661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 651661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#MANAGE_ACCOUNTS} 652661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 653661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account whose password to clear 654756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 655ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void clearPassword(final Account account) { 656382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 657603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana try { 658603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana mService.clearPassword(account); 659603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } catch (RemoteException e) { 660ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // won't ever happen 661ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throw new RuntimeException(e); 662603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 663603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 664603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 665756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 666661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Sets one userdata key for an account. Intended by use for the 667661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * authenticator to stash state for itself, not directly by applications. 668661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * The meaning of the keys and values is up to the authenticator. 669661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 670661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 671661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 672661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 673661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} 674661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * and to have the same UID as the account's authenticator. 675661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 676661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account to set the userdata for 677661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param key The userdata key to set. Must not be null 678661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param value The value to set, null to clear this userdata key 679756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 680ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void setUserData(final Account account, final String key, final String value) { 681382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 682382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (key == null) throw new IllegalArgumentException("key is null"); 683603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana try { 684603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana mService.setUserData(account, key, value); 685603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } catch (RemoteException e) { 686ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // won't ever happen 687ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throw new RuntimeException(e); 688603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 689603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 690603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 691756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 692661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Adds an auth token to the AccountManager cache for an account. 693756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * If the account does not exist then this call has no effect. 694661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Replaces any previous auth token for this account and auth token type. 695661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Intended for use by the authenticator, not directly by applications. 696661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 697661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 698661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 699661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 700661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} 701661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * and to have the same UID as the account's authenticator. 702661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 703661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account to set an auth token for 704661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param authTokenType The type of the auth token, see {#getAuthToken} 705661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param authToken The auth token to add to the cache 706756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 707ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void setAuthToken(Account account, final String authTokenType, final String authToken) { 708382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 709382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); 710603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana try { 711603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana mService.setAuthToken(account, authTokenType, authToken); 712603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } catch (RemoteException e) { 713ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // won't ever happen 714ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throw new RuntimeException(e); 715603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 716603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 717603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 718756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 719661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * This convenience helper synchronously gets an auth token with 720661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, Handler)}. 721661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 722661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method may block while a network request completes, and must 723661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * never be made from the main thread. 724661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 725661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 726661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#USE_CREDENTIALS}. 727661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 728661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account to fetch an auth token for 729661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param authTokenType The auth token type, see {#link getAuthToken} 730661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param notifyAuthFailure If true, display a notification and return null 731661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * if authentication fails; if false, prompt and wait for the user to 732661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * re-enter correct credentials before returning 733661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An auth token of the specified type for this account, or null 734661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * if authentication fails or none can be fetched. 735661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @throws AuthenticatorException if the authenticator failed to respond 736661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @throws OperationCanceledException if the request was canceled for any 737661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * reason, including the user canceling a credential request 738661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @throws java.io.IOException if the authenticator experienced an I/O problem 739661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * creating a new auth token, usually because of network trouble 740756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 741a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public String blockingGetAuthToken(Account account, String authTokenType, 742a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana boolean notifyAuthFailure) 743a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throws OperationCanceledException, IOException, AuthenticatorException { 744382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 745382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); 746a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */, 747a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana null /* handler */).getResult(); 74896580e00654a052a82120c374c6b5961ef349a92Fred Quintana if (bundle == null) { 74996580e00654a052a82120c374c6b5961ef349a92Fred Quintana // This should never happen, but it does, occasionally. If it does return null to 75096580e00654a052a82120c374c6b5961ef349a92Fred Quintana // signify that we were not able to get the authtoken. 75196580e00654a052a82120c374c6b5961ef349a92Fred Quintana // TODO: remove this when the bug is found that sometimes causes a null bundle to be 75296580e00654a052a82120c374c6b5961ef349a92Fred Quintana // returned 75396580e00654a052a82120c374c6b5961ef349a92Fred Quintana Log.e(TAG, "blockingGetAuthToken: null was returned from getResult() for " 75496580e00654a052a82120c374c6b5961ef349a92Fred Quintana + account + ", authTokenType " + authTokenType); 75596580e00654a052a82120c374c6b5961ef349a92Fred Quintana return null; 75696580e00654a052a82120c374c6b5961ef349a92Fred Quintana } 757f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana return bundle.getString(KEY_AUTHTOKEN); 758a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 759a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 760a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana /** 761661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Gets an auth token of the specified type for a particular account, 762661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * prompting the user for credentials if necessary. This method is 763661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * intended for applications running in the foreground where it makes 764661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * sense to ask the user directly for a password. 765661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 766661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>If a previously generated auth token is cached for this account and 7678e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * type, then it is returned. Otherwise, if a saved password is 7688e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * available, it is sent to the server to generate a new auth token. 7698e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * Otherwise, the user is prompted to enter a password. 770661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 7718e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * <p>Some authenticators have auth token <em>types</em>, whose value 7728e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * is authenticator-dependent. Some services use different token types to 7738e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * access different functionality -- for example, Google uses different auth 7748e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * tokens to access Gmail and Google Calendar for the same account. 775661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 776661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method may be called from any thread, but the returned 777661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture} must not be used on the main thread. 778661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 779661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 780661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#USE_CREDENTIALS}. 781661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 782661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account to fetch an auth token for 783661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param authTokenType The auth token type, an authenticator-dependent 784661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * string token, must not be null 785661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param options Authenticator-specific options for the request, 786661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * may be null or empty 787661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param activity The {@link Activity} context to use for launching a new 788661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * authenticator-defined sub-Activity to prompt the user for a password 789661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * if necessary; used only to call startActivity(); must not be null. 790661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param callback Callback to invoke when the request completes, 791661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for no callback 792661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param handler {@link Handler} identifying the callback thread, 793661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for the main thread 794661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An {@link AccountManagerFuture} which resolves to a Bundle with 795661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * at least the following fields: 796661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <ul> 797661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied 798661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account 799661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted 800661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * </ul> 801661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 802661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * (Other authenticator-specific values may be returned.) If an auth token 803661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * could not be fetched, {@link AccountManagerFuture#getResult()} throws: 804756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * <ul> 805661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link AuthenticatorException} if the authenticator failed to respond 806661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link OperationCanceledException} if the operation is canceled for 807661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * any reason, incluidng the user canceling a credential request 808661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link IOException} if the authenticator experienced an I/O problem 809661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * creating a new auth token, usually because of network trouble 810756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * </ul> 8118e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * If the account is no longer present on the device, the return value is 8128e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * authenticator-dependent. The caller should verify the validity of the 8138e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * account before requesting an auth token. 814a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana */ 815ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public AccountManagerFuture<Bundle> getAuthToken( 81631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana final Account account, final String authTokenType, final Bundle options, 817ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { 818382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 819a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); 820e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache final Bundle optionsIn = new Bundle(); 821e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache if (options != null) { 822e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache optionsIn.putAll(options); 823e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache } 824b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName()); 825a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return new AmsTask(activity, handler, callback) { 826a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public void doWork() throws RemoteException { 827a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana mService.getAuthToken(mResponse, account, authTokenType, 828a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana false /* notifyOnAuthFailure */, true /* expectActivityLaunch */, 829b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache optionsIn); 830a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 8313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana }.start(); 832a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 833a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 834756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 835661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Gets an auth token of the specified type for a particular account, 836661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * optionally raising a notification if the user must enter credentials. 837661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * This method is intended for background tasks and services where the 838661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * user should not be immediately interrupted with a password prompt. 839661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 840661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>If a previously generated auth token is cached for this account and 8418e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * type, then it is returned. Otherwise, if a saved password is 8428e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * available, it is sent to the server to generate a new auth token. 8438e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * Otherwise, an {@link Intent} is returned which, when started, will 8448e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * prompt the user for a password. If the notifyAuthFailure parameter is 8458e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * set, a status bar notification is also created with the same Intent, 846661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * alerting the user that they need to enter a password at some point. 847661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 8488e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * <p>In that case, you may need to wait until the user responds, which 8498e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * could take hours or days or forever. When the user does respond and 8508e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * supply a new password, the account manager will broadcast the 8518e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can 8528e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * use to try again. 853661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 8548e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * <p>If notifyAuthFailure is not set, it is the application's 8558e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * responsibility to launch the returned Intent at some point. 8568e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * Either way, the result from this call will not wait for user action. 857661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 8588e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * <p>Some authenticators have auth token <em>types</em>, whose value 8598e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * is authenticator-dependent. Some services use different token types to 8608e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * access different functionality -- for example, Google uses different auth 8618e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * tokens to access Gmail and Google Calendar for the same account. 862661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 863661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method may be called from any thread, but the returned 864661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture} must not be used on the main thread. 865661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 866661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 867661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#USE_CREDENTIALS}. 868661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 869661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account to fetch an auth token for 870661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param authTokenType The auth token type, an authenticator-dependent 871661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * string token, must not be null 872661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param notifyAuthFailure True to add a notification to prompt the 873661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * user for a password if necessary, false to leave that to the caller 874661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param callback Callback to invoke when the request completes, 875661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for no callback 876661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param handler {@link Handler} identifying the callback thread, 877661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for the main thread 878661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An {@link AccountManagerFuture} which resolves to a Bundle with 879661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * at least the following fields on success: 880756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * <ul> 881661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied 882661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account 883661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted 884661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * </ul> 885661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 886661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * (Other authenticator-specific values may be returned.) If the user 887661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * must enter credentials, the returned Bundle contains only 888661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt. 889661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 8908e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * If an error occurred, {@link AccountManagerFuture#getResult()} throws: 891661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <ul> 892661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link AuthenticatorException} if the authenticator failed to respond 893661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link OperationCanceledException} if the operation is canceled for 894661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * any reason, incluidng the user canceling a credential request 895661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link IOException} if the authenticator experienced an I/O problem 896661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * creating a new auth token, usually because of network trouble 897756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * </ul> 8988e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * If the account is no longer present on the device, the return value is 8998e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * authenticator-dependent. The caller should verify the validity of the 9008e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * account before requesting an auth token. 901ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * @deprecated use {@link #getAuthToken(Account, String, android.os.Bundle, 902ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * boolean, AccountManagerCallback, android.os.Handler)} instead 903756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 904ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana @Deprecated 905ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public AccountManagerFuture<Bundle> getAuthToken( 906b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache final Account account, final String authTokenType, 907b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache final boolean notifyAuthFailure, 908ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana AccountManagerCallback<Bundle> callback, Handler handler) { 909b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache return getAuthToken(account, authTokenType, null, notifyAuthFailure, callback, 910b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache handler); 911a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 912a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 913756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 914ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * Gets an auth token of the specified type for a particular account, 915ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * optionally raising a notification if the user must enter credentials. 916ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * This method is intended for background tasks and services where the 917ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * user should not be immediately interrupted with a password prompt. 918ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * 919ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <p>If a previously generated auth token is cached for this account and 920ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * type, then it is returned. Otherwise, if a saved password is 921ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * available, it is sent to the server to generate a new auth token. 922ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * Otherwise, an {@link Intent} is returned which, when started, will 923ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * prompt the user for a password. If the notifyAuthFailure parameter is 924ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * set, a status bar notification is also created with the same Intent, 925ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * alerting the user that they need to enter a password at some point. 926ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * 927ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <p>In that case, you may need to wait until the user responds, which 928ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * could take hours or days or forever. When the user does respond and 929ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * supply a new password, the account manager will broadcast the 930ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can 931ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * use to try again. 932ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * 933ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <p>If notifyAuthFailure is not set, it is the application's 934ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * responsibility to launch the returned Intent at some point. 935ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * Either way, the result from this call will not wait for user action. 936ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * 937ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <p>Some authenticators have auth token <em>types</em>, whose value 938ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * is authenticator-dependent. Some services use different token types to 939ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * access different functionality -- for example, Google uses different auth 940ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * tokens to access Gmail and Google Calendar for the same account. 941ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * 942ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <p>This method may be called from any thread, but the returned 943ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * {@link AccountManagerFuture} must not be used on the main thread. 944ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * 945ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <p>This method requires the caller to hold the permission 946ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * {@link android.Manifest.permission#USE_CREDENTIALS}. 947ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * 948ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * @param account The account to fetch an auth token for 949ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * @param authTokenType The auth token type, an authenticator-dependent 950ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * string token, must not be null 951ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * @param options Authenticator-specific options for the request, 952ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * may be null or empty 953ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * @param notifyAuthFailure True to add a notification to prompt the 954ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * user for a password if necessary, false to leave that to the caller 955ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * @param callback Callback to invoke when the request completes, 956ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * null for no callback 957ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * @param handler {@link Handler} identifying the callback thread, 958ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * null for the main thread 959ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * @return An {@link AccountManagerFuture} which resolves to a Bundle with 960ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * at least the following fields on success: 961ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <ul> 962ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied 963ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account 964ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted 965ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * </ul> 966ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * 967ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * (Other authenticator-specific values may be returned.) If the user 968ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * must enter credentials, the returned Bundle contains only 969ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt. 970ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * 971ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * If an error occurred, {@link AccountManagerFuture#getResult()} throws: 972ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <ul> 973ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <li> {@link AuthenticatorException} if the authenticator failed to respond 974ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <li> {@link OperationCanceledException} if the operation is canceled for 975ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * any reason, incluidng the user canceling a credential request 976ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * <li> {@link IOException} if the authenticator experienced an I/O problem 977ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * creating a new auth token, usually because of network trouble 978ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * </ul> 979ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * If the account is no longer present on the device, the return value is 980ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * authenticator-dependent. The caller should verify the validity of the 981ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana * account before requesting an auth token. 982ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana */ 983ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana public AccountManagerFuture<Bundle> getAuthToken( 984b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache final Account account, final String authTokenType, final Bundle options, 985b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache final boolean notifyAuthFailure, 986ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana AccountManagerCallback<Bundle> callback, Handler handler) { 987b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache 988ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 989ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); 990e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache final Bundle optionsIn = new Bundle(); 991e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache if (options != null) { 992e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache optionsIn.putAll(options); 993e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache } 994b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName()); 995ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana return new AmsTask(null, handler, callback) { 996ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana public void doWork() throws RemoteException { 997ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana mService.getAuthToken(mResponse, account, authTokenType, 998b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache notifyAuthFailure, false /* expectActivityLaunch */, optionsIn); 999ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana } 1000ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana }.start(); 1001ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana } 1002ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana 1003ad93a323fef9761528512aff753c709b895c8ea0Fred Quintana /** 1004661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Asks the user to add an account of a specified type. The authenticator 1005661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * for this account type processes this request with the appropriate user 1006661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * interface. If the user does elect to create a new account, the account 1007661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * name is returned. 1008661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1009661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method may be called from any thread, but the returned 1010661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture} must not be used on the main thread. 1011661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1012661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 1013661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. 1014661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1015661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param accountType The type of account to add; must not be null 1016661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param authTokenType The type of auth token (see {@link #getAuthToken}) 1017661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * this account will need to be able to generate, null for none 1018661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param requiredFeatures The features (see {@link #hasFeatures}) this 1019661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * account must have, null for none 1020661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param addAccountOptions Authenticator-specific options for the request, 1021661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * may be null or empty 1022661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param activity The {@link Activity} context to use for launching a new 1023661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * authenticator-defined sub-Activity to prompt the user to create an 1024661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * account; used only to call startActivity(); if null, the prompt 1025661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * will not be launched directly, but the necessary {@link Intent} 1026661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * will be returned to the caller instead 1027661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param callback Callback to invoke when the request completes, 1028661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for no callback 1029661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param handler {@link Handler} identifying the callback thread, 1030661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for the main thread 1031ff592dc2fa53d48e4121d9b8fd70efc19938c4a1Doug Zongker * @return An {@link AccountManagerFuture} which resolves to a Bundle with 1032661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * these fields if activity was specified and an account was created: 1033756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * <ul> 1034661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created 1035661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account 1036661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * </ul> 1037661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1038661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * If no activity was specified, the returned Bundle contains only 1039661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #KEY_INTENT} with the {@link Intent} needed to launch the 10408e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * actual account creation process. If an error occurred, 10418e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * {@link AccountManagerFuture#getResult()} throws: 1042661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <ul> 1043661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link AuthenticatorException} if no authenticator was registered for 1044661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * this account type or the authenticator failed to respond 1045661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link OperationCanceledException} if the operation was canceled for 1046661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * any reason, including the user canceling the creation process 1047661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link IOException} if the authenticator experienced an I/O problem 1048661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * creating a new account, usually because of network trouble 1049756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * </ul> 1050756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 1051ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public AccountManagerFuture<Bundle> addAccount(final String accountType, 10523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana final String authTokenType, final String[] requiredFeatures, 10533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana final Bundle addAccountOptions, 1054ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { 1055382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (accountType == null) throw new IllegalArgumentException("accountType is null"); 1056e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache final Bundle optionsIn = new Bundle(); 1057e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache if (addAccountOptions != null) { 1058e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache optionsIn.putAll(addAccountOptions); 1059e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache } 1060e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName()); 1061b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache 1062a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return new AmsTask(activity, handler, callback) { 1063a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public void doWork() throws RemoteException { 1064a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana mService.addAcount(mResponse, accountType, authTokenType, 1065e5847ada7bdf99386dc13471a7d4f08bf779531bCostin Manolache requiredFeatures, activity != null, optionsIn); 1066a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 10673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana }.start(); 1068a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1069a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 10708570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana /** 1071661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Confirms that the user knows the password for an account to make extra 1072661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * sure they are the owner of the account. The user-entered password can 1073661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * be supplied directly, otherwise the authenticator for this account type 1074661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * prompts the user with the appropriate interface. This method is 1075661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * intended for applications which want extra assurance; for example, the 1076661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * phone lock screen uses this to let the user unlock the phone with an 1077661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * account password if they forget the lock pattern. 1078661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1079661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>If the user-entered password matches a saved password for this 1080661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * account, the request is considered valid; otherwise the authenticator 1081661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * verifies the password (usually by contacting the server). 1082661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1083661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method may be called from any thread, but the returned 1084661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture} must not be used on the main thread. 1085661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1086661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 1087661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. 1088661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1089661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account to confirm password knowledge for 1090661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param options Authenticator-specific options for the request; 1091661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * if the {@link #KEY_PASSWORD} string field is present, the 1092661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * authenticator may use it directly rather than prompting the user; 1093661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * may be null or empty 1094661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param activity The {@link Activity} context to use for launching a new 1095661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * authenticator-defined sub-Activity to prompt the user to enter a 1096661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * password; used only to call startActivity(); if null, the prompt 1097661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * will not be launched directly, but the necessary {@link Intent} 1098661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * will be returned to the caller instead 1099661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param callback Callback to invoke when the request completes, 1100661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for no callback 1101661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param handler {@link Handler} identifying the callback thread, 1102661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for the main thread 1103661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An {@link AccountManagerFuture} which resolves to a Bundle 1104661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * with these fields if activity or password was supplied and 1105661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * the account was successfully verified: 1106661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <ul> 1107661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created 1108661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account 1109661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_BOOLEAN_RESULT} - true to indicate success 1110661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * </ul> 1111661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1112661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * If no activity or password was specified, the returned Bundle contains 1113661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * only {@link #KEY_INTENT} with the {@link Intent} needed to launch the 11148e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * password prompt. If an error occurred, 11158e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * {@link AccountManagerFuture#getResult()} throws: 1116756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * <ul> 1117661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link AuthenticatorException} if the authenticator failed to respond 1118661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link OperationCanceledException} if the operation was canceled for 1119661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * any reason, including the user canceling the password prompt 1120661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link IOException} if the authenticator experienced an I/O problem 1121661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * verifying the password, usually because of network trouble 1122756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * </ul> 1123756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 1124f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public AccountManagerFuture<Bundle> confirmCredentials(final Account account, 1125f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana final Bundle options, 1126f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana final Activity activity, 1127ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final AccountManagerCallback<Bundle> callback, 1128a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana final Handler handler) { 1129382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 1130a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return new AmsTask(activity, handler, callback) { 1131a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public void doWork() throws RemoteException { 1132f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana mService.confirmCredentials(mResponse, account, options, activity != null); 1133a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 11343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana }.start(); 1135a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1136a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1137756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 1138661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Asks the user to enter a new password for an account, updating the 1139661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * saved credentials for the account. Normally this happens automatically 1140661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * when the server rejects credentials during an auth token fetch, but this 1141661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * can be invoked directly to ensure we have the correct credentials stored. 1142661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1143661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method may be called from any thread, but the returned 1144661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture} must not be used on the main thread. 1145661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1146661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 1147661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. 1148661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1149661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param account The account to update credentials for 1150661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param authTokenType The credentials entered must allow an auth token 1151661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * of this type to be created (but no actual auth token is returned); 1152661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * may be null 1153661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param options Authenticator-specific options for the request; 1154661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * may be null or empty 1155661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param activity The {@link Activity} context to use for launching a new 1156661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * authenticator-defined sub-Activity to prompt the user to enter a 1157661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * password; used only to call startActivity(); if null, the prompt 1158661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * will not be launched directly, but the necessary {@link Intent} 1159661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * will be returned to the caller instead 1160661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param callback Callback to invoke when the request completes, 1161661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for no callback 1162661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param handler {@link Handler} identifying the callback thread, 1163661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for the main thread 1164661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An {@link AccountManagerFuture} which resolves to a Bundle 1165661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * with these fields if an activity was supplied and the account 1166661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * credentials were successfully updated: 1167756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * <ul> 1168661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created 1169661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account 1170661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * </ul> 1171661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1172661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * If no activity was specified, the returned Bundle contains only 1173661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #KEY_INTENT} with the {@link Intent} needed to launch the 11748e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * password prompt. If an error occurred, 11758e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * {@link AccountManagerFuture#getResult()} throws: 1176661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <ul> 1177661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link AuthenticatorException} if the authenticator failed to respond 1178661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link OperationCanceledException} if the operation was canceled for 1179661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * any reason, including the user canceling the password prompt 1180661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link IOException} if the authenticator experienced an I/O problem 1181661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * verifying the password, usually because of network trouble 1182756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * </ul> 1183756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 1184756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana public AccountManagerFuture<Bundle> updateCredentials(final Account account, 1185756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana final String authTokenType, 118631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana final Bundle options, final Activity activity, 1187ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final AccountManagerCallback<Bundle> callback, 1188a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana final Handler handler) { 1189382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (account == null) throw new IllegalArgumentException("account is null"); 1190a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return new AmsTask(activity, handler, callback) { 1191a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public void doWork() throws RemoteException { 1192a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana mService.updateCredentials(mResponse, account, authTokenType, activity != null, 119331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana options); 1194a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 11953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana }.start(); 1196a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1197a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1198756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 1199661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Offers the user an opportunity to change an authenticator's settings. 1200661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * These properties are for the authenticator in general, not a particular 1201661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * account. Not all authenticators support this method. 1202661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1203661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method may be called from any thread, but the returned 1204661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture} must not be used on the main thread. 1205661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1206661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 1207661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. 1208661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1209661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param accountType The account type associated with the authenticator 1210661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * to adjust 1211661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param activity The {@link Activity} context to use for launching a new 1212661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * authenticator-defined sub-Activity to adjust authenticator settings; 1213661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * used only to call startActivity(); if null, the settings dialog will 1214661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * not be launched directly, but the necessary {@link Intent} will be 1215661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * returned to the caller instead 1216661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param callback Callback to invoke when the request completes, 1217661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for no callback 1218661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param handler {@link Handler} identifying the callback thread, 1219661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for the main thread 1220661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An {@link AccountManagerFuture} which resolves to a Bundle 1221661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * which is empty if properties were edited successfully, or 1222661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * if no activity was specified, contains only {@link #KEY_INTENT} 1223661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * needed to launch the authenticator's settings dialog. 12248e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * If an error occurred, {@link AccountManagerFuture#getResult()} 12258e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * throws: 1226756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * <ul> 1227661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link AuthenticatorException} if no authenticator was registered for 1228661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * this account type or the authenticator failed to respond 1229661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link OperationCanceledException} if the operation was canceled for 1230661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * any reason, including the user canceling the settings dialog 1231661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link IOException} if the authenticator experienced an I/O problem 1232661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * updating settings, usually because of network trouble 1233756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * </ul> 1234756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 1235756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana public AccountManagerFuture<Bundle> editProperties(final String accountType, 1236756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana final Activity activity, final AccountManagerCallback<Bundle> callback, 1237a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana final Handler handler) { 1238382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (accountType == null) throw new IllegalArgumentException("accountType is null"); 1239a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return new AmsTask(activity, handler, callback) { 1240a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public void doWork() throws RemoteException { 1241a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana mService.editProperties(mResponse, accountType, activity != null); 1242a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 12433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana }.start(); 1244a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1245a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1246a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana private void ensureNotOnMainThread() { 1247a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana final Looper looper = Looper.myLooper(); 1248a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana if (looper != null && looper == mContext.getMainLooper()) { 124953bd2522ca7767f46646606123b6e2689b811850Fred Quintana final IllegalStateException exception = new IllegalStateException( 125053bd2522ca7767f46646606123b6e2689b811850Fred Quintana "calling this from your main thread can lead to deadlock"); 125153bd2522ca7767f46646606123b6e2689b811850Fred Quintana Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs", 125253bd2522ca7767f46646606123b6e2689b811850Fred Quintana exception); 1253751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.FROYO) { 1254751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana throw exception; 1255751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana } 1256a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1257a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1258a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1259ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana private void postToHandler(Handler handler, final AccountManagerCallback<Bundle> callback, 1260ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final AccountManagerFuture<Bundle> future) { 1261d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana handler = handler == null ? mMainHandler : handler; 1262d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana handler.post(new Runnable() { 1263a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public void run() { 1264a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana callback.run(future); 1265a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1266a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana }); 1267603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 1268603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 1269f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana private void postToHandler(Handler handler, final OnAccountsUpdateListener listener, 1270d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana final Account[] accounts) { 1271ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final Account[] accountsCopy = new Account[accounts.length]; 1272ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // send a copy to make sure that one doesn't 1273ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // change what another sees 1274ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length); 1275ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana handler = (handler == null) ? mMainHandler : handler; 1276d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana handler.post(new Runnable() { 1277a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public void run() { 1278b6437245c280596d0a580b8d67189739cf793250Costin Manolache try { 1279b6437245c280596d0a580b8d67189739cf793250Costin Manolache listener.onAccountsUpdated(accountsCopy); 1280b6437245c280596d0a580b8d67189739cf793250Costin Manolache } catch (SQLException e) { 1281b6437245c280596d0a580b8d67189739cf793250Costin Manolache // Better luck next time. If the problem was disk-full, 1282b6437245c280596d0a580b8d67189739cf793250Costin Manolache // the STORAGE_OK intent will re-trigger the update. 1283b6437245c280596d0a580b8d67189739cf793250Costin Manolache Log.e(TAG, "Can't update accounts", e); 1284b6437245c280596d0a580b8d67189739cf793250Costin Manolache } 1285a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1286a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana }); 1287a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1288a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1289ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> { 1290a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana final IAccountManagerResponse mResponse; 1291a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana final Handler mHandler; 1292ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final AccountManagerCallback<Bundle> mCallback; 1293a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana final Activity mActivity; 1294ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) { 1295a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana super(new Callable<Bundle>() { 1296a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public Bundle call() throws Exception { 1297a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw new IllegalStateException("this should never be called"); 1298a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1299a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana }); 1300a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1301a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana mHandler = handler; 1302a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana mCallback = callback; 1303a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana mActivity = activity; 1304a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana mResponse = new Response(); 13053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 13063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana 1307ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public final AccountManagerFuture<Bundle> start() { 1308ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana try { 1309ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana doWork(); 1310ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } catch (RemoteException e) { 1311ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana setException(e); 1312ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 13133326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana return this; 1314a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1315a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 131696580e00654a052a82120c374c6b5961ef349a92Fred Quintana protected void set(Bundle bundle) { 131796580e00654a052a82120c374c6b5961ef349a92Fred Quintana // TODO: somehow a null is being set as the result of the Future. Log this 131896580e00654a052a82120c374c6b5961ef349a92Fred Quintana // case to help debug where this is occurring. When this bug is fixed this 131996580e00654a052a82120c374c6b5961ef349a92Fred Quintana // condition statement should be removed. 132096580e00654a052a82120c374c6b5961ef349a92Fred Quintana if (bundle == null) { 132196580e00654a052a82120c374c6b5961ef349a92Fred Quintana Log.e(TAG, "the bundle must not be null", new Exception()); 132296580e00654a052a82120c374c6b5961ef349a92Fred Quintana } 132396580e00654a052a82120c374c6b5961ef349a92Fred Quintana super.set(bundle); 132496580e00654a052a82120c374c6b5961ef349a92Fred Quintana } 132596580e00654a052a82120c374c6b5961ef349a92Fred Quintana 1326a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public abstract void doWork() throws RemoteException; 1327603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 1328a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana private Bundle internalGetResult(Long timeout, TimeUnit unit) 1329a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throws OperationCanceledException, IOException, AuthenticatorException { 133053bd2522ca7767f46646606123b6e2689b811850Fred Quintana if (!isDone()) { 133153bd2522ca7767f46646606123b6e2689b811850Fred Quintana ensureNotOnMainThread(); 133253bd2522ca7767f46646606123b6e2689b811850Fred Quintana } 1333a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana try { 1334a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana if (timeout == null) { 1335a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return get(); 1336a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else { 1337a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return get(timeout, unit); 1338a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1339a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } catch (CancellationException e) { 1340a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw new OperationCanceledException(); 1341a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } catch (TimeoutException e) { 1342a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana // fall through and cancel 1343a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } catch (InterruptedException e) { 1344a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana // fall through and cancel 1345a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } catch (ExecutionException e) { 1346a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana final Throwable cause = e.getCause(); 1347a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana if (cause instanceof IOException) { 1348a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw (IOException) cause; 1349a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else if (cause instanceof UnsupportedOperationException) { 1350a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw new AuthenticatorException(cause); 1351a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else if (cause instanceof AuthenticatorException) { 1352a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw (AuthenticatorException) cause; 1353a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else if (cause instanceof RuntimeException) { 1354a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw (RuntimeException) cause; 1355a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else if (cause instanceof Error) { 1356a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw (Error) cause; 1357a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else { 1358a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw new IllegalStateException(cause); 1359a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1360a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } finally { 1361a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana cancel(true /* interrupt if running */); 1362603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 1363a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw new OperationCanceledException(); 1364603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 1365603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 1366a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public Bundle getResult() 1367a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throws OperationCanceledException, IOException, AuthenticatorException { 1368a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return internalGetResult(null, null); 1369603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 1370603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 1371a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public Bundle getResult(long timeout, TimeUnit unit) 1372a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throws OperationCanceledException, IOException, AuthenticatorException { 1373a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return internalGetResult(timeout, unit); 1374603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 1375603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 1376a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana protected void done() { 1377a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana if (mCallback != null) { 1378a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana postToHandler(mHandler, mCallback, this); 1379a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1380a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1381a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1382a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana /** Handles the responses from the AccountManager */ 1383a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana private class Response extends IAccountManagerResponse.Stub { 1384a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public void onResult(Bundle bundle) { 138546703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom Intent intent = bundle.getParcelable(KEY_INTENT); 1386a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana if (intent != null && mActivity != null) { 1387a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana // since the user provided an Activity we will silently start intents 1388a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana // that we see 1389a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana mActivity.startActivity(intent); 1390a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana // leave the Future running to wait for the real response to this request 1391d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana } else if (bundle.getBoolean("retry")) { 1392d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana try { 1393d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana doWork(); 1394d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana } catch (RemoteException e) { 1395d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana // this will only happen if the system process is dead, which means 1396d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana // we will be dying ourselves 1397d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana } 1398a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else { 1399a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana set(bundle); 1400a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1401a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1402a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1403a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana public void onError(int code, String message) { 1404f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana if (code == ERROR_CODE_CANCELED) { 1405a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana // the authenticator indicated that this request was canceled, do so now 1406a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana cancel(true /* mayInterruptIfRunning */); 1407a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return; 1408a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1409a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana setException(convertErrorToException(code, message)); 1410a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1411603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 1412a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1413603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 1414603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 1415ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana private abstract class BaseFutureTask<T> extends FutureTask<T> { 1416ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final public IAccountManagerResponse mResponse; 1417a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana final Handler mHandler; 1418ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana 1419ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public BaseFutureTask(Handler handler) { 1420ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana super(new Callable<T>() { 1421ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public T call() throws Exception { 1422a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw new IllegalStateException("this should never be called"); 1423a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1424a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana }); 1425a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana mHandler = handler; 1426ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mResponse = new Response(); 1427ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1428a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1429ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public abstract void doWork() throws RemoteException; 1430ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana 1431ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException; 1432ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana 1433ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana protected void postRunnableToHandler(Runnable runnable) { 1434ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana Handler handler = (mHandler == null) ? mMainHandler : mHandler; 1435ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana handler.post(runnable); 1436ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1437ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana 1438ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana protected void startTask() { 1439ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana try { 1440ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana doWork(); 1441ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } catch (RemoteException e) { 1442ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana setException(e); 1443ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1444ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1445ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana 1446ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana protected class Response extends IAccountManagerResponse.Stub { 1447ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void onResult(Bundle bundle) { 1448ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana try { 1449ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana T result = bundleToResult(bundle); 1450ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana if (result == null) { 1451ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana return; 1452a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1453ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana set(result); 1454ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana return; 1455ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } catch (ClassCastException e) { 1456ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // we will set the exception below 1457ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } catch (AuthenticatorException e) { 1458ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // we will set the exception below 1459a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1460f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana onError(ERROR_CODE_INVALID_RESPONSE, "no result in response"); 1461ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1462a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1463ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void onError(int code, String message) { 1464f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana if (code == ERROR_CODE_CANCELED) { 1465ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana cancel(true /* mayInterruptIfRunning */); 1466ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana return; 1467ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1468ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana setException(convertErrorToException(code, message)); 1469ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1470ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1471ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1472a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1473ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana private abstract class Future2Task<T> 1474ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana extends BaseFutureTask<T> implements AccountManagerFuture<T> { 1475ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final AccountManagerCallback<T> mCallback; 1476ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public Future2Task(Handler handler, AccountManagerCallback<T> callback) { 1477ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana super(handler); 1478ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mCallback = callback; 1479ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1480a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1481a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana protected void done() { 1482a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana if (mCallback != null) { 1483ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana postRunnableToHandler(new Runnable() { 1484ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void run() { 1485ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mCallback.run(Future2Task.this); 1486ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1487ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana }); 1488a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1489a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1490a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1491ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public Future2Task<T> start() { 1492ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana startTask(); 1493ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana return this; 1494ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1495ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana 1496ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana private T internalGetResult(Long timeout, TimeUnit unit) 1497ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throws OperationCanceledException, IOException, AuthenticatorException { 149853bd2522ca7767f46646606123b6e2689b811850Fred Quintana if (!isDone()) { 149953bd2522ca7767f46646606123b6e2689b811850Fred Quintana ensureNotOnMainThread(); 150053bd2522ca7767f46646606123b6e2689b811850Fred Quintana } 1501a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana try { 1502a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana if (timeout == null) { 1503a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return get(); 1504a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else { 1505a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return get(timeout, unit); 1506a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1507a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } catch (InterruptedException e) { 1508a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana // fall through and cancel 1509a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } catch (TimeoutException e) { 1510a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana // fall through and cancel 1511a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } catch (CancellationException e) { 1512ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // fall through and cancel 1513a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } catch (ExecutionException e) { 1514a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana final Throwable cause = e.getCause(); 1515a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana if (cause instanceof IOException) { 1516ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throw (IOException) cause; 1517a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else if (cause instanceof UnsupportedOperationException) { 1518ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throw new AuthenticatorException(cause); 1519a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else if (cause instanceof AuthenticatorException) { 1520ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throw (AuthenticatorException) cause; 1521a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else if (cause instanceof RuntimeException) { 1522a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw (RuntimeException) cause; 1523a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else if (cause instanceof Error) { 1524a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw (Error) cause; 1525a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } else { 1526a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana throw new IllegalStateException(cause); 1527a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1528a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } finally { 1529a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana cancel(true /* interrupt if running */); 1530a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1531ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throw new OperationCanceledException(); 1532a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1533a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1534ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public T getResult() 1535ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throws OperationCanceledException, IOException, AuthenticatorException { 1536a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return internalGetResult(null, null); 1537603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 1538a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1539ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public T getResult(long timeout, TimeUnit unit) 1540ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throws OperationCanceledException, IOException, AuthenticatorException { 1541a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return internalGetResult(timeout, unit); 1542a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1543a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1544603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 1545603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana 1546a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana private Exception convertErrorToException(int code, String message) { 1547f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana if (code == ERROR_CODE_NETWORK_ERROR) { 1548a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana return new IOException(message); 1549603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 1550a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1551f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana if (code == ERROR_CODE_UNSUPPORTED_OPERATION) { 15523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana return new UnsupportedOperationException(message); 1553a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 1554a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1555f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana if (code == ERROR_CODE_INVALID_RESPONSE) { 15563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana return new AuthenticatorException(message); 15573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 15583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana 1559f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana if (code == ERROR_CODE_BAD_ARGUMENTS) { 15603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana return new IllegalArgumentException(message); 15613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 15623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana 15633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana return new AuthenticatorException(message); 15643326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 15653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana 1566ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana private class GetAuthTokenByTypeAndFeaturesTask 1567ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana extends AmsTask implements AccountManagerCallback<Bundle> { 15683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType, 15693326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana final String[] features, Activity activityForPrompting, 15703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana final Bundle addAccountOptions, final Bundle loginOptions, 1571ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana AccountManagerCallback<Bundle> callback, Handler handler) { 15723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana super(activityForPrompting, handler, callback); 15733326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana if (accountType == null) throw new IllegalArgumentException("account type is null"); 15743326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana mAccountType = accountType; 15753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana mAuthTokenType = authTokenType; 15763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana mFeatures = features; 15773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana mAddAccountOptions = addAccountOptions; 15783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana mLoginOptions = loginOptions; 15793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana mMyCallback = this; 15803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 1581ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana volatile AccountManagerFuture<Bundle> mFuture = null; 15823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana final String mAccountType; 15833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana final String mAuthTokenType; 15843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana final String[] mFeatures; 15853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana final Bundle mAddAccountOptions; 15863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana final Bundle mLoginOptions; 1587ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final AccountManagerCallback<Bundle> mMyCallback; 1588f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana private volatile int mNumAccounts = 0; 15893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana 15903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana public void doWork() throws RemoteException { 1591ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana getAccountsByTypeAndFeatures(mAccountType, mFeatures, 1592ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana new AccountManagerCallback<Account[]>() { 1593ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void run(AccountManagerFuture<Account[]> future) { 1594ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana Account[] accounts; 15953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana try { 1596ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana accounts = future.getResult(); 1597ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } catch (OperationCanceledException e) { 1598ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana setException(e); 1599ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana return; 1600ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } catch (IOException e) { 1601ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana setException(e); 1602ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana return; 1603ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } catch (AuthenticatorException e) { 1604ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana setException(e); 1605ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana return; 16063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 1607ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana 1608f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana mNumAccounts = accounts.length; 1609f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana 1610ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana if (accounts.length == 0) { 1611ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana if (mActivity != null) { 1612ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // no accounts, add one now. pretend that the user directly 1613ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // made this request 1614ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures, 1615ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mAddAccountOptions, mActivity, mMyCallback, mHandler); 1616ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } else { 1617ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // send result since we can't prompt to add an account 1618ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana Bundle result = new Bundle(); 1619f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana result.putString(KEY_ACCOUNT_NAME, null); 1620f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana result.putString(KEY_ACCOUNT_TYPE, null); 1621f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana result.putString(KEY_AUTHTOKEN, null); 1622ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana try { 1623ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mResponse.onResult(result); 1624ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } catch (RemoteException e) { 1625ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // this will never happen 1626ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1627ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // we are done 1628ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1629ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } else if (accounts.length == 1) { 1630ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // have a single account, return an authtoken for it 1631ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana if (mActivity == null) { 1632ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mFuture = getAuthToken(accounts[0], mAuthTokenType, 1633ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana false /* notifyAuthFailure */, mMyCallback, mHandler); 1634ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } else { 1635ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mFuture = getAuthToken(accounts[0], 1636ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mAuthTokenType, mLoginOptions, 16373326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana mActivity, mMyCallback, mHandler); 16383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 1639ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } else { 1640ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana if (mActivity != null) { 1641ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana IAccountManagerResponse chooseResponse = 1642ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana new IAccountManagerResponse.Stub() { 1643ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void onResult(Bundle value) throws RemoteException { 1644ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana Account account = new Account( 1645f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana value.getString(KEY_ACCOUNT_NAME), 1646f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana value.getString(KEY_ACCOUNT_TYPE)); 1647ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions, 1648ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mActivity, mMyCallback, mHandler); 1649ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1650ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana 1651ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void onError(int errorCode, String errorMessage) 1652ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana throws RemoteException { 1653ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mResponse.onError(errorCode, errorMessage); 1654ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1655ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana }; 1656ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // have many accounts, launch the chooser 1657ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana Intent intent = new Intent(); 1658ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana intent.setClassName("android", 1659ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana "android.accounts.ChooseAccountActivity"); 1660f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana intent.putExtra(KEY_ACCOUNTS, accounts); 1661f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana intent.putExtra(KEY_ACCOUNT_MANAGER_RESPONSE, 1662ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana new AccountManagerResponse(chooseResponse)); 1663ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mActivity.startActivity(intent); 1664ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // the result will arrive via the IAccountManagerResponse 1665ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } else { 1666ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // send result since we can't prompt to select an account 1667ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana Bundle result = new Bundle(); 1668f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana result.putString(KEY_ACCOUNTS, null); 1669ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana try { 1670ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mResponse.onResult(result); 1671ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } catch (RemoteException e) { 1672ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // this will never happen 1673ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1674ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // we are done 16753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 16763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 1677ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana }}, mHandler); 16783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 16793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana 1680ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana public void run(AccountManagerFuture<Bundle> future) { 16813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana try { 1682f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana final Bundle result = future.getResult(); 1683f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana if (mNumAccounts == 0) { 1684f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana final String accountName = result.getString(KEY_ACCOUNT_NAME); 1685f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana final String accountType = result.getString(KEY_ACCOUNT_TYPE); 1686f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) { 1687f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana setException(new AuthenticatorException("account not in result")); 1688f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana return; 1689f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana } 1690f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana final Account account = new Account(accountName, accountType); 1691f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana mNumAccounts = 1; 1692f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana getAuthToken(account, mAuthTokenType, null /* options */, mActivity, 1693f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana mMyCallback, mHandler); 1694f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana return; 1695f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana } 1696f0fd8436b3ec2aa47cd5de61072b8395bbe46765Fred Quintana set(result); 1697f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana } catch (OperationCanceledException e) { 1698f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana cancel(true /* mayInterruptIfRUnning */); 1699f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana } catch (IOException e) { 1700f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana setException(e); 1701f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana } catch (AuthenticatorException e) { 1702f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana setException(e); 17033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 1704a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana } 17053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana } 1706a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana 1707756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana /** 1708661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * This convenience helper combines the functionality of 1709661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #getAccountsByTypeAndFeatures}, {@link #getAuthToken}, and 1710661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #addAccount}. 1711661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1712661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method gets a list of the accounts matching the 1713661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * specified type and feature set; if there is exactly one, it is 1714661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * used; if there are more than one, the user is prompted to pick one; 1715661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * if there are none, the user is prompted to add one. Finally, 1716661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * an auth token is acquired for the chosen account. 1717661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1718661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method may be called from any thread, but the returned 1719661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManagerFuture} must not be used on the main thread. 1720661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1721661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>This method requires the caller to hold the permission 1722661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. 1723661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1724661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param accountType The account type required 1725ff592dc2fa53d48e4121d9b8fd70efc19938c4a1Doug Zongker * (see {@link #getAccountsByType}), must not be null 1726661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param authTokenType The desired auth token type 1727661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * (see {@link #getAuthToken}), must not be null 1728661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param features Required features for the account 1729661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * (see {@link #getAccountsByTypeAndFeatures}), may be null or empty 1730661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param activity The {@link Activity} context to use for launching new 1731661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * sub-Activities to prompt to add an account, select an account, 1732661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * and/or enter a password, as necessary; used only to call 1733661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * startActivity(); should not be null 1734661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param addAccountOptions Authenticator-specific options to use for 1735661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * adding new accounts; may be null or empty 1736661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param getAuthTokenOptions Authenticator-specific options to use for 1737661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * getting auth tokens; may be null or empty 1738661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param callback Callback to invoke when the request completes, 1739661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for no callback 1740661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param handler {@link Handler} identifying the callback thread, 1741661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * null for the main thread 1742661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @return An {@link AccountManagerFuture} which resolves to a Bundle with 1743661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * at least the following fields: 1744756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * <ul> 1745661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account 1746661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account 1747661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted 1748661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * </ul> 1749661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 17508e4378b3ae7c3b343f92b8f7fb8e46bdfdb01649Dan Egnor * If an error occurred, {@link AccountManagerFuture#getResult()} throws: 1751661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <ul> 1752661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link AuthenticatorException} if no authenticator was registered for 1753661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * this account type or the authenticator failed to respond 1754661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link OperationCanceledException} if the operation was canceled for 1755661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * any reason, including the user canceling any operation 1756661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <li> {@link IOException} if the authenticator experienced an I/O problem 1757661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * updating settings, usually because of network trouble 1758756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * </ul> 1759756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana */ 1760f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public AccountManagerFuture<Bundle> getAuthTokenByFeatures( 17613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana final String accountType, final String authTokenType, final String[] features, 1762661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor final Activity activity, final Bundle addAccountOptions, 176331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana final Bundle getAuthTokenOptions, 1764ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final AccountManagerCallback<Bundle> callback, final Handler handler) { 17653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana if (accountType == null) throw new IllegalArgumentException("account type is null"); 17663326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); 1767f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana final GetAuthTokenByTypeAndFeaturesTask task = 1768f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features, 1769661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor activity, addAccountOptions, getAuthTokenOptions, callback, handler); 1770f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana task.start(); 1771f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana return task; 1772603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana } 1773d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana 17741121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana /** 17751121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * Returns an intent to an {@link Activity} that prompts the user to choose from a list of 17761121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * accounts. 17771121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * The caller will then typically start the activity by calling 17781121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * <code>startActivityWithResult(intent, ...);</code>. 17791121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * <p> 17801121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * On success the activity returns a Bundle with the account name and type specified using 17811121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}. 17821121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * <p> 17831121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * The most common case is to call this with one account type, e.g.: 17841121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * <p> 1785d88324d8ab8b98bbc2c21551be3a8981ee431181Fred Quintana * <pre> newChooseAccountsIntent(null, null, new String[]{"com.google"}, false, null, 1786d88324d8ab8b98bbc2c21551be3a8981ee431181Fred Quintana * null, null, null);</pre> 17871121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * @param selectedAccount if specified, indicates that the {@link Account} is the currently 17881121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * selected one, according to the caller's definition of selected. 17891121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * @param allowableAccounts an optional {@link ArrayList} of accounts that are allowed to be 17901121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * shown. If not specified then this field will not limit the displayed accounts. 17911121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * @param allowableAccountTypes an optional string array of account types. These are used 17921121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * both to filter the shown accounts and to filter the list of account types that are shown 17931121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana * when adding an account. 1794b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana * @param alwaysPromptForAccount if set the account chooser screen is always shown, otherwise 1795b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana * it is only shown when there is more than one account from which to choose 1796d88324d8ab8b98bbc2c21551be3a8981ee431181Fred Quintana * @param descriptionOverrideText if non-null this string is used as the description in the 1797b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana * accounts chooser screen rather than the default 1798d88324d8ab8b98bbc2c21551be3a8981ee431181Fred Quintana * @param addAccountAuthTokenType this string is passed as the {@link #addAccount} 1799d88324d8ab8b98bbc2c21551be3a8981ee431181Fred Quintana * authTokenType parameter 1800d88324d8ab8b98bbc2c21551be3a8981ee431181Fred Quintana * @param addAccountRequiredFeatures this string array is passed as the {@link #addAccount} 1801d88324d8ab8b98bbc2c21551be3a8981ee431181Fred Quintana * requiredFeatures parameter 1802b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana * @param addAccountOptions This {@link Bundle} is passed as the {@link #addAccount} options 1803d88324d8ab8b98bbc2c21551be3a8981ee431181Fred Quintana * parameter 1804b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana * @return an {@link Intent} that can be used to launch the ChooseAccount activity flow. 18051121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana */ 18061121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana static public Intent newChooseAccountIntent(Account selectedAccount, 18071121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana ArrayList<Account> allowableAccounts, 18081121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana String[] allowableAccountTypes, 1809b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana boolean alwaysPromptForAccount, 1810b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana String descriptionOverrideText, 1811b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana String addAccountAuthTokenType, 1812b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana String[] addAccountRequiredFeatures, 18131121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana Bundle addAccountOptions) { 18141121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana Intent intent = new Intent(); 18151121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana intent.setClassName("android", "android.accounts.ChooseTypeAndAccountActivity"); 18161121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST, 18171121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana allowableAccounts); 1818b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY, 1819b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana allowableAccountTypes); 18201121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE, 18211121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana addAccountOptions); 18221121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_SELECTED_ACCOUNT, selectedAccount); 1823b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, 1824b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana alwaysPromptForAccount); 1825b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_DESCRIPTION_TEXT_OVERRIDE, 1826b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana descriptionOverrideText); 1827b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING, 1828b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana addAccountAuthTokenType); 1829b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana intent.putExtra( 1830b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY, 1831b04fe4e82abb073b4e5d82563b0882cea0dcc139Fred Quintana addAccountRequiredFeatures); 18321121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana return intent; 18331121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana } 18341121bb5e6ff20a2c694225300507ed486e04fea2Fred Quintana 1835f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana private final HashMap<OnAccountsUpdateListener, Handler> mAccountsUpdatedListeners = 1836d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana Maps.newHashMap(); 1837d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana 1838d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana /** 1839d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent 1840d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana * so that it can read the updated list of accounts and send them to the listener 1841d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana * in mAccountsUpdatedListeners. 1842d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana */ 1843d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() { 1844d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana public void onReceive(final Context context, final Intent intent) { 1845ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana final Account[] accounts = getAccounts(); 1846ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana // send the result to the listeners 1847ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana synchronized (mAccountsUpdatedListeners) { 1848f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana for (Map.Entry<OnAccountsUpdateListener, Handler> entry : 1849ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana mAccountsUpdatedListeners.entrySet()) { 1850ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana postToHandler(entry.getValue(), entry.getKey(), accounts); 1851d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 1852ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana } 1853d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 1854d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana }; 1855d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana 1856d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana /** 1857661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Adds an {@link OnAccountsUpdateListener} to this instance of the 1858661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link AccountManager}. This listener will be notified whenever the 1859661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * list of accounts on the device changes. 1860661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1861661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>As long as this listener is present, the AccountManager instance 1862661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * will not be garbage-collected, and neither will the {@link Context} 1863661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * used to retrieve it, which may be a large Activity instance. To avoid 1864661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * memory leaks, you must remove this listener before then. Normally 1865661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * listeners are added in an Activity or Service's {@link Activity#onCreate} 1866661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * and removed in {@link Activity#onDestroy}. 1867661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1868661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 1869661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1870661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>No permission is required to call this method. 1871661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1872661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param listener The listener to send notifications to 1873661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param handler {@link Handler} identifying the thread to use 1874661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * for notifications, null for the main thread 1875661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param updateImmediately If true, the listener will be invoked 1876661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * (on the handler thread) right away with the current account list 1877d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana * @throws IllegalArgumentException if listener is null 1878d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana * @throws IllegalStateException if listener was already added 1879d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana */ 1880f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener, 1881d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana Handler handler, boolean updateImmediately) { 1882d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana if (listener == null) { 1883d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana throw new IllegalArgumentException("the listener is null"); 1884d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 1885d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana synchronized (mAccountsUpdatedListeners) { 1886d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana if (mAccountsUpdatedListeners.containsKey(listener)) { 1887d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana throw new IllegalStateException("this listener is already added"); 1888d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 1889d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty(); 1890d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana 1891d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana mAccountsUpdatedListeners.put(listener, handler); 1892d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana 1893d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana if (wasEmpty) { 1894d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana // Register a broadcast receiver to monitor account changes 1895d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana IntentFilter intentFilter = new IntentFilter(); 1896f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION); 1897b6437245c280596d0a580b8d67189739cf793250Costin Manolache // To recover from disk-full. 1898c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); 1899d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter); 1900d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 1901d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 1902d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana 1903d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana if (updateImmediately) { 1904ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana postToHandler(handler, listener, getAccounts()); 1905d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 1906d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 1907d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana 1908d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana /** 1909661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * Removes an {@link OnAccountsUpdateListener} previously registered with 1910661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * {@link #addOnAccountsUpdatedListener}. The listener will no longer 1911661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * receive notifications of account changes. 1912661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1913661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>It is safe to call this method from the main thread. 1914661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1915661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * <p>No permission is required to call this method. 1916661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * 1917661f0130de6a4e1592b679a212c8f758133d36eeDan Egnor * @param listener The previously added listener to remove 1918d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana * @throws IllegalArgumentException if listener is null 1919d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana * @throws IllegalStateException if listener was not already added 1920d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana */ 1921f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana public void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) { 1922382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana if (listener == null) throw new IllegalArgumentException("listener is null"); 1923d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana synchronized (mAccountsUpdatedListeners) { 19245be61f5b3ad61706b72c1f6b00914ab042dc6bedBryan Mawhinney if (!mAccountsUpdatedListeners.containsKey(listener)) { 192588a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache Log.e(TAG, "Listener was not previously added"); 192688a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache return; 1927d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 19285be61f5b3ad61706b72c1f6b00914ab042dc6bedBryan Mawhinney mAccountsUpdatedListeners.remove(listener); 1929d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana if (mAccountsUpdatedListeners.isEmpty()) { 1930d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver); 1931d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 1932d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 1933d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana } 1934603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana} 1935