AccountManager.java revision 751fdc09bb7ab0ce6feac7b7a823e38ed858feb0
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;
32603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
33a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.IOException;
34a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.Callable;
35a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.CancellationException;
36a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.ExecutionException;
37a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.FutureTask;
38a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.TimeoutException;
39a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.concurrent.TimeUnit;
40d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport java.util.HashMap;
41d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport java.util.Map;
42d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
43d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport com.google.android.collect.Maps;
44603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
45603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/**
46756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * A class that helps with interactions with the AccountManager Service. It provides
47603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * methods to allow for account, password, and authtoken management for all accounts on the
484db3a5b327038e4dc1bc58e3213bb9ad0719bcc1Fred Quintana * device. One accesses the {@link AccountManager} by calling:
49756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * <pre>
50a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana *    AccountManager accountManager = AccountManager.get(context);
51756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * </pre>
52603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
53603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * <p>
54756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * The AccountManager Service provides storage for the accounts known to the system,
55756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * provides methods to manage them, and allows the registration of authenticators to
56756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * which operations such as addAccount and getAuthToken are delegated.
57756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * <p>
58756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * Many of the calls take an {@link AccountManagerCallback} and {@link Handler} as parameters.
59756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * These calls return immediately but run asynchronously. If a callback is provided then
60756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * {@link AccountManagerCallback#run} will be invoked wen the request completes, successfully
61756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * or not. An {@link AccountManagerFuture} is returned by these requests and also passed into the
62756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * callback. The result if retrieved by calling {@link AccountManagerFuture#getResult()} which
63756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * either returns the result or throws an exception as appropriate.
64756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * <p>
65756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * The asynchronous request can be made blocking by not providing a callback and instead
66756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * calling {@link AccountManagerFuture#getResult()} on the future that is returned. This will
67756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * cause the running thread to block until the result is returned. Keep in mind that one
68756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * should not block the main thread in this way. Instead one should either use a callback,
69756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * thus making the call asynchronous, or make the blocking call on a separate thread.
70756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * <p>
71756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * If one wants to ensure that the callback is invoked from a specific handler then they should
72756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * pass the handler to the request. This makes it easier to ensure thread-safety by running
73756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana * all of one's logic from a single handler.
74603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
75603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapublic class AccountManager {
76603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TAG = "AccountManager";
77603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
78f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_REMOTE_EXCEPTION = 1;
79f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_NETWORK_ERROR = 3;
80f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_CANCELED = 4;
81f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_INVALID_RESPONSE = 5;
82f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6;
83f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
84f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final int ERROR_CODE_BAD_REQUEST = 8;
85756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana
86f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_ACCOUNTS = "accounts";
87f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
88f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_USERDATA = "userdata";
89f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_AUTHTOKEN = "authtoken";
90f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_PASSWORD = "password";
91f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_ACCOUNT_NAME = "authAccount";
92f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_ACCOUNT_TYPE = "accountType";
93f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_ERROR_CODE = "errorCode";
94f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_ERROR_MESSAGE = "errorMessage";
95f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_INTENT = "intent";
96f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_BOOLEAN_RESULT = "booleanResult";
97f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
98f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
99f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage";
100f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey";
101f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String ACTION_AUTHENTICATOR_INTENT =
102f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            "android.accounts.AccountAuthenticator";
103f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String AUTHENTICATOR_META_DATA_NAME =
104f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    "android.accounts.AccountAuthenticator";
105f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
106f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana
107603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final Context mContext;
108603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final IAccountManager mService;
109d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    private final Handler mMainHandler;
110f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    /**
111f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana     * Action sent as a broadcast Intent by the AccountsService
112f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana     * when accounts are added to and/or removed from the device's
113f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana     * database.
114f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana     */
115f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
116f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        "android.accounts.LOGIN_ACCOUNTS_CHANGED";
117603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1183326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    /**
1193326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana     * @hide
1203326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana     */
121603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public AccountManager(Context context, IAccountManager service) {
122603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mContext = context;
123603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mService = service;
124d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        mMainHandler = new Handler(mContext.getMainLooper());
125603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
126603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1270eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana    /**
1280eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana     * @hide used for testing only
1290eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana     */
1300eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana    public AccountManager(Context context, IAccountManager service, Handler handler) {
1310eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana        mContext = context;
1320eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana        mService = service;
1330eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana        mMainHandler = handler;
1340eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana    }
1350eabf0228a17e07ef831bc1ee1951c9697d2a079Fred Quintana
136756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
137756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Retrieve an AccountManager instance that is associated with the context that is passed in.
138756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Certain calls such as {@link #addOnAccountsUpdatedListener} use this context internally,
139756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * so the caller must take care to use a {@link Context} whose lifetime is associated with
140756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * the listener registration.
141756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param context The {@link Context} to use when necessary
142756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an {@link AccountManager} instance that is associated with context
143756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
144a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public static AccountManager get(Context context) {
145a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
146a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
147a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
148756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
149756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Get the password that is associated with the account. Returns null if the account does
150756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * not exist.
151756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
152756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission
153756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
154756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * with the same UID as the Authenticator for the account.
155756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
156ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public String getPassword(final Account account) {
157603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
158603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return mService.getPassword(account);
159603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
160ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // will never happen
161603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
162603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
163603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
164603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
165756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
166756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Get the user data named by "key" that is associated with the account.
167756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Returns null if the account does not exist or if it does not have a value for key.
168756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
169756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission
170756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
171756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * with the same UID as the Authenticator for the account.
172756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
173ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public String getUserData(final Account account, final String key) {
174603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
175603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return mService.getUserData(account, key);
176603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
177ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // will never happen
178603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
179603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
180603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
181603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
182756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
183756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Query the AccountManager Service for an array that contains a
184756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link AuthenticatorDescription} for each registered authenticator.
185756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an array that contains all the authenticators known to the AccountManager service.
186756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This array will be empty if there are no authenticators and will never return null.
187756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
188756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * No permission is required to make this call.
189756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
190ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public AuthenticatorDescription[] getAuthenticatorTypes() {
191603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
192a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return mService.getAuthenticatorTypes();
193603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
194ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // will never happen
195603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
196603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
197603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
198603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
199756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
200756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Query the AccountManager Service for all accounts.
201756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an array that contains all the accounts known to the AccountManager service.
202756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This array will be empty if there are no accounts and will never return null.
203756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
204756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}
205756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
206ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccounts() {
207a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        try {
208ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return mService.getAccounts(null);
209a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        } catch (RemoteException e) {
210ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
211a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            throw new RuntimeException(e);
212a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
213603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
214603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
215756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
216756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Query the AccountManager for the set of accounts that have a given type. If null
217756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * is passed as the type than all accounts are returned.
218756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param type the account type by which to filter, or null to get all accounts
219756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an array that contains the accounts that match the specified type. This array
220756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * will be empty if no accounts match. It will never return null.
221756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
222756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}
223756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
224ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccountsByType(String type) {
225603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
226ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return mService.getAccounts(type);
227603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
228ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
229603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
230603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
231603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
232603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
233756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
234bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * Tests that the given account has the specified features. If this account does not exist
235bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * then this call returns false.
236bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * <p>
237bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * This call returns immediately but runs asynchronously and the result is accessed via the
238bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
239bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
240bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * method asynchronously then they will generally pass in a callback object that will get
241bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
242bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * they will generally pass null for the callback and instead call
243bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
244bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * which will then block until the request completes.
245bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * <p>
246bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}.
247bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     *
248bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * @param account The {@link Account} to test
249bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * @param features the features for which to test
250bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * @param callback A callback to invoke when the request completes. If null then
251bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * no callback is invoked.
252bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * @param handler The {@link Handler} to use to invoke the callback. If null then the
253bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * main thread's {@link Handler} is used.
254bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * @return an {@link AccountManagerFuture} that represents the future result of the call.
255bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * The future result is a {@link Boolean} that is true if the account exists and has the
256bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     * specified features.
257bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana     */
2583084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana    public AccountManagerFuture<Boolean> hasFeatures(final Account account,
259bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            final String[] features,
260bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            AccountManagerCallback<Boolean> callback, Handler handler) {
261bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        return new Future2Task<Boolean>(handler, callback) {
262bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            public void doWork() throws RemoteException {
2633084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana                mService.hasFeatures(mResponse, account, features);
264bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
265bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
266bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
267bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    throw new AuthenticatorException("no result in response");
268bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                }
269bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                return bundle.getBoolean(KEY_BOOLEAN_RESULT);
270bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
271bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }.start();
272bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
273bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
274bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    /**
275c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana     * Add an account to the AccountManager's set of known accounts.
276756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
277756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission
278756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
279756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * with the same UID as the Authenticator for the account.
280756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account The account to add
281756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param password The password to associate with the account. May be null.
28231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana     * @param userdata A bundle of key/value pairs to set as the account's userdata. May be null.
283756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return true if the account was sucessfully added, false otherwise, for example,
284756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * if the account already exists or if the account is null
285756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
28631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana    public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
287603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
28831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return mService.addAccount(account, password, userdata);
289603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
290ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
291603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
292603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
293603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
294603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
295756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
296756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Removes the given account. If this account does not exist then this call has no effect.
297756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
298756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This call returns immediately but runs asynchronously and the result is accessed via the
299756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
300756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
301756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * method asynchronously then they will generally pass in a callback object that will get
302756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
303756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * they will generally pass null for the callback and instead call
304756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
305756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * which will then block until the request completes.
306756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
307756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
308756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     *
309756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account The {@link Account} to remove
310756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param callback A callback to invoke when the request completes. If null then
311756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * no callback is invoked.
312756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param handler The {@link Handler} to use to invoke the callback. If null then the
313756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * main thread's {@link Handler} is used.
314756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an {@link AccountManagerFuture} that represents the future result of the call.
315756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * The future result is a {@link Boolean} that is true if the account is successfully removed
316756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * or false if the authenticator refuses to remove the account.
317756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
318ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public AccountManagerFuture<Boolean> removeAccount(final Account account,
319ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            AccountManagerCallback<Boolean> callback, Handler handler) {
320ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        return new Future2Task<Boolean>(handler, callback) {
321ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            public void doWork() throws RemoteException {
322ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                mService.removeAccount(mResponse, account);
323a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
324ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
325f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
326ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    throw new AuthenticatorException("no result in response");
327ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
328f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                return bundle.getBoolean(KEY_BOOLEAN_RESULT);
329a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
330ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }.start();
331a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
332a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
333756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
334756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Removes the given authtoken. If this authtoken does not exist for the given account type
335756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * then this call has no effect.
336756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
337756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
338756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param accountType the account type of the authtoken to invalidate
339756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param authToken the authtoken to invalidate
340756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
341ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void invalidateAuthToken(final String accountType, final String authToken) {
342603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
343603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mService.invalidateAuthToken(accountType, authToken);
344603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
345ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
346ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new RuntimeException(e);
347603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
348603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
349603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
350756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
351756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Gets the authtoken named by "authTokenType" for the specified account if it is cached
352756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * by the AccountManager. If no authtoken is cached then null is returned rather than
353756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * asking the authenticaticor to generate one. If the account or the
354756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * authtoken do not exist then null is returned.
355756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
356756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission
357756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
358756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * with the same UID as the Authenticator for the account.
359756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account the account whose authtoken is to be retrieved, must not be null
360756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param authTokenType the type of authtoken to retrieve
361756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an authtoken for the given account and authTokenType, if one is cached by the
362756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * AccountManager, null otherwise.
363756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
364ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public String peekAuthToken(final Account account, final String authTokenType) {
36531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
36688a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            Log.e(TAG, "peekAuthToken: the account must not be null");
36788a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            return null;
36831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
36931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (authTokenType == null) {
37031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
37131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
372603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
373603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return mService.peekAuthToken(account, authTokenType);
374603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
375ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
376603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            throw new RuntimeException(e);
377603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
378603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
379603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
380756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
381756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Sets the password for the account. The password may be null. If the account does not exist
382756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * then this call has no affect.
383756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
384756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission
385756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
386756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * with the same UID as the Authenticator for the account.
387756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account the account whose password is to be set. Must not be null.
388756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param password the password to set for the account. May be null.
389756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
390ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void setPassword(final Account account, final String password) {
39131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
39288a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            Log.e(TAG, "the account must not be null");
39388a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            return;
39431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
395603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
396603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mService.setPassword(account, password);
397603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
398ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
399ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new RuntimeException(e);
400603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
401603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
402603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
403756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
404756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Sets the password for account to null. If the account does not exist then this call
405756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * has no effect.
406756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
407756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
408756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account the account whose password is to be cleared. Must not be null.
409756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
410ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void clearPassword(final Account account) {
41131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
41288a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            Log.e(TAG, "the account must not be null");
41388a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            return;
41431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
415603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
416603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mService.clearPassword(account);
417603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
418ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
419ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new RuntimeException(e);
420603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
421603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
422603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
423756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
424756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Sets account's userdata named "key" to the specified value. If the account does not
425756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * exist then this call has no effect.
426756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
427756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission
428756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
429756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * with the same UID as the Authenticator for the account.
430756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account the account whose userdata is to be set. Must not be null.
431756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param key the key of the userdata to set. Must not be null.
432756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param value the value to set. May be null.
433756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
434ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void setUserData(final Account account, final String key, final String value) {
43531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
43688a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            Log.e(TAG, "the account must not be null");
43788a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            return;
43831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
43931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (key == null) {
44088a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            Log.e(TAG, "the key must not be null");
44188a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            return;
44231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
443603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
444603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mService.setUserData(account, key, value);
445603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
446ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
447ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new RuntimeException(e);
448603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
449603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
450603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
451756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
452756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Sets the authtoken named by "authTokenType" to the value specified by authToken.
453756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * If the account does not exist then this call has no effect.
454756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
455756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission
456756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
457756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * with the same UID as the Authenticator for the account.
458756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account the account whose authtoken is to be set. Must not be null.
459756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param authTokenType the type of the authtoken to set. Must not be null.
460756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param authToken the authToken to set. May be null.
461756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
462ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void setAuthToken(Account account, final String authTokenType, final String authToken) {
463603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
464603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mService.setAuthToken(account, authTokenType, authToken);
465603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } catch (RemoteException e) {
466ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // won't ever happen
467ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new RuntimeException(e);
468603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
469603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
470603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
471756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
472756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Convenience method that makes a blocking call to
473756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, Handler)}
474756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * then extracts and returns the value of {@link #KEY_AUTHTOKEN} from its result.
475756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
476756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
477756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account the account whose authtoken is to be retrieved, must not be null
478756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param authTokenType the type of authtoken to retrieve
479756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param notifyAuthFailure if true, cause the AccountManager to put up a "sign-on" notification
480756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * for the account if no authtoken is cached by the AccountManager and the the authenticator
481756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * does not have valid credentials to get an authtoken.
482756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an authtoken for the given account and authTokenType, if one is cached by the
483756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * AccountManager, null otherwise.
484756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @throws AuthenticatorException if the authenticator is not present, unreachable or returns
485756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * an invalid response.
486756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @throws OperationCanceledException if the request is canceled for any reason
487756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @throws java.io.IOException if the authenticator experiences an IOException while attempting
488756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * to communicate with its backend server.
489756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
490a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String blockingGetAuthToken(Account account, String authTokenType,
491a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            boolean notifyAuthFailure)
492a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            throws OperationCanceledException, IOException, AuthenticatorException {
493a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */,
494a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                null /* handler */).getResult();
495f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        return bundle.getString(KEY_AUTHTOKEN);
496a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
497a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
498a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    /**
499756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Request that an authtoken of the specified type be returned for an account.
500756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * If the Account Manager has a cached authtoken of the requested type then it will
501756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * service the request itself. Otherwise it will pass the request on to the authenticator.
502756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * The authenticator can try to service this request with information it already has stored
503756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * in the AccountManager but may need to launch an activity to prompt the
504756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * user to enter credentials. If it is able to retrieve the authtoken it will be returned
505756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * in the result.
506756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
507756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * If the authenticator needs to prompt the user for credentials it will return an intent to
508756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * the activity that will do the prompting. If an activity is supplied then that activity
509756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * will be used to launch the intent and the result will come from it. Otherwise a result will
510756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * be returned that contains the intent.
511756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
512756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This call returns immediately but runs asynchronously and the result is accessed via the
513756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
514756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
515756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * method asynchronously then they will generally pass in a callback object that will get
516756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
517756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * they will generally pass null for the callback and instead call
518756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
519756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * which will then block until the request completes.
520756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
521756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
522a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana     *
523756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account The account whose credentials are to be updated.
524756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param authTokenType the auth token to retrieve as part of updating the credentials.
525756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * May be null.
52631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana     * @param options authenticator specific options for the request
527756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
528756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * the intent will be started with this activity. If activity is null then the result will
529756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * be returned as-is.
530756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param callback A callback to invoke when the request completes. If null then
531756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * no callback is invoked.
532756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param handler The {@link Handler} to use to invoke the callback. If null then the
533756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * main thread's {@link Handler} is used.
534756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an {@link AccountManagerFuture} that represents the future result of the call.
535756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * The future result is a {@link Bundle} that contains:
536756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
537756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_ACCOUNT_NAME}, {@link #KEY_ACCOUNT_TYPE} and {@link #KEY_AUTHTOKEN}
538756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
539756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * If the user presses "back" then the request will be canceled.
540a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana     */
541ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public AccountManagerFuture<Bundle> getAuthToken(
54231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            final Account account, final String authTokenType, final Bundle options,
543ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
544a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        if (activity == null) throw new IllegalArgumentException("activity is null");
545a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
546a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(activity, handler, callback) {
547a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
548a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mService.getAuthToken(mResponse, account, authTokenType,
549a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
55031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                        options);
551a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
5523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
553a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
554a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
555756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
556756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Request that an authtoken of the specified type be returned for an account.
557756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * If the Account Manager has a cached authtoken of the requested type then it will
558756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * service the request itself. Otherwise it will pass the request on to the authenticator.
559756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * The authenticator can try to service this request with information it already has stored
560756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * in the AccountManager but may need to launch an activity to prompt the
561756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * user to enter credentials. If it is able to retrieve the authtoken it will be returned
562756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * in the result.
563756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
564c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana     * If the authenticator needs to prompt the user for credentials, rather than returning the
565c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana     * authtoken it will instead return an intent for
566756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * an activity that will do the prompting. If an intent is returned and notifyAuthFailure
567c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana     * is true then a notification will be created that launches this intent. This intent can be
568c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana     * invoked by the caller directly to start the activity that prompts the user for the
569c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana     * updated credentials. Otherwise this activity will not be run until the user activates
570c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana     * the notification.
571756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
572756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This call returns immediately but runs asynchronously and the result is accessed via the
573756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
574756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
575756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * method asynchronously then they will generally pass in a callback object that will get
576756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
577756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * they will generally pass null for the callback and instead call
578756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
579756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * which will then block until the request completes.
580756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
581756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
582756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     *
583756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account The account whose credentials are to be updated.
584756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param authTokenType the auth token to retrieve as part of updating the credentials.
585756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * May be null.
586756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param notifyAuthFailure if true and the authenticator returns a {@link #KEY_INTENT} in the
587756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * result then a "sign-on needed" notification will be created that will launch this intent.
588756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param callback A callback to invoke when the request completes. If null then
589756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * no callback is invoked.
590756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param handler The {@link Handler} to use to invoke the callback. If null then the
591756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * main thread's {@link Handler} is used.
592756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an {@link AccountManagerFuture} that represents the future result of the call.
593756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * The future result is a {@link Bundle} that contains either:
594756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
595756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_INTENT}, which is to be used to prompt the user for the credentials
596756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_ACCOUNT_NAME}, {@link #KEY_ACCOUNT_TYPE} and {@link #KEY_AUTHTOKEN}
597756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * if the authenticator is able to retrieve the auth token
598756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
599756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * If the user presses "back" then the request will be canceled.
600756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
601ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public AccountManagerFuture<Bundle> getAuthToken(
602a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Account account, final String authTokenType, final boolean notifyAuthFailure,
603ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            AccountManagerCallback<Bundle> callback, Handler handler) {
604a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
605a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
606a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(null, handler, callback) {
607a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
608a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mService.getAuthToken(mResponse, account, authTokenType,
609a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        notifyAuthFailure, false /* expectActivityLaunch */, null /* options */);
610a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
6113326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
612a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
613a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
614756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
615756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Request that an account be added with the given accountType. This request
616756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * is processed by the authenticator for the account type. If no authenticator is registered
617756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * in the system then {@link AuthenticatorException} is thrown.
618756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
619756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This call returns immediately but runs asynchronously and the result is accessed via the
620756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
621756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
622756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * method asynchronously then they will generally pass in a callback object that will get
623756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
624756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * they will generally pass null for the callback and instead call
625756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
626756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * which will then block until the request completes.
627756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
628756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
629756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     *
630756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param accountType The type of account to add. This must not be null.
631756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param authTokenType The account that is added should be able to service this auth token
632756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * type. This may be null.
633756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param requiredFeatures The account that is added should support these features.
634756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This array may be null or empty.
635756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param addAccountOptions A bundle of authenticator-specific options that is passed on
636756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * to the authenticator. This may be null.
637756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
638756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * the intent will be started with this activity. If activity is null then the result will
639756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * be returned as-is.
640756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param callback A callback to invoke when the request completes. If null then
641756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * no callback is invoked.
642756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param handler The {@link Handler} to use to invoke the callback. If null then the
643756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * main thread's {@link Handler} is used.
644756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an {@link AccountManagerFuture} that represents the future result of the call.
645756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * The future result is a {@link Bundle} that contains either:
646756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
647756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_INTENT}, or
648756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_ACCOUNT_NAME}, {@link #KEY_ACCOUNT_TYPE}
649756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * and {@link #KEY_AUTHTOKEN} (if an authTokenType was specified).
650756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
651756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
652ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public AccountManagerFuture<Bundle> addAccount(final String accountType,
6533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String authTokenType, final String[] requiredFeatures,
6543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final Bundle addAccountOptions,
655ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
656a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(activity, handler, callback) {
657a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
65888a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                if (accountType == null) {
65988a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                    Log.e(TAG, "the account must not be null");
66088a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                    // to unblock caller waiting on Future.get()
661c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    set(new Bundle());
66288a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                    return;
66388a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                }
664a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mService.addAcount(mResponse, accountType, authTokenType,
6653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        requiredFeatures, activity != null, addAccountOptions);
666a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
6673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
668a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
669a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
670ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
6713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String type, final String[] features,
672ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            AccountManagerCallback<Account[]> callback, Handler handler) {
673ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        return new Future2Task<Account[]>(handler, callback) {
6743326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            public void doWork() throws RemoteException {
67588a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                if (type == null) {
67688a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                    Log.e(TAG, "Type is null");
67788a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                    set(new Account[0]);
67888a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                    return;
67988a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                }
680ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                mService.getAccountsByFeatures(mResponse, type, features);
681ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
682ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
683f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                if (!bundle.containsKey(KEY_ACCOUNTS)) {
684ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    throw new AuthenticatorException("no result in response");
685ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
686f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                final Parcelable[] parcelables = bundle.getParcelableArray(KEY_ACCOUNTS);
687ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                Account[] descs = new Account[parcelables.length];
688ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                for (int i = 0; i < parcelables.length; i++) {
689ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    descs[i] = (Account) parcelables[i];
690ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
691ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return descs;
6923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
6933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
6943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
6953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
696756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
697756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requests that the authenticator checks that the user knows the credentials for the account.
698756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This is typically done by returning an intent to an activity that prompts the user to
699756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * enter the credentials. This request
700756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * is processed by the authenticator for the account. If no matching authenticator is
701756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * registered in the system then {@link AuthenticatorException} is thrown.
702756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
703756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This call returns immediately but runs asynchronously and the result is accessed via the
704756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
705756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
706756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * method asynchronously then they will generally pass in a callback object that will get
707756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
708756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * they will generally pass null for the callback and instead call
709756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
710756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * which will then block until the request completes.
711756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
712756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
713756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     *
714756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account The account whose credentials are to be checked
715756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param options authenticator specific options for the request
716756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
717756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * the intent will be started with this activity. If activity is null then the result will
718756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * be returned as-is.
719756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param callback A callback to invoke when the request completes. If null then
720756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * no callback is invoked.
721756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param handler The {@link Handler} to use to invoke the callback. If null then the
722756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * main thread's {@link Handler} is used.
723756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an {@link AccountManagerFuture} that represents the future result of the call.
724756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * The future result is a {@link Bundle} that contains either:
725756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
726756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_INTENT}, which is to be used to prompt the user for the credentials
727756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE} if the user enters the correct
728756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * credentials
729756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
730756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * If the user presses "back" then the request will be canceled.
731756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
732f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public AccountManagerFuture<Bundle> confirmCredentials(final Account account,
733f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            final Bundle options,
734f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            final Activity activity,
735ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final AccountManagerCallback<Bundle> callback,
736a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Handler handler) {
737a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(activity, handler, callback) {
738a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
739f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                mService.confirmCredentials(mResponse, account, options, activity != null);
740a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
7413326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
742a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
743a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
744756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
745756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requests that the authenticator update the the credentials for a user. This is typically
746756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * done by returning an intent to an activity that will prompt the user to update the stored
747756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * credentials for the account. This request
748756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * is processed by the authenticator for the account. If no matching authenticator is
749756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * registered in the system then {@link AuthenticatorException} is thrown.
750756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
751756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This call returns immediately but runs asynchronously and the result is accessed via the
752756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
753756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
754756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * method asynchronously then they will generally pass in a callback object that will get
755756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
756756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * they will generally pass null for the callback and instead call
757756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
758756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * which will then block until the request completes.
759756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
760756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
761756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     *
762756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param account The account whose credentials are to be updated.
763756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param authTokenType the auth token to retrieve as part of updating the credentials.
764756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * May be null.
76531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana     * @param options authenticator specific options for the request
766756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
767756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * the intent will be started with this activity. If activity is null then the result will
768756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * be returned as-is.
769756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param callback A callback to invoke when the request completes. If null then
770756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * no callback is invoked.
771756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param handler The {@link Handler} to use to invoke the callback. If null then the
772756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * main thread's {@link Handler} is used.
773756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an {@link AccountManagerFuture} that represents the future result of the call.
774756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * The future result is a {@link Bundle} that contains either:
775756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
776756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_INTENT}, which is to be used to prompt the user for the credentials
777756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE} if the user enters the correct
778756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * credentials, and optionally a {@link #KEY_AUTHTOKEN} if an authTokenType was provided.
779756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
780756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * If the user presses "back" then the request will be canceled.
781756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
782756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    public AccountManagerFuture<Bundle> updateCredentials(final Account account,
783756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana            final String authTokenType,
78431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            final Bundle options, final Activity activity,
785ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final AccountManagerCallback<Bundle> callback,
786a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Handler handler) {
787a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(activity, handler, callback) {
788a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
789a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mService.updateCredentials(mResponse, account, authTokenType, activity != null,
79031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                        options);
791a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
7923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
793a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
794a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
795756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
796756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Request that the properties for an authenticator be updated. This is typically done by
797756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * returning an intent to an activity that will allow the user to make changes. This request
798756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * is processed by the authenticator for the account. If no matching authenticator is
799756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * registered in the system then {@link AuthenticatorException} is thrown.
800756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
801756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This call returns immediately but runs asynchronously and the result is accessed via the
802756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
803756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
804756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * method asynchronously then they will generally pass in a callback object that will get
805756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
806756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * they will generally pass null for the callback and instead call
807756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
808756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * which will then block until the request completes.
809756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
810756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
811756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     *
812756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param accountType The account type of the authenticator whose properties are to be edited.
813756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
814756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * the intent will be started with this activity. If activity is null then the result will
815756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * be returned as-is.
816756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param callback A callback to invoke when the request completes. If null then
817756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * no callback is invoked.
818756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param handler The {@link Handler} to use to invoke the callback. If null then the
819756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * main thread's {@link Handler} is used.
820756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an {@link AccountManagerFuture} that represents the future result of the call.
821756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * The future result is a {@link Bundle} that contains either:
822756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
823756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_INTENT}, which is to be used to prompt the user for the credentials
824756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> nothing, returned if the edit completes successfully
825756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
826756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * If the user presses "back" then the request will be canceled.
827756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
828756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    public AccountManagerFuture<Bundle> editProperties(final String accountType,
829756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana            final Activity activity, final AccountManagerCallback<Bundle> callback,
830a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Handler handler) {
831a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        return new AmsTask(activity, handler, callback) {
832a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void doWork() throws RemoteException {
833a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mService.editProperties(mResponse, accountType, activity != null);
834a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
8353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }.start();
836a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
837a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
838a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private void ensureNotOnMainThread() {
839a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final Looper looper = Looper.myLooper();
840a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        if (looper != null && looper == mContext.getMainLooper()) {
84153bd2522ca7767f46646606123b6e2689b811850Fred Quintana            final IllegalStateException exception = new IllegalStateException(
84253bd2522ca7767f46646606123b6e2689b811850Fred Quintana                    "calling this from your main thread can lead to deadlock");
84353bd2522ca7767f46646606123b6e2689b811850Fred Quintana            Log.e(TAG, "calling this from your main thread can lead to deadlock and/or ANRs",
84453bd2522ca7767f46646606123b6e2689b811850Fred Quintana                    exception);
845751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana            if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.FROYO) {
846751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana                throw exception;
847751fdc09bb7ab0ce6feac7b7a823e38ed858feb0Fred Quintana            }
848a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
849a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
850a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
851ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private void postToHandler(Handler handler, final AccountManagerCallback<Bundle> callback,
852ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final AccountManagerFuture<Bundle> future) {
853d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        handler = handler == null ? mMainHandler : handler;
854d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        handler.post(new Runnable() {
855a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void run() {
856a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                callback.run(future);
857a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
858a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        });
859603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
860603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
861f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    private void postToHandler(Handler handler, final OnAccountsUpdateListener listener,
862d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            final Account[] accounts) {
863ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final Account[] accountsCopy = new Account[accounts.length];
864ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        // send a copy to make sure that one doesn't
865ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        // change what another sees
866ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        System.arraycopy(accounts, 0, accountsCopy, 0, accountsCopy.length);
867ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        handler = (handler == null) ? mMainHandler : handler;
868d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        handler.post(new Runnable() {
869a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void run() {
870b6437245c280596d0a580b8d67189739cf793250Costin Manolache                try {
871b6437245c280596d0a580b8d67189739cf793250Costin Manolache                    listener.onAccountsUpdated(accountsCopy);
872b6437245c280596d0a580b8d67189739cf793250Costin Manolache                } catch (SQLException e) {
873b6437245c280596d0a580b8d67189739cf793250Costin Manolache                    // Better luck next time.  If the problem was disk-full,
874b6437245c280596d0a580b8d67189739cf793250Costin Manolache                    // the STORAGE_OK intent will re-trigger the update.
875b6437245c280596d0a580b8d67189739cf793250Costin Manolache                    Log.e(TAG, "Can't update accounts", e);
876b6437245c280596d0a580b8d67189739cf793250Costin Manolache                }
877a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
878a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        });
879a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
880a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
881ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private abstract class AmsTask extends FutureTask<Bundle> implements AccountManagerFuture<Bundle> {
882a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final IAccountManagerResponse mResponse;
883a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final Handler mHandler;
884ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final AccountManagerCallback<Bundle> mCallback;
885a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final Activity mActivity;
886ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public AmsTask(Activity activity, Handler handler, AccountManagerCallback<Bundle> callback) {
887a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            super(new Callable<Bundle>() {
888a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                public Bundle call() throws Exception {
889a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw new IllegalStateException("this should never be called");
890a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
891a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            });
892a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
893a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mHandler = handler;
894a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mCallback = callback;
895a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mActivity = activity;
896a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mResponse = new Response();
8973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
8983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
899ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public final AccountManagerFuture<Bundle> start() {
900ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            try {
901ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                doWork();
902ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } catch (RemoteException e) {
903ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                setException(e);
904ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
9053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return this;
906a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
907a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
908a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public abstract void doWork() throws RemoteException;
909603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
910a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private Bundle internalGetResult(Long timeout, TimeUnit unit)
911a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
91253bd2522ca7767f46646606123b6e2689b811850Fred Quintana            if (!isDone()) {
91353bd2522ca7767f46646606123b6e2689b811850Fred Quintana                ensureNotOnMainThread();
91453bd2522ca7767f46646606123b6e2689b811850Fred Quintana            }
915a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
916a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (timeout == null) {
917a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return get();
918a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else {
919a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return get(timeout, unit);
920a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
921a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (CancellationException e) {
922a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                throw new OperationCanceledException();
923a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (TimeoutException e) {
924a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // fall through and cancel
925a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (InterruptedException e) {
926a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // fall through and cancel
927a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (ExecutionException e) {
928a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                final Throwable cause = e.getCause();
929a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (cause instanceof IOException) {
930a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (IOException) cause;
931a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof UnsupportedOperationException) {
932a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw new AuthenticatorException(cause);
933a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof AuthenticatorException) {
934a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (AuthenticatorException) cause;
935a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof RuntimeException) {
936a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (RuntimeException) cause;
937a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof Error) {
938a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (Error) cause;
939a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else {
940a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw new IllegalStateException(cause);
941a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
942a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } finally {
943a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                cancel(true /* interrupt if running */);
944603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
945a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            throw new OperationCanceledException();
946603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
947603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
948a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public Bundle getResult()
949a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
950a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return internalGetResult(null, null);
951603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
952603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
953a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public Bundle getResult(long timeout, TimeUnit unit)
954a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
955a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return internalGetResult(timeout, unit);
956603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
957603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
958a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected void done() {
959a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mCallback != null) {
960a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                postToHandler(mHandler, mCallback, this);
961a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
962a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
963a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
964a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        /** Handles the responses from the AccountManager */
965a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private class Response extends IAccountManagerResponse.Stub {
966a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void onResult(Bundle bundle) {
967a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Intent intent = bundle.getParcelable("intent");
968a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (intent != null && mActivity != null) {
969a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // since the user provided an Activity we will silently start intents
970a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // that we see
971a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    mActivity.startActivity(intent);
972a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // leave the Future running to wait for the real response to this request
973d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                } else if (bundle.getBoolean("retry")) {
974d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    try {
975d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        doWork();
976d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    } catch (RemoteException e) {
977d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        // this will only happen if the system process is dead, which means
978d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        // we will be dying ourselves
979d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    }
980a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else {
981a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    set(bundle);
982a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
983a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
984a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
985a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            public void onError(int code, String message) {
986f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                if (code == ERROR_CODE_CANCELED) {
987a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // the authenticator indicated that this request was canceled, do so now
988a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    cancel(true /* mayInterruptIfRunning */);
989a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return;
990a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
991a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                setException(convertErrorToException(code, message));
992a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
993603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
994a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
995603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
996603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
997ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private abstract class BaseFutureTask<T> extends FutureTask<T> {
998ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final public IAccountManagerResponse mResponse;
999a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final Handler mHandler;
1000ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1001ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public BaseFutureTask(Handler handler) {
1002ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super(new Callable<T>() {
1003ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                public T call() throws Exception {
1004a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw new IllegalStateException("this should never be called");
1005a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1006a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            });
1007a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mHandler = handler;
1008ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mResponse = new Response();
1009ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1010a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1011ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public abstract void doWork() throws RemoteException;
1012ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1013ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public abstract T bundleToResult(Bundle bundle) throws AuthenticatorException;
1014ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1015ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected void postRunnableToHandler(Runnable runnable) {
1016ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            Handler handler = (mHandler == null) ? mMainHandler : mHandler;
1017ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            handler.post(runnable);
1018ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1019ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1020ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected void startTask() {
1021ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            try {
1022ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                doWork();
1023ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            } catch (RemoteException e) {
1024ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                setException(e);
1025ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
1026ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1027ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1028ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected class Response extends IAccountManagerResponse.Stub {
1029ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            public void onResult(Bundle bundle) {
1030ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                try {
1031ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    T result = bundleToResult(bundle);
1032ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    if (result == null) {
1033ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        return;
1034a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1035ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    set(result);
1036ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
1037ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                } catch (ClassCastException e) {
1038ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    // we will set the exception below
1039ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                } catch (AuthenticatorException e) {
1040ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    // we will set the exception below
1041a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1042f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(ERROR_CODE_INVALID_RESPONSE, "no result in response");
1043ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
1044a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1045ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            public void onError(int code, String message) {
1046f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                if (code == ERROR_CODE_CANCELED) {
1047ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    cancel(true /* mayInterruptIfRunning */);
1048ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
1049ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
1050ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                setException(convertErrorToException(code, message));
1051ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
1052ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1053ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
1054a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1055ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private abstract class Future2Task<T>
1056ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            extends BaseFutureTask<T> implements AccountManagerFuture<T> {
1057ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final AccountManagerCallback<T> mCallback;
1058ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public Future2Task(Handler handler, AccountManagerCallback<T> callback) {
1059ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super(handler);
1060ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mCallback = callback;
1061ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1062a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1063a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected void done() {
1064a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mCallback != null) {
1065ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                postRunnableToHandler(new Runnable() {
1066ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    public void run() {
1067ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        mCallback.run(Future2Task.this);
1068ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    }
1069ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                });
1070a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1071a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1072a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1073ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public Future2Task<T> start() {
1074ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            startTask();
1075ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return this;
1076ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1077ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1078ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        private T internalGetResult(Long timeout, TimeUnit unit)
1079ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
108053bd2522ca7767f46646606123b6e2689b811850Fred Quintana            if (!isDone()) {
108153bd2522ca7767f46646606123b6e2689b811850Fred Quintana                ensureNotOnMainThread();
108253bd2522ca7767f46646606123b6e2689b811850Fred Quintana            }
1083a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1084a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (timeout == null) {
1085a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return get();
1086a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else {
1087a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return get(timeout, unit);
1088a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1089a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (InterruptedException e) {
1090a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // fall through and cancel
1091a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (TimeoutException e) {
1092a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // fall through and cancel
1093a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (CancellationException e) {
1094ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                // fall through and cancel
1095a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (ExecutionException e) {
1096a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                final Throwable cause = e.getCause();
1097a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (cause instanceof IOException) {
1098ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    throw (IOException) cause;
1099a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof UnsupportedOperationException) {
1100ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    throw new AuthenticatorException(cause);
1101a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof AuthenticatorException) {
1102ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    throw (AuthenticatorException) cause;
1103a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof RuntimeException) {
1104a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (RuntimeException) cause;
1105a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else if (cause instanceof Error) {
1106a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw (Error) cause;
1107a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } else {
1108a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    throw new IllegalStateException(cause);
1109a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1110a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } finally {
1111a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                cancel(true /* interrupt if running */);
1112a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1113ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            throw new OperationCanceledException();
1114a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1115a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1116ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public T getResult()
1117ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
1118a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return internalGetResult(null, null);
1119603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1120a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1121ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public T getResult(long timeout, TimeUnit unit)
1122ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                throws OperationCanceledException, IOException, AuthenticatorException {
1123a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return internalGetResult(timeout, unit);
1124a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1125a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1126603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1127603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1128a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private Exception convertErrorToException(int code, String message) {
1129f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        if (code == ERROR_CODE_NETWORK_ERROR) {
1130a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return new IOException(message);
1131603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1132a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1133f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        if (code == ERROR_CODE_UNSUPPORTED_OPERATION) {
11343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return new UnsupportedOperationException(message);
1135a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1136a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1137f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        if (code == ERROR_CODE_INVALID_RESPONSE) {
11383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return new AuthenticatorException(message);
11393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
11403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1141f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        if (code == ERROR_CODE_BAD_ARGUMENTS) {
11423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return new IllegalArgumentException(message);
11433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
11443326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
11453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        return new AuthenticatorException(message);
11463326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
11473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1148ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private class GetAuthTokenByTypeAndFeaturesTask
1149ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            extends AmsTask implements AccountManagerCallback<Bundle> {
11503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        GetAuthTokenByTypeAndFeaturesTask(final String accountType, final String authTokenType,
11513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                final String[] features, Activity activityForPrompting,
11523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                final Bundle addAccountOptions, final Bundle loginOptions,
1153ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                AccountManagerCallback<Bundle> callback, Handler handler) {
11543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            super(activityForPrompting, handler, callback);
11553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountType == null) throw new IllegalArgumentException("account type is null");
11563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountType = accountType;
11573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAuthTokenType = authTokenType;
11583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mFeatures = features;
11593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAddAccountOptions = addAccountOptions;
11603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mLoginOptions = loginOptions;
11613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mMyCallback = this;
11623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
1163ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        volatile AccountManagerFuture<Bundle> mFuture = null;
11643326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        final String mAccountType;
11653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        final String mAuthTokenType;
11663326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        final String[] mFeatures;
11673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        final Bundle mAddAccountOptions;
11683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        final Bundle mLoginOptions;
1169ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final AccountManagerCallback<Bundle> mMyCallback;
11703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
11713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void doWork() throws RemoteException {
1172ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            getAccountsByTypeAndFeatures(mAccountType, mFeatures,
1173ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    new AccountManagerCallback<Account[]>() {
1174ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        public void run(AccountManagerFuture<Account[]> future) {
1175ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            Account[] accounts;
11763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            try {
1177ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                accounts = future.getResult();
1178ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            } catch (OperationCanceledException e) {
1179ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                setException(e);
1180ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                return;
1181ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            } catch (IOException e) {
1182ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                setException(e);
1183ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                return;
1184ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            } catch (AuthenticatorException e) {
1185ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                setException(e);
1186ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                return;
11873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            }
1188ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1189ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            if (accounts.length == 0) {
1190ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                if (mActivity != null) {
1191ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // no accounts, add one now. pretend that the user directly
1192ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // made this request
1193ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    mFuture = addAccount(mAccountType, mAuthTokenType, mFeatures,
1194ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            mAddAccountOptions, mActivity, mMyCallback, mHandler);
1195ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                } else {
1196ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // send result since we can't prompt to add an account
1197ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    Bundle result = new Bundle();
1198f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.putString(KEY_ACCOUNT_NAME, null);
1199f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.putString(KEY_ACCOUNT_TYPE, null);
1200f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.putString(KEY_AUTHTOKEN, null);
1201ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    try {
1202ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        mResponse.onResult(result);
1203ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    } catch (RemoteException e) {
1204ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        // this will never happen
1205ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    }
1206ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // we are done
1207ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                }
1208ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            } else if (accounts.length == 1) {
1209ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                // have a single account, return an authtoken for it
1210ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                if (mActivity == null) {
1211ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    mFuture = getAuthToken(accounts[0], mAuthTokenType,
1212ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            false /* notifyAuthFailure */, mMyCallback, mHandler);
1213ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                } else {
1214ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    mFuture = getAuthToken(accounts[0],
1215ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            mAuthTokenType, mLoginOptions,
12163326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                                            mActivity, mMyCallback, mHandler);
12173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                                }
1218ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                            } else {
1219ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                if (mActivity != null) {
1220ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    IAccountManagerResponse chooseResponse =
1221ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            new IAccountManagerResponse.Stub() {
1222ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        public void onResult(Bundle value) throws RemoteException {
1223ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            Account account = new Account(
1224f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                                    value.getString(KEY_ACCOUNT_NAME),
1225f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                                    value.getString(KEY_ACCOUNT_TYPE));
1226ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
1227ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                                    mActivity, mMyCallback, mHandler);
1228ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        }
1229ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1230ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        public void onError(int errorCode, String errorMessage)
1231ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                                throws RemoteException {
1232ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            mResponse.onError(errorCode, errorMessage);
1233ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        }
1234ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    };
1235ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // have many accounts, launch the chooser
1236ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    Intent intent = new Intent();
1237ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    intent.setClassName("android",
1238ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            "android.accounts.ChooseAccountActivity");
1239f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    intent.putExtra(KEY_ACCOUNTS, accounts);
1240f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    intent.putExtra(KEY_ACCOUNT_MANAGER_RESPONSE,
1241ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                            new AccountManagerResponse(chooseResponse));
1242ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    mActivity.startActivity(intent);
1243ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // the result will arrive via the IAccountManagerResponse
1244ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                } else {
1245ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // send result since we can't prompt to select an account
1246ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    Bundle result = new Bundle();
1247f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.putString(KEY_ACCOUNTS, null);
1248ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    try {
1249ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        mResponse.onResult(result);
1250ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    } catch (RemoteException e) {
1251ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                        // this will never happen
1252ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    }
1253ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                    // we are done
12543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                                }
12553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            }
1256ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        }}, mHandler);
12573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
12583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1259ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void run(AccountManagerFuture<Bundle> future) {
12603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            try {
1261f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                set(future.getResult());
1262f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            } catch (OperationCanceledException e) {
1263f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                cancel(true /* mayInterruptIfRUnning */);
1264f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            } catch (IOException e) {
1265f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                setException(e);
1266f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            } catch (AuthenticatorException e) {
1267f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                setException(e);
12683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
1269a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
12703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
1271a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1272756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana    /**
1273756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Convenience method that combines the functionality of {@link #getAccountsByTypeAndFeatures},
1274756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link #getAuthToken(Account, String, Bundle, Activity, AccountManagerCallback, Handler)},
1275756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * and {@link #addAccount}. It first gets the list of accounts that match accountType and the
1276756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * feature set. If there are none then {@link #addAccount} is invoked with the authTokenType
1277756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * feature set, and addAccountOptions. If there is exactly one then
1278756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link #getAuthToken(Account, String, Bundle, Activity, AccountManagerCallback, Handler)} is
1279756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * called with that account. If there are more than one then a chooser activity is launched
1280756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * to prompt the user to select one of them and then the authtoken is retrieved for it,
1281756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
1282756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * This call returns immediately but runs asynchronously and the result is accessed via the
1283756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
1284756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
1285756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * method asynchronously then they will generally pass in a callback object that will get
1286756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
1287756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * they will generally pass null for the callback and instead call
1288756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
1289756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * which will then block until the request completes.
1290756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <p>
1291756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
1292756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     *
1293756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param accountType the accountType to query; this must be non-null
1294756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param authTokenType the type of authtoken to retrieve; this must be non-null
1295756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param features a filter for the accounts. See {@link #getAccountsByTypeAndFeatures}.
1296756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param activityForPrompting The activity used to start any account management
1297756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * activities that are required to fulfill this request. This may be null.
1298756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param addAccountOptions authenticator-specific options used if an account needs to be added
129931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana     * @param getAuthTokenOptions authenticator-specific options passed to getAuthToken
1300756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param callback A callback to invoke when the request completes. If null then
1301756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * no callback is invoked.
1302756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @param handler The {@link Handler} to use to invoke the callback. If null then the
1303756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * main thread's {@link Handler} is used.
1304756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * @return an {@link AccountManagerFuture} that represents the future result of the call.
1305756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * The future result is a {@link Bundle} that contains either:
1306756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <ul>
1307756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_INTENT}, if no activity is supplied yet an activity needs to launched to
1308756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * fulfill the request.
1309756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * <li> {@link #KEY_ACCOUNT_NAME}, {@link #KEY_ACCOUNT_TYPE} and {@link #KEY_AUTHTOKEN} if the
1310756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * request completes successfully.
1311756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * </ul>
1312756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     * If the user presses "back" then the request will be canceled.
1313756b735e9312ee52618158270f0bdd0ec691a712Fred Quintana     */
1314f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
13153326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String accountType, final String authTokenType, final String[] features,
13163326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final Activity activityForPrompting, final Bundle addAccountOptions,
131731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            final Bundle getAuthTokenOptions,
1318ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final AccountManagerCallback<Bundle> callback, final Handler handler) {
13193326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        if (accountType == null) throw new IllegalArgumentException("account type is null");
13203326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
1321f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        final GetAuthTokenByTypeAndFeaturesTask task =
1322f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features,
132331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                activityForPrompting, addAccountOptions, getAuthTokenOptions, callback, handler);
1324f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        task.start();
1325f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        return task;
1326603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1327d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1328f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    private final HashMap<OnAccountsUpdateListener, Handler> mAccountsUpdatedListeners =
1329d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            Maps.newHashMap();
1330d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1331d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    /**
1332d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * BroadcastReceiver that listens for the LOGIN_ACCOUNTS_CHANGED_ACTION intent
1333d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * so that it can read the updated list of accounts and send them to the listener
1334d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * in mAccountsUpdatedListeners.
1335d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     */
1336d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    private final BroadcastReceiver mAccountsChangedBroadcastReceiver = new BroadcastReceiver() {
1337d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        public void onReceive(final Context context, final Intent intent) {
1338ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            final Account[] accounts = getAccounts();
1339ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            // send the result to the listeners
1340ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            synchronized (mAccountsUpdatedListeners) {
1341f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                for (Map.Entry<OnAccountsUpdateListener, Handler> entry :
1342ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        mAccountsUpdatedListeners.entrySet()) {
1343ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    postToHandler(entry.getValue(), entry.getKey(), accounts);
1344d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                }
1345ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
1346d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
1347d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    };
1348d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1349d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    /**
1350f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana     * Add a {@link OnAccountsUpdateListener} to this instance of the {@link AccountManager}.
1351d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * The listener is guaranteed to be invoked on the thread of the Handler that is passed
1352d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * in or the main thread's Handler if handler is null.
1353e00a31155b95686eecc6e1999e904472f8f300caFred Quintana     * <p>
1354e00a31155b95686eecc6e1999e904472f8f300caFred Quintana     * You must remove this listener before the context that was used to retrieve this
1355e00a31155b95686eecc6e1999e904472f8f300caFred Quintana     * {@link AccountManager} instance goes away. This generally means when the Activity
1356e00a31155b95686eecc6e1999e904472f8f300caFred Quintana     * or Service you are running is stopped.
1357d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @param listener the listener to add
1358d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @param handler the Handler whose thread will be used to invoke the listener. If null
1359d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * the AccountManager context's main thread will be used.
1360d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @param updateImmediately if true then the listener will be invoked as a result of this
1361d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * call.
1362d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @throws IllegalArgumentException if listener is null
1363d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @throws IllegalStateException if listener was already added
1364d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     */
1365f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
1366d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            Handler handler, boolean updateImmediately) {
1367d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        if (listener == null) {
1368d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            throw new IllegalArgumentException("the listener is null");
1369d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
1370d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        synchronized (mAccountsUpdatedListeners) {
1371d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            if (mAccountsUpdatedListeners.containsKey(listener)) {
1372d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                throw new IllegalStateException("this listener is already added");
1373d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            }
1374d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            final boolean wasEmpty = mAccountsUpdatedListeners.isEmpty();
1375d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1376d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            mAccountsUpdatedListeners.put(listener, handler);
1377d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1378d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            if (wasEmpty) {
1379d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                // Register a broadcast receiver to monitor account changes
1380d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                IntentFilter intentFilter = new IntentFilter();
1381f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
1382b6437245c280596d0a580b8d67189739cf793250Costin Manolache                // To recover from disk-full.
1383c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
1384d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
1385d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            }
1386d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
1387d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1388d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        if (updateImmediately) {
1389ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            postToHandler(handler, listener, getAccounts());
1390d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
1391d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    }
1392d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
1393d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    /**
1394f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana     * Remove an {@link OnAccountsUpdateListener} that was previously registered with
1395d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * {@link #addOnAccountsUpdatedListener}.
1396d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @param listener the listener to remove
1397d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @throws IllegalArgumentException if listener is null
1398d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     * @throws IllegalStateException if listener was not already added
1399d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana     */
1400f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana    public void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) {
1401d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        if (listener == null) {
140288a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            Log.e(TAG, "Missing listener");
140388a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache            return;
1404d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
1405d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        synchronized (mAccountsUpdatedListeners) {
14065be61f5b3ad61706b72c1f6b00914ab042dc6bedBryan Mawhinney            if (!mAccountsUpdatedListeners.containsKey(listener)) {
140788a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                Log.e(TAG, "Listener was not previously added");
140888a211b148dd94df1f178338c94fdd7d01f53863Costin Manolache                return;
1409d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            }
14105be61f5b3ad61706b72c1f6b00914ab042dc6bedBryan Mawhinney            mAccountsUpdatedListeners.remove(listener);
1411d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            if (mAccountsUpdatedListeners.isEmpty()) {
1412d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                mContext.unregisterReceiver(mAccountsChangedBroadcastReceiver);
1413d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana            }
1414d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
1415d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    }
1416603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
1417