FileDocCategorySizeDatePackage
ChooseTypeAndAccountActivity.javaAPI DocAndroid 5.1 API24850Thu Mar 12 22:22:08 GMT 2015android.accounts

ChooseTypeAndAccountActivity

public class ChooseTypeAndAccountActivity extends android.app.Activity implements AccountManagerCallback
hide

Fields Summary
private static final String
TAG
public static final String
EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST
A Parcelable ArrayList of Account objects that limits the choosable accounts to those in this list, if this parameter is supplied.
public static final String
EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY
A Parcelable ArrayList of String objects that limits the accounts to choose to those that match the types in this list, if this parameter is supplied. This list is also used to filter the allowable account types if add account is selected.
public static final String
EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE
This is passed as the addAccountOptions parameter in AccountManager.addAccount() if it is called.
public static final String
EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY
This is passed as the requiredFeatures parameter in AccountManager.addAccount() if it is called.
public static final String
EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING
This is passed as the authTokenType string in AccountManager.addAccount() if it is called.
public static final String
EXTRA_SELECTED_ACCOUNT
If set then the specified account is already "selected".
public static final String
EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT
If true then display the account selection list even if there is just one account to choose from. boolean.
public static final String
EXTRA_DESCRIPTION_TEXT_OVERRIDE
If set then this string willb e used as the description rather than the default.
public static final int
REQUEST_NULL
public static final int
REQUEST_CHOOSE_TYPE
public static final int
REQUEST_ADD_ACCOUNT
private static final String
KEY_INSTANCE_STATE_PENDING_REQUEST
private static final String
KEY_INSTANCE_STATE_EXISTING_ACCOUNTS
private static final String
KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME
private static final String
KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT
private static final String
KEY_INSTANCE_STATE_ACCOUNT_LIST
private static final int
SELECTED_ITEM_NONE
private Set
mSetOfAllowableAccounts
private Set
mSetOfRelevantAccountTypes
private String
mSelectedAccountName
private boolean
mSelectedAddNewAccount
private boolean
mAlwaysPromptForAccount
private String
mDescriptionOverride
private ArrayList
mAccounts
private int
mPendingRequest
private android.os.Parcelable[]
mExistingAccounts
private int
mSelectedItemIndex
private android.widget.Button
mOkButton
private int
mCallingUid
private String
mCallingPackage
private boolean
mDisallowAddAccounts
private boolean
mDontShowPicker
Constructors Summary
Methods Summary
private java.util.ArrayListgetAcceptableAccountChoices(AccountManager accountManager)
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.

      final Account[] accounts = accountManager.getAccountsForPackage(mCallingPackage,
              mCallingUid);
      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;
    
private java.util.SetgetAllowableAccountSet(android.content.Intent intent)
Returns a set of whitelisted accounts given by the intent or null if none specified by the 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;
    
private intgetItemIndexToSelect(java.util.ArrayList accounts, java.lang.String selectedAccountName, boolean selectedAddNewAccount)

return
a value between 0 (inclusive) and accounts.size() (inclusive) or SELECTED_ITEM_NONE. An index value of accounts.size() indicates 'Add account' option.

      // 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 java.lang.String[]getListOfDisplayableOptions(java.util.ArrayList 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() + (mDisallowAddAccounts ? 0 : 1)];
      for (int i = 0; i < accounts.size(); i++) {
          listItems[i] = accounts.get(i).name;
      }
      if (!mDisallowAddAccounts) {
          listItems[accounts.size()] = getResources().getString(
                  R.string.add_account_button_label);
      }
      return listItems;
    
private java.util.SetgetReleventAccountTypes(android.content.Intent intent)
Return a set of account types speficied by the intent as well as supported by the AccountManager.

      // 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;
    
private voidonAccountSelected(Account account)

      Log.d(TAG, "selected account " + account);
      setResultAndFinish(account.name, account.type);
    
protected voidonActivityResult(int requestCode, int resultCode, android.content.Intent data)

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            if (data != null && data.getExtras() != null) data.getExtras().keySet();
            Bundle extras = data != null ? data.getExtras() : null;
            Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult(reqCode=" + requestCode
                    + ", resCode=" + resultCode + ", extras=" + extras + ")");
        }

        // we got our result, so clear the fact that we had a pending request
        mPendingRequest = REQUEST_NULL;

        if (resultCode == RESULT_CANCELED) {
            // if canceling out of addAccount and the original state caused us to skip this,
            // finish this activity
            if (mAccounts.isEmpty()) {
                setResult(Activity.RESULT_CANCELED);
                finish();
            }
            return;
        }

        if (resultCode == RESULT_OK) {
            if (requestCode == REQUEST_CHOOSE_TYPE) {
                if (data != null) {
                    String accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
                    if (accountType != null) {
                        runAddAccountForAuthenticator(accountType);
                        return;
                    }
                }
                Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: unable to find account "
                        + "type, pretending the request was canceled");
            } else if (requestCode == REQUEST_ADD_ACCOUNT) {
                String accountName = null;
                String accountType = null;

                if (data != null) {
                    accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
                    accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
                }

                if (accountName == null || accountType == null) {
                    Account[] currentAccounts = AccountManager.get(this).getAccountsForPackage(
                            mCallingPackage, mCallingUid);
                    Set<Account> preExistingAccounts = new HashSet<Account>();
                    for (Parcelable accountParcel : mExistingAccounts) {
                        preExistingAccounts.add((Account) accountParcel);
                    }
                    for (Account account : currentAccounts) {
                        if (!preExistingAccounts.contains(account)) {
                            accountName = account.name;
                            accountType = account.type;
                            break;
                        }
                    }
                }

                if (accountName != null || accountType != null) {
                    setResultAndFinish(accountName, accountType);
                    return;
                }
            }
            Log.d(TAG, "ChooseTypeAndAccountActivity.onActivityResult: unable to find added "
                    + "account, pretending the request was canceled");
        }
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "ChooseTypeAndAccountActivity.onActivityResult: canceled");
        }
        setResult(Activity.RESULT_CANCELED);
        finish();
    
public voidonCancelButtonClicked(android.view.View view)

        onBackPressed();
    
public voidonCreate(android.os.Bundle savedInstanceState)


    
        
        super.onCreate(savedInstanceState);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "ChooseTypeAndAccountActivity.onCreate(savedInstanceState="
                    + savedInstanceState + ")");
        }

        String message = null;

        try {
            IBinder activityToken = getActivityToken();
            mCallingUid = ActivityManagerNative.getDefault().getLaunchedFromUid(activityToken);
            mCallingPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
                    activityToken);
            if (mCallingUid != 0 && mCallingPackage != null) {
                Bundle restrictions = UserManager.get(this)
                        .getUserRestrictions(new UserHandle(UserHandle.getUserId(mCallingUid)));
                mDisallowAddAccounts =
                        restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false);
            }
        } catch (RemoteException re) {
            // Couldn't figure out caller details
            Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re);
        }

        // save some items we use frequently
        final Intent intent = getIntent();

        if (savedInstanceState != null) {
            mPendingRequest = savedInstanceState.getInt(KEY_INSTANCE_STATE_PENDING_REQUEST);
            mExistingAccounts =
                    savedInstanceState.getParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS);

            // Makes sure that any user selection is preserved across orientation changes.
            mSelectedAccountName = savedInstanceState.getString(
                    KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME);

            mSelectedAddNewAccount = savedInstanceState.getBoolean(
                    KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
            mAccounts = savedInstanceState.getParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST);
        } else {
            mPendingRequest = REQUEST_NULL;
            mExistingAccounts = null;
            // If the selected account as specified in the intent matches one in the list we will
            // show is as pre-selected.
            Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
            if (selectedAccount != null) {
                mSelectedAccountName = selectedAccount.name;
            }
        }

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "selected account name is " + mSelectedAccountName);
        }


        mSetOfAllowableAccounts = getAllowableAccountSet(intent);
        mSetOfRelevantAccountTypes = getReleventAccountTypes(intent);
        mAlwaysPromptForAccount = intent.getBooleanExtra(EXTRA_ALWAYS_PROMPT_FOR_ACCOUNT, false);
        mDescriptionOverride = intent.getStringExtra(EXTRA_DESCRIPTION_TEXT_OVERRIDE);

        // Need to do this once here to request the window feature. Can't do it in onResume
        mAccounts = getAcceptableAccountChoices(AccountManager.get(this));
        if (mAccounts.isEmpty()
                && mDisallowAddAccounts) {
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.app_not_authorized);
            mDontShowPicker = true;
        }
    
protected voidonDestroy()

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "ChooseTypeAndAccountActivity.onDestroy()");
        }
        super.onDestroy();
    
public voidonOkButtonClicked(android.view.View view)

        if (mSelectedItemIndex == mAccounts.size()) {
            // Selected "Add New Account" option
            startChooseAccountTypeActivity();
        } else if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
            onAccountSelected(mAccounts.get(mSelectedItemIndex));
        }
    
protected voidonResume()

        super.onResume();

        if (mDontShowPicker) return;

        final AccountManager accountManager = AccountManager.get(this);

        mAccounts = getAcceptableAccountChoices(accountManager);

        // 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 there are no relevant accounts and only one relevant account type go directly to
            // add account. Otherwise let the user choose.
            if (mAccounts.isEmpty()) {
                if (mSetOfRelevantAccountTypes.size() == 1) {
                    runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next());
                } else {
                    startChooseAccountTypeActivity();
                }
                return;
            }

            // if there is only one allowable account return it
            if (!mAlwaysPromptForAccount && mAccounts.size() == 1) {
                Account account = mAccounts.get(0);
                setResultAndFinish(account.name, account.type);
                return;
            }
        }

        String[] listItems = getListOfDisplayableOptions(mAccounts);
        mSelectedItemIndex = getItemIndexToSelect(
            mAccounts, mSelectedAccountName, mSelectedAddNewAccount);

        // Cannot set content view until we know that mPendingRequest is not null, otherwise
        // would cause screen flicker.
        setContentView(R.layout.choose_type_and_account);
        overrideDescriptionIfSupplied(mDescriptionOverride);
        populateUIAccountList(listItems);

        // Only enable "OK" button if something has been selected.
        mOkButton = (Button) findViewById(android.R.id.button2);
        mOkButton.setEnabled(mSelectedItemIndex != SELECTED_ITEM_NONE);
    
protected voidonSaveInstanceState(android.os.Bundle outState)

        super.onSaveInstanceState(outState);
        outState.putInt(KEY_INSTANCE_STATE_PENDING_REQUEST, mPendingRequest);
        if (mPendingRequest == REQUEST_ADD_ACCOUNT) {
            outState.putParcelableArray(KEY_INSTANCE_STATE_EXISTING_ACCOUNTS, mExistingAccounts);
        }
        if (mSelectedItemIndex != SELECTED_ITEM_NONE) {
            if (mSelectedItemIndex == mAccounts.size()) {
                outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, true);
            } else {
                outState.putBoolean(KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
                outState.putString(KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME,
                        mAccounts.get(mSelectedItemIndex).name);
            }
        }
        outState.putParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST, mAccounts);
    
private voidoverrideDescriptionIfSupplied(java.lang.String descriptionOverride)
Overrides the description text view for the picker activity if specified by the intent. If not specified then makes the description invisible.

      TextView descriptionView = (TextView) findViewById(R.id.description);
      if (!TextUtils.isEmpty(descriptionOverride)) {
          descriptionView.setText(descriptionOverride);
      } else {
          descriptionView.setVisibility(View.GONE);
      }
    
private final voidpopulateUIAccountList(java.lang.String[] listItems)
Populates the UI ListView with the given list of items and selects an item based on {@code mSelectedItemIndex} member variable.

      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");
          }
      }
    
public voidrun(AccountManagerFuture accountManagerFuture)

        try {
            final Bundle accountManagerResult = accountManagerFuture.getResult();
            final Intent intent = (Intent)accountManagerResult.getParcelable(
                    AccountManager.KEY_INTENT);
            if (intent != null) {
                mPendingRequest = REQUEST_ADD_ACCOUNT;
                mExistingAccounts = AccountManager.get(this).getAccountsForPackage(mCallingPackage,
                        mCallingUid);
                intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivityForResult(intent, REQUEST_ADD_ACCOUNT);
                return;
            }
        } catch (OperationCanceledException e) {
            setResult(Activity.RESULT_CANCELED);
            finish();
            return;
        } catch (IOException e) {
        } catch (AuthenticatorException e) {
        }
        Bundle bundle = new Bundle();
        bundle.putString(AccountManager.KEY_ERROR_MESSAGE, "error communicating with server");
        setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
        finish();
    
protected voidrunAddAccountForAuthenticator(java.lang.String type)

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "runAddAccountForAuthenticator: " + type);
        }
        final Bundle options = getIntent().getBundleExtra(
                ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE);
        final String[] requiredFeatures = getIntent().getStringArrayExtra(
                ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY);
        final String authTokenType = getIntent().getStringExtra(
                ChooseTypeAndAccountActivity.EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING);
        AccountManager.get(this).addAccount(type, authTokenType, requiredFeatures,
                options, null /* activity */, this /* callback */, null /* Handler */);
    
private voidsetResultAndFinish(java.lang.String accountName, java.lang.String accountType)

        Bundle bundle = new Bundle();
        bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
        bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
        setResult(Activity.RESULT_OK, new Intent().putExtras(bundle));
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "ChooseTypeAndAccountActivity.setResultAndFinish: "
                    + "selected account " + accountName + ", " + accountType);
        }
        finish();
    
private voidstartChooseAccountTypeActivity()

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "ChooseAccountTypeActivity.startChooseAccountTypeActivity()");
        }
        final Intent intent = new Intent(this, ChooseAccountTypeActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
        intent.putExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
                getIntent().getStringArrayExtra(EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY));
        intent.putExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE,
                getIntent().getBundleExtra(EXTRA_ADD_ACCOUNT_OPTIONS_BUNDLE));
        intent.putExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY,
                getIntent().getStringArrayExtra(EXTRA_ADD_ACCOUNT_REQUIRED_FEATURES_STRING_ARRAY));
        intent.putExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING,
                getIntent().getStringExtra(EXTRA_ADD_ACCOUNT_AUTH_TOKEN_TYPE_STRING));
        startActivityForResult(intent, REQUEST_CHOOSE_TYPE);
        mPendingRequest = REQUEST_CHOOSE_TYPE;