1515 */
1616package android .accounts ;
1717
18+ import com .google .android .collect .Sets ;
19+
1820import android .app .Activity ;
1921import android .content .Intent ;
2022import 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