Merge "Update account list on account picker activity resume" into jb-mr1-dev

This commit is contained in:
Jatin Lodhia
2012-09-14 14:41:59 -07:00
committed by Android (Google) Code Review

View File

@@ -15,6 +15,8 @@
*/ */
package android.accounts; package android.accounts;
import com.google.android.collect.Sets;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
@@ -105,6 +107,13 @@ public class ChooseTypeAndAccountActivity extends Activity
private static final int SELECTED_ITEM_NONE = -1; private static final int SELECTED_ITEM_NONE = -1;
private Set<Account> mSetOfAllowableAccounts;
private Set<String> mSetOfRelevantAccountTypes;
private String mSelectedAccountName = null;
private boolean mSelectedAddNewAccount = false;
private boolean mAlwaysPromptForAccount = false;
private String mDescriptionOverride;
private ArrayList<Account> mAccounts; private ArrayList<Account> mAccounts;
private int mPendingRequest = REQUEST_NULL; private int mPendingRequest = REQUEST_NULL;
private Parcelable[] mExistingAccounts = null; private Parcelable[] mExistingAccounts = null;
@@ -120,22 +129,18 @@ public class ChooseTypeAndAccountActivity extends Activity
} }
// save some items we use frequently // save some items we use frequently
final AccountManager accountManager = AccountManager.get(this);
final Intent intent = getIntent(); final Intent intent = getIntent();
String selectedAccountName = null;
boolean selectedAddNewAccount = false;
if (savedInstanceState != null) { if (savedInstanceState != null) {
mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST); mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
mExistingAccounts = mExistingAccounts =
savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS); savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
// Makes sure that any user selection is preserved across orientation changes. // Makes sure that any user selection is preserved across orientation changes.
selectedAccountName = savedInstanceState.getString( mSelectedAccountName = savedInstanceState.getString(
KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME); KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
selectedAddNewAccount = savedInstanceState.getBoolean( mSelectedAddNewAccount = savedInstanceState.getBoolean(
KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false); KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
} else { } else {
mPendingRequest = REQUEST_NULL; mPendingRequest = REQUEST_NULL;
@@ -144,85 +149,38 @@ public class ChooseTypeAndAccountActivity extends Activity
// show is as pre-selected. // show is as pre-selected.
Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT); Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
if (selectedAccount != null) { if (selectedAccount != null) {
selectedAccountName = selectedAccount.name; mSelectedAccountName = selectedAccount.name;
} }
} }
if (Log.isLoggable(TAG, Log.VERBOSE)) { if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "selected account name is " + selectedAccountName); Log.v(TAG, "selected account name is " + mSelectedAccountName);
} }
// build an efficiently queryable map of account types to authenticator descriptions
final HashMap<String, AuthenticatorDescription> typeToAuthDescription = mSetOfAllowableAccounts = getAllowableAccountSet(intent);
new HashMap<String, AuthenticatorDescription>(); mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);
for(AuthenticatorDescription desc : accountManager.getAuthenticatorTypes()) { mAlwaysPromptForAccount = intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false);
typeToAuthDescription.put(desc.type, desc); mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
} }
// Read the validAccounts, if present, and add them to the setOfAllowableAccounts @Override
Set<Account> setOfAllowableAccounts = null; protected void onResume() {
final ArrayList<Parcelable> validAccounts = super.onResume();
intent.getParcelableArrayListExtra(EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST); final AccountManager accountManager = AccountManager.get(this);
if (validAccounts != null) {
setOfAllowableAccounts = new HashSet<Account>(validAccounts.size());
for (Parcelable parcelable : validAccounts) {
setOfAllowableAccounts.add((Account)parcelable);
}
}
// An account type is relevant iff it is allowed by the caller and supported by the account mAccounts = getAcceptableAccountChoices(accountManager);
// manager.
Set<String> setOfRelevantAccountTypes = null;
final String[] allowedAccountTypes =
intent.getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
if (allowedAccountTypes != null) {
setOfRelevantAccountTypes = new HashSet<String>(allowedAccountTypes.length);
Set<String> setOfAllowedAccountTypes = new HashSet<String>(allowedAccountTypes.length);
for (String type : allowedAccountTypes) {
setOfAllowedAccountTypes.add(type);
}
AuthenticatorDescription[] descs = AccountManager.get(this).getAuthenticatorTypes();
Set<String> supportedAccountTypes = new HashSet<String>(descs.length);
for (AuthenticatorDescription desc : descs) {
supportedAccountTypes.add(desc.type);
}
for (String acctType : setOfAllowedAccountTypes) {
if (supportedAccountTypes.contains(acctType)) {
setOfRelevantAccountTypes.add(acctType);
}
}
}
// Create a list of AccountInfo objects for each account that is allowable. Filter out
// accounts that don't match the allowable types, if provided, or that don't match the
// allowable accounts, if provided.
final Account[] accounts = accountManager.getAccounts();
mAccounts = new ArrayList<Account>(accounts.length);
mSelectedItemIndex = SELECTED_ITEM_NONE;
for (Account account : accounts) {
if (setOfAllowableAccounts != null
&& !setOfAllowableAccounts.contains(account)) {
continue;
}
if (setOfRelevantAccountTypes != null
&& !setOfRelevantAccountTypes.contains(account.type)) {
continue;
}
if (account.name.equals(selectedAccountName)) {
mSelectedItemIndex = mAccounts.size();
}
mAccounts.add(account);
}
// In cases where the activity does not need to show an account picker, cut the chase
// and return the result directly. Eg:
// Single account -> select it directly
// No account -> launch add account activity directly
if (mPendingRequest == REQUEST_NULL) { if (mPendingRequest == REQUEST_NULL) {
// If there are no relevant accounts and only one relevant account type go directly to // If there are no relevant accounts and only one relevant account type go directly to
// add account. Otherwise let the user choose. // add account. Otherwise let the user choose.
if (mAccounts.isEmpty()) { if (mAccounts.isEmpty()) {
if (setOfRelevantAccountTypes.size() == 1) { if (mSetOfRelevantAccountTypes.size() == 1) {
runAddAccountForAuthenticator(setOfRelevantAccountTypes.iterator().next()); runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next());
} else { } else {
startChooseAccountTypeActivity(); startChooseAccountTypeActivity();
} }
@@ -230,61 +188,22 @@ public class ChooseTypeAndAccountActivity extends Activity
} }
// if there is only one allowable account return it // if there is only one allowable account return it
if (!intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false) if (!mAlwaysPromptForAccount && mAccounts.size() == 1) {
&& mAccounts.size() == 1) {
Account account = mAccounts.get(0); Account account = mAccounts.get(0);
setResultAndFinish(account.name, account.type); setResultAndFinish(account.name, account.type);
return; return;
} }
} }
String[] listItems = getListOfDisplayableOptions(mAccounts);
mSelectedItemIndex = getItemIndexToSelect(
mAccounts, mSelectedAccountName, mSelectedAddNewAccount);
// Cannot set content view until we know that mPendingRequest is not null, otherwise // Cannot set content view until we know that mPendingRequest is not null, otherwise
// would cause screen flicker. // would cause screen flicker.
setContentView(R.layout.choose_type_and_account); setContentView(R.layout.choose_type_and_account);
overrideDescriptionIfSupplied(mDescriptionOverride);
// Override the description text if supplied populateUIAccountList(listItems);
final String descriptionOverride =
intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
TextView descriptionView = (TextView) findViewById(R.id.description);
if (!TextUtils.isEmpty(descriptionOverride)) {
descriptionView.setText(descriptionOverride);
} else {
descriptionView.setVisibility(View.GONE);
}
// List of options includes all accounts found together with "Add new account" as the
// last item in the list.
String[] listItems = new String[mAccounts.size() + 1];
for (int i = 0; i < mAccounts.size(); i++) {
listItems[i] = mAccounts.get(i).name;
}
listItems[mAccounts.size()] = getResources().getString(
R.string.add_account_button_label);
ListView list = (ListView) findViewById(android.R.id.list);
list.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_single_choice, listItems));
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
list.setItemsCanFocus(false);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
mSelectedItemIndex = position;
mOkButton.setEnabled(true);
}
});
// If "Add account" option was previously selected by user, preserve it across
// orientation changes.
if (selectedAddNewAccount) {
mSelectedItemIndex = mAccounts.size();
}
if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
list.setItemChecked(mSelectedItemIndex, true);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "List item " + mSelectedItemIndex + " should be selected");
}
}
// Only enable "OK" button if something has been selected. // Only enable "OK" button if something has been selected.
mOkButton = (Button) findViewById(android.R.id.button2); mOkButton = (Button) findViewById(android.R.id.button2);
@@ -480,4 +399,137 @@ public class ChooseTypeAndAccountActivity extends Activity
startActivityForResult(intent, REQUEST_CHOOSE_TYPE); startActivityForResult(intent, REQUEST_CHOOSE_TYPE);
mPendingRequest = REQUEST_CHOOSE_TYPE; mPendingRequest = REQUEST_CHOOSE_TYPE;
} }
/**
* @return a value between 0 (inclusive) and accounts.size() (inclusive) or SELECTED_ITEM_NONE.
* An index value of accounts.size() indicates 'Add account' option.
*/
private int getItemIndexToSelect(ArrayList<Account> accounts, String selectedAccountName,
boolean selectedAddNewAccount) {
// If "Add account" option was previously selected by user, preserve it across
// orientation changes.
if (selectedAddNewAccount) {
return accounts.size();
}
// search for the selected account name if present
for (int i = 0; i < accounts.size(); i++) {
if (accounts.get(i).name.equals(selectedAccountName)) {
return i;
}
}
// no account selected.
return SELECTED_ITEM_NONE;
}
private String[] getListOfDisplayableOptions(ArrayList<Account> accounts) {
// List of options includes all accounts found together with "Add new account" as the
// last item in the list.
String[] listItems = new String[accounts.size() + 1];
for (int i = 0; i < accounts.size(); i++) {
listItems[i] = accounts.get(i).name;
}
listItems[accounts.size()] = getResources().getString(
R.string.add_account_button_label);
return listItems;
}
/**
* Create a list of Account objects for each account that is acceptable. Filter out
* accounts that don't match the allowable types, if provided, or that don't match the
* allowable accounts, if provided.
*/
private ArrayList<Account> getAcceptableAccountChoices(AccountManager accountManager) {
final Account[] accounts = accountManager.getAccounts();
ArrayList<Account> accountsToPopulate = new ArrayList<Account>(accounts.length);
for (Account account : accounts) {
if (mSetOfAllowableAccounts != null
&& !mSetOfAllowableAccounts.contains(account)) {
continue;
}
if (mSetOfRelevantAccountTypes != null
&& !mSetOfRelevantAccountTypes.contains(account.type)) {
continue;
}
accountsToPopulate.add(account);
}
return accountsToPopulate;
}
/**
* Return a set of account types speficied by the intent as well as supported by the
* AccountManager.
*/
private Set<String> getReleventAccountTypes(final Intent intent) {
// An account type is relevant iff it is allowed by the caller and supported by the account
// manager.
Set<String> setOfRelevantAccountTypes = null;
final String[] allowedAccountTypes =
intent.getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY);
if (allowedAccountTypes != null) {
setOfRelevantAccountTypes = Sets.newHashSet(allowedAccountTypes);
AuthenticatorDescription[] descs = AccountManager.get(this).getAuthenticatorTypes();
Set<String> supportedAccountTypes = new HashSet<String>(descs.length);
for (AuthenticatorDescription desc : descs) {
supportedAccountTypes.add(desc.type);
}
setOfRelevantAccountTypes.retainAll(supportedAccountTypes);
}
return setOfRelevantAccountTypes;
}
/**
* Returns a set of whitelisted accounts given by the intent or null if none specified by the
* intent.
*/
private Set<Account> getAllowableAccountSet(final Intent intent) {
Set<Account> setOfAllowableAccounts = null;
final ArrayList<Parcelable> validAccounts =
intent.getParcelableArrayListExtra(EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST);
if (validAccounts != null) {
setOfAllowableAccounts = new HashSet<Account>(validAccounts.size());
for (Parcelable parcelable : validAccounts) {
setOfAllowableAccounts.add((Account)parcelable);
}
}
return setOfAllowableAccounts;
}
/**
* Overrides the description text view for the picker activity if specified by the intent.
* If not specified then makes the description invisible.
*/
private void overrideDescriptionIfSupplied(String descriptionOverride) {
TextView descriptionView = (TextView) findViewById(R.id.description);
if (!TextUtils.isEmpty(descriptionOverride)) {
descriptionView.setText(descriptionOverride);
} else {
descriptionView.setVisibility(View.GONE);
}
}
/**
* Populates the UI ListView with the given list of items and selects an item
* based on {@code mSelectedItemIndex} member variable.
*/
private final void populateUIAccountList(String[] listItems) {
ListView list = (ListView) findViewById(android.R.id.list);
list.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_single_choice, listItems));
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
list.setItemsCanFocus(false);
list.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
mSelectedItemIndex = position;
mOkButton.setEnabled(true);
}
});
if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
list.setItemChecked(mSelectedItemIndex, true);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "List item " + mSelectedItemIndex + " should be selected");
}
}
}
} }