blob: 79d1361192e35474e2f7889a1d5c406cfd08daa3 [file] [log] [blame]
Fred Quintana60307342009-03-24 22:48:12 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.accounts;
18
Fred Quintanad4a1d2e2009-07-16 16:36:38 -070019import android.Manifest;
Sandra Kwan390c9d22016-01-12 14:13:37 -080020import android.content.Context;
21import android.content.Intent;
22import android.content.pm.PackageManager;
23import android.os.Binder;
24import android.os.Bundle;
25import android.os.IBinder;
26import android.os.RemoteException;
27import android.text.TextUtils;
Fred Quintanaf0fd8432010-03-08 12:48:05 -080028import android.util.Log;
29
30import java.util.Arrays;
Fred Quintana60307342009-03-24 22:48:12 -070031
32/**
Fred Quintana756b7352009-10-21 13:43:10 -070033 * Abstract base class for creating AccountAuthenticators.
koprivab0cbd162018-10-02 12:46:55 -070034 * In order to be an authenticator one must extend this class, provide implementations for the
35 * abstract methods, and write a service that returns the result of {@link #getIBinder()}
Fred Quintana756b7352009-10-21 13:43:10 -070036 * in the service's {@link android.app.Service#onBind(android.content.Intent)} when invoked
37 * with an intent with action {@link AccountManager#ACTION_AUTHENTICATOR_INTENT}. This service
38 * must specify the following intent filter and metadata tags in its AndroidManifest.xml file
39 * <pre>
40 * &lt;intent-filter&gt;
41 * &lt;action android:name="android.accounts.AccountAuthenticator" /&gt;
42 * &lt;/intent-filter&gt;
43 * &lt;meta-data android:name="android.accounts.AccountAuthenticator"
44 * android:resource="@xml/authenticator" /&gt;
45 * </pre>
46 * The <code>android:resource</code> attribute must point to a resource that looks like:
47 * <pre>
48 * &lt;account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
49 * android:accountType="typeOfAuthenticator"
50 * android:icon="@drawable/icon"
51 * android:smallIcon="@drawable/miniIcon"
52 * android:label="@string/label"
53 * android:accountPreferences="@xml/account_preferences"
54 * /&gt;
55 * </pre>
56 * Replace the icons and labels with your own resources. The <code>android:accountType</code>
57 * attribute must be a string that uniquely identifies your authenticator and will be the same
58 * string that user will use when making calls on the {@link AccountManager} and it also
59 * corresponds to {@link Account#type} for your accounts. One user of the android:icon is the
60 * "Account & Sync" settings page and one user of the android:smallIcon is the Contact Application's
61 * tab panels.
62 * <p>
Ken Wakasaf76a50c2012-03-09 19:56:35 +090063 * The preferences attribute points to a PreferenceScreen xml hierarchy that contains
Fred Quintana756b7352009-10-21 13:43:10 -070064 * a list of PreferenceScreens that can be invoked to manage the authenticator. An example is:
65 * <pre>
66 * &lt;PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"&gt;
67 * &lt;PreferenceCategory android:title="@string/title_fmt" /&gt;
68 * &lt;PreferenceScreen
69 * android:key="key1"
70 * android:title="@string/key1_action"
71 * android:summary="@string/key1_summary"&gt;
72 * &lt;intent
73 * android:action="key1.ACTION"
74 * android:targetPackage="key1.package"
75 * android:targetClass="key1.class" /&gt;
76 * &lt;/PreferenceScreen&gt;
77 * &lt;/PreferenceScreen&gt;
78 * </pre>
79 *
80 * <p>
81 * The standard pattern for implementing any of the abstract methods is the following:
82 * <ul>
83 * <li> If the supplied arguments are enough for the authenticator to fully satisfy the request
84 * then it will do so and return a {@link Bundle} that contains the results.
85 * <li> If the authenticator needs information from the user to satisfy the request then it
86 * will create an {@link Intent} to an activity that will prompt the user for the information
87 * and then carry out the request. This intent must be returned in a Bundle as key
88 * {@link AccountManager#KEY_INTENT}.
89 * <p>
90 * The activity needs to return the final result when it is complete so the Intent should contain
91 * the {@link AccountAuthenticatorResponse} as {@link AccountManager#KEY_ACCOUNT_MANAGER_RESPONSE}.
92 * The activity must then call {@link AccountAuthenticatorResponse#onResult} or
93 * {@link AccountAuthenticatorResponse#onError} when it is complete.
Fred Quintana31957f12009-10-21 13:43:10 -070094 * <li> If the authenticator cannot synchronously process the request and return a result then it
Ed Heyld6f158b2009-10-29 10:18:45 -070095 * may choose to return null and then use the AccountManagerResponse to send the result
Fred Quintana31957f12009-10-21 13:43:10 -070096 * when it has completed the request.
Fred Quintana756b7352009-10-21 13:43:10 -070097 * </ul>
98 * <p>
99 * The following descriptions of each of the abstract authenticator methods will not describe the
100 * possible asynchronous nature of the request handling and will instead just describe the input
101 * parameters and the expected result.
102 * <p>
103 * When writing an activity to satisfy these requests one must pass in the AccountManagerResponse
104 * and return the result via that response when the activity finishes (or whenever else the
105 * activity author deems it is the correct time to respond).
106 * The {@link AccountAuthenticatorActivity} handles this, so one may wish to extend that when
107 * writing activities to handle these requests.
Fred Quintana60307342009-03-24 22:48:12 -0700108 */
109public abstract class AbstractAccountAuthenticator {
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800110 private static final String TAG = "AccountAuthenticator";
111
Carlos Valdivia91979be2015-05-22 14:11:35 -0700112 /**
113 * Bundle key used for the {@code long} expiration time (in millis from the unix epoch) of the
114 * associated auth token.
115 *
116 * @see #getAuthToken
117 */
118 public static final String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
119
Sandra Kwan78812282015-11-04 11:19:47 -0800120 /**
121 * Bundle key used for the {@link String} account type in session bundle.
122 * This is used in the default implementation of
Sandra Kwane68c37e2015-11-12 17:11:49 -0800123 * {@link #startAddAccountSession} and {@link startUpdateCredentialsSession}.
Sandra Kwan78812282015-11-04 11:19:47 -0800124 */
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800125 private static final String KEY_AUTH_TOKEN_TYPE =
126 "android.accounts.AbstractAccountAuthenticato.KEY_AUTH_TOKEN_TYPE";
Sandra Kwan78812282015-11-04 11:19:47 -0800127 /**
128 * Bundle key used for the {@link String} array of required features in
129 * session bundle. This is used in the default implementation of
Sandra Kwane68c37e2015-11-12 17:11:49 -0800130 * {@link #startAddAccountSession} and {@link startUpdateCredentialsSession}.
Sandra Kwan78812282015-11-04 11:19:47 -0800131 */
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800132 private static final String KEY_REQUIRED_FEATURES =
133 "android.accounts.AbstractAccountAuthenticator.KEY_REQUIRED_FEATURES";
Sandra Kwan78812282015-11-04 11:19:47 -0800134 /**
135 * Bundle key used for the {@link Bundle} options in session bundle. This is
Sandra Kwane68c37e2015-11-12 17:11:49 -0800136 * used in default implementation of {@link #startAddAccountSession} and
137 * {@link startUpdateCredentialsSession}.
Sandra Kwan78812282015-11-04 11:19:47 -0800138 */
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800139 private static final String KEY_OPTIONS =
140 "android.accounts.AbstractAccountAuthenticator.KEY_OPTIONS";
Sandra Kwane68c37e2015-11-12 17:11:49 -0800141 /**
142 * Bundle key used for the {@link Account} account in session bundle. This is used
143 * used in default implementation of {@link startUpdateCredentialsSession}.
144 */
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800145 private static final String KEY_ACCOUNT =
146 "android.accounts.AbstractAccountAuthenticator.KEY_ACCOUNT";
Sandra Kwan78812282015-11-04 11:19:47 -0800147
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700148 private final Context mContext;
149
150 public AbstractAccountAuthenticator(Context context) {
151 mContext = context;
152 }
153
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700154 private class Transport extends IAccountAuthenticator.Stub {
Carlos Valdivia91979be2015-05-22 14:11:35 -0700155 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -0700156 public void addAccount(IAccountAuthenticatorResponse response, String accountType,
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800157 String authTokenType, String[] features, Bundle options)
Fred Quintana60307342009-03-24 22:48:12 -0700158 throws RemoteException {
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800159 if (Log.isLoggable(TAG, Log.VERBOSE)) {
160 Log.v(TAG, "addAccount: accountType " + accountType
161 + ", authTokenType " + authTokenType
162 + ", features " + (features == null ? "[]" : Arrays.toString(features)));
163 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700164 checkBinderPermission();
Fred Quintanaa698f422009-04-08 19:14:54 -0700165 try {
Fred Quintana31957f12009-10-21 13:43:10 -0700166 final Bundle result = AbstractAccountAuthenticator.this.addAccount(
Fred Quintanaa698f422009-04-08 19:14:54 -0700167 new AccountAuthenticatorResponse(response),
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800168 accountType, authTokenType, features, options);
169 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000170 if (result != null) {
171 result.keySet(); // force it to be unparcelled
172 }
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800173 Log.v(TAG, "addAccount: result " + AccountManager.sanitizeResult(result));
174 }
Fred Quintana31957f12009-10-21 13:43:10 -0700175 if (result != null) {
176 response.onResult(result);
tiansimingf58793c2017-09-03 16:48:34 +0800177 } else {
178 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
179 "null bundle returned");
Fred Quintana31957f12009-10-21 13:43:10 -0700180 }
Fred Quintana5d1a0c32011-06-23 16:37:58 -0700181 } catch (Exception e) {
182 handleException(response, "addAccount", accountType, e);
Fred Quintanaa698f422009-04-08 19:14:54 -0700183 }
Fred Quintana60307342009-03-24 22:48:12 -0700184 }
185
Carlos Valdivia91979be2015-05-22 14:11:35 -0700186 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -0700187 public void confirmCredentials(IAccountAuthenticatorResponse response,
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700188 Account account, Bundle options) throws RemoteException {
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800189 if (Log.isLoggable(TAG, Log.VERBOSE)) {
190 Log.v(TAG, "confirmCredentials: " + account);
191 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700192 checkBinderPermission();
Fred Quintanaa698f422009-04-08 19:14:54 -0700193 try {
Fred Quintana31957f12009-10-21 13:43:10 -0700194 final Bundle result = AbstractAccountAuthenticator.this.confirmCredentials(
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700195 new AccountAuthenticatorResponse(response), account, options);
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800196 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000197 if (result != null) {
198 result.keySet(); // force it to be unparcelled
199 }
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800200 Log.v(TAG, "confirmCredentials: result "
201 + AccountManager.sanitizeResult(result));
202 }
Fred Quintana31957f12009-10-21 13:43:10 -0700203 if (result != null) {
204 response.onResult(result);
205 }
Fred Quintana5d1a0c32011-06-23 16:37:58 -0700206 } catch (Exception e) {
207 handleException(response, "confirmCredentials", account.toString(), e);
Fred Quintanaa698f422009-04-08 19:14:54 -0700208 }
Fred Quintana60307342009-03-24 22:48:12 -0700209 }
210
Carlos Valdivia91979be2015-05-22 14:11:35 -0700211 @Override
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700212 public void getAuthTokenLabel(IAccountAuthenticatorResponse response,
213 String authTokenType)
214 throws RemoteException {
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800215 if (Log.isLoggable(TAG, Log.VERBOSE)) {
216 Log.v(TAG, "getAuthTokenLabel: authTokenType " + authTokenType);
217 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700218 checkBinderPermission();
219 try {
220 Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700221 result.putString(AccountManager.KEY_AUTH_TOKEN_LABEL,
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700222 AbstractAccountAuthenticator.this.getAuthTokenLabel(authTokenType));
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800223 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000224 if (result != null) {
225 result.keySet(); // force it to be unparcelled
226 }
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800227 Log.v(TAG, "getAuthTokenLabel: result "
228 + AccountManager.sanitizeResult(result));
229 }
Fred Quintana5d1a0c32011-06-23 16:37:58 -0700230 response.onResult(result);
231 } catch (Exception e) {
232 handleException(response, "getAuthTokenLabel", authTokenType, e);
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700233 }
234 }
235
Carlos Valdivia91979be2015-05-22 14:11:35 -0700236 @Override
Fred Quintana60307342009-03-24 22:48:12 -0700237 public void getAuthToken(IAccountAuthenticatorResponse response,
Fred Quintanaa698f422009-04-08 19:14:54 -0700238 Account account, String authTokenType, Bundle loginOptions)
Fred Quintana60307342009-03-24 22:48:12 -0700239 throws RemoteException {
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800240 if (Log.isLoggable(TAG, Log.VERBOSE)) {
241 Log.v(TAG, "getAuthToken: " + account
242 + ", authTokenType " + authTokenType);
243 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700244 checkBinderPermission();
Fred Quintanaa698f422009-04-08 19:14:54 -0700245 try {
246 final Bundle result = AbstractAccountAuthenticator.this.getAuthToken(
247 new AccountAuthenticatorResponse(response), account,
248 authTokenType, loginOptions);
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800249 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000250 if (result != null) {
251 result.keySet(); // force it to be unparcelled
252 }
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800253 Log.v(TAG, "getAuthToken: result " + AccountManager.sanitizeResult(result));
254 }
Fred Quintanaa698f422009-04-08 19:14:54 -0700255 if (result != null) {
256 response.onResult(result);
257 }
Fred Quintana5d1a0c32011-06-23 16:37:58 -0700258 } catch (Exception e) {
259 handleException(response, "getAuthToken",
260 account.toString() + "," + authTokenType, e);
Fred Quintanaa698f422009-04-08 19:14:54 -0700261 }
Fred Quintana60307342009-03-24 22:48:12 -0700262 }
263
Carlos Valdivia91979be2015-05-22 14:11:35 -0700264 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -0700265 public void updateCredentials(IAccountAuthenticatorResponse response, Account account,
266 String authTokenType, Bundle loginOptions) throws RemoteException {
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800267 if (Log.isLoggable(TAG, Log.VERBOSE)) {
268 Log.v(TAG, "updateCredentials: " + account
269 + ", authTokenType " + authTokenType);
270 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700271 checkBinderPermission();
Fred Quintanaa698f422009-04-08 19:14:54 -0700272 try {
Fred Quintana31957f12009-10-21 13:43:10 -0700273 final Bundle result = AbstractAccountAuthenticator.this.updateCredentials(
Fred Quintanaa698f422009-04-08 19:14:54 -0700274 new AccountAuthenticatorResponse(response), account,
275 authTokenType, loginOptions);
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800276 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000277 // Result may be null.
278 if (result != null) {
279 result.keySet(); // force it to be unparcelled
280 }
Fred Quintanaf0fd8432010-03-08 12:48:05 -0800281 Log.v(TAG, "updateCredentials: result "
282 + AccountManager.sanitizeResult(result));
283 }
Fred Quintana31957f12009-10-21 13:43:10 -0700284 if (result != null) {
285 response.onResult(result);
286 }
Fred Quintana5d1a0c32011-06-23 16:37:58 -0700287 } catch (Exception e) {
288 handleException(response, "updateCredentials",
289 account.toString() + "," + authTokenType, e);
Fred Quintanaa698f422009-04-08 19:14:54 -0700290 }
Fred Quintana60307342009-03-24 22:48:12 -0700291 }
292
Carlos Valdivia91979be2015-05-22 14:11:35 -0700293 @Override
Fred Quintanaa698f422009-04-08 19:14:54 -0700294 public void editProperties(IAccountAuthenticatorResponse response,
295 String accountType) throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700296 checkBinderPermission();
Fred Quintanaa698f422009-04-08 19:14:54 -0700297 try {
Fred Quintana31957f12009-10-21 13:43:10 -0700298 final Bundle result = AbstractAccountAuthenticator.this.editProperties(
Fred Quintana60307342009-03-24 22:48:12 -0700299 new AccountAuthenticatorResponse(response), accountType);
Fred Quintana31957f12009-10-21 13:43:10 -0700300 if (result != null) {
301 response.onResult(result);
302 }
Fred Quintana5d1a0c32011-06-23 16:37:58 -0700303 } catch (Exception e) {
304 handleException(response, "editProperties", accountType, e);
Fred Quintanaa698f422009-04-08 19:14:54 -0700305 }
Fred Quintana60307342009-03-24 22:48:12 -0700306 }
Fred Quintana33269202009-04-20 16:05:10 -0700307
Carlos Valdivia91979be2015-05-22 14:11:35 -0700308 @Override
Fred Quintana33269202009-04-20 16:05:10 -0700309 public void hasFeatures(IAccountAuthenticatorResponse response,
310 Account account, String[] features) throws RemoteException {
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700311 checkBinderPermission();
Fred Quintana33269202009-04-20 16:05:10 -0700312 try {
Fred Quintana31957f12009-10-21 13:43:10 -0700313 final Bundle result = AbstractAccountAuthenticator.this.hasFeatures(
Fred Quintana33269202009-04-20 16:05:10 -0700314 new AccountAuthenticatorResponse(response), account, features);
Fred Quintana31957f12009-10-21 13:43:10 -0700315 if (result != null) {
316 response.onResult(result);
317 }
Fred Quintana5d1a0c32011-06-23 16:37:58 -0700318 } catch (Exception e) {
319 handleException(response, "hasFeatures", account.toString(), e);
Fred Quintana33269202009-04-20 16:05:10 -0700320 }
321 }
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700322
Carlos Valdivia91979be2015-05-22 14:11:35 -0700323 @Override
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700324 public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response,
325 Account account) throws RemoteException {
326 checkBinderPermission();
327 try {
328 final Bundle result = AbstractAccountAuthenticator.this.getAccountRemovalAllowed(
329 new AccountAuthenticatorResponse(response), account);
330 if (result != null) {
331 response.onResult(result);
332 }
Fred Quintana5d1a0c32011-06-23 16:37:58 -0700333 } catch (Exception e) {
334 handleException(response, "getAccountRemovalAllowed", account.toString(), e);
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700335 }
336 }
Amith Yamasani67df64b2012-12-14 12:09:36 -0800337
Carlos Valdivia91979be2015-05-22 14:11:35 -0700338 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -0800339 public void getAccountCredentialsForCloning(IAccountAuthenticatorResponse response,
340 Account account) throws RemoteException {
341 checkBinderPermission();
342 try {
343 final Bundle result =
344 AbstractAccountAuthenticator.this.getAccountCredentialsForCloning(
345 new AccountAuthenticatorResponse(response), account);
346 if (result != null) {
347 response.onResult(result);
348 }
349 } catch (Exception e) {
350 handleException(response, "getAccountCredentialsForCloning", account.toString(), e);
351 }
352 }
353
Carlos Valdivia91979be2015-05-22 14:11:35 -0700354 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -0800355 public void addAccountFromCredentials(IAccountAuthenticatorResponse response,
356 Account account,
357 Bundle accountCredentials) throws RemoteException {
358 checkBinderPermission();
359 try {
360 final Bundle result =
361 AbstractAccountAuthenticator.this.addAccountFromCredentials(
362 new AccountAuthenticatorResponse(response), account,
363 accountCredentials);
364 if (result != null) {
365 response.onResult(result);
366 }
367 } catch (Exception e) {
368 handleException(response, "addAccountFromCredentials", account.toString(), e);
369 }
370 }
Sandra Kwan78812282015-11-04 11:19:47 -0800371
372 @Override
373 public void startAddAccountSession(IAccountAuthenticatorResponse response,
374 String accountType, String authTokenType, String[] features, Bundle options)
375 throws RemoteException {
376 if (Log.isLoggable(TAG, Log.VERBOSE)) {
377 Log.v(TAG,
378 "startAddAccountSession: accountType " + accountType
379 + ", authTokenType " + authTokenType
380 + ", features " + (features == null ? "[]" : Arrays.toString(features)));
381 }
382 checkBinderPermission();
383 try {
384 final Bundle result = AbstractAccountAuthenticator.this.startAddAccountSession(
385 new AccountAuthenticatorResponse(response), accountType, authTokenType,
386 features, options);
387 if (Log.isLoggable(TAG, Log.VERBOSE)) {
388 if (result != null) {
389 result.keySet(); // force it to be unparcelled
390 }
391 Log.v(TAG, "startAddAccountSession: result "
392 + AccountManager.sanitizeResult(result));
393 }
394 if (result != null) {
395 response.onResult(result);
396 }
397 } catch (Exception e) {
398 handleException(response, "startAddAccountSession", accountType, e);
399 }
400 }
Sandra Kwane68c37e2015-11-12 17:11:49 -0800401
402 @Override
403 public void startUpdateCredentialsSession(
404 IAccountAuthenticatorResponse response,
405 Account account,
406 String authTokenType,
407 Bundle loginOptions) throws RemoteException {
408 if (Log.isLoggable(TAG, Log.VERBOSE)) {
409 Log.v(TAG, "startUpdateCredentialsSession: "
410 + account
411 + ", authTokenType "
412 + authTokenType);
413 }
414 checkBinderPermission();
415 try {
416 final Bundle result = AbstractAccountAuthenticator.this
417 .startUpdateCredentialsSession(
418 new AccountAuthenticatorResponse(response),
419 account,
420 authTokenType,
421 loginOptions);
422 if (Log.isLoggable(TAG, Log.VERBOSE)) {
423 // Result may be null.
424 if (result != null) {
425 result.keySet(); // force it to be unparcelled
426 }
427 Log.v(TAG, "startUpdateCredentialsSession: result "
428 + AccountManager.sanitizeResult(result));
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800429
Sandra Kwane68c37e2015-11-12 17:11:49 -0800430 }
431 if (result != null) {
432 response.onResult(result);
433 }
434 } catch (Exception e) {
435 handleException(response, "startUpdateCredentialsSession",
436 account.toString() + "," + authTokenType, e);
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800437
438 }
439 }
440
Sandra Kwan390c9d22016-01-12 14:13:37 -0800441 @Override
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800442 public void finishSession(
443 IAccountAuthenticatorResponse response,
444 String accountType,
445 Bundle sessionBundle) throws RemoteException {
446 if (Log.isLoggable(TAG, Log.VERBOSE)) {
447 Log.v(TAG, "finishSession: accountType " + accountType);
448 }
449 checkBinderPermission();
450 try {
451 final Bundle result = AbstractAccountAuthenticator.this.finishSession(
452 new AccountAuthenticatorResponse(response), accountType, sessionBundle);
453 if (result != null) {
454 result.keySet(); // force it to be unparcelled
455 }
456 if (Log.isLoggable(TAG, Log.VERBOSE)) {
457 Log.v(TAG, "finishSession: result " + AccountManager.sanitizeResult(result));
458 }
459 if (result != null) {
460 response.onResult(result);
461 }
462 } catch (Exception e) {
463 handleException(response, "finishSession", accountType, e);
464
Sandra Kwane68c37e2015-11-12 17:11:49 -0800465 }
466 }
Sandra Kwan390c9d22016-01-12 14:13:37 -0800467
468 @Override
469 public void isCredentialsUpdateSuggested(
470 IAccountAuthenticatorResponse response,
471 Account account,
472 String statusToken) throws RemoteException {
473 checkBinderPermission();
474 try {
475 final Bundle result = AbstractAccountAuthenticator.this
476 .isCredentialsUpdateSuggested(
477 new AccountAuthenticatorResponse(response), account, statusToken);
478 if (result != null) {
479 response.onResult(result);
480 }
481 } catch (Exception e) {
482 handleException(response, "isCredentialsUpdateSuggested", account.toString(), e);
483 }
484 }
Fred Quintana60307342009-03-24 22:48:12 -0700485 }
486
Fred Quintana5d1a0c32011-06-23 16:37:58 -0700487 private void handleException(IAccountAuthenticatorResponse response, String method,
488 String data, Exception e) throws RemoteException {
489 if (e instanceof NetworkErrorException) {
490 if (Log.isLoggable(TAG, Log.VERBOSE)) {
491 Log.v(TAG, method + "(" + data + ")", e);
492 }
493 response.onError(AccountManager.ERROR_CODE_NETWORK_ERROR, e.getMessage());
494 } else if (e instanceof UnsupportedOperationException) {
495 if (Log.isLoggable(TAG, Log.VERBOSE)) {
496 Log.v(TAG, method + "(" + data + ")", e);
497 }
498 response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
499 method + " not supported");
500 } else if (e instanceof IllegalArgumentException) {
501 if (Log.isLoggable(TAG, Log.VERBOSE)) {
502 Log.v(TAG, method + "(" + data + ")", e);
503 }
504 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS,
505 method + " not supported");
506 } else {
507 Log.w(TAG, method + "(" + data + ")", e);
508 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
509 method + " failed");
510 }
511 }
512
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700513 private void checkBinderPermission() {
514 final int uid = Binder.getCallingUid();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700515 final String perm = Manifest.permission.ACCOUNT_MANAGER;
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700516 if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
517 throw new SecurityException("caller uid " + uid + " lacks " + perm);
518 }
519 }
520
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700521 private Transport mTransport = new Transport();
Fred Quintana60307342009-03-24 22:48:12 -0700522
523 /**
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700524 * @return the IBinder for the AccountAuthenticator
Fred Quintana60307342009-03-24 22:48:12 -0700525 */
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700526 public final IBinder getIBinder() {
527 return mTransport.asBinder();
Fred Quintana60307342009-03-24 22:48:12 -0700528 }
529
530 /**
Fred Quintanaa698f422009-04-08 19:14:54 -0700531 * Returns a Bundle that contains the Intent of the activity that can be used to edit the
532 * properties. In order to indicate success the activity should call response.setResult()
533 * with a non-null Bundle.
534 * @param response used to set the result for the request. If the Constants.INTENT_KEY
535 * is set in the bundle then this response field is to be used for sending future
536 * results if and when the Intent is started.
537 * @param accountType the AccountType whose properties are to be edited.
538 * @return a Bundle containing the result or the Intent to start to continue the request.
539 * If this is null then the request is considered to still be active and the result should
540 * sent later using response.
Fred Quintana60307342009-03-24 22:48:12 -0700541 */
Fred Quintanaa698f422009-04-08 19:14:54 -0700542 public abstract Bundle editProperties(AccountAuthenticatorResponse response,
543 String accountType);
Fred Quintana756b7352009-10-21 13:43:10 -0700544
545 /**
546 * Adds an account of the specified accountType.
547 * @param response to send the result back to the AccountManager, will never be null
548 * @param accountType the type of account to add, will never be null
549 * @param authTokenType the type of auth token to retrieve after adding the account, may be null
550 * @param requiredFeatures a String array of authenticator-specific features that the added
551 * account must support, may be null
sunjian87d0c3c2017-07-14 11:54:46 -0700552 * @param options a Bundle of authenticator-specific options. It always contains
553 * {@link AccountManager#KEY_CALLER_PID} and {@link AccountManager#KEY_CALLER_UID}
554 * fields which will let authenticator know the identity of the caller.
Fred Quintana756b7352009-10-21 13:43:10 -0700555 * @return a Bundle result or null if the result is to be returned via the response. The result
556 * will contain either:
557 * <ul>
558 * <li> {@link AccountManager#KEY_INTENT}, or
559 * <li> {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of
Fred Quintana8570f742010-02-18 10:32:54 -0800560 * the account that was added, or
Fred Quintana756b7352009-10-21 13:43:10 -0700561 * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
562 * indicate an error
563 * </ul>
564 * @throws NetworkErrorException if the authenticator could not honor the request due to a
565 * network error
566 */
Fred Quintanaa698f422009-04-08 19:14:54 -0700567 public abstract Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
Fred Quintana33269202009-04-20 16:05:10 -0700568 String authTokenType, String[] requiredFeatures, Bundle options)
569 throws NetworkErrorException;
Fred Quintana756b7352009-10-21 13:43:10 -0700570
571 /**
572 * Checks that the user knows the credentials of an account.
573 * @param response to send the result back to the AccountManager, will never be null
574 * @param account the account whose credentials are to be checked, will never be null
575 * @param options a Bundle of authenticator-specific options, may be null
576 * @return a Bundle result or null if the result is to be returned via the response. The result
577 * will contain either:
578 * <ul>
579 * <li> {@link AccountManager#KEY_INTENT}, or
580 * <li> {@link AccountManager#KEY_BOOLEAN_RESULT}, true if the check succeeded, false otherwise
581 * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
582 * indicate an error
583 * </ul>
Fred Quintana31957f12009-10-21 13:43:10 -0700584 * @throws NetworkErrorException if the authenticator could not honor the request due to a
585 * network error
Fred Quintana756b7352009-10-21 13:43:10 -0700586 */
Fred Quintanaa698f422009-04-08 19:14:54 -0700587 public abstract Bundle confirmCredentials(AccountAuthenticatorResponse response,
Fred Quintana31957f12009-10-21 13:43:10 -0700588 Account account, Bundle options)
589 throws NetworkErrorException;
Carlos Valdivia91979be2015-05-22 14:11:35 -0700590
Fred Quintana756b7352009-10-21 13:43:10 -0700591 /**
Carlos Valdivia91979be2015-05-22 14:11:35 -0700592 * Gets an authtoken for an account.
593 *
594 * If not {@code null}, the resultant {@link Bundle} will contain different sets of keys
595 * depending on whether a token was successfully issued and, if not, whether one
596 * could be issued via some {@link android.app.Activity}.
597 * <p>
598 * If a token cannot be provided without some additional activity, the Bundle should contain
599 * {@link AccountManager#KEY_INTENT} with an associated {@link Intent}. On the other hand, if
600 * there is no such activity, then a Bundle containing
601 * {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} should be
602 * returned.
603 * <p>
604 * If a token can be successfully issued, the implementation should return the
605 * {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of the
606 * account associated with the token as well as the {@link AccountManager#KEY_AUTHTOKEN}. In
607 * addition {@link AbstractAccountAuthenticator} implementations that declare themselves
608 * {@code android:customTokens=true} may also provide a non-negative {@link
609 * #KEY_CUSTOM_TOKEN_EXPIRY} long value containing the expiration timestamp of the expiration
sunjian87d0c3c2017-07-14 11:54:46 -0700610 * time (in millis since the unix epoch), tokens will be cached in memory based on
611 * application's packageName/signature for however long that was specified.
Carlos Valdivia91979be2015-05-22 14:11:35 -0700612 * <p>
613 * Implementers should assume that tokens will be cached on the basis of account and
614 * authTokenType. The system may ignore the contents of the supplied options Bundle when
615 * determining to re-use a cached token. Furthermore, implementers should assume a supplied
616 * expiration time will be treated as non-binding advice.
617 * <p>
sunjian87d0c3c2017-07-14 11:54:46 -0700618 * Finally, note that for {@code android:customTokens=false} authenticators, tokens are cached
Carlos Valdivia91979be2015-05-22 14:11:35 -0700619 * indefinitely until some client calls {@link
620 * AccountManager#invalidateAuthToken(String,String)}.
621 *
Fred Quintana756b7352009-10-21 13:43:10 -0700622 * @param response to send the result back to the AccountManager, will never be null
623 * @param account the account whose credentials are to be retrieved, will never be null
624 * @param authTokenType the type of auth token to retrieve, will never be null
sunjian87d0c3c2017-07-14 11:54:46 -0700625 * @param options a Bundle of authenticator-specific options. It always contains
626 * {@link AccountManager#KEY_CALLER_PID} and {@link AccountManager#KEY_CALLER_UID}
627 * fields which will let authenticator know the identity of the caller.
Carlos Valdivia91979be2015-05-22 14:11:35 -0700628 * @return a Bundle result or null if the result is to be returned via the response.
Fred Quintana756b7352009-10-21 13:43:10 -0700629 * @throws NetworkErrorException if the authenticator could not honor the request due to a
630 * network error
631 */
Fred Quintanaa698f422009-04-08 19:14:54 -0700632 public abstract Bundle getAuthToken(AccountAuthenticatorResponse response,
Fred Quintana31957f12009-10-21 13:43:10 -0700633 Account account, String authTokenType, Bundle options)
Fred Quintanaa698f422009-04-08 19:14:54 -0700634 throws NetworkErrorException;
Fred Quintana756b7352009-10-21 13:43:10 -0700635
636 /**
637 * Ask the authenticator for a localized label for the given authTokenType.
638 * @param authTokenType the authTokenType whose label is to be returned, will never be null
639 * @return the localized label of the auth token type, may be null if the type isn't known
640 */
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700641 public abstract String getAuthTokenLabel(String authTokenType);
Fred Quintana756b7352009-10-21 13:43:10 -0700642
643 /**
644 * Update the locally stored credentials for an account.
645 * @param response to send the result back to the AccountManager, will never be null
646 * @param account the account whose credentials are to be updated, will never be null
647 * @param authTokenType the type of auth token to retrieve after updating the credentials,
648 * may be null
Fred Quintana31957f12009-10-21 13:43:10 -0700649 * @param options a Bundle of authenticator-specific options, may be null
Fred Quintana756b7352009-10-21 13:43:10 -0700650 * @return a Bundle result or null if the result is to be returned via the response. The result
651 * will contain either:
652 * <ul>
653 * <li> {@link AccountManager#KEY_INTENT}, or
654 * <li> {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of
Ian Pedowitz6cc066d2015-08-05 14:23:43 +0000655 * the account whose credentials were updated, or
Fred Quintana756b7352009-10-21 13:43:10 -0700656 * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
657 * indicate an error
658 * </ul>
Fred Quintana31957f12009-10-21 13:43:10 -0700659 * @throws NetworkErrorException if the authenticator could not honor the request due to a
660 * network error
Fred Quintana756b7352009-10-21 13:43:10 -0700661 */
Fred Quintanaa698f422009-04-08 19:14:54 -0700662 public abstract Bundle updateCredentials(AccountAuthenticatorResponse response,
Fred Quintana31957f12009-10-21 13:43:10 -0700663 Account account, String authTokenType, Bundle options) throws NetworkErrorException;
Fred Quintana8570f742010-02-18 10:32:54 -0800664
Fred Quintana756b7352009-10-21 13:43:10 -0700665 /**
666 * Checks if the account supports all the specified authenticator specific features.
667 * @param response to send the result back to the AccountManager, will never be null
668 * @param account the account to check, will never be null
669 * @param features an array of features to check, will never be null
670 * @return a Bundle result or null if the result is to be returned via the response. The result
671 * will contain either:
672 * <ul>
673 * <li> {@link AccountManager#KEY_INTENT}, or
674 * <li> {@link AccountManager#KEY_BOOLEAN_RESULT}, true if the account has all the features,
675 * false otherwise
676 * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
677 * indicate an error
678 * </ul>
679 * @throws NetworkErrorException if the authenticator could not honor the request due to a
680 * network error
681 */
Fred Quintana33269202009-04-20 16:05:10 -0700682 public abstract Bundle hasFeatures(AccountAuthenticatorResponse response,
683 Account account, String[] features) throws NetworkErrorException;
Fred Quintana756b7352009-10-21 13:43:10 -0700684
685 /**
686 * Checks if the removal of this account is allowed.
687 * @param response to send the result back to the AccountManager, will never be null
688 * @param account the account to check, will never be null
689 * @return a Bundle result or null if the result is to be returned via the response. The result
690 * will contain either:
691 * <ul>
692 * <li> {@link AccountManager#KEY_INTENT}, or
693 * <li> {@link AccountManager#KEY_BOOLEAN_RESULT}, true if the removal of the account is
694 * allowed, false otherwise
695 * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
696 * indicate an error
697 * </ul>
698 * @throws NetworkErrorException if the authenticator could not honor the request due to a
699 * network error
700 */
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700701 public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response,
702 Account account) throws NetworkErrorException {
703 final Bundle result = new Bundle();
Fred Quintanaf7ae77c2009-10-02 17:19:31 -0700704 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
Fred Quintanaffd0cb042009-08-15 21:45:26 -0700705 return result;
706 }
Amith Yamasani67df64b2012-12-14 12:09:36 -0800707
708 /**
Amith Yamasani67df64b2012-12-14 12:09:36 -0800709 * Returns a Bundle that contains whatever is required to clone the account on a different
710 * user. The Bundle is passed to the authenticator instance in the target user via
711 * {@link #addAccountFromCredentials(AccountAuthenticatorResponse, Account, Bundle)}.
712 * The default implementation returns null, indicating that cloning is not supported.
713 * @param response to send the result back to the AccountManager, will never be null
714 * @param account the account to clone, will never be null
715 * @return a Bundle result or null if the result is to be returned via the response.
716 * @throws NetworkErrorException
Elliot Waite54de7742017-01-11 15:30:35 -0800717 * @see #addAccountFromCredentials(AccountAuthenticatorResponse, Account, Bundle)
Amith Yamasani67df64b2012-12-14 12:09:36 -0800718 */
719 public Bundle getAccountCredentialsForCloning(final AccountAuthenticatorResponse response,
720 final Account account) throws NetworkErrorException {
721 new Thread(new Runnable() {
Carlos Valdivia91979be2015-05-22 14:11:35 -0700722 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -0800723 public void run() {
724 Bundle result = new Bundle();
725 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
726 response.onResult(result);
727 }
728 }).start();
729 return null;
730 }
731
732 /**
Amith Yamasani67df64b2012-12-14 12:09:36 -0800733 * Creates an account based on credentials provided by the authenticator instance of another
734 * user on the device, who has chosen to share the account with this user.
735 * @param response to send the result back to the AccountManager, will never be null
736 * @param account the account to clone, will never be null
737 * @param accountCredentials the Bundle containing the required credentials to create the
738 * account. Contents of the Bundle are only meaningful to the authenticator. This Bundle is
739 * provided by {@link #getAccountCredentialsForCloning(AccountAuthenticatorResponse, Account)}.
740 * @return a Bundle result or null if the result is to be returned via the response.
741 * @throws NetworkErrorException
Elliot Waite54de7742017-01-11 15:30:35 -0800742 * @see #getAccountCredentialsForCloning(AccountAuthenticatorResponse, Account)
Amith Yamasani67df64b2012-12-14 12:09:36 -0800743 */
744 public Bundle addAccountFromCredentials(final AccountAuthenticatorResponse response,
745 Account account,
746 Bundle accountCredentials) throws NetworkErrorException {
747 new Thread(new Runnable() {
Carlos Valdivia91979be2015-05-22 14:11:35 -0700748 @Override
Amith Yamasani67df64b2012-12-14 12:09:36 -0800749 public void run() {
750 Bundle result = new Bundle();
751 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
752 response.onResult(result);
753 }
754 }).start();
755 return null;
756 }
Sandra Kwan78812282015-11-04 11:19:47 -0800757
758 /**
759 * Starts the add account session to authenticate user to an account of the
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800760 * specified accountType. No file I/O should be performed in this call.
761 * Account should be added to device only when {@link #finishSession} is
762 * called after this.
763 * <p>
764 * Note: when overriding this method, {@link #finishSession} should be
765 * overridden too.
766 * </p>
Sandra Kwan78812282015-11-04 11:19:47 -0800767 *
768 * @param response to send the result back to the AccountManager, will never
769 * be null
770 * @param accountType the type of account to authenticate with, will never
771 * be null
772 * @param authTokenType the type of auth token to retrieve after
773 * authenticating with the account, may be null
774 * @param requiredFeatures a String array of authenticator-specific features
775 * that the account authenticated with must support, may be null
776 * @param options a Bundle of authenticator-specific options, may be null
777 * @return a Bundle result or null if the result is to be returned via the
778 * response. The result will contain either:
779 * <ul>
780 * <li>{@link AccountManager#KEY_INTENT}, or
781 * <li>{@link AccountManager#KEY_ACCOUNT_SESSION_BUNDLE} for adding
782 * the account to device later, and if account is authenticated,
783 * optional {@link AccountManager#KEY_PASSWORD} and
784 * {@link AccountManager#KEY_ACCOUNT_STATUS_TOKEN} for checking the
785 * status of the account, or
786 * <li>{@link AccountManager#KEY_ERROR_CODE} and
787 * {@link AccountManager#KEY_ERROR_MESSAGE} to indicate an error
788 * </ul>
789 * @throws NetworkErrorException if the authenticator could not honor the
790 * request due to a network error
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800791 * @see #finishSession(AccountAuthenticatorResponse, String, Bundle)
Sandra Kwan78812282015-11-04 11:19:47 -0800792 */
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800793 public Bundle startAddAccountSession(
794 final AccountAuthenticatorResponse response,
795 final String accountType,
796 final String authTokenType,
797 final String[] requiredFeatures,
Sandra Kwan78812282015-11-04 11:19:47 -0800798 final Bundle options)
799 throws NetworkErrorException {
800 new Thread(new Runnable() {
801 @Override
802 public void run() {
803 Bundle sessionBundle = new Bundle();
804 sessionBundle.putString(KEY_AUTH_TOKEN_TYPE, authTokenType);
805 sessionBundle.putStringArray(KEY_REQUIRED_FEATURES, requiredFeatures);
806 sessionBundle.putBundle(KEY_OPTIONS, options);
807 Bundle result = new Bundle();
808 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
809 response.onResult(result);
810 }
811
812 }).start();
813 return null;
814 }
Sandra Kwane68c37e2015-11-12 17:11:49 -0800815
816 /**
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800817 * Asks user to re-authenticate for an account but defers updating the
818 * locally stored credentials. No file I/O should be performed in this call.
819 * Local credentials should be updated only when {@link #finishSession} is
820 * called after this.
821 * <p>
822 * Note: when overriding this method, {@link #finishSession} should be
823 * overridden too.
824 * </p>
Sandra Kwane68c37e2015-11-12 17:11:49 -0800825 *
826 * @param response to send the result back to the AccountManager, will never
827 * be null
828 * @param account the account whose credentials are to be updated, will
829 * never be null
830 * @param authTokenType the type of auth token to retrieve after updating
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800831 * the credentials, may be null
Sandra Kwane68c37e2015-11-12 17:11:49 -0800832 * @param options a Bundle of authenticator-specific options, may be null
833 * @return a Bundle result or null if the result is to be returned via the
834 * response. The result will contain either:
835 * <ul>
836 * <li>{@link AccountManager#KEY_INTENT}, or
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800837 * <li>{@link AccountManager#KEY_ACCOUNT_SESSION_BUNDLE} for
838 * updating the locally stored credentials later, and if account is
839 * re-authenticated, optional {@link AccountManager#KEY_PASSWORD}
840 * and {@link AccountManager#KEY_ACCOUNT_STATUS_TOKEN} for checking
841 * the status of the account later, or
Sandra Kwane68c37e2015-11-12 17:11:49 -0800842 * <li>{@link AccountManager#KEY_ERROR_CODE} and
843 * {@link AccountManager#KEY_ERROR_MESSAGE} to indicate an error
844 * </ul>
845 * @throws NetworkErrorException if the authenticator could not honor the
846 * request due to a network error
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800847 * @see #finishSession(AccountAuthenticatorResponse, String, Bundle)
Sandra Kwane68c37e2015-11-12 17:11:49 -0800848 */
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800849 public Bundle startUpdateCredentialsSession(
850 final AccountAuthenticatorResponse response,
851 final Account account,
852 final String authTokenType,
853 final Bundle options) throws NetworkErrorException {
Sandra Kwane68c37e2015-11-12 17:11:49 -0800854 new Thread(new Runnable() {
855 @Override
856 public void run() {
857 Bundle sessionBundle = new Bundle();
858 sessionBundle.putString(KEY_AUTH_TOKEN_TYPE, authTokenType);
859 sessionBundle.putParcelable(KEY_ACCOUNT, account);
860 sessionBundle.putBundle(KEY_OPTIONS, options);
861 Bundle result = new Bundle();
862 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
863 response.onResult(result);
864 }
865
866 }).start();
867 return null;
868 }
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800869
870 /**
871 * Finishes the session started by #startAddAccountSession or
872 * #startUpdateCredentials by installing the account to device with
873 * AccountManager, or updating the local credentials. File I/O may be
874 * performed in this call.
875 * <p>
876 * Note: when overriding this method, {@link #startAddAccountSession} and
877 * {@link #startUpdateCredentialsSession} should be overridden too.
878 * </p>
879 *
880 * @param response to send the result back to the AccountManager, will never
881 * be null
882 * @param accountType the type of account to authenticate with, will never
883 * be null
884 * @param sessionBundle a bundle of session data created by
885 * {@link #startAddAccountSession} used for adding account to
886 * device, or by {@link #startUpdateCredentialsSession} used for
887 * updating local credentials.
888 * @return a Bundle result or null if the result is to be returned via the
889 * response. The result will contain either:
890 * <ul>
891 * <li>{@link AccountManager#KEY_INTENT}, or
892 * <li>{@link AccountManager#KEY_ACCOUNT_NAME} and
893 * {@link AccountManager#KEY_ACCOUNT_TYPE} of the account that was
Hongming Jin8b442752016-06-26 10:36:21 -0700894 * added or local credentials were updated, and optional
895 * {@link AccountManager#KEY_ACCOUNT_STATUS_TOKEN} for checking
896 * the status of the account later, or
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800897 * <li>{@link AccountManager#KEY_ERROR_CODE} and
898 * {@link AccountManager#KEY_ERROR_MESSAGE} to indicate an error
899 * </ul>
Sandra Kwan390c9d22016-01-12 14:13:37 -0800900 * @throws NetworkErrorException if the authenticator could not honor the request due to a
901 * network error
Sandra Kwan920f6ef2015-11-10 14:13:29 -0800902 * @see #startAddAccountSession and #startUpdateCredentialsSession
903 */
904 public Bundle finishSession(
905 final AccountAuthenticatorResponse response,
906 final String accountType,
907 final Bundle sessionBundle) throws NetworkErrorException {
908 if (TextUtils.isEmpty(accountType)) {
909 Log.e(TAG, "Account type cannot be empty.");
910 Bundle result = new Bundle();
911 result.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_BAD_ARGUMENTS);
912 result.putString(AccountManager.KEY_ERROR_MESSAGE,
913 "accountType cannot be empty.");
914 return result;
915 }
916
917 if (sessionBundle == null) {
918 Log.e(TAG, "Session bundle cannot be null.");
919 Bundle result = new Bundle();
920 result.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_BAD_ARGUMENTS);
921 result.putString(AccountManager.KEY_ERROR_MESSAGE,
922 "sessionBundle cannot be null.");
923 return result;
924 }
925
926 if (!sessionBundle.containsKey(KEY_AUTH_TOKEN_TYPE)) {
927 // We cannot handle Session bundle not created by default startAddAccountSession(...)
928 // nor startUpdateCredentialsSession(...) implementation. Return error.
929 Bundle result = new Bundle();
930 result.putInt(AccountManager.KEY_ERROR_CODE,
931 AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION);
932 result.putString(AccountManager.KEY_ERROR_MESSAGE,
933 "Authenticator must override finishSession if startAddAccountSession"
934 + " or startUpdateCredentialsSession is overridden.");
935 response.onResult(result);
936 return result;
937 }
938 String authTokenType = sessionBundle.getString(KEY_AUTH_TOKEN_TYPE);
939 Bundle options = sessionBundle.getBundle(KEY_OPTIONS);
940 String[] requiredFeatures = sessionBundle.getStringArray(KEY_REQUIRED_FEATURES);
941 Account account = sessionBundle.getParcelable(KEY_ACCOUNT);
942 boolean containsKeyAccount = sessionBundle.containsKey(KEY_ACCOUNT);
943
944 // Actual options passed to add account or update credentials flow.
945 Bundle sessionOptions = new Bundle(sessionBundle);
946 // Remove redundant extras in session bundle before passing it to addAccount(...) or
947 // updateCredentials(...).
948 sessionOptions.remove(KEY_AUTH_TOKEN_TYPE);
949 sessionOptions.remove(KEY_REQUIRED_FEATURES);
950 sessionOptions.remove(KEY_OPTIONS);
951 sessionOptions.remove(KEY_ACCOUNT);
952
953 if (options != null) {
954 // options may contains old system info such as
955 // AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or update
956 // credentials flow, we should replace with the new values of the current call added
957 // to sessionBundle by AccountManager or AccountManagerService.
958 options.putAll(sessionOptions);
959 sessionOptions = options;
960 }
961
962 // Session bundle created by startUpdateCredentialsSession default implementation should
963 // contain KEY_ACCOUNT.
964 if (containsKeyAccount) {
965 return updateCredentials(response, account, authTokenType, options);
966 }
967 // Otherwise, session bundle was created by startAddAccountSession default implementation.
968 return addAccount(response, accountType, authTokenType, requiredFeatures, sessionOptions);
969 }
Sandra Kwan390c9d22016-01-12 14:13:37 -0800970
971 /**
972 * Checks if update of the account credentials is suggested.
973 *
974 * @param response to send the result back to the AccountManager, will never be null.
975 * @param account the account to check, will never be null
976 * @param statusToken a String of token to check if update of credentials is suggested.
977 * @return a Bundle result or null if the result is to be returned via the response. The result
978 * will contain either:
979 * <ul>
980 * <li>{@link AccountManager#KEY_BOOLEAN_RESULT}, true if update of account's
981 * credentials is suggested, false otherwise
982 * <li>{@link AccountManager#KEY_ERROR_CODE} and
983 * {@link AccountManager#KEY_ERROR_MESSAGE} to indicate an error
984 * </ul>
985 * @throws NetworkErrorException if the authenticator could not honor the request due to a
986 * network error
Sandra Kwan390c9d22016-01-12 14:13:37 -0800987 */
Sandra Kwan390c9d22016-01-12 14:13:37 -0800988 public Bundle isCredentialsUpdateSuggested(
989 final AccountAuthenticatorResponse response,
990 Account account,
991 String statusToken) throws NetworkErrorException {
992 Bundle result = new Bundle();
993 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
994 return result;
995 }
Fred Quintana60307342009-03-24 22:48:12 -0700996}