Skip to content

Commit 8d16778

Browse files
committed
Update account list on account picker activity resume
Activities which help select an account gather the list of accounts only during create and dont update it agian. When a user moves out of the account selection activity by clicking home page, deletes an accout in the background and comes back to the earlier accout selection activity, the deleted account still exists as an option. This cl fixes this by updating the account list on resume. Bug: 7135608 Change-Id: Idc9a2fa6451b032310c0ad66f6db0e2f0967feeb
1 parent 1679b36 commit 8d16778

File tree

1 file changed

+169
-117
lines changed

1 file changed

+169
-117
lines changed

core/java/android/accounts/ChooseTypeAndAccountActivity.java

Lines changed: 169 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package android.accounts;
1717

18+
import com.google.android.collect.Sets;
19+
1820
import android.app.Activity;
1921
import android.content.Intent;
2022
import android.os.Bundle;
@@ -105,6 +107,13 @@ public class ChooseTypeAndAccountActivity extends Activity
105107

106108
private static final int SELECTED_ITEM_NONE = -1;
107109

110+
private Set<Account> mSetOfAllowableAccounts;
111+
private Set<String> mSetOfRelevantAccountTypes;
112+
private String mSelectedAccountName = null;
113+
private boolean mSelectedAddNewAccount = false;
114+
private boolean mAlwaysPromptForAccount = false;
115+
private String mDescriptionOverride;
116+
108117
private ArrayList<Account> mAccounts;
109118
private int mPendingRequest = REQUEST_NULL;
110119
private Parcelable[] mExistingAccounts = null;
@@ -120,22 +129,18 @@ public void onCreate(Bundle savedInstanceState) {
120129
}
121130

122131
// save some items we use frequently
123-
final AccountManager accountManager = AccountManager.get(this);
124132
final Intent intent = getIntent();
125133

126-
String selectedAccountName = null;
127-
boolean selectedAddNewAccount = false;
128-
129134
if (savedInstanceState != null) {
130135
mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
131136
mExistingAccounts =
132137
savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
133138

134139
// Makes sure that any user selection is preserved across orientation changes.
135-
selectedAccountName = savedInstanceState.getString(
140+
mSelectedAccountName = savedInstanceState.getString(
136141
KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
137142

138-
selectedAddNewAccount = savedInstanceState.getBoolean(
143+
mSelectedAddNewAccount = savedInstanceState.getBoolean(
139144
KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
140145
} else {
141146
mPendingRequest = REQUEST_NULL;
@@ -144,147 +149,61 @@ public void onCreate(Bundle savedInstanceState) {
144149
// show is as pre-selected.
145150
Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
146151
if (selectedAccount != null) {
147-
selectedAccountName = selectedAccount.name;
152+
mSelectedAccountName = selectedAccount.name;
148153
}
149154
}
150155

151156
if (Log.isLoggable(TAG, Log.VERBOSE)) {
152-
Log.v(TAG, "selected account name is " + selectedAccountName);
157+
Log.v(TAG, "selected account name is " + mSelectedAccountName);
153158
}
154159

155-
// build an efficiently queryable map of account types to authenticator descriptions
156-
final HashMap<String, AuthenticatorDescription> typeToAuthDescription =
157-
new HashMap<String, AuthenticatorDescription>();
158-
for(AuthenticatorDescription desc : accountManager.getAuthenticatorTypes()) {
159-
typeToAuthDescription.put(desc.type, desc);
160-
}
161-
162-
// Read the validAccounts, if present, and add them to the setOfAllowableAccounts
163-
Set<Account> setOfAllowableAccounts = null;
164-
final ArrayList<Parcelable> validAccounts =
165-
intent.getParcelableArrayListExtra(EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST);
166-
if (validAccounts != null) {
167-
setOfAllowableAccounts = new HashSet<Account>(validAccounts.size());
168-
for (Parcelable parcelable : validAccounts) {
169-
setOfAllowableAccounts.add((Account)parcelable);
170-
}
171-
}
172160

173-
// An account type is relevant iff it is allowed by the caller and supported by the account
174-
// manager.
175-
Set<String> setOfRelevantAccountTypes = null;
176-
final String[] allowedAccountTypes =
177-
intent.getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
178-
if (allowedAccountTypes != null) {
179-
180-
setOfRelevantAccountTypes = new HashSet<String>(allowedAccountTypes.length);
181-
Set<String> setOfAllowedAccountTypes = new HashSet<String>(allowedAccountTypes.length);
182-
for (String type : allowedAccountTypes) {
183-
setOfAllowedAccountTypes.add(type);
184-
}
185-
186-
AuthenticatorDescription[] descs = AccountManager.get(this).getAuthenticatorTypes();
187-
Set<String> supportedAccountTypes = new HashSet<String>(descs.length);
188-
for (AuthenticatorDescription desc : descs) {
189-
supportedAccountTypes.add(desc.type);
190-
}
161+
mSetOfAllowableAccounts = getAllowableAccountSet(intent);
162+
mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);
163+
mAlwaysPromptForAccount = intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false);
164+
mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
165+
}
191166

192-
for (String acctType : setOfAllowedAccountTypes) {
193-
if (supportedAccountTypes.contains(acctType)) {
194-
setOfRelevantAccountTypes.add(acctType);
195-
}
196-
}
197-
}
167+
@Override
168+
protected void onResume() {
169+
super.onResume();
170+
final AccountManager accountManager = AccountManager.get(this);
198171

199-
// Create a list of AccountInfo objects for each account that is allowable. Filter out
200-
// accounts that don't match the allowable types, if provided, or that don't match the
201-
// allowable accounts, if provided.
202-
final Account[] accounts = accountManager.getAccounts();
203-
mAccounts = new ArrayList<Account>(accounts.length);
204-
mSelectedItemIndex = SELECTED_ITEM_NONE;
205-
for (Account account : accounts) {
206-
if (setOfAllowableAccounts != null
207-
&& !setOfAllowableAccounts.contains(account)) {
208-
continue;
209-
}
210-
if (setOfRelevantAccountTypes != null
211-
&& !setOfRelevantAccountTypes.contains(account.type)) {
212-
continue;
213-
}
214-
if (account.name.equals(selectedAccountName)) {
215-
mSelectedItemIndex = mAccounts.size();
216-
}
217-
mAccounts.add(account);
218-
}
172+
mAccounts = getAcceptableAccountChoices(accountManager);
219173

174+
// In cases where the activity does not need to show an account picker, cut the chase
175+
// and return the result directly. Eg:
176+
// Single account -> select it directly
177+
// No account -> launch add account activity directly
220178
if (mPendingRequest == REQUEST_NULL) {
221179
// If there are no relevant accounts and only one relevant account type go directly to
222180
// add account. Otherwise let the user choose.
223181
if (mAccounts.isEmpty()) {
224-
if (setOfRelevantAccountTypes.size() == 1) {
225-
runAddAccountForAuthenticator(setOfRelevantAccountTypes.iterator().next());
182+
if (mSetOfRelevantAccountTypes.size() == 1) {
183+
runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next());
226184
} else {
227185
startChooseAccountTypeActivity();
228186
}
229187
return;
230188
}
231189

232190
// if there is only one allowable account return it
233-
if (!intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false)
234-
&& mAccounts.size() == 1) {
191+
if (!mAlwaysPromptForAccount && mAccounts.size() == 1) {
235192
Account account = mAccounts.get(0);
236193
setResultAndFinish(account.name, account.type);
237194
return;
238195
}
239196
}
240197

198+
String[] listItems = getListOfDisplayableOptions(mAccounts);
199+
mSelectedItemIndex = getItemIndexToSelect(
200+
mAccounts, mSelectedAccountName, mSelectedAddNewAccount);
201+
241202
// Cannot set content view until we know that mPendingRequest is not null, otherwise
242203
// would cause screen flicker.
243204
setContentView(R.layout.choose_type_and_account);
244-
245-
// Override the description text if supplied
246-
final String descriptionOverride =
247-
intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
248-
TextView descriptionView = (TextView) findViewById(R.id.description);
249-
if (!TextUtils.isEmpty(descriptionOverride)) {
250-
descriptionView.setText(descriptionOverride);
251-
} else {
252-
descriptionView.setVisibility(View.GONE);
253-
}
254-
255-
// List of options includes all accounts found together with "Add new account" as the
256-
// last item in the list.
257-
String[] listItems = new String[mAccounts.size() + 1];
258-
for (int i = 0; i < mAccounts.size(); i++) {
259-
listItems[i] = mAccounts.get(i).name;
260-
}
261-
listItems[mAccounts.size()] = getResources().getString(
262-
R.string.add_account_button_label);
263-
264-
ListView list = (ListView) findViewById(android.R.id.list);
265-
list.setAdapter(new ArrayAdapter<String>(this,
266-
android.R.layout.simple_list_item_single_choice, listItems));
267-
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
268-
list.setItemsCanFocus(false);
269-
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
270-
@Override
271-
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
272-
mSelectedItemIndex = position;
273-
mOkButton.setEnabled(true);
274-
}
275-
});
276-
277-
// If "Add account" option was previously selected by user, preserve it across
278-
// orientation changes.
279-
if (selectedAddNewAccount) {
280-
mSelectedItemIndex = mAccounts.size();
281-
}
282-
if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
283-
list.setItemChecked(mSelectedItemIndex, true);
284-
if (Log.isLoggable(TAG, Log.VERBOSE)) {
285-
Log.v(TAG, "List item " + mSelectedItemIndex + " should be selected");
286-
}
287-
}
205+
overrideDescriptionIfSupplied(mDescriptionOverride);
206+
populateUIAccountList(listItems);
288207

289208
// Only enable "OK" button if something has been selected.
290209
mOkButton = (Button) findViewById(android.R.id.button2);
@@ -480,4 +399,137 @@ private void startChooseAccountTypeActivity() {
480399
startActivityForResult(intent, REQUEST_CHOOSE_TYPE);
481400
mPendingRequest = REQUEST_CHOOSE_TYPE;
482401
}
402+
403+
/**
404+
* @return a value between 0 (inclusive) and accounts.size() (inclusive) or SELECTED_ITEM_NONE.
405+
* An index value of accounts.size() indicates 'Add account' option.
406+
*/
407+
private int getItemIndexToSelect(ArrayList<Account> accounts, String selectedAccountName,
408+
boolean selectedAddNewAccount) {
409+
// If "Add account" option was previously selected by user, preserve it across
410+
// orientation changes.
411+
if (selectedAddNewAccount) {
412+
return accounts.size();
413+
}
414+
// search for the selected account name if present
415+
for (int i = 0; i < accounts.size(); i++) {
416+
if (accounts.get(i).name.equals(selectedAccountName)) {
417+
return i;
418+
}
419+
}
420+
// no account selected.
421+
return SELECTED_ITEM_NONE;
422+
}
423+
424+
private String[] getListOfDisplayableOptions(ArrayList<Account> accounts) {
425+
// List of options includes all accounts found together with "Add new account" as the
426+
// last item in the list.
427+
String[] listItems = new String[accounts.size() + 1];
428+
for (int i = 0; i < accounts.size(); i++) {
429+
listItems[i] = accounts.get(i).name;
430+
}
431+
listItems[accounts.size()] = getResources().getString(
432+
R.string.add_account_button_label);
433+
return listItems;
434+
}
435+
436+
/**
437+
* Create a list of Account objects for each account that is acceptable. Filter out
438+
* accounts that don't match the allowable types, if provided, or that don't match the
439+
* allowable accounts, if provided.
440+
*/
441+
private ArrayList<Account> getAcceptableAccountChoices(AccountManager accountManager) {
442+
final Account[] accounts = accountManager.getAccounts();
443+
ArrayList<Account> accountsToPopulate = new ArrayList<Account>(accounts.length);
444+
for (Account account : accounts) {
445+
if (mSetOfAllowableAccounts != null
446+
&& !mSetOfAllowableAccounts.contains(account)) {
447+
continue;
448+
}
449+
if (mSetOfRelevantAccountTypes != null
450+
&& !mSetOfRelevantAccountTypes.contains(account.type)) {
451+
continue;
452+
}
453+
accountsToPopulate.add(account);
454+
}
455+
return accountsToPopulate;
456+
}
457+
458+
/**
459+
* Return a set of account types speficied by the intent as well as supported by the
460+
* AccountManager.
461+
*/
462+
private Set<String> getReleventAccountTypes(final Intent intent) {
463+
// An account type is relevant iff it is allowed by the caller and supported by the account
464+
// manager.
465+
Set<String> setOfRelevantAccountTypes = null;
466+
final String[] allowedAccountTypes =
467+
intent.getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
468+
if (allowedAccountTypes != null) {
469+
setOfRelevantAccountTypes = Sets.newHashSet(allowedAccountTypes);
470+
AuthenticatorDescription[] descs = AccountManager.get(this).getAuthenticatorTypes();
471+
Set<String> supportedAccountTypes = new HashSet<String>(descs.length);
472+
for (AuthenticatorDescription desc : descs) {
473+
supportedAccountTypes.add(desc.type);
474+
}
475+
setOfRelevantAccountTypes.retainAll(supportedAccountTypes);
476+
}
477+
return setOfRelevantAccountTypes;
478+
}
479+
480+
/**
481+
* Returns a set of whitelisted accounts given by the intent or null if none specified by the
482+
* intent.
483+
*/
484+
private Set<Account> getAllowableAccountSet(final Intent intent) {
485+
Set<Account> setOfAllowableAccounts = null;
486+
final ArrayList<Parcelable> validAccounts =
487+
intent.getParcelableArrayListExtra(EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST);
488+
if (validAccounts != null) {
489+
setOfAllowableAccounts = new HashSet<Account>(validAccounts.size());
490+
for (Parcelable parcelable : validAccounts) {
491+
setOfAllowableAccounts.add((Account)parcelable);
492+
}
493+
}
494+
return setOfAllowableAccounts;
495+
}
496+
497+
/**
498+
* Overrides the description text view for the picker activity if specified by the intent.
499+
* If not specified then makes the description invisible.
500+
*/
501+
private void overrideDescriptionIfSupplied(String descriptionOverride) {
502+
TextView descriptionView = (TextView) findViewById(R.id.description);
503+
if (!TextUtils.isEmpty(descriptionOverride)) {
504+
descriptionView.setText(descriptionOverride);
505+
} else {
506+
descriptionView.setVisibility(View.GONE);
507+
}
508+
}
509+
510+
/**
511+
* Populates the UI ListView with the given list of items and selects an item
512+
* based on {@code mSelectedItemIndex} member variable.
513+
*/
514+
private final void populateUIAccountList(String[] listItems) {
515+
ListView list = (ListView) findViewById(android.R.id.list);
516+
list.setAdapter(new ArrayAdapter<String>(this,
517+
android.R.layout.simple_list_item_single_choice, listItems));
518+
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
519+
list.setItemsCanFocus(false);
520+
list.setOnItemClickListener(
521+
new AdapterView.OnItemClickListener() {
522+
@Override
523+
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
524+
mSelectedItemIndex = position;
525+
mOkButton.setEnabled(true);
526+
}
527+
});
528+
if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
529+
list.setItemChecked(mSelectedItemIndex, true);
530+
if (Log.isLoggable(TAG, Log.VERBOSE)) {
531+
Log.v(TAG, "List item " + mSelectedItemIndex + " should be selected");
532+
}
533+
}
534+
}
483535
}

0 commit comments

Comments
 (0)