/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.accounts; import android.app.Activity; import android.content.Intent; import android.content.Context; import android.content.IntentFilter; import android.content.BroadcastReceiver; import android.database.SQLException; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.Parcelable; import android.os.Build; import android.util.Log; import android.text.TextUtils; import java.io.IOException; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeUnit; import java.util.HashMap; import java.util.Map; import com.google.android.collect.Maps; /** * This class provides access to a centralized registry of the user's * online accounts. The user enters credentials (username and password) once * per account, granting applications access to online resources with * "one-click" approval. * *
Different online services have different ways of handling accounts and * authentication, so the account manager uses pluggable authenticator * modules for different account types. Authenticators (which may be * written by third parties) handle the actual details of validating account * credentials and storing account information. For example, Google, Facebook, * and Microsoft Exchange each have their own authenticator. * *
Many servers support some notion of an authentication token, * which can be used to authenticate a request to the server without sending * the user's actual password. (Auth tokens are normally created with a * separate request which does include the user's credentials.) AccountManager * can generate auth tokens for applications, so the application doesn't need to * handle passwords directly. Auth tokens are normally reusable and cached by * AccountManager, but must be refreshed periodically. It's the responsibility * of applications to invalidate auth tokens when they stop working so * the AccountManager knows it needs to regenerate them. * *
Applications accessing a server normally go through these steps: * *
Some AccountManager methods may need to interact with the user to * prompt for credentials, present options, or ask the user to add an account. * The caller may choose whether to allow AccountManager to directly launch the * necessary user interface and wait for the user, or to return an Intent which * the caller may use to launch the interface, or (in some cases) to install a * notification which the user can select at any time to launch the interface. * To have AccountManager launch the interface directly, the caller must supply * the current foreground {@link Activity} context. * *
Many AccountManager methods take {@link AccountManagerCallback} and * {@link Handler} as parameters. These methods return immediately and * run asynchronously. If a callback is provided then * {@link AccountManagerCallback#run} will be invoked on the Handler's * thread when the request completes, successfully or not. * The result is retrieved by calling {@link AccountManagerFuture#getResult()} * on the {@link AccountManagerFuture} returned by the method (and also passed * to the callback). This method waits for the operation to complete (if * necessary) and either returns the result or throws an exception if an error * occurred during the operation. To make the request synchronously, call * {@link AccountManagerFuture#getResult()} immediately on receiving the * future from the method; no callback need be supplied. * *
Requests which may block, including
* {@link AccountManagerFuture#getResult()}, must never be called on
* the application's main event thread. These operations throw
* {@link IllegalStateException} if they are used on the main thread.
*/
public class AccountManager {
private static final String TAG = "AccountManager";
public static final int ERROR_CODE_REMOTE_EXCEPTION = 1;
public static final int ERROR_CODE_NETWORK_ERROR = 3;
public static final int ERROR_CODE_CANCELED = 4;
public static final int ERROR_CODE_INVALID_RESPONSE = 5;
public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6;
public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
public static final int ERROR_CODE_BAD_REQUEST = 8;
/**
* Bundle key used for the {@link String} account name in results
* from methods which return information about a particular account.
*/
public static final String KEY_ACCOUNT_NAME = "authAccount";
/**
* Bundle key used for the {@link String} account type in results
* from methods which return information about a particular account.
*/
public static final String KEY_ACCOUNT_TYPE = "accountType";
/**
* Bundle key used for the auth token value in results
* from {@link #getAuthToken} and friends.
*/
public static final String KEY_AUTHTOKEN = "authtoken";
/**
* Bundle key used for an {@link Intent} in results from methods that
* may require the caller to interact with the user. The Intent can
* be used to start the corresponding user interface activity.
*/
public static final String KEY_INTENT = "intent";
/**
* Bundle key used to supply the password directly in options to
* {@link #confirmCredentials}, rather than prompting the user with
* the standard password prompt.
*/
public static final String KEY_PASSWORD = "password";
public static final String KEY_ACCOUNTS = "accounts";
public static final String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
public static final String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
public static final String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
public static final String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage";
public static final String KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey";
public static final String KEY_BOOLEAN_RESULT = "booleanResult";
public static final String KEY_ERROR_CODE = "errorCode";
public static final String KEY_ERROR_MESSAGE = "errorMessage";
public static final String KEY_USERDATA = "userdata";
/**
* Authenticators using 'customTokens' option will also get the UID of the
* caller
* @hide
*/
public static final String KEY_CALLER_UID = "callerUid";
/**
* @hide
*/
public static final String KEY_CALLER_PID = "callerPid";
/**
* Boolean, if set and 'customTokens' the authenticator is responsible for
* notifications.
* @hide
*/
public static final String KEY_NOTIFY_ON_FAILURE = "notifyOnAuthFailure";
public static final String ACTION_AUTHENTICATOR_INTENT =
"android.accounts.AccountAuthenticator";
public static final String AUTHENTICATOR_META_DATA_NAME =
"android.accounts.AccountAuthenticator";
public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
private final Context mContext;
private final IAccountManager mService;
private final Handler mMainHandler;
/**
* Action sent as a broadcast Intent by the AccountsService
* when accounts are added, accounts are removed, or an
* account's credentials (saved password, etc) are changed.
*
* @see #addOnAccountsUpdatedListener
*/
public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
"android.accounts.LOGIN_ACCOUNTS_CHANGED";
/**
* @hide
*/
public AccountManager(Context context, IAccountManager service) {
mContext = context;
mService = service;
mMainHandler = new Handler(mContext.getMainLooper());
}
/**
* @hide used for testing only
*/
public AccountManager(Context context, IAccountManager service, Handler handler) {
mContext = context;
mService = service;
mMainHandler = handler;
}
/**
* @hide for internal use only
*/
public static Bundle sanitizeResult(Bundle result) {
if (result != null) {
if (result.containsKey(KEY_AUTHTOKEN)
&& !TextUtils.isEmpty(result.getString(KEY_AUTHTOKEN))) {
final Bundle newResult = new Bundle(result);
newResult.putString(KEY_AUTHTOKEN, " It is safe to call this method from the main thread.
*
* No permission is required to call this method.
*
* @param context The {@link Context} to use when necessary
* @return An {@link AccountManager} instance
*/
public static AccountManager get(Context context) {
if (context == null) throw new IllegalArgumentException("context is null");
return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
}
/**
* Gets the saved password associated with the account.
* This is intended for authenticators and related code; applications
* should get an auth token instead.
*
* It is safe to call this method from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
* and to have the same UID as the account's authenticator.
*
* @param account The account to query for a password
* @return The account's password, null if none or if the account doesn't exist
*/
public String getPassword(final Account account) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
return mService.getPassword(account);
} catch (RemoteException e) {
// will never happen
throw new RuntimeException(e);
}
}
/**
* Gets the user data named by "key" associated with the account.
* This is intended for authenticators and related code to store
* arbitrary metadata along with accounts. The meaning of the keys
* and values is up to the authenticator for the account.
*
* It is safe to call this method from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
* and to have the same UID as the account's authenticator.
*
* @param account The account to query for user data
* @return The user data, null if the account or key doesn't exist
*/
public String getUserData(final Account account, final String key) {
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
try {
return mService.getUserData(account, key);
} catch (RemoteException e) {
// will never happen
throw new RuntimeException(e);
}
}
/**
* Lists the currently registered authenticators.
*
* It is safe to call this method from the main thread.
*
* No permission is required to call this method.
*
* @return An array of {@link AuthenticatorDescription} for every
* authenticator known to the AccountManager service. Empty (never
* null) if no authenticators are known.
*/
public AuthenticatorDescription[] getAuthenticatorTypes() {
try {
return mService.getAuthenticatorTypes();
} catch (RemoteException e) {
// will never happen
throw new RuntimeException(e);
}
}
/**
* Lists all accounts of any type registered on the device.
* Equivalent to getAccountsByType(null).
*
* It is safe to call this method from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#GET_ACCOUNTS}.
*
* @return An array of {@link Account}, one for each account. Empty
* (never null) if no accounts have been added.
*/
public Account[] getAccounts() {
try {
return mService.getAccounts(null);
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
}
}
/**
* Lists all accounts of a particular type. The account type is a
* string token corresponding to the authenticator and useful domain
* of the account. For example, there are types corresponding to Google
* and Facebook. The exact string token to use will be published somewhere
* associated with the authenticator in question.
*
* It is safe to call this method from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#GET_ACCOUNTS}.
*
* @param type The type of accounts to return, null to retrieve all accounts
* @return An array of {@link Account}, one per matching account. Empty
* (never null) if no accounts of the specified type have been added.
*/
public Account[] getAccountsByType(String type) {
try {
return mService.getAccounts(type);
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
}
}
/**
* Finds out whether a particular account has all the specified features.
* Account features are authenticator-specific string tokens identifying
* boolean account properties. For example, features are used to tell
* whether Google accounts have a particular service (such as Google
* Calendar or Google Talk) enabled. The feature names and their meanings
* are published somewhere associated with the authenticator in question.
*
* This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#GET_ACCOUNTS}.
*
* @param account The {@link Account} to test
* @param features An array of the account features to check
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
* @return An {@link AccountManagerFuture} which resolves to a Boolean,
* true if the account exists and has all of the specified features.
*/
public AccountManagerFuture Unlike {@link #getAccountsByType}, this method calls the authenticator,
* which may contact the server or do other work to check account features,
* so the method returns an {@link AccountManagerFuture}.
*
* This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#GET_ACCOUNTS}.
*
* @param type The type of accounts to return, must not be null
* @param features An array of the account features to require,
* may be null or empty
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
* @return An {@link AccountManagerFuture} which resolves to an array of
* {@link Account}, one per account of the specified type which
* matches the requested features.
*/
public AccountManagerFuture It is safe to call this method from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
* and to have the same UID as the added account's authenticator.
*
* @param account The {@link Account} to add
* @param password The password to associate with the account, null for none
* @param userdata String values to use for the account's userdata, null for none
* @return True if the account was successfully added, false if the account
* already exists, the account is null, or another error occurs.
*/
public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
return mService.addAccount(account, password, userdata);
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
}
}
/**
* Removes an account from the AccountManager. Does nothing if the account
* does not exist. Does not delete the account from the server.
* The authenticator may have its own policies preventing account
* deletion, in which case the account will not be deleted.
*
* This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param account The {@link Account} to remove
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
* @return An {@link AccountManagerFuture} which resolves to a Boolean,
* true if the account has been successfully removed,
* false if the authenticator forbids deleting this account.
*/
public AccountManagerFuture It is safe to call this method from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#MANAGE_ACCOUNTS} or
* {@link android.Manifest.permission#USE_CREDENTIALS}
*
* @param accountType The account type of the auth token to invalidate, must not be null
* @param authToken The auth token to invalidate, may be null
*/
public void invalidateAuthToken(final String accountType, final String authToken) {
if (accountType == null) throw new IllegalArgumentException("accountType is null");
try {
if (authToken != null) {
mService.invalidateAuthToken(accountType, authToken);
}
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
}
}
/**
* Gets an auth token from the AccountManager's cache. If no auth
* token is cached for this account, null will be returned -- a new
* auth token will not be generated, and the server will not be contacted.
* Intended for use by the authenticator, not directly by applications.
*
* It is safe to call this method from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
* and to have the same UID as the account's authenticator.
*
* @param account The account to fetch an auth token for
* @param authTokenType The type of auth token to fetch, see {#getAuthToken}
* @return The cached auth token for this account and type, or null if
* no auth token is cached or the account does not exist.
*/
public String peekAuthToken(final Account account, final String authTokenType) {
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
try {
return mService.peekAuthToken(account, authTokenType);
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
}
}
/**
* Sets or forgets a saved password. This modifies the local copy of the
* password used to automatically authenticate the user; it does
* not change the user's account password on the server. Intended for use
* by the authenticator, not directly by applications.
*
* It is safe to call this method from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
* and have the same UID as the account's authenticator.
*
* @param account The account to set a password for
* @param password The password to set, null to clear the password
*/
public void setPassword(final Account account, final String password) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
mService.setPassword(account, password);
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
}
}
/**
* Forgets a saved password. This erases the local copy of the password;
* it does not change the user's account password on the server.
* Has the same effect as setPassword(account, null) but requires fewer
* permissions, and may be used by applications or management interfaces
* to "sign out" from an account.
*
* It is safe to call this method from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#MANAGE_ACCOUNTS}
*
* @param account The account whose password to clear
*/
public void clearPassword(final Account account) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
mService.clearPassword(account);
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
}
}
/**
* Sets one userdata key for an account. Intended by use for the
* authenticator to stash state for itself, not directly by applications.
* The meaning of the keys and values is up to the authenticator.
*
* It is safe to call this method from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
* and to have the same UID as the account's authenticator.
*
* @param account The account to set the userdata for
* @param key The userdata key to set. Must not be null
* @param value The value to set, null to clear this userdata key
*/
public void setUserData(final Account account, final String key, final String value) {
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
try {
mService.setUserData(account, key, value);
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
}
}
/**
* Adds an auth token to the AccountManager cache for an account.
* If the account does not exist then this call has no effect.
* Replaces any previous auth token for this account and auth token type.
* Intended for use by the authenticator, not directly by applications.
*
* It is safe to call this method from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
* and to have the same UID as the account's authenticator.
*
* @param account The account to set an auth token for
* @param authTokenType The type of the auth token, see {#getAuthToken}
* @param authToken The auth token to add to the cache
*/
public void setAuthToken(Account account, final String authTokenType, final String authToken) {
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
try {
mService.setAuthToken(account, authTokenType, authToken);
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
}
}
/**
* This convenience helper synchronously gets an auth token with
* {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, Handler)}.
*
* This method may block while a network request completes, and must
* never be made from the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#USE_CREDENTIALS}.
*
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, see {#link getAuthToken}
* @param notifyAuthFailure If true, display a notification and return null
* if authentication fails; if false, prompt and wait for the user to
* re-enter correct credentials before returning
* @return An auth token of the specified type for this account, or null
* if authentication fails or none can be fetched.
* @throws AuthenticatorException if the authenticator failed to respond
* @throws OperationCanceledException if the request was canceled for any
* reason, including the user canceling a credential request
* @throws java.io.IOException if the authenticator experienced an I/O problem
* creating a new auth token, usually because of network trouble
*/
public String blockingGetAuthToken(Account account, String authTokenType,
boolean notifyAuthFailure)
throws OperationCanceledException, IOException, AuthenticatorException {
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */,
null /* handler */).getResult();
if (bundle == null) {
// This should never happen, but it does, occasionally. If it does return null to
// signify that we were not able to get the authtoken.
// TODO: remove this when the bug is found that sometimes causes a null bundle to be
// returned
Log.e(TAG, "blockingGetAuthToken: null was returned from getResult() for "
+ account + ", authTokenType " + authTokenType);
return null;
}
return bundle.getString(KEY_AUTHTOKEN);
}
/**
* Gets an auth token of the specified type for a particular account,
* prompting the user for credentials if necessary. This method is
* intended for applications running in the foreground where it makes
* sense to ask the user directly for a password.
*
* If a previously generated auth token is cached for this account and
* type, then it is returned. Otherwise, if a saved password is
* available, it is sent to the server to generate a new auth token.
* Otherwise, the user is prompted to enter a password.
*
* Some authenticators have auth token types, whose value
* is authenticator-dependent. Some services use different token types to
* access different functionality -- for example, Google uses different auth
* tokens to access Gmail and Google Calendar for the same account.
*
* This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#USE_CREDENTIALS}.
*
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, an authenticator-dependent
* string token, must not be null
* @param options Authenticator-specific options for the request,
* may be null or empty
* @param activity The {@link Activity} context to use for launching a new
* authenticator-defined sub-Activity to prompt the user for a password
* if necessary; used only to call startActivity(); must not be null.
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
* @return An {@link AccountManagerFuture} which resolves to a Bundle with
* at least the following fields:
* If a previously generated auth token is cached for this account and
* type, then it is returned. Otherwise, if a saved password is
* available, it is sent to the server to generate a new auth token.
* Otherwise, an {@link Intent} is returned which, when started, will
* prompt the user for a password. If the notifyAuthFailure parameter is
* set, a status bar notification is also created with the same Intent,
* alerting the user that they need to enter a password at some point.
*
* In that case, you may need to wait until the user responds, which
* could take hours or days or forever. When the user does respond and
* supply a new password, the account manager will broadcast the
* {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
* use to try again.
*
* If notifyAuthFailure is not set, it is the application's
* responsibility to launch the returned Intent at some point.
* Either way, the result from this call will not wait for user action.
*
* Some authenticators have auth token types, whose value
* is authenticator-dependent. Some services use different token types to
* access different functionality -- for example, Google uses different auth
* tokens to access Gmail and Google Calendar for the same account.
*
* This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#USE_CREDENTIALS}.
*
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, an authenticator-dependent
* string token, must not be null
* @param notifyAuthFailure True to add a notification to prompt the
* user for a password if necessary, false to leave that to the caller
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
* @return An {@link AccountManagerFuture} which resolves to a Bundle with
* at least the following fields on success:
* This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param accountType The type of account to add; must not be null
* @param authTokenType The type of auth token (see {@link #getAuthToken})
* this account will need to be able to generate, null for none
* @param requiredFeatures The features (see {@link #hasFeatures}) this
* account must have, null for none
* @param addAccountOptions Authenticator-specific options for the request,
* may be null or empty
* @param activity The {@link Activity} context to use for launching a new
* authenticator-defined sub-Activity to prompt the user to create an
* account; used only to call startActivity(); if null, the prompt
* will not be launched directly, but the necessary {@link Intent}
* will be returned to the caller instead
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
* @return An {@link AccountManagerFuture} which resolves to a Bundle with
* these fields if activity was specified and an account was created:
* If the user-entered password matches a saved password for this
* account, the request is considered valid; otherwise the authenticator
* verifies the password (usually by contacting the server).
*
* This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param account The account to confirm password knowledge for
* @param options Authenticator-specific options for the request;
* if the {@link #KEY_PASSWORD} string field is present, the
* authenticator may use it directly rather than prompting the user;
* may be null or empty
* @param activity The {@link Activity} context to use for launching a new
* authenticator-defined sub-Activity to prompt the user to enter a
* password; used only to call startActivity(); if null, the prompt
* will not be launched directly, but the necessary {@link Intent}
* will be returned to the caller instead
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
* @return An {@link AccountManagerFuture} which resolves to a Bundle
* with these fields if activity or password was supplied and
* the account was successfully verified:
* This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param account The account to update credentials for
* @param authTokenType The credentials entered must allow an auth token
* of this type to be created (but no actual auth token is returned);
* may be null
* @param options Authenticator-specific options for the request;
* may be null or empty
* @param activity The {@link Activity} context to use for launching a new
* authenticator-defined sub-Activity to prompt the user to enter a
* password; used only to call startActivity(); if null, the prompt
* will not be launched directly, but the necessary {@link Intent}
* will be returned to the caller instead
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
* @return An {@link AccountManagerFuture} which resolves to a Bundle
* with these fields if an activity was supplied and the account
* credentials were successfully updated:
* This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param accountType The account type associated with the authenticator
* to adjust
* @param activity The {@link Activity} context to use for launching a new
* authenticator-defined sub-Activity to adjust authenticator settings;
* used only to call startActivity(); if null, the settings dialog will
* not be launched directly, but the necessary {@link Intent} will be
* returned to the caller instead
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
* @return An {@link AccountManagerFuture} which resolves to a Bundle
* which is empty if properties were edited successfully, or
* if no activity was specified, contains only {@link #KEY_INTENT}
* needed to launch the authenticator's settings dialog.
* If an error occurred, {@link AccountManagerFuture#getResult()}
* throws:
* This method gets a list of the accounts matching the
* specified type and feature set; if there is exactly one, it is
* used; if there are more than one, the user is prompted to pick one;
* if there are none, the user is prompted to add one. Finally,
* an auth token is acquired for the chosen account.
*
* This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
* This method requires the caller to hold the permission
* {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param accountType The account type required
* (see {@link #getAccountsByType}), must not be null
* @param authTokenType The desired auth token type
* (see {@link #getAuthToken}), must not be null
* @param features Required features for the account
* (see {@link #getAccountsByTypeAndFeatures}), may be null or empty
* @param activity The {@link Activity} context to use for launching new
* sub-Activities to prompt to add an account, select an account,
* and/or enter a password, as necessary; used only to call
* startActivity(); should not be null
* @param addAccountOptions Authenticator-specific options to use for
* adding new accounts; may be null or empty
* @param getAuthTokenOptions Authenticator-specific options to use for
* getting auth tokens; may be null or empty
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
* @return An {@link AccountManagerFuture} which resolves to a Bundle with
* at least the following fields:
* As long as this listener is present, the AccountManager instance
* will not be garbage-collected, and neither will the {@link Context}
* used to retrieve it, which may be a large Activity instance. To avoid
* memory leaks, you must remove this listener before then. Normally
* listeners are added in an Activity or Service's {@link Activity#onCreate}
* and removed in {@link Activity#onDestroy}.
*
* It is safe to call this method from the main thread.
*
* No permission is required to call this method.
*
* @param listener The listener to send notifications to
* @param handler {@link Handler} identifying the thread to use
* for notifications, null for the main thread
* @param updateImmediately If true, the listener will be invoked
* (on the handler thread) right away with the current account list
* @throws IllegalArgumentException if listener is null
* @throws IllegalStateException if listener was already added
*/
public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
Handler handler, boolean updateImmediately) {
if (listener == null) {
throw new IllegalArgumentException("the listener is null");
}
synchronized (mAccountsUpdatedListeners) {
if (mAccountsUpdatedListeners.containsKey(listener)) {
throw new IllegalStateException("this listener is already added");
}
final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
mAccountsUpdatedListeners.put(listener, handler);
if (wasEmpty) {
// Register a broadcast receiver to monitor account changes
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
// To recover from disk-full.
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
}
}
if (updateImmediately) {
postToHandler(handler, listener, getAccounts());
}
}
/**
* Removes an {@link OnAccountsUpdateListener} previously registered with
* {@link #addOnAccountsUpdatedListener}. The listener will no longer
* receive notifications of account changes.
*
* It is safe to call this method from the main thread.
*
* No permission is required to call this method.
*
* @param listener The previously added listener to remove
* @throws IllegalArgumentException if listener is null
* @throws IllegalStateException if listener was not already added
*/
public void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) {
if (listener == null) throw new IllegalArgumentException("listener is null");
synchronized (mAccountsUpdatedListeners) {
if (!mAccountsUpdatedListeners.containsKey(listener)) {
Log.e(TAG, "Listener was not previously added");
return;
}
mAccountsUpdatedListeners.remove(listener);
if (mAccountsUpdatedListeners.isEmpty()) {
mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
}
}
}
}
*
*
* (Other authenticator-specific values may be returned.) If an auth token
* could not be fetched, {@link AccountManagerFuture#getResult()} throws:
*
*
* If the account is no longer present on the device, the return value is
* authenticator-dependent. The caller should verify the validity of the
* account before requesting an auth token.
*/
public AccountManagerFuture
*
*
* (Other authenticator-specific values may be returned.) If the user
* must enter credentials, the returned Bundle contains only
* {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
*
* If an error occurred, {@link AccountManagerFuture#getResult()} throws:
*
*
* If the account is no longer present on the device, the return value is
* authenticator-dependent. The caller should verify the validity of the
* account before requesting an auth token.
*/
public AccountManagerFuture
*
*
* If no activity was specified, the returned Bundle contains only
* {@link #KEY_INTENT} with the {@link Intent} needed to launch the
* actual account creation process. If an error occurred,
* {@link AccountManagerFuture#getResult()} throws:
*
*
*/
public AccountManagerFuture
*
*
* If no activity or password was specified, the returned Bundle contains
* only {@link #KEY_INTENT} with the {@link Intent} needed to launch the
* password prompt. If an error occurred,
* {@link AccountManagerFuture#getResult()} throws:
*
*
*/
public AccountManagerFuture
*
*
* If no activity was specified, the returned Bundle contains only
* {@link #KEY_INTENT} with the {@link Intent} needed to launch the
* password prompt. If an error occurred,
* {@link AccountManagerFuture#getResult()} throws:
*
*
*/
public AccountManagerFuture
*
*/
public AccountManagerFuture
*
*
* If an error occurred, {@link AccountManagerFuture#getResult()} throws:
*
*
*/
public AccountManagerFuture