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