blob: 58eb66f8d390068ca0329b7188785e8766c549f1 [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;
Fred Quintana1121bb52011-09-14 23:19:35 -070032import android.widget.AdapterView;
33import android.widget.ArrayAdapter;
34import android.widget.Button;
Fred Quintana1121bb52011-09-14 23:19:35 -070035import android.widget.ListView;
36import android.widget.TextView;
Alice Yang727c5992012-05-29 13:31:04 -070037
Fred Quintana1121bb52011-09-14 23:19:35 -070038import com.android.internal.R;
39
Fred Quintana9bbdd0b2011-09-27 17:24:32 -070040import java.io.IOException;
Fred Quintana1121bb52011-09-14 23:19:35 -070041import java.util.ArrayList;
Fred Quintana1121bb52011-09-14 23:19:35 -070042import java.util.HashSet;
43import java.util.Set;
44
45/**
46 * @hide
47 */
Fred Quintana9bbdd0b2011-09-27 17:24:32 -070048public class ChooseTypeAndAccountActivity extends Activity
49 implements AccountManagerCallback<Bundle> {
Fred Quintanae9095bd2011-10-11 17:47:58 -070050 private static final String TAG = "AccountChooser";
Fred Quintana1121bb52011-09-14 23:19:35 -070051
52 /**
53 * A Parcelable ArrayList of Account objects that limits the choosable accounts to those
54 * in this list, if this parameter is supplied.
55 */
56 public static final String EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST = "allowableAccounts";
57
58 /**
59 * A Parcelable ArrayList of String objects that limits the accounts to choose to those
60 * that match the types in this list, if this parameter is supplied. This list is also
61 * used to filter the allowable account types if add account is selected.
62 */
Fred Quintanab04fe4e2011-09-16 21:17:21 -070063 public static final String EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY = "allowableAccountTypes";
Fred Quintana1121bb52011-09-14 23:19:35 -070064
65 /**
Fred Quintanab04fe4e2011-09-16 21:17:21 -070066 * This is passed as the addAccountOptions parameter in AccountManager.addAccount()
67 * if it is called.
Fred Quintana1121bb52011-09-14 23:19:35 -070068 */
69 public static final String EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE = "addAccountOptions";
70
71 /**
Fred Quintanab04fe4e2011-09-16 21:17:21 -070072 * This is passed as the requiredFeatures parameter in AccountManager.addAccount()
73 * if it is called.
74 */
Fred Quintana01df6a82011-10-17 21:04:47 -070075 public static final String EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY =
Fred Quintanab04fe4e2011-09-16 21:17:21 -070076 "addAccountRequiredFeatures";
77
78 /**
79 * This is passed as the authTokenType string in AccountManager.addAccount()
80 * if it is called.
81 */
82 public static final String EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING = "authTokenType";
83
84 /**
Fred Quintana1121bb52011-09-14 23:19:35 -070085 * If set then the specified account is already "selected".
86 */
87 public static final String EXTRA_SELECTED_ACCOUNT = "selectedAccount";
88
Fred Quintanab04fe4e2011-09-16 21:17:21 -070089 /**
90 * If true then display the account selection list even if there is just
91 * one account to choose from. boolean.
92 */
93 public static final String EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT =
94 "alwaysPromptForAccount";
95
96 /**
97 * If set then this string willb e used as the description rather than
98 * the default.
99 */
100 public static final String EXTRA_DESCRIPTION_TEXT_OVERRIDE =
101 "descriptionTextOverride";
102
Fred Quintanae9095bd2011-10-11 17:47:58 -0700103 public static final int REQUEST_NULL = 0;
104 public static final int REQUEST_CHOOSE_TYPE = 1;
105 public static final int REQUEST_ADD_ACCOUNT = 2;
106
107 private static final String KEY_INSTANCE_STATE_PENDING_REQUEST = "pendingRequest";
108 private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = "existingAccounts";
Alice Yang727c5992012-05-29 13:31:04 -0700109 private static final String KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME = "selectedAccountName";
110 private static final String KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT = "selectedAddAccount";
Carlos Valdivia1b64c9d2013-04-19 01:07:12 -0700111 private static final String KEY_INSTANCE_STATE_ACCOUNT_LIST = "accountList";
Fred Quintanae9095bd2011-10-11 17:47:58 -0700112
Alice Yang727c5992012-05-29 13:31:04 -0700113 private static final int SELECTED_ITEM_NONE = -1;
114
Jatin Lodhia8d167782012-09-12 13:59:33 -0700115 private Set<Account> mSetOfAllowableAccounts;
116 private Set<String> mSetOfRelevantAccountTypes;
117 private String mSelectedAccountName = null;
118 private boolean mSelectedAddNewAccount = false;
119 private boolean mAlwaysPromptForAccount = false;
120 private String mDescriptionOverride;
121
Alice Yang727c5992012-05-29 13:31:04 -0700122 private ArrayList<Account> mAccounts;
Fred Quintanae9095bd2011-10-11 17:47:58 -0700123 private int mPendingRequest = REQUEST_NULL;
124 private Parcelable[] mExistingAccounts = null;
Alice Yang727c5992012-05-29 13:31:04 -0700125 private int mSelectedItemIndex;
126 private Button mOkButton;
Amith Yamasani27db4682013-03-30 17:07:47 -0700127 private int mCallingUid;
128 private String mCallingPackage;
129 private boolean mDisallowAddAccounts;
Fred Quintana1121bb52011-09-14 23:19:35 -0700130
131 @Override
132 public void onCreate(Bundle savedInstanceState) {
133 super.onCreate(savedInstanceState);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700134 if (Log.isLoggable(TAG, Log.VERBOSE)) {
135 Log.v(TAG, "ChooseTypeAndAccountActivity.onCreate(savedInstanceState="
136 + savedInstanceState + ")");
137 }
138
Amith Yamasani27db4682013-03-30 17:07:47 -0700139 String message = null;
140
141 try {
142 IBinder activityToken = getActivityToken();
143 mCallingUid = ActivityManagerNative.getDefault().getLaunchedFromUid(activityToken);
144 mCallingPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
145 activityToken);
146 if (mCallingUid != 0 && mCallingPackage != null) {
147 Bundle restrictions = UserManager.get(this)
148 .getUserRestrictions(new UserHandle(UserHandle.getUserId(mCallingUid)));
149 mDisallowAddAccounts =
150 restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false);
151 }
152 } catch (RemoteException re) {
153 // Couldn't figure out caller details
154 Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re);
155 }
156
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700157 // save some items we use frequently
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700158 final Intent intent = getIntent();
159
Alice Yang727c5992012-05-29 13:31:04 -0700160 if (savedInstanceState != null) {
161 mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
162 mExistingAccounts =
163 savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
164
165 // Makes sure that any user selection is preserved across orientation changes.
Jatin Lodhia8d167782012-09-12 13:59:33 -0700166 mSelectedAccountName = savedInstanceState.getString(
Alice Yang727c5992012-05-29 13:31:04 -0700167 KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
168
Jatin Lodhia8d167782012-09-12 13:59:33 -0700169 mSelectedAddNewAccount = savedInstanceState.getBoolean(
Alice Yang727c5992012-05-29 13:31:04 -0700170 KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
Carlos Valdivia1b64c9d2013-04-19 01:07:12 -0700171 mAccounts = savedInstanceState.getParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST);
Alice Yang727c5992012-05-29 13:31:04 -0700172 } else {
173 mPendingRequest = REQUEST_NULL;
174 mExistingAccounts = null;
175 // If the selected account as specified in the intent matches one in the list we will
176 // show is as pre-selected.
177 Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
178 if (selectedAccount != null) {
Jatin Lodhia8d167782012-09-12 13:59:33 -0700179 mSelectedAccountName = selectedAccount.name;
Alice Yang727c5992012-05-29 13:31:04 -0700180 }
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700181 }
182
Alice Yang727c5992012-05-29 13:31:04 -0700183 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Jatin Lodhia8d167782012-09-12 13:59:33 -0700184 Log.v(TAG, "selected account name is " + mSelectedAccountName);
Alice Yang727c5992012-05-29 13:31:04 -0700185 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700186
Fred Quintana1121bb52011-09-14 23:19:35 -0700187
Jatin Lodhia8d167782012-09-12 13:59:33 -0700188 mSetOfAllowableAccounts = getAllowableAccountSet(intent);
189 mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);
190 mAlwaysPromptForAccount = intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false);
191 mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
192 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700193
Jatin Lodhia8d167782012-09-12 13:59:33 -0700194 @Override
195 protected void onResume() {
196 super.onResume();
197 final AccountManager accountManager = AccountManager.get(this);
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700198
Jatin Lodhia8d167782012-09-12 13:59:33 -0700199 mAccounts = getAcceptableAccountChoices(accountManager);
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700200
Jatin Lodhia8d167782012-09-12 13:59:33 -0700201 // In cases where the activity does not need to show an account picker, cut the chase
202 // and return the result directly. Eg:
203 // Single account -> select it directly
204 // No account -> launch add account activity directly
Fred Quintanae9095bd2011-10-11 17:47:58 -0700205 if (mPendingRequest == REQUEST_NULL) {
Alice Yang727c5992012-05-29 13:31:04 -0700206 // If there are no relevant accounts and only one relevant account type go directly to
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700207 // add account. Otherwise let the user choose.
Alice Yang727c5992012-05-29 13:31:04 -0700208 if (mAccounts.isEmpty()) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700209 if (mDisallowAddAccounts) {
210 setContentView(R.layout.app_not_authorized);
211 setTitle(R.string.error_message_title);
212 return;
213 }
Jatin Lodhia8d167782012-09-12 13:59:33 -0700214 if (mSetOfRelevantAccountTypes.size() == 1) {
215 runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next());
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700216 } else {
217 startChooseAccountTypeActivity();
218 }
Fred Quintanae9095bd2011-10-11 17:47:58 -0700219 return;
220 }
221
222 // if there is only one allowable account return it
Jatin Lodhia8d167782012-09-12 13:59:33 -0700223 if (!mAlwaysPromptForAccount && mAccounts.size() == 1) {
Alice Yang727c5992012-05-29 13:31:04 -0700224 Account account = mAccounts.get(0);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700225 setResultAndFinish(account.name, account.type);
226 return;
227 }
228 }
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700229
Jatin Lodhia8d167782012-09-12 13:59:33 -0700230 String[] listItems = getListOfDisplayableOptions(mAccounts);
231 mSelectedItemIndex = getItemIndexToSelect(
232 mAccounts, mSelectedAccountName, mSelectedAddNewAccount);
233
Alice Yang727c5992012-05-29 13:31:04 -0700234 // Cannot set content view until we know that mPendingRequest is not null, otherwise
235 // would cause screen flicker.
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700236 setContentView(R.layout.choose_type_and_account);
Jatin Lodhia8d167782012-09-12 13:59:33 -0700237 overrideDescriptionIfSupplied(mDescriptionOverride);
238 populateUIAccountList(listItems);
Alice Yang6cab5e82012-05-31 15:48:51 -0700239
240 // Only enable "OK" button if something has been selected.
241 mOkButton = (Button) findViewById(android.R.id.button2);
242 mOkButton.setEnabled(mSelectedItemIndex != SELECTED_ITEM_NONE);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700243 }
244
245 @Override
246 protected void onDestroy() {
247 if (Log.isLoggable(TAG, Log.VERBOSE)) {
248 Log.v(TAG, "ChooseTypeAndAccountActivity.onDestroy()");
249 }
250 super.onDestroy();
251 }
252
253 @Override
254 protected void onSaveInstanceState(final Bundle outState) {
255 super.onSaveInstanceState(outState);
256 outState.putInt(KEY_INSTANCE_STATE_PENDING_REQUEST, mPendingRequest);
Fred Quintana01df6a82011-10-17 21:04:47 -0700257 if (mPendingRequest == REQUEST_ADD_ACCOUNT) {
258 outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
259 }
Alice Yang727c5992012-05-29 13:31:04 -0700260 if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
261 if (mSelectedItemIndex == mAccounts.size()) {
262 outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
263 } else {
264 outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
265 outState.putString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME,
266 mAccounts.get(mSelectedItemIndex).name);
267 }
268 }
Carlos Valdivia1b64c9d2013-04-19 01:07:12 -0700269 outState.putParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST, mAccounts);
Alice Yang727c5992012-05-29 13:31:04 -0700270 }
271
272 public void onCancelButtonClicked(View view) {
273 onBackPressed();
274 }
275
276 public void onOkButtonClicked(View view) {
277 if (mSelectedItemIndex == mAccounts.size()) {
278 // Selected "Add New Account" option
279 startChooseAccountTypeActivity();
280 } else if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
281 onAccountSelected(mAccounts.get(mSelectedItemIndex));
282 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700283 }
284
285 // Called when the choose account type activity (for adding an account) returns.
286 // If it was a success read the account and set it in the result. In all cases
287 // return the result and finish this activity.
288 @Override
289 protected void onActivityResult(final int requestCode, final int resultCode,
290 final Intent data) {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700291 if (Log.isLoggable(TAG, Log.VERBOSE)) {
292 if (data != null && data.getExtras() != null) data.getExtras().keySet();
293 Bundle extras = data != null ? data.getExtras() : null;
294 Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult(reqCode=" + requestCode
295 + ", resCode=" + resultCode + ", extras=" + extras + ")");
Fred Quintana1121bb52011-09-14 23:19:35 -0700296 }
Fred Quintanae9095bd2011-10-11 17:47:58 -0700297
298 // we got our result, so clear the fact that we had a pending request
299 mPendingRequest = REQUEST_NULL;
Fred Quintanae9095bd2011-10-11 17:47:58 -0700300
301 if (resultCode == RESULT_CANCELED) {
Alice Yang727c5992012-05-29 13:31:04 -0700302 // if canceling out of addAccount and the original state caused us to skip this,
Fred Quintana2becf932011-11-15 17:33:08 -0800303 // finish this activity
Alice Yang727c5992012-05-29 13:31:04 -0700304 if (mAccounts.isEmpty()) {
Fred Quintana2becf932011-11-15 17:33:08 -0800305 setResult(Activity.RESULT_CANCELED);
306 finish();
307 }
Fred Quintanae9095bd2011-10-11 17:47:58 -0700308 return;
309 }
310
311 if (resultCode == RESULT_OK) {
312 if (requestCode == REQUEST_CHOOSE_TYPE) {
313 if (data != null) {
314 String accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
315 if (accountType != null) {
316 runAddAccountForAuthenticator(accountType);
317 return;
318 }
319 }
320 Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: unable to find account "
321 + "type, pretending the request was canceled");
322 } else if (requestCode == REQUEST_ADD_ACCOUNT) {
323 String accountName = null;
324 String accountType = null;
325
326 if (data != null) {
327 accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
328 accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
329 }
330
331 if (accountName == null || accountType == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700332 Account[] currentAccounts = AccountManager.get(this).getAccountsForPackage(
333 mCallingPackage, mCallingUid);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700334 Set<Account> preExistingAccounts = new HashSet<Account>();
Fred Quintana01df6a82011-10-17 21:04:47 -0700335 for (Parcelable accountParcel : mExistingAccounts) {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700336 preExistingAccounts.add((Account) accountParcel);
337 }
338 for (Account account : currentAccounts) {
339 if (!preExistingAccounts.contains(account)) {
340 accountName = account.name;
341 accountType = account.type;
342 break;
343 }
344 }
345 }
346
347 if (accountName != null || accountType != null) {
348 setResultAndFinish(accountName, accountType);
349 return;
350 }
351 }
352 Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: unable to find added "
353 + "account, pretending the request was canceled");
354 }
355 if (Log.isLoggable(TAG, Log.VERBOSE)) {
356 Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult: canceled");
357 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700358 setResult(Activity.RESULT_CANCELED);
359 finish();
360 }
361
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700362 protected void runAddAccountForAuthenticator(String type) {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700363 if (Log.isLoggable(TAG, Log.VERBOSE)) {
364 Log.v(TAG, "runAddAccountForAuthenticator: " + type);
365 }
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700366 final Bundle options = getIntent().getBundleExtra(
367 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE);
368 final String[] requiredFeatures = getIntent().getStringArrayExtra(
369 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY);
370 final String authTokenType = getIntent().getStringExtra(
371 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING);
372 AccountManager.get(this).addAccount(type, authTokenType, requiredFeatures,
Fred Quintanae9095bd2011-10-11 17:47:58 -0700373 options, null /* activity */, this /* callback */, null /* Handler */);
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700374 }
375
Alice Yang727c5992012-05-29 13:31:04 -0700376 @Override
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700377 public void run(final AccountManagerFuture<Bundle> accountManagerFuture) {
378 try {
379 final Bundle accountManagerResult = accountManagerFuture.getResult();
Fred Quintanae9095bd2011-10-11 17:47:58 -0700380 final Intent intent = (Intent)accountManagerResult.getParcelable(
381 AccountManager.KEY_INTENT);
382 if (intent != null) {
383 mPendingRequest = REQUEST_ADD_ACCOUNT;
Amith Yamasani27db4682013-03-30 17:07:47 -0700384 mExistingAccounts = AccountManager.get(this).getAccountsForPackage(mCallingPackage,
385 mCallingUid);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700386 intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
387 startActivityForResult(intent, REQUEST_ADD_ACCOUNT);
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700388 return;
389 }
390 } catch (OperationCanceledException e) {
391 setResult(Activity.RESULT_CANCELED);
392 finish();
393 return;
394 } catch (IOException e) {
395 } catch (AuthenticatorException e) {
396 }
397 Bundle bundle = new Bundle();
398 bundle.putString(AccountManager.KEY_ERROR_MESSAGE, "error communicating with server");
399 setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
400 finish();
401 }
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700402
Alice Yang727c5992012-05-29 13:31:04 -0700403 private void onAccountSelected(Account account) {
404 Log.d(TAG, "selected account " + account);
405 setResultAndFinish(account.name, account.type);
Fred Quintana1121bb52011-09-14 23:19:35 -0700406 }
407
408 private void setResultAndFinish(final String accountName, final String accountType) {
409 Bundle bundle = new Bundle();
410 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
411 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
412 setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
Fred Quintanae9095bd2011-10-11 17:47:58 -0700413 if (Log.isLoggable(TAG, Log.VERBOSE)) {
414 Log.v(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: "
415 + "selected account " + accountName + ", " + accountType);
416 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700417 finish();
418 }
419
420 private void startChooseAccountTypeActivity() {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700421 if (Log.isLoggable(TAG, Log.VERBOSE)) {
422 Log.v(TAG, "ChooseAccountTypeActivity.startChooseAccountTypeActivity()");
423 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700424 final Intent intent = new Intent(this, ChooseAccountTypeActivity.class);
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700425 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
Fred Quintanaa77253a2011-09-19 15:28:18 -0700426 intent.putExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
427 getIntent().getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY));
Fred Quintana1121bb52011-09-14 23:19:35 -0700428 intent.putExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700429 getIntent().getBundleExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE));
430 intent.putExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,
431 getIntent().getStringArrayExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY));
432 intent.putExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,
Fred Quintanaa77253a2011-09-19 15:28:18 -0700433 getIntent().getStringExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING));
Fred Quintanae9095bd2011-10-11 17:47:58 -0700434 startActivityForResult(intent, REQUEST_CHOOSE_TYPE);
435 mPendingRequest = REQUEST_CHOOSE_TYPE;
Fred Quintana1121bb52011-09-14 23:19:35 -0700436 }
Jatin Lodhia8d167782012-09-12 13:59:33 -0700437
438 /**
439 * @return a value between 0 (inclusive) and accounts.size() (inclusive) or SELECTED_ITEM_NONE.
440 * An index value of accounts.size() indicates 'Add account' option.
441 */
442 private int getItemIndexToSelect(ArrayList<Account> accounts, String selectedAccountName,
443 boolean selectedAddNewAccount) {
444 // If "Add account" option was previously selected by user, preserve it across
445 // orientation changes.
446 if (selectedAddNewAccount) {
447 return accounts.size();
448 }
449 // search for the selected account name if present
450 for (int i = 0; i < accounts.size(); i++) {
451 if (accounts.get(i).name.equals(selectedAccountName)) {
452 return i;
453 }
454 }
455 // no account selected.
456 return SELECTED_ITEM_NONE;
457 }
458
459 private String[] getListOfDisplayableOptions(ArrayList<Account> accounts) {
460 // List of options includes all accounts found together with "Add new account" as the
461 // last item in the list.
Amith Yamasani27db4682013-03-30 17:07:47 -0700462 String[] listItems = new String[accounts.size() + (mDisallowAddAccounts ? 0 : 1)];
Jatin Lodhia8d167782012-09-12 13:59:33 -0700463 for (int i = 0; i < accounts.size(); i++) {
464 listItems[i] = accounts.get(i).name;
465 }
Amith Yamasani27db4682013-03-30 17:07:47 -0700466 if (!mDisallowAddAccounts) {
467 listItems[accounts.size()] = getResources().getString(
468 R.string.add_account_button_label);
469 }
Jatin Lodhia8d167782012-09-12 13:59:33 -0700470 return listItems;
471 }
472
473 /**
474 * Create a list of Account objects for each account that is acceptable. Filter out
475 * accounts that don't match the allowable types, if provided, or that don't match the
476 * allowable accounts, if provided.
477 */
478 private ArrayList<Account> getAcceptableAccountChoices(AccountManager accountManager) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700479 final Account[] accounts = accountManager.getAccountsForPackage(mCallingPackage,
480 mCallingUid);
Jatin Lodhia8d167782012-09-12 13:59:33 -0700481 ArrayList<Account> accountsToPopulate = new ArrayList<Account>(accounts.length);
482 for (Account account : accounts) {
483 if (mSetOfAllowableAccounts != null
484 && !mSetOfAllowableAccounts.contains(account)) {
485 continue;
486 }
487 if (mSetOfRelevantAccountTypes != null
488 && !mSetOfRelevantAccountTypes.contains(account.type)) {
489 continue;
490 }
491 accountsToPopulate.add(account);
492 }
493 return accountsToPopulate;
494 }
495
496 /**
497 * Return a set of account types speficied by the intent as well as supported by the
498 * AccountManager.
499 */
500 private Set<String> getReleventAccountTypes(final Intent intent) {
501 // An account type is relevant iff it is allowed by the caller and supported by the account
502 // manager.
503 Set<String> setOfRelevantAccountTypes = null;
504 final String[] allowedAccountTypes =
505 intent.getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
506 if (allowedAccountTypes != null) {
507 setOfRelevantAccountTypes = Sets.newHashSet(allowedAccountTypes);
508 AuthenticatorDescription[] descs = AccountManager.get(this).getAuthenticatorTypes();
509 Set<String> supportedAccountTypes = new HashSet<String>(descs.length);
510 for (AuthenticatorDescription desc : descs) {
511 supportedAccountTypes.add(desc.type);
512 }
513 setOfRelevantAccountTypes.retainAll(supportedAccountTypes);
514 }
515 return setOfRelevantAccountTypes;
516 }
517
518 /**
519 * Returns a set of whitelisted accounts given by the intent or null if none specified by the
520 * intent.
521 */
522 private Set<Account> getAllowableAccountSet(final Intent intent) {
523 Set<Account> setOfAllowableAccounts = null;
524 final ArrayList<Parcelable> validAccounts =
525 intent.getParcelableArrayListExtra(EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST);
526 if (validAccounts != null) {
527 setOfAllowableAccounts = new HashSet<Account>(validAccounts.size());
528 for (Parcelable parcelable : validAccounts) {
529 setOfAllowableAccounts.add((Account)parcelable);
530 }
531 }
532 return setOfAllowableAccounts;
533 }
534
535 /**
536 * Overrides the description text view for the picker activity if specified by the intent.
537 * If not specified then makes the description invisible.
538 */
539 private void overrideDescriptionIfSupplied(String descriptionOverride) {
540 TextView descriptionView = (TextView) findViewById(R.id.description);
541 if (!TextUtils.isEmpty(descriptionOverride)) {
542 descriptionView.setText(descriptionOverride);
543 } else {
544 descriptionView.setVisibility(View.GONE);
545 }
546 }
547
548 /**
549 * Populates the UI ListView with the given list of items and selects an item
550 * based on {@code mSelectedItemIndex} member variable.
551 */
552 private final void populateUIAccountList(String[] listItems) {
553 ListView list = (ListView) findViewById(android.R.id.list);
554 list.setAdapter(new ArrayAdapter<String>(this,
555 android.R.layout.simple_list_item_single_choice, listItems));
556 list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
557 list.setItemsCanFocus(false);
558 list.setOnItemClickListener(
559 new AdapterView.OnItemClickListener() {
560 @Override
561 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
562 mSelectedItemIndex = position;
563 mOkButton.setEnabled(true);
564 }
565 });
566 if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
567 list.setItemChecked(mSelectedItemIndex, true);
568 if (Log.isLoggable(TAG, Log.VERBOSE)) {
569 Log.v(TAG, "List item " + mSelectedItemIndex + " should be selected");
570 }
571 }
572 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700573}