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