Skip to content

Commit 6c66e98

Browse files
Alice YangAndroid (Google) Code Review
authored andcommitted
Merge "New UI for account picker" into jb-dev
2 parents 5ab6e12 + 727c599 commit 6c66e98

File tree

6 files changed

+144
-204
lines changed

6 files changed

+144
-204
lines changed

core/java/android/accounts/ChooseTypeAndAccountActivity.java

Lines changed: 115 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,19 @@
1616
package android.accounts;
1717

1818
import android.app.Activity;
19-
import android.content.Context;
2019
import android.content.Intent;
21-
import android.content.pm.PackageManager;
22-
import android.content.res.Resources;
23-
import android.graphics.drawable.Drawable;
2420
import android.os.Bundle;
2521
import android.os.Parcelable;
2622
import android.text.TextUtils;
2723
import android.util.Log;
28-
import android.view.LayoutInflater;
2924
import android.view.View;
3025
import android.view.ViewGroup;
3126
import android.widget.AdapterView;
3227
import android.widget.ArrayAdapter;
3328
import android.widget.Button;
34-
import android.widget.ImageView;
3529
import android.widget.ListView;
3630
import android.widget.TextView;
31+
3732
import com.android.internal.R;
3833

3934
import java.io.IOException;
@@ -106,10 +101,16 @@ public class ChooseTypeAndAccountActivity extends Activity
106101

107102
private static final String KEY_INSTANCE_STATE_PENDING_REQUEST = "pendingRequest";
108103
private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = "existingAccounts";
104+
private static final String KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME = "selectedAccountName";
105+
private static final String KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT = "selectedAddAccount";
106+
107+
private static final int SELECTED_ITEM_NONE = -1;
109108

110-
private ArrayList<AccountInfo> mAccountInfos;
109+
private ArrayList<Account> mAccounts;
111110
private int mPendingRequest = REQUEST_NULL;
112111
private Parcelable[] mExistingAccounts = null;
112+
private int mSelectedItemIndex;
113+
private Button mOkButton;
113114

114115
@Override
115116
public void onCreate(Bundle savedInstanceState) {
@@ -119,31 +120,39 @@ public void onCreate(Bundle savedInstanceState) {
119120
+ savedInstanceState + ")");
120121
}
121122

123+
// save some items we use frequently
124+
final AccountManager accountManager = AccountManager.get(this);
125+
final Intent intent = getIntent();
126+
127+
String selectedAccountName = null;
128+
boolean selectedAddNewAccount = false;
129+
122130
if (savedInstanceState != null) {
123131
mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
124132
mExistingAccounts =
125133
savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);
134+
135+
// Makes sure that any user selection is preserved across orientation changes.
136+
selectedAccountName = savedInstanceState.getString(
137+
KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);
138+
139+
selectedAddNewAccount = savedInstanceState.getBoolean(
140+
KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
126141
} else {
127142
mPendingRequest = REQUEST_NULL;
128143
mExistingAccounts = null;
144+
// If the selected account as specified in the intent matches one in the list we will
145+
// show is as pre-selected.
146+
Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
147+
if (selectedAccount != null) {
148+
selectedAccountName = selectedAccount.name;
149+
}
129150
}
130151

131-
// save some items we use frequently
132-
final AccountManager accountManager = AccountManager.get(this);
133-
final Intent intent = getIntent();
134-
135-
// override the description text if supplied
136-
final String descriptionOverride =
137-
intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
138-
if (!TextUtils.isEmpty(descriptionOverride)) {
139-
((TextView)findViewById(R.id.description)).setText(descriptionOverride);
152+
if (Log.isLoggable(TAG, Log.VERBOSE)) {
153+
Log.v(TAG, "selected account name is " + selectedAccountName);
140154
}
141155

142-
// If the selected account matches one in the list we will place a
143-
// checkmark next to it.
144-
final Account selectedAccount =
145-
(Account)intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
146-
147156
// build an efficiently queryable map of account types to authenticator descriptions
148157
final HashMap<String, AuthenticatorDescription> typeToAuthDescription =
149158
new HashMap<String, AuthenticatorDescription>();
@@ -192,7 +201,8 @@ public void onCreate(Bundle savedInstanceState) {
192201
// accounts that don't match the allowable types, if provided, or that don't match the
193202
// allowable accounts, if provided.
194203
final Account[] accounts = accountManager.getAccounts();
195-
mAccountInfos = new ArrayList<AccountInfo>(accounts.length);
204+
mAccounts = new ArrayList<Account>(accounts.length);
205+
mSelectedItemIndex = SELECTED_ITEM_NONE;
196206
for (Account account : accounts) {
197207
if (setOfAllowableAccounts != null
198208
&& !setOfAllowableAccounts.contains(account)) {
@@ -202,15 +212,16 @@ public void onCreate(Bundle savedInstanceState) {
202212
&& !setOfRelevantAccountTypes.contains(account.type)) {
203213
continue;
204214
}
205-
mAccountInfos.add(new AccountInfo(account,
206-
getDrawableForType(typeToAuthDescription, account.type),
207-
account.equals(selectedAccount)));
215+
if (account.name.equals(selectedAccountName)) {
216+
mSelectedItemIndex = mAccounts.size();
217+
}
218+
mAccounts.add(account);
208219
}
209220

210221
if (mPendingRequest == REQUEST_NULL) {
211-
// If there are no relevant accounts and only one relevant account typoe go directly to
222+
// If there are no relevant accounts and only one relevant account type go directly to
212223
// add account. Otherwise let the user choose.
213-
if (mAccountInfos.isEmpty()) {
224+
if (mAccounts.isEmpty()) {
214225
if (setOfRelevantAccountTypes.size() == 1) {
215226
runAddAccountForAuthenticator(setOfRelevantAccountTypes.iterator().next());
216227
} else {
@@ -221,36 +232,71 @@ public void onCreate(Bundle savedInstanceState) {
221232

222233
// if there is only one allowable account return it
223234
if (!intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false)
224-
&& mAccountInfos.size() == 1) {
225-
Account account = mAccountInfos.get(0).account;
235+
&& mAccounts.size() == 1) {
236+
Account account = mAccounts.get(0);
226237
setResultAndFinish(account.name, account.type);
227238
return;
228239
}
229240
}
230241

242+
// Cannot set content view until we know that mPendingRequest is not null, otherwise
243+
// would cause screen flicker.
231244
setContentView(R.layout.choose_type_and_account);
232245

233-
// there is more than one allowable account. initialize the list adapter to allow
234-
// the user to select an account.
246+
// Override the description text if supplied
247+
final String descriptionOverride =
248+
intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);
249+
TextView descriptionView = (TextView) findViewById(R.id.description);
250+
if (!TextUtils.isEmpty(descriptionOverride)) {
251+
descriptionView.setText(descriptionOverride);
252+
} else {
253+
descriptionView.setVisibility(View.GONE);
254+
}
255+
256+
// List of options includes all accounts found together with "Add new account" as the
257+
// last item in the list.
258+
String[] listItems = new String[mAccounts.size() + 1];
259+
for (int i = 0; i < mAccounts.size(); i++) {
260+
listItems[i] = mAccounts.get(i).name;
261+
}
262+
listItems[mAccounts.size()] = getResources().getString(
263+
R.string.add_account_button_label);
264+
235265
ListView list = (ListView) findViewById(android.R.id.list);
236-
list.setAdapter(new AccountArrayAdapter(this,
237-
android.R.layout.simple_list_item_1, mAccountInfos));
266+
list.setAdapter(new ArrayAdapter<String>(this,
267+
android.R.layout.simple_list_item_single_choice, listItems));
238268
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
269+
list.setItemsCanFocus(false);
239270
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
240271
@Override
241272
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
242-
onListItemClick((ListView)parent, v, position, id);
273+
mSelectedItemIndex = position;
274+
mOkButton.setEnabled(true);
243275
}
244276
});
245277

246-
// set the listener for the addAccount button
247-
Button addAccountButton = (Button) findViewById(R.id.addAccount);
248-
addAccountButton.setOnClickListener(new View.OnClickListener() {
249-
@Override
250-
public void onClick(final View v) {
251-
startChooseAccountTypeActivity();
278+
// If "Add account" option was previously selected by user, preserve it across
279+
// orientation changes.
280+
if (selectedAddNewAccount) {
281+
mSelectedItemIndex = mAccounts.size();
282+
}
283+
if (Log.isLoggable(TAG, Log.VERBOSE)) {
284+
Log.v(TAG, "mSelectedItemIndex is " + mSelectedItemIndex);
285+
}
286+
287+
ViewGroup buttonBar = (ViewGroup) findViewById(R.id.button_bar);
288+
if (buttonBar != null) {
289+
mOkButton = (Button) buttonBar.findViewById(android.R.id.button2);
290+
if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
291+
// If caller specified a selectedAccount, then display that as selected and enable
292+
// the "OK" button by default.
293+
list.setSelection(mSelectedItemIndex);
294+
mOkButton.setEnabled(true);
295+
} else {
296+
// Otherwise "OK" button is disabled since nothing is pre-selected.
297+
mOkButton.setEnabled(false);
252298
}
253-
});
299+
}
254300
}
255301

256302
@Override
@@ -268,6 +314,28 @@ protected void onSaveInstanceState(final Bundle outState) {
268314
if (mPendingRequest == REQUEST_ADD_ACCOUNT) {
269315
outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
270316
}
317+
if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
318+
if (mSelectedItemIndex == mAccounts.size()) {
319+
outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
320+
} else {
321+
outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
322+
outState.putString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME,
323+
mAccounts.get(mSelectedItemIndex).name);
324+
}
325+
}
326+
}
327+
328+
public void onCancelButtonClicked(View view) {
329+
onBackPressed();
330+
}
331+
332+
public void onOkButtonClicked(View view) {
333+
if (mSelectedItemIndex == mAccounts.size()) {
334+
// Selected "Add New Account" option
335+
startChooseAccountTypeActivity();
336+
} else if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
337+
onAccountSelected(mAccounts.get(mSelectedItemIndex));
338+
}
271339
}
272340

273341
// Called when the choose account type activity (for adding an account) returns.
@@ -287,9 +355,9 @@ protected void onActivityResult(final int requestCode, final int resultCode,
287355
mPendingRequest = REQUEST_NULL;
288356

289357
if (resultCode == RESULT_CANCELED) {
290-
// if cancelling out of addAccount and the original state caused us to skip this,
358+
// if canceling out of addAccount and the original state caused us to skip this,
291359
// finish this activity
292-
if (mAccountInfos.isEmpty()) {
360+
if (mAccounts.isEmpty()) {
293361
setResult(Activity.RESULT_CANCELED);
294362
finish();
295363
}
@@ -360,6 +428,7 @@ protected void runAddAccountForAuthenticator(String type) {
360428
options, null /* activity */, this /* callback */, null /* Handler */);
361429
}
362430

431+
@Override
363432
public void run(final AccountManagerFuture<Bundle> accountManagerFuture) {
364433
try {
365434
final Bundle accountManagerResult = accountManagerFuture.getResult();
@@ -385,34 +454,9 @@ public void run(final AccountManagerFuture<Bundle> accountManagerFuture) {
385454
finish();
386455
}
387456

388-
private Drawable getDrawableForType(
389-
final HashMap<String, AuthenticatorDescription> typeToAuthDescription,
390-
String accountType) {
391-
Drawable icon = null;
392-
if (typeToAuthDescription.containsKey(accountType)) {
393-
try {
394-
AuthenticatorDescription desc = typeToAuthDescription.get(accountType);
395-
Context authContext = createPackageContext(desc.packageName, 0);
396-
icon = authContext.getResources().getDrawable(desc.iconId);
397-
} catch (PackageManager.NameNotFoundException e) {
398-
// Nothing we can do much here, just log
399-
if (Log.isLoggable(TAG, Log.WARN)) {
400-
Log.w(TAG, "No icon name for account type " + accountType);
401-
}
402-
} catch (Resources.NotFoundException e) {
403-
// Nothing we can do much here, just log
404-
if (Log.isLoggable(TAG, Log.WARN)) {
405-
Log.w(TAG, "No icon resource for account type " + accountType);
406-
}
407-
}
408-
}
409-
return icon;
410-
}
411-
412-
protected void onListItemClick(ListView l, View v, int position, long id) {
413-
AccountInfo accountInfo = mAccountInfos.get(position);
414-
Log.d(TAG, "selected account " + accountInfo.account);
415-
setResultAndFinish(accountInfo.account.name, accountInfo.account.type);
457+
private void onAccountSelected(Account account) {
458+
Log.d(TAG, "selected account " + account);
459+
setResultAndFinish(account.name, account.type);
416460
}
417461

418462
private void setResultAndFinish(final String accountName, final String accountType) {
@@ -444,58 +488,4 @@ private void startChooseAccountTypeActivity() {
444488
startActivityForResult(intent, REQUEST_CHOOSE_TYPE);
445489
mPendingRequest = REQUEST_CHOOSE_TYPE;
446490
}
447-
448-
private static class AccountInfo {
449-
final Account account;
450-
final Drawable drawable;
451-
private final boolean checked;
452-
453-
AccountInfo(Account account, Drawable drawable, boolean checked) {
454-
this.account = account;
455-
this.drawable = drawable;
456-
this.checked = checked;
457-
}
458-
}
459-
460-
private static class ViewHolder {
461-
ImageView icon;
462-
TextView text;
463-
ImageView checkmark;
464-
}
465-
466-
private static class AccountArrayAdapter extends ArrayAdapter<AccountInfo> {
467-
private LayoutInflater mLayoutInflater;
468-
private ArrayList<AccountInfo> mInfos;
469-
470-
public AccountArrayAdapter(Context context, int textViewResourceId,
471-
ArrayList<AccountInfo> infos) {
472-
super(context, textViewResourceId, infos);
473-
mInfos = infos;
474-
mLayoutInflater = (LayoutInflater) context.getSystemService(
475-
Context.LAYOUT_INFLATER_SERVICE);
476-
}
477-
478-
@Override
479-
public View getView(int position, View convertView, ViewGroup parent) {
480-
ViewHolder holder;
481-
482-
if (convertView == null) {
483-
convertView = mLayoutInflater.inflate(R.layout.choose_selected_account_row, null);
484-
holder = new ViewHolder();
485-
holder.text = (TextView) convertView.findViewById(R.id.account_row_text);
486-
holder.icon = (ImageView) convertView.findViewById(R.id.account_row_icon);
487-
holder.checkmark = (ImageView) convertView.findViewById(R.id.account_row_checkmark);
488-
convertView.setTag(holder);
489-
} else {
490-
holder = (ViewHolder) convertView.getTag();
491-
}
492-
493-
holder.text.setText(mInfos.get(position).account.name);
494-
holder.icon.setImageDrawable(mInfos.get(position).drawable);
495-
final int displayCheckmark =
496-
mInfos.get(position).checked ? View.VISIBLE : View.INVISIBLE;
497-
holder.checkmark.setVisibility(displayCheckmark);
498-
return convertView;
499-
}
500-
}
501491
}

core/res/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1983,7 +1983,7 @@
19831983
<activity android:name="android.accounts.ChooseTypeAndAccountActivity"
19841984
android:excludeFromRecents="true"
19851985
android:exported="true"
1986-
android:theme="@android:style/Theme.Holo.DialogWhenLarge.NoActionBar"
1986+
android:theme="@android:style/Theme.Holo.Dialog"
19871987
android:label="@string/choose_account_label"
19881988
android:process=":ui">
19891989
</activity>

0 commit comments

Comments
 (0)