blob: 133df2bfa16aadafaf5d9baa69cf0151d6edb4e7 [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 /**
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -070091 * Deprecated. Providing this extra to {@link ChooseTypeAndAccountActivity}
92 * will have no effect.
Fred Quintanab04fe4e2011-09-16 21:17:21 -070093 */
Carlos Valdiviaa3db8ac2015-07-10 13:04:43 -070094 @Deprecated
Fred Quintanab04fe4e2011-09-16 21:17:21 -070095 public static final String EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT =
96 "alwaysPromptForAccount";
97
98 /**
99 * If set then this string willb e used as the description rather than
100 * the default.
101 */
102 public static final String EXTRA_DESCRIPTION_TEXT_OVERRIDE =
103 "descriptionTextOverride";
104
Fred Quintanae9095bd2011-10-11 17:47:58 -0700105 public static final int REQUEST_NULL = 0;
106 public static final int REQUEST_CHOOSE_TYPE = 1;
107 public static final int REQUEST_ADD_ACCOUNT = 2;
108
109 private static final String KEY_INSTANCE_STATE_PENDING_REQUEST = "pendingRequest";
110 private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = "existingAccounts";
Alice Yang727c5992012-05-29 13:31:04 -0700111 private static final String KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME = "selectedAccountName";
112 private static final String KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT = "selectedAddAccount";
Carlos Valdivia1b64c9d2013-04-19 01:07:12 -0700113 private static final String KEY_INSTANCE_STATE_ACCOUNT_LIST = "accountList";
Fred Quintanae9095bd2011-10-11 17:47:58 -0700114
Alice Yang727c5992012-05-29 13:31:04 -0700115 private static final int SELECTED_ITEM_NONE = -1;
116
Jatin Lodhia8d167782012-09-12 13:59:33 -0700117 private Set<Account> mSetOfAllowableAccounts;
118 private Set<String> mSetOfRelevantAccountTypes;
119 private String mSelectedAccountName = null;
120 private boolean mSelectedAddNewAccount = false;
Jatin Lodhia8d167782012-09-12 13:59:33 -0700121 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) {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700135 if (Log.isLoggable(TAG, Log.VERBOSE)) {
136 Log.v(TAG, "ChooseTypeAndAccountActivity.onCreate(savedInstanceState="
137 + savedInstanceState + ")");
138 }
139
Amith Yamasani27db4682013-03-30 17:07:47 -0700140 String message = null;
141
142 try {
143 IBinder activityToken = getActivityToken();
144 mCallingUid = ActivityManagerNative.getDefault().getLaunchedFromUid(activityToken);
145 mCallingPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
146 activityToken);
147 if (mCallingUid != 0 && mCallingPackage != null) {
148 Bundle restrictions = UserManager.get(this)
149 .getUserRestrictions(new UserHandle(UserHandle.getUserId(mCallingUid)));
150 mDisallowAddAccounts =
151 restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false);
152 }
153 } catch (RemoteException re) {
154 // Couldn't figure out caller details
155 Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re);
156 }
157
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700158 // save some items we use frequently
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700159 final Intent intent = getIntent();
160
Alice Yang727c5992012-05-29 13:31:04 -0700161 if (savedInstanceState != null) {
162 mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
163 mExistingAccounts =
164 savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
165
166 // Makes sure that any user selection is preserved across orientation changes.
Jatin Lodhia8d167782012-09-12 13:59:33 -0700167 mSelectedAccountName = savedInstanceState.getString(
Alice Yang727c5992012-05-29 13:31:04 -0700168 KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
169
Jatin Lodhia8d167782012-09-12 13:59:33 -0700170 mSelectedAddNewAccount = savedInstanceState.getBoolean(
Alice Yang727c5992012-05-29 13:31:04 -0700171 KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
Carlos Valdivia1b64c9d2013-04-19 01:07:12 -0700172 mAccounts = savedInstanceState.getParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST);
Alice Yang727c5992012-05-29 13:31:04 -0700173 } else {
174 mPendingRequest = REQUEST_NULL;
175 mExistingAccounts = null;
176 // If the selected account as specified in the intent matches one in the list we will
177 // show is as pre-selected.
178 Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
179 if (selectedAccount != null) {
Jatin Lodhia8d167782012-09-12 13:59:33 -0700180 mSelectedAccountName = selectedAccount.name;
Alice Yang727c5992012-05-29 13:31:04 -0700181 }
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700182 }
183
Alice Yang727c5992012-05-29 13:31:04 -0700184 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Jatin Lodhia8d167782012-09-12 13:59:33 -0700185 Log.v(TAG, "selected account name is " + mSelectedAccountName);
Alice Yang727c5992012-05-29 13:31:04 -0700186 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700187
Fred Quintana1121bb52011-09-14 23:19:35 -0700188
Jatin Lodhia8d167782012-09-12 13:59:33 -0700189 mSetOfAllowableAccounts = getAllowableAccountSet(intent);
190 mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);
Jatin Lodhia8d167782012-09-12 13:59:33 -0700191 mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
Amith Yamasani5a3915b2013-05-24 09:53:47 -0700192
Amith Yamasani5a3915b2013-05-24 09:53:47 -0700193 mAccounts = getAcceptableAccountChoices(AccountManager.get(this));
194 if (mAccounts.isEmpty()
195 && mDisallowAddAccounts) {
196 requestWindowFeature(Window.FEATURE_NO_TITLE);
197 setContentView(R.layout.app_not_authorized);
198 mDontShowPicker = true;
199 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700200
Simranjit Singh Kohli734f8fb2015-05-22 14:00:32 -0700201 if (mDontShowPicker) {
202 super.onCreate(savedInstanceState);
203 return;
204 }
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700205
Jatin Lodhia8d167782012-09-12 13:59:33 -0700206 // In cases where the activity does not need to show an account picker, cut the chase
207 // and return the result directly. Eg:
208 // Single account -> select it directly
209 // No account -> launch add account activity directly
Fred Quintanae9095bd2011-10-11 17:47:58 -0700210 if (mPendingRequest == REQUEST_NULL) {
Alice Yang727c5992012-05-29 13:31:04 -0700211 // If there are no relevant accounts and only one relevant account type go directly to
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700212 // add account. Otherwise let the user choose.
Alice Yang727c5992012-05-29 13:31:04 -0700213 if (mAccounts.isEmpty()) {
Simranjit Singh Kohli734f8fb2015-05-22 14:00:32 -0700214 setNonLabelThemeAndCallSuperCreate(savedInstanceState);
Jatin Lodhia8d167782012-09-12 13:59:33 -0700215 if (mSetOfRelevantAccountTypes.size() == 1) {
216 runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next());
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700217 } else {
218 startChooseAccountTypeActivity();
219 }
Fred Quintanae9095bd2011-10-11 17:47:58 -0700220 }
221 }
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700222
Jatin Lodhia8d167782012-09-12 13:59:33 -0700223 String[] listItems = getListOfDisplayableOptions(mAccounts);
224 mSelectedItemIndex = getItemIndexToSelect(
225 mAccounts, mSelectedAccountName, mSelectedAddNewAccount);
226
Simranjit Singh Kohli734f8fb2015-05-22 14:00:32 -0700227 super.onCreate(savedInstanceState);
Carlos Valdiviacf0a8812012-05-16 16:32:06 -0700228 setContentView(R.layout.choose_type_and_account);
Jatin Lodhia8d167782012-09-12 13:59:33 -0700229 overrideDescriptionIfSupplied(mDescriptionOverride);
230 populateUIAccountList(listItems);
Alice Yang6cab5e82012-05-31 15:48:51 -0700231
232 // Only enable "OK" button if something has been selected.
233 mOkButton = (Button) findViewById(android.R.id.button2);
234 mOkButton.setEnabled(mSelectedItemIndex != SELECTED_ITEM_NONE);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700235 }
236
237 @Override
238 protected void onDestroy() {
239 if (Log.isLoggable(TAG, Log.VERBOSE)) {
240 Log.v(TAG, "ChooseTypeAndAccountActivity.onDestroy()");
241 }
242 super.onDestroy();
243 }
244
245 @Override
246 protected void onSaveInstanceState(final Bundle outState) {
247 super.onSaveInstanceState(outState);
248 outState.putInt(KEY_INSTANCE_STATE_PENDING_REQUEST, mPendingRequest);
Fred Quintana01df6a82011-10-17 21:04:47 -0700249 if (mPendingRequest == REQUEST_ADD_ACCOUNT) {
250 outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
251 }
Alice Yang727c5992012-05-29 13:31:04 -0700252 if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
253 if (mSelectedItemIndex == mAccounts.size()) {
254 outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
255 } else {
256 outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
257 outState.putString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME,
258 mAccounts.get(mSelectedItemIndex).name);
259 }
260 }
Carlos Valdivia1b64c9d2013-04-19 01:07:12 -0700261 outState.putParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST, mAccounts);
Alice Yang727c5992012-05-29 13:31:04 -0700262 }
263
264 public void onCancelButtonClicked(View view) {
265 onBackPressed();
266 }
267
268 public void onOkButtonClicked(View view) {
269 if (mSelectedItemIndex == mAccounts.size()) {
270 // Selected "Add New Account" option
271 startChooseAccountTypeActivity();
272 } else if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
273 onAccountSelected(mAccounts.get(mSelectedItemIndex));
274 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700275 }
276
277 // Called when the choose account type activity (for adding an account) returns.
278 // If it was a success read the account and set it in the result. In all cases
279 // return the result and finish this activity.
280 @Override
281 protected void onActivityResult(final int requestCode, final int resultCode,
282 final Intent data) {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700283 if (Log.isLoggable(TAG, Log.VERBOSE)) {
284 if (data != null && data.getExtras() != null) data.getExtras().keySet();
285 Bundle extras = data != null ? data.getExtras() : null;
286 Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult(reqCode=" + requestCode
287 + ", resCode=" + resultCode + ", extras=" + extras + ")");
Fred Quintana1121bb52011-09-14 23:19:35 -0700288 }
Fred Quintanae9095bd2011-10-11 17:47:58 -0700289
290 // we got our result, so clear the fact that we had a pending request
291 mPendingRequest = REQUEST_NULL;
Fred Quintanae9095bd2011-10-11 17:47:58 -0700292
293 if (resultCode == RESULT_CANCELED) {
Alice Yang727c5992012-05-29 13:31:04 -0700294 // if canceling out of addAccount and the original state caused us to skip this,
Fred Quintana2becf932011-11-15 17:33:08 -0800295 // finish this activity
Alice Yang727c5992012-05-29 13:31:04 -0700296 if (mAccounts.isEmpty()) {
Fred Quintana2becf932011-11-15 17:33:08 -0800297 setResult(Activity.RESULT_CANCELED);
298 finish();
299 }
Fred Quintanae9095bd2011-10-11 17:47:58 -0700300 return;
301 }
302
303 if (resultCode == RESULT_OK) {
304 if (requestCode == REQUEST_CHOOSE_TYPE) {
305 if (data != null) {
306 String accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
307 if (accountType != null) {
308 runAddAccountForAuthenticator(accountType);
309 return;
310 }
311 }
312 Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: unable to find account "
313 + "type, pretending the request was canceled");
314 } else if (requestCode == REQUEST_ADD_ACCOUNT) {
315 String accountName = null;
316 String accountType = null;
317
318 if (data != null) {
319 accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
320 accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
321 }
322
323 if (accountName == null || accountType == null) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700324 Account[] currentAccounts = AccountManager.get(this).getAccountsForPackage(
325 mCallingPackage, mCallingUid);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700326 Set<Account> preExistingAccounts = new HashSet<Account>();
Fred Quintana01df6a82011-10-17 21:04:47 -0700327 for (Parcelable accountParcel : mExistingAccounts) {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700328 preExistingAccounts.add((Account) accountParcel);
329 }
330 for (Account account : currentAccounts) {
331 if (!preExistingAccounts.contains(account)) {
332 accountName = account.name;
333 accountType = account.type;
334 break;
335 }
336 }
337 }
338
339 if (accountName != null || accountType != null) {
340 setResultAndFinish(accountName, accountType);
341 return;
342 }
343 }
344 Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: unable to find added "
345 + "account, pretending the request was canceled");
346 }
347 if (Log.isLoggable(TAG, Log.VERBOSE)) {
348 Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult: canceled");
349 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700350 setResult(Activity.RESULT_CANCELED);
351 finish();
352 }
353
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700354 protected void runAddAccountForAuthenticator(String type) {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700355 if (Log.isLoggable(TAG, Log.VERBOSE)) {
356 Log.v(TAG, "runAddAccountForAuthenticator: " + type);
357 }
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700358 final Bundle options = getIntent().getBundleExtra(
359 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE);
360 final String[] requiredFeatures = getIntent().getStringArrayExtra(
361 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY);
362 final String authTokenType = getIntent().getStringExtra(
363 ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING);
364 AccountManager.get(this).addAccount(type, authTokenType, requiredFeatures,
Fred Quintanae9095bd2011-10-11 17:47:58 -0700365 options, null /* activity */, this /* callback */, null /* Handler */);
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700366 }
367
Alice Yang727c5992012-05-29 13:31:04 -0700368 @Override
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700369 public void run(final AccountManagerFuture<Bundle> accountManagerFuture) {
370 try {
371 final Bundle accountManagerResult = accountManagerFuture.getResult();
Fred Quintanae9095bd2011-10-11 17:47:58 -0700372 final Intent intent = (Intent)accountManagerResult.getParcelable(
373 AccountManager.KEY_INTENT);
374 if (intent != null) {
375 mPendingRequest = REQUEST_ADD_ACCOUNT;
Amith Yamasani27db4682013-03-30 17:07:47 -0700376 mExistingAccounts = AccountManager.get(this).getAccountsForPackage(mCallingPackage,
377 mCallingUid);
Fred Quintanae9095bd2011-10-11 17:47:58 -0700378 intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
379 startActivityForResult(intent, REQUEST_ADD_ACCOUNT);
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700380 return;
381 }
382 } catch (OperationCanceledException e) {
383 setResult(Activity.RESULT_CANCELED);
384 finish();
385 return;
386 } catch (IOException e) {
387 } catch (AuthenticatorException e) {
388 }
389 Bundle bundle = new Bundle();
390 bundle.putString(AccountManager.KEY_ERROR_MESSAGE, "error communicating with server");
391 setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
392 finish();
393 }
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700394
Simranjit Singh Kohli734f8fb2015-05-22 14:00:32 -0700395 /**
396 * The default activity theme shows label at the top. Set a theme which does
397 * not show label, which effectively makes the activity invisible. Note that
398 * no content is being set. If something gets set, using this theme may be
399 * useless.
400 */
401 private void setNonLabelThemeAndCallSuperCreate(Bundle savedInstanceState) {
402 setTheme(R.style.Theme_Material_Light_Dialog_NoActionBar);
403 super.onCreate(savedInstanceState);
404 }
405
Alice Yang727c5992012-05-29 13:31:04 -0700406 private void onAccountSelected(Account account) {
407 Log.d(TAG, "selected account " + account);
408 setResultAndFinish(account.name, account.type);
Fred Quintana1121bb52011-09-14 23:19:35 -0700409 }
410
411 private void setResultAndFinish(final String accountName, final String accountType) {
412 Bundle bundle = new Bundle();
413 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
414 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
415 setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
Fred Quintanae9095bd2011-10-11 17:47:58 -0700416 if (Log.isLoggable(TAG, Log.VERBOSE)) {
417 Log.v(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: "
418 + "selected account " + accountName + ", " + accountType);
419 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700420 finish();
421 }
422
423 private void startChooseAccountTypeActivity() {
Fred Quintanae9095bd2011-10-11 17:47:58 -0700424 if (Log.isLoggable(TAG, Log.VERBOSE)) {
425 Log.v(TAG, "ChooseAccountTypeActivity.startChooseAccountTypeActivity()");
426 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700427 final Intent intent = new Intent(this, ChooseAccountTypeActivity.class);
Fred Quintana9bbdd0b2011-09-27 17:24:32 -0700428 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
Fred Quintanaa77253a2011-09-19 15:28:18 -0700429 intent.putExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
430 getIntent().getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY));
Fred Quintana1121bb52011-09-14 23:19:35 -0700431 intent.putExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
Fred Quintanab04fe4e2011-09-16 21:17:21 -0700432 getIntent().getBundleExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE));
433 intent.putExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,
434 getIntent().getStringArrayExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY));
435 intent.putExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,
Fred Quintanaa77253a2011-09-19 15:28:18 -0700436 getIntent().getStringExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING));
Fred Quintanae9095bd2011-10-11 17:47:58 -0700437 startActivityForResult(intent, REQUEST_CHOOSE_TYPE);
438 mPendingRequest = REQUEST_CHOOSE_TYPE;
Fred Quintana1121bb52011-09-14 23:19:35 -0700439 }
Jatin Lodhia8d167782012-09-12 13:59:33 -0700440
441 /**
442 * @return a value between 0 (inclusive) and accounts.size() (inclusive) or SELECTED_ITEM_NONE.
443 * An index value of accounts.size() indicates 'Add account' option.
444 */
445 private int getItemIndexToSelect(ArrayList<Account> accounts, String selectedAccountName,
446 boolean selectedAddNewAccount) {
447 // If "Add account" option was previously selected by user, preserve it across
448 // orientation changes.
449 if (selectedAddNewAccount) {
450 return accounts.size();
451 }
452 // search for the selected account name if present
453 for (int i = 0; i < accounts.size(); i++) {
454 if (accounts.get(i).name.equals(selectedAccountName)) {
455 return i;
456 }
457 }
458 // no account selected.
459 return SELECTED_ITEM_NONE;
460 }
461
462 private String[] getListOfDisplayableOptions(ArrayList<Account> accounts) {
463 // List of options includes all accounts found together with "Add new account" as the
464 // last item in the list.
Amith Yamasani27db4682013-03-30 17:07:47 -0700465 String[] listItems = new String[accounts.size() + (mDisallowAddAccounts ? 0 : 1)];
Jatin Lodhia8d167782012-09-12 13:59:33 -0700466 for (int i = 0; i < accounts.size(); i++) {
467 listItems[i] = accounts.get(i).name;
468 }
Amith Yamasani27db4682013-03-30 17:07:47 -0700469 if (!mDisallowAddAccounts) {
470 listItems[accounts.size()] = getResources().getString(
471 R.string.add_account_button_label);
472 }
Jatin Lodhia8d167782012-09-12 13:59:33 -0700473 return listItems;
474 }
475
476 /**
477 * Create a list of Account objects for each account that is acceptable. Filter out
478 * accounts that don't match the allowable types, if provided, or that don't match the
479 * allowable accounts, if provided.
480 */
481 private ArrayList<Account> getAcceptableAccountChoices(AccountManager accountManager) {
Amith Yamasani27db4682013-03-30 17:07:47 -0700482 final Account[] accounts = accountManager.getAccountsForPackage(mCallingPackage,
483 mCallingUid);
Jatin Lodhia8d167782012-09-12 13:59:33 -0700484 ArrayList<Account> accountsToPopulate = new ArrayList<Account>(accounts.length);
485 for (Account account : accounts) {
Simranjit Singh Kohli734f8fb2015-05-22 14:00:32 -0700486 if (mSetOfAllowableAccounts != null && !mSetOfAllowableAccounts.contains(account)) {
Jatin Lodhia8d167782012-09-12 13:59:33 -0700487 continue;
488 }
489 if (mSetOfRelevantAccountTypes != null
490 && !mSetOfRelevantAccountTypes.contains(account.type)) {
491 continue;
492 }
493 accountsToPopulate.add(account);
494 }
495 return accountsToPopulate;
496 }
497
498 /**
Simranjit Singh Kohli734f8fb2015-05-22 14:00:32 -0700499 * Return a set of account types specified by the intent as well as supported by the
Jatin Lodhia8d167782012-09-12 13:59:33 -0700500 * AccountManager.
501 */
502 private Set<String> getReleventAccountTypes(final Intent intent) {
503 // An account type is relevant iff it is allowed by the caller and supported by the account
504 // manager.
505 Set<String> setOfRelevantAccountTypes = null;
506 final String[] allowedAccountTypes =
507 intent.getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
Simranjit Singh Kohli734f8fb2015-05-22 14:00:32 -0700508 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 if (allowedAccountTypes != null) {
514 setOfRelevantAccountTypes = Sets.newHashSet(allowedAccountTypes);
515 setOfRelevantAccountTypes.retainAll(supportedAccountTypes);
516 } else {
517 setOfRelevantAccountTypes = supportedAccountTypes;
Jatin Lodhia8d167782012-09-12 13:59:33 -0700518 }
519 return setOfRelevantAccountTypes;
520 }
521
522 /**
523 * Returns a set of whitelisted accounts given by the intent or null if none specified by the
524 * intent.
525 */
526 private Set<Account> getAllowableAccountSet(final Intent intent) {
527 Set<Account> setOfAllowableAccounts = null;
528 final ArrayList<Parcelable> validAccounts =
529 intent.getParcelableArrayListExtra(EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST);
530 if (validAccounts != null) {
531 setOfAllowableAccounts = new HashSet<Account>(validAccounts.size());
532 for (Parcelable parcelable : validAccounts) {
533 setOfAllowableAccounts.add((Account)parcelable);
534 }
535 }
536 return setOfAllowableAccounts;
537 }
538
539 /**
540 * Overrides the description text view for the picker activity if specified by the intent.
541 * If not specified then makes the description invisible.
542 */
543 private void overrideDescriptionIfSupplied(String descriptionOverride) {
544 TextView descriptionView = (TextView) findViewById(R.id.description);
545 if (!TextUtils.isEmpty(descriptionOverride)) {
546 descriptionView.setText(descriptionOverride);
547 } else {
548 descriptionView.setVisibility(View.GONE);
549 }
550 }
551
552 /**
553 * Populates the UI ListView with the given list of items and selects an item
554 * based on {@code mSelectedItemIndex} member variable.
555 */
556 private final void populateUIAccountList(String[] listItems) {
557 ListView list = (ListView) findViewById(android.R.id.list);
558 list.setAdapter(new ArrayAdapter<String>(this,
559 android.R.layout.simple_list_item_single_choice, listItems));
560 list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
561 list.setItemsCanFocus(false);
562 list.setOnItemClickListener(
563 new AdapterView.OnItemClickListener() {
564 @Override
565 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
566 mSelectedItemIndex = position;
567 mOkButton.setEnabled(true);
568 }
569 });
570 if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
571 list.setItemChecked(mSelectedItemIndex, true);
572 if (Log.isLoggable(TAG, Log.VERBOSE)) {
573 Log.v(TAG, "List item " + mSelectedItemIndex + " should be selected");
574 }
575 }
576 }
Fred Quintana1121bb52011-09-14 23:19:35 -0700577}