blob: 82c2159d25f474c3904f19d80c939300d12475af [file] [log] [blame]
Fred Quintana1121bb52011-09-14 23:19:35 -07001/*
2 * Copyright (C) 2011 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 */
16package android.accounts;
17
Jatin Lodhia8d167782012-09-12 13:59:33 -070018import com.google.android.collect.Sets;
19
Fred Quintana1121bb52011-09-14 23:19:35 -070020import android.app.Activity;
Amith Yamasani27db4682013-03-30 17:07:47 -070021import android.app.ActivityManagerNative;
Fred Quintana1121bb52011-09-14 23:19:35 -070022import android.content.Intent;
Fred Quintana1121bb52011-09-14 23:19:35 -070023import android.os.Bundle;
Amith Yamasani27db4682013-03-30 17:07:47 -070024import android.os.IBinder;
Fred Quintana1121bb52011-09-14 23:19:35 -070025import android.os.Parcelable;
Amith Yamasani27db4682013-03-30 17:07:47 -070026import android.os.RemoteException;
27import android.os.UserHandle;
28import android.os.UserManager;
Fred Quintanab04fe4e2011-09-16 21:17:21 -070029import android.text.TextUtils;
Fred Quintana1121bb52011-09-14 23:19:35 -070030import android.util.Log;
Fred Quintana1121bb52011-09-14 23:19:35 -070031import android.view.View;
Amith Yamasani5a3915b2013-05-24 09:53:47 -070032import android.view.Window;
Fred Quintana1121bb52011-09-14 23:19:35 -070033import android.widget.AdapterView;
34import android.widget.ArrayAdapter;
35import android.widget.Button;
Fred Quintana1121bb52011-09-14 23:19:35 -070036import android.widget.ListView;
37import android.widget.TextView;
Alice Yang727c5992012-05-29 13:31:04 -070038
Fred Quintana1121bb52011-09-14 23:19:35 -070039import com.android.internal.R;
40
Fred Quintana9bbdd0b2011-09-27 17:24:32 -070041import java.io.IOException;
Fred Quintana1121bb52011-09-14 23:19:35 -070042import java.util.ArrayList;
Fred Quintana1121bb52011-09-14 23:19:35 -070043import java.util.HashSet;
44import java.util.Set;
45
46/**
47 * @hide
48 */
Fred Quintana9bbdd0b2011-09-27 17:24:32 -070049public class ChooseTypeAndAccountActivity extends Activity
50 implements AccountManagerCallback<Bundle> {
Fred Quintanae9095bd2011-10-11 17:47:58 -070051 private static final String TAG = "AccountChooser";
Fred Quintana1121bb52011-09-14 23:19:35 -070052
53 /**
54 * A Parcelable ArrayList of Account objects that limits the choosable accounts to those
55 * in this list, if this parameter is supplied.
56 */
57 public static final String EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST = "allowableAccounts";
58
59 /**
60 * A Parcelable ArrayList of String objects that limits the accounts to choose to those
61 * that match the types in this list, if this parameter is supplied. This list is also
62 * used to filter the allowable account types if add account is selected.
63 */
Fred Quintanab04fe4e2011-09-16 21:17:21 -070064 public static final String EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY = "allowableAccountTypes";
Fred Quintana1121bb52011-09-14 23:19:35 -070065
66 /**
Fred Quintanab04fe4e2011-09-16 21:17:21 -070067 * This is passed as the addAccountOptions parameter in AccountManager.addAccount()
68 * if it is called.
Fred Quintana1121bb52011-09-14 23:19:35 -070069 */
70 public static final String EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE = "addAccountOptions";
71
72 /**
Fred Quintanab04fe4e2011-09-16 21:17:21 -070073 * This is passed as the requiredFeatures parameter in AccountManager.addAccount()
74 * if it is called.
75 */
Fred Quintana01df6a82011-10-17 21:04:47 -070076 public static final String EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY =
Fred Quintanab04fe4e2011-09-16 21:17:21 -070077 "addAccountRequiredFeatures";
78
79 /**
80 * This is passed as the authTokenType string in AccountManager.addAccount()
81 * if it is called.
82 */
83 public static final String EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING = "authTokenType";
84
85 /**
Fred Quintana1121bb52011-09-14 23:19:35 -070086 * If set then the specified account is already "selected".
87 */
88 public static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
89
Fred Quintanab04fe4e2011-09-16 21:17:21 -070090 /**
91 * If true then display the account selection list even if there is just
92 * one account to choose from. boolean.
93 */
94 public static final String EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT =
95 "alwaysPromptForAccount";
96
97 /**
98 * If set then this string willb e used as the description rather than
99 * the default.
100 */
101 public static final String EXTRA_DESCRIPTION_TEXT_OVERRIDE =
102 "descriptionTextOverride";
103
Fred Quintanae9095bd2011-10-11 17:47:58 -0700104 public static final int REQUEST_NULL = 0;
105 public static final int REQUEST_CHOOSE_TYPE = 1;
106 public static final int REQUEST_ADD_ACCOUNT = 2;
107
108 private static final String KEY_INSTANCE_STATE_PENDING_REQUEST = "pendingRequest";
109 private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = "existingAccounts";
Alice Yang727c5992012-05-29 13:31:04 -0700110 private static final String KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME = "selectedAccountName";
111 private static final String KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT = "selectedAddAccount";
Carlos Valdivia1b64c9d2013-04-19 01:07:12 -0700112 private static final String KEY_INSTANCE_STATE_ACCOUNT_LIST = "accountList";
Fred Quintanae9095bd2011-10-11 17:47:58 -0700113
Alice Yang727c5992012-05-29 13:31:04 -0700114 private static final int SELECTED_ITEM_NONE = -1;
115
Jatin Lodhia8d167782012-09-12 13:59:33 -0700116 private Set<Account> mSetOfAllowableAccounts;
117 private Set<String> mSetOfRelevantAccountTypes;
118 private String mSelectedAccountName = null;
119 private boolean mSelectedAddNewAccount = false;
120 private boolean mAlwaysPromptForAccount = false;
121 private String mDescriptionOverride;
122
Alice Yang727c5992012-05-29 13:31:04 -0700123 private ArrayList<Account> mAccounts;
Fred Quintanae9095bd2011-10-11 17:47:58 -0700124 private int mPendingRequest = REQUEST_NULL;
125 private Parcelable[] mExistingAccounts = null;
Alice Yang727c5992012-05-29 13:31:04 -0700126 private int mSelectedItemIndex;
127 private Button mOkButton;
Amith Yamasani27db4682013-03-30 17:07:47 -0700128 private int mCallingUid;
129 private String mCallingPackage;
130 private boolean mDisallowAddAccounts;
Amith Yamasani5a3915b2013-05-24 09:53:47 -0700131 private boolean mDontShowPicker;
Fred Quintana1121bb52011-09-14 23:19:35 -0700132
133 @Override
134 public void onCreate(Bundle savedInstanceState) {
135 super.onCreate(savedInstanceState);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700136 if (Log.isLoggable(TAG, Log.VERBOSE)) {
137 Log.v(TAG, "ChooseTypeAndAccountActivity.onCreate(savedInstanceState="
138 + savedInstanceState + ")");
139 }
140
Amith Yamasani27db4682013-03-30 17:07:47 -0700141 String message = null;
142
143 try {
144 IBinder activityToken = getActivityToken();
145 mCallingUid = ActivityManagerNative.getDefault().getLaunchedFromUid(activityToken);
146 mCallingPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
147 activityToken);
148 if (mCallingUid != 0 && mCallingPackage != null) {
149 Bundle restrictions = UserManager.get(this)
150 .getUserRestrictions(new UserHandle(UserHandle.getUserId(mCallingUid)));
151 mDisallowAddAccounts =
152 restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false);
153 }
154 } catch (RemoteException re) {
155 // Couldn't figure out caller details
156 Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re);
157 }
158
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700159 // save some items we use frequently
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700160 final Intent intent = getIntent();
161
Alice Yang727c5992012-05-29 13:31:04 -0700162 if (savedInstanceState != null) {
163 mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
164 mExistingAccounts =
165 savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
166
167 // Makes sure that any user selection is preserved across orientation changes.
Jatin Lodhia8d167782012-09-12 13:59:33 -0700168 mSelectedAccountName = savedInstanceState.getString(
Alice Yang727c5992012-05-29 13:31:04 -0700169 KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
170
Jatin Lodhia8d167782012-09-12 13:59:33 -0700171 mSelectedAddNewAccount = savedInstanceState.getBoolean(
Alice Yang727c5992012-05-29 13:31:04 -0700172 KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
Carlos Valdivia1b64c9d2013-04-19 01:07:12 -0700173 mAccounts = savedInstanceState.getParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST);
Alice Yang727c5992012-05-29 13:31:04 -0700174 } else {
175 mPendingRequest = REQUEST_NULL;
176 mExistingAccounts = null;
177 // If the selected account as specified in the intent matches one in the list we will
178 // show is as pre-selected.
179 Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
180 if (selectedAccount != null) {
Jatin Lodhia8d167782012-09-12 13:59:33 -0700181 mSelectedAccountName = selectedAccount.name;
Alice Yang727c5992012-05-29 13:31:04 -0700182 }
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700183 }
184
Alice Yang727c5992012-05-29 13:31:04 -0700185 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Jatin Lodhia8d167782012-09-12 13:59:33 -0700186 Log.v(TAG, "selected account name is " + mSelectedAccountName);
Alice Yang727c5992012-05-29 13:31:04 -0700187 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700188
Fred Quintana1121bb52011-09-14 23:19:35 -0700189
Jatin Lodhia8d167782012-09-12 13:59:33 -0700190 mSetOfAllowableAccounts = getAllowableAccountSet(intent);
191 mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);
192 mAlwaysPromptForAccount = intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false);
193 mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
Amith Yamasani5a3915b2013-05-24 09:53:47 -0700194
195 // Need to do this once here to request the window feature. Can't do it in onResume
196 mAccounts = getAcceptableAccountChoices(AccountManager.get(this));
197 if (mAccounts.isEmpty()
198 && mDisallowAddAccounts) {
199 requestWindowFeature(Window.FEATURE_NO_TITLE);
200 setContentView(R.layout.app_not_authorized);
201 mDontShowPicker = true;
202 }
Jatin Lodhia8d167782012-09-12 13:59:33 -0700203 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700204
Jatin Lodhia8d167782012-09-12 13:59:33 -0700205 @Override
206 protected void onResume() {
207 super.onResume();
Amith Yamasani5a3915b2013-05-24 09:53:47 -0700208
209 if (mDontShowPicker) return;
210
Jatin Lodhia8d167782012-09-12 13:59:33 -0700211 final AccountManager accountManager = AccountManager.get(this);
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700212
Jatin Lodhia8d167782012-09-12 13:59:33 -0700213 mAccounts = getAcceptableAccountChoices(accountManager);
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700214
Jatin Lodhia8d167782012-09-12 13:59:33 -0700215 // In cases where the activity does not need to show an account picker, cut the chase
216 // and return the result directly. Eg:
217 // Single account -> select it directly
218 // No account -> launch add account activity directly
Fred Quintanae9095bd2011-10-11 17:47:58 -0700219 if (mPendingRequest == REQUEST_NULL) {
Alice Yang727c5992012-05-29 13:31:04 -0700220 // If there are no relevant accounts and only one relevant account type go directly to
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700221 // add account. Otherwise let the user choose.
Alice Yang727c5992012-05-29 13:31:04 -0700222 if (mAccounts.isEmpty()) {
Jatin Lodhia8d167782012-09-12 13:59:33 -0700223 if (mSetOfRelevantAccountTypes.size() == 1) {
224 runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next());
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700225 } else {
226 startChooseAccountTypeActivity();
227 }
Fred Quintanae9095bd2011-10-11 17:47:58 -0700228 return;
229 }
230
231 // if there is only one allowable account return it
Jatin Lodhia8d167782012-09-12 13:59:33 -0700232 if (!mAlwaysPromptForAccount && mAccounts.size() == 1) {
Alice Yang727c5992012-05-29 13:31:04 -0700233 Account account = mAccounts.get(0);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700234 setResultAndFinish(account.name, account.type);
235 return;
236 }
237 }
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700238
Jatin Lodhia8d167782012-09-12 13:59:33 -0700239 String[] listItems = getListOfDisplayableOptions(mAccounts);
240 mSelectedItemIndex = getItemIndexToSelect(
241 mAccounts, mSelectedAccountName, mSelectedAddNewAccount);
242
Alice Yang727c5992012-05-29 13:31:04 -0700243 // Cannot set content view until we know that mPendingRequest is not null, otherwise
244 // would cause screen flicker.
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700245 setContentView(R.layout.choose_type_and_account);
Jatin Lodhia8d167782012-09-12 13:59:33 -0700246 overrideDescriptionIfSupplied(mDescriptionOverride);
247 populateUIAccountList(listItems);
Alice Yang6cab5e82012-05-31 15:48:51 -0700248
249 // Only enable "OK" button if something has been selected.
250 mOkButton = (Button) findViewById(android.R.id.button2);
251 mOkButton.setEnabled(mSelectedItemIndex != SELECTED_ITEM_NONE);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700252 }
253
254 @Override
255 protected void onDestroy() {
256 if (Log.isLoggable(TAG, Log.VERBOSE)) {
257 Log.v(TAG, "ChooseTypeAndAccountActivity.onDestroy()");
258 }
259 super.onDestroy();
260 }
261
262 @Override
263 protected void onSaveInstanceState(final Bundle outState) {
264 super.onSaveInstanceState(outState);
265 outState.putInt(KEY_INSTANCE_STATE_PENDING_REQUEST, mPendingRequest);
Fred Quintana01df6a82011-10-17 21:04:47 -0700266 if (mPendingRequest == REQUEST_ADD_ACCOUNT) {
267 outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
268 }
Alice Yang727c5992012-05-29 13:31:04 -0700269 if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
270 if (mSelectedItemIndex == mAccounts.size()) {
271 outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
272 } else {
273 outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
274 outState.putString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME,
275 mAccounts.get(mSelectedItemIndex).name);
276 }
277 }
Carlos Valdivia1b64c9d2013-04-19 01:07:12 -0700278 outState.putParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST, mAccounts);
Alice Yang727c5992012-05-29 13:31:04 -0700279 }
280
281 public void onCancelButtonClicked(View view) {
282 onBackPressed();
283 }
284
285 public void onOkButtonClicked(View view) {
286 if (mSelectedItemIndex == mAccounts.size()) {
287 // Selected "Add New Account" option
288 startChooseAccountTypeActivity();
289 } else if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
290 onAccountSelected(mAccounts.get(mSelectedItemIndex));
291 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700292 }
293
294 // Called when the choose account type activity (for adding an account) returns.
295 // If it was a success read the account and set it in the result. In all cases
296 // return the result and finish this activity.
297 @Override
298 protected void onActivityResult(final int requestCode, final int resultCode,
299 final Intent data) {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700300 if (Log.isLoggable(TAG, Log.VERBOSE)) {
301 if (data != null && data.getExtras() != null) data.getExtras().keySet();
302 Bundle extras = data != null ? data.getExtras() : null;
303 Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult(reqCode=" + requestCode
304 + ", resCode=" + resultCode + ", extras=" + extras + ")");
Fred Quintana1121bb52011-09-14 23:19:35 -0700305 }
Fred Quintanae9095bd2011-10-11 17:47:58 -0700306
307 // we got our result, so clear the fact that we had a pending request
308 mPendingRequest = REQUEST_NULL;
Fred Quintanae9095bd2011-10-11 17:47:58 -0700309
310 if (resultCode == RESULT_CANCELED) {
Alice Yang727c5992012-05-29 13:31:04 -0700311 // if canceling out of addAccount and the original state caused us to skip this,
Fred Quintana2becf932011-11-15 17:33:08 -0800312 // finish this activity
Alice Yang727c5992012-05-29 13:31:04 -0700313 if (mAccounts.isEmpty()) {
Fred Quintana2becf932011-11-15 17:33:08 -0800314 setResult(Activity.RESULT_CANCELED);
315 finish();
316 }
Fred Quintanae9095bd2011-10-11 17:47:58 -0700317 return;
318 }
319
320 if (resultCode == RESULT_OK) {
321 if (requestCode == REQUEST_CHOOSE_TYPE) {
322 if (data != null) {
323 String accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
324 if (accountType != null) {
325 runAddAccountForAuthenticator(accountType);
326 return;
327 }
328 }
329 Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: unable to find account "
330 + "type, pretending the request was canceled");
331 } else if (requestCode == REQUEST_ADD_ACCOUNT) {
332 String accountName = null;
333 String accountType = null;
334
335 if (data != null) {
336 accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
337 accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
338 }
339
340 if (accountName == null || accountType == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700341 Account[] currentAccounts = AccountManager.get(this).getAccountsForPackage(
342 mCallingPackage, mCallingUid);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700343 Set<Account> preExistingAccounts = new HashSet<Account>();
Fred Quintana01df6a82011-10-17 21:04:47 -0700344 for (Parcelable accountParcel : mExistingAccounts) {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700345 preExistingAccounts.add((Account) accountParcel);
346 }
347 for (Account account : currentAccounts) {
348 if (!preExistingAccounts.contains(account)) {
349 accountName = account.name;
350 accountType = account.type;
351 break;
352 }
353 }
354 }
355
356 if (accountName != null || accountType != null) {
357 setResultAndFinish(accountName, accountType);
358 return;
359 }
360 }
361 Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: unable to find added "
362 + "account, pretending the request was canceled");
363 }
364 if (Log.isLoggable(TAG, Log.VERBOSE)) {
365 Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult: canceled");
366 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700367 setResult(Activity.RESULT_CANCELED);
368 finish();
369 }
370
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700371 protected void runAddAccountForAuthenticator(String type) {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700372 if (Log.isLoggable(TAG, Log.VERBOSE)) {
373 Log.v(TAG, "runAddAccountForAuthenticator: " + type);
374 }
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700375 final Bundle options = getIntent().getBundleExtra(
376 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE);
377 final String[] requiredFeatures = getIntent().getStringArrayExtra(
378 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY);
379 final String authTokenType = getIntent().getStringExtra(
380 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING);
381 AccountManager.get(this).addAccount(type, authTokenType, requiredFeatures,
Fred Quintanae9095bd2011-10-11 17:47:58 -0700382 options, null /* activity */, this /* callback */, null /* Handler */);
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700383 }
384
Alice Yang727c5992012-05-29 13:31:04 -0700385 @Override
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700386 public void run(final AccountManagerFuture<Bundle> accountManagerFuture) {
387 try {
388 final Bundle accountManagerResult = accountManagerFuture.getResult();
Fred Quintanae9095bd2011-10-11 17:47:58 -0700389 final Intent intent = (Intent)accountManagerResult.getParcelable(
390 AccountManager.KEY_INTENT);
391 if (intent != null) {
392 mPendingRequest = REQUEST_ADD_ACCOUNT;
Amith Yamasani27db4682013-03-30 17:07:47 -0700393 mExistingAccounts = AccountManager.get(this).getAccountsForPackage(mCallingPackage,
394 mCallingUid);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700395 intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
396 startActivityForResult(intent, REQUEST_ADD_ACCOUNT);
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700397 return;
398 }
399 } catch (OperationCanceledException e) {
400 setResult(Activity.RESULT_CANCELED);
401 finish();
402 return;
403 } catch (IOException e) {
404 } catch (AuthenticatorException e) {
405 }
406 Bundle bundle = new Bundle();
407 bundle.putString(AccountManager.KEY_ERROR_MESSAGE, "error communicating with server");
408 setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
409 finish();
410 }
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700411
Alice Yang727c5992012-05-29 13:31:04 -0700412 private void onAccountSelected(Account account) {
413 Log.d(TAG, "selected account " + account);
414 setResultAndFinish(account.name, account.type);
Fred Quintana1121bb52011-09-14 23:19:35 -0700415 }
416
417 private void setResultAndFinish(final String accountName, final String accountType) {
418 Bundle bundle = new Bundle();
419 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
420 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
421 setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
Fred Quintanae9095bd2011-10-11 17:47:58 -0700422 if (Log.isLoggable(TAG, Log.VERBOSE)) {
423 Log.v(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: "
424 + "selected account " + accountName + ", " + accountType);
425 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700426 finish();
427 }
428
429 private void startChooseAccountTypeActivity() {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700430 if (Log.isLoggable(TAG, Log.VERBOSE)) {
431 Log.v(TAG, "ChooseAccountTypeActivity.startChooseAccountTypeActivity()");
432 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700433 final Intent intent = new Intent(this, ChooseAccountTypeActivity.class);
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700434 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
Fred Quintanaa77253a2011-09-19 15:28:18 -0700435 intent.putExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
436 getIntent().getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY));
Fred Quintana1121bb52011-09-14 23:19:35 -0700437 intent.putExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700438 getIntent().getBundleExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE));
439 intent.putExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,
440 getIntent().getStringArrayExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY));
441 intent.putExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,
Fred Quintanaa77253a2011-09-19 15:28:18 -0700442 getIntent().getStringExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING));
Fred Quintanae9095bd2011-10-11 17:47:58 -0700443 startActivityForResult(intent, REQUEST_CHOOSE_TYPE);
444 mPendingRequest = REQUEST_CHOOSE_TYPE;
Fred Quintana1121bb52011-09-14 23:19:35 -0700445 }
Jatin Lodhia8d167782012-09-12 13:59:33 -0700446
447 /**
448 * @return a value between 0 (inclusive) and accounts.size() (inclusive) or SELECTED_ITEM_NONE.
449 * An index value of accounts.size() indicates 'Add account' option.
450 */
451 private int getItemIndexToSelect(ArrayList<Account> accounts, String selectedAccountName,
452 boolean selectedAddNewAccount) {
453 // If "Add account" option was previously selected by user, preserve it across
454 // orientation changes.
455 if (selectedAddNewAccount) {
456 return accounts.size();
457 }
458 // search for the selected account name if present
459 for (int i = 0; i < accounts.size(); i++) {
460 if (accounts.get(i).name.equals(selectedAccountName)) {
461 return i;
462 }
463 }
464 // no account selected.
465 return SELECTED_ITEM_NONE;
466 }
467
468 private String[] getListOfDisplayableOptions(ArrayList<Account> accounts) {
469 // List of options includes all accounts found together with "Add new account" as the
470 // last item in the list.
Amith Yamasani27db4682013-03-30 17:07:47 -0700471 String[] listItems = new String[accounts.size() + (mDisallowAddAccounts ? 0 : 1)];
Jatin Lodhia8d167782012-09-12 13:59:33 -0700472 for (int i = 0; i < accounts.size(); i++) {
473 listItems[i] = accounts.get(i).name;
474 }
Amith Yamasani27db4682013-03-30 17:07:47 -0700475 if (!mDisallowAddAccounts) {
476 listItems[accounts.size()] = getResources().getString(
477 R.string.add_account_button_label);
478 }
Jatin Lodhia8d167782012-09-12 13:59:33 -0700479 return listItems;
480 }
481
482 /**
483 * Create a list of Account objects for each account that is acceptable. Filter out
484 * accounts that don't match the allowable types, if provided, or that don't match the
485 * allowable accounts, if provided.
486 */
487 private ArrayList<Account> getAcceptableAccountChoices(AccountManager accountManager) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700488 final Account[] accounts = accountManager.getAccountsForPackage(mCallingPackage,
489 mCallingUid);
Jatin Lodhia8d167782012-09-12 13:59:33 -0700490 ArrayList<Account> accountsToPopulate = new ArrayList<Account>(accounts.length);
491 for (Account account : accounts) {
492 if (mSetOfAllowableAccounts != null
493 && !mSetOfAllowableAccounts.contains(account)) {
494 continue;
495 }
496 if (mSetOfRelevantAccountTypes != null
497 && !mSetOfRelevantAccountTypes.contains(account.type)) {
498 continue;
499 }
500 accountsToPopulate.add(account);
501 }
502 return accountsToPopulate;
503 }
504
505 /**
506 * Return a set of account types speficied by the intent as well as supported by the
507 * AccountManager.
508 */
509 private Set<String> getReleventAccountTypes(final Intent intent) {
510 // An account type is relevant iff it is allowed by the caller and supported by the account
511 // manager.
512 Set<String> setOfRelevantAccountTypes = null;
513 final String[] allowedAccountTypes =
514 intent.getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
515 if (allowedAccountTypes != null) {
516 setOfRelevantAccountTypes = Sets.newHashSet(allowedAccountTypes);
517 AuthenticatorDescription[] descs = AccountManager.get(this).getAuthenticatorTypes();
518 Set<String> supportedAccountTypes = new HashSet<String>(descs.length);
519 for (AuthenticatorDescription desc : descs) {
520 supportedAccountTypes.add(desc.type);
521 }
522 setOfRelevantAccountTypes.retainAll(supportedAccountTypes);
523 }
524 return setOfRelevantAccountTypes;
525 }
526
527 /**
528 * Returns a set of whitelisted accounts given by the intent or null if none specified by the
529 * intent.
530 */
531 private Set<Account> getAllowableAccountSet(final Intent intent) {
532 Set<Account> setOfAllowableAccounts = null;
533 final ArrayList<Parcelable> validAccounts =
534 intent.getParcelableArrayListExtra(EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST);
535 if (validAccounts != null) {
536 setOfAllowableAccounts = new HashSet<Account>(validAccounts.size());
537 for (Parcelable parcelable : validAccounts) {
538 setOfAllowableAccounts.add((Account)parcelable);
539 }
540 }
541 return setOfAllowableAccounts;
542 }
543
544 /**
545 * Overrides the description text view for the picker activity if specified by the intent.
546 * If not specified then makes the description invisible.
547 */
548 private void overrideDescriptionIfSupplied(String descriptionOverride) {
549 TextView descriptionView = (TextView) findViewById(R.id.description);
550 if (!TextUtils.isEmpty(descriptionOverride)) {
551 descriptionView.setText(descriptionOverride);
552 } else {
553 descriptionView.setVisibility(View.GONE);
554 }
555 }
556
557 /**
558 * Populates the UI ListView with the given list of items and selects an item
559 * based on {@code mSelectedItemIndex} member variable.
560 */
561 private final void populateUIAccountList(String[] listItems) {
562 ListView list = (ListView) findViewById(android.R.id.list);
563 list.setAdapter(new ArrayAdapter<String>(this,
564 android.R.layout.simple_list_item_single_choice, listItems));
565 list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
566 list.setItemsCanFocus(false);
567 list.setOnItemClickListener(
568 new AdapterView.OnItemClickListener() {
569 @Override
570 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
571 mSelectedItemIndex = position;
572 mOkButton.setEnabled(true);
573 }
574 });
575 if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
576 list.setItemChecked(mSelectedItemIndex, true);
577 if (Log.isLoggable(TAG, Log.VERBOSE)) {
578 Log.v(TAG, "List item " + mSelectedItemIndex + " should be selected");
579 }
580 }
581 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700582}