diff options
author | Fabrice Di Meglio <fdimeglio@google.com> | 2014-02-20 14:41:51 -0800 |
---|---|---|
committer | Fabrice Di Meglio <fdimeglio@google.com> | 2014-02-20 16:21:14 -0800 |
commit | 74309ea53a5a72430bafaa8cea4d82d4e24f61bd (patch) | |
tree | 2b52da2b96af969339c4dc93dd7a93c6bb535581 /src/com/android/settings/accounts/ChooseAccountActivity.java | |
parent | e611b8590d8da69bb95e29a7faa5200a95b427f3 (diff) | |
download | packages_apps_Settings-74309ea53a5a72430bafaa8cea4d82d4e24f61bd.tar.gz packages_apps_Settings-74309ea53a5a72430bafaa8cea4d82d4e24f61bd.tar.bz2 packages_apps_Settings-74309ea53a5a72430bafaa8cea4d82d4e24f61bd.zip |
Fix bug #13058470 Cannot add account -- Settings app crashes
- revert back to an Activity instead of a fragment. This
is a straight reverse of the changes introduced for trying
to have a Fragment.
Basically ChooseAccountActivity was previously an Activity for
choosing an account type. If the list of account types was containing
only one item, then the ChooseAccountActivity was just a pass thru
and was falling back to the only account authority available.
In the current reported bug, this was happening by disabling the
Email app and thus having only the GoogleAuthenticator as an
Authority.
Then in the onCreate() the ChooseAccountFragment was seeing that
there was only one account authenticator and issuing a BACK button
press. Too bad, this was done into a non finished Fragment transaction
and leading to a crash.
All in all, we NEED to have an Activity and cannot use a Fragment
in that case.
Change-Id: I4a867a25fe9580929ec50a6775105adac1f88c52
Diffstat (limited to 'src/com/android/settings/accounts/ChooseAccountActivity.java')
-rw-r--r-- | src/com/android/settings/accounts/ChooseAccountActivity.java | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/src/com/android/settings/accounts/ChooseAccountActivity.java b/src/com/android/settings/accounts/ChooseAccountActivity.java new file mode 100644 index 000000000..631fe47d6 --- /dev/null +++ b/src/com/android/settings/accounts/ChooseAccountActivity.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.accounts; + +import android.accounts.AccountManager; +import android.accounts.AuthenticatorDescription; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.SyncAdapterType; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceGroup; +import android.preference.PreferenceScreen; +import android.util.Log; +import com.android.internal.util.CharSequences; +import com.android.settings.R; +import com.google.android.collect.Maps; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +/** + * Activity asking a user to select an account to be set up. + */ +public class ChooseAccountActivity extends PreferenceActivity { + + private static final String TAG = "ChooseAccountActivity"; + private String[] mAuthorities; + private PreferenceGroup mAddAccountGroup; + private final ArrayList<ProviderEntry> mProviderList = new ArrayList<ProviderEntry>(); + public HashSet<String> mAccountTypesFilter; + private AuthenticatorDescription[] mAuthDescs; + private HashMap<String, ArrayList<String>> mAccountTypeToAuthorities = null; + private Map<String, AuthenticatorDescription> mTypeToAuthDescription + = new HashMap<String, AuthenticatorDescription>(); + + private static class ProviderEntry implements Comparable<ProviderEntry> { + private final CharSequence name; + private final String type; + ProviderEntry(CharSequence providerName, String accountType) { + name = providerName; + type = accountType; + } + + public int compareTo(ProviderEntry another) { + if (name == null) { + return -1; + } + if (another.name == null) { + return +1; + } + return CharSequences.compareToIgnoreCase(name, another.name); + } + } + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + + setContentView(R.layout.add_account_screen); + addPreferencesFromResource(R.xml.add_account_settings); + mAuthorities = getIntent().getStringArrayExtra( + AccountPreferenceBase.AUTHORITIES_FILTER_KEY); + String[] accountTypesFilter = getIntent().getStringArrayExtra( + AccountPreferenceBase.ACCOUNT_TYPES_FILTER_KEY); + if (accountTypesFilter != null) { + mAccountTypesFilter = new HashSet<String>(); + for (String accountType : accountTypesFilter) { + mAccountTypesFilter.add(accountType); + } + } + mAddAccountGroup = getPreferenceScreen(); + updateAuthDescriptions(); + } + + /** + * Updates provider icons. Subclasses should call this in onCreate() + * and update any UI that depends on AuthenticatorDescriptions in onAuthDescriptionsUpdated(). + */ + private void updateAuthDescriptions() { + mAuthDescs = AccountManager.get(this).getAuthenticatorTypes(); + for (int i = 0; i < mAuthDescs.length; i++) { + mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]); + } + onAuthDescriptionsUpdated(); + } + + private void onAuthDescriptionsUpdated() { + // Create list of providers to show on preference screen + for (int i = 0; i < mAuthDescs.length; i++) { + String accountType = mAuthDescs[i].type; + CharSequence providerName = getLabelForType(accountType); + + // Skip preferences for authorities not specified. If no authorities specified, + // then include them all. + ArrayList<String> accountAuths = getAuthoritiesForAccountType(accountType); + boolean addAccountPref = true; + if (mAuthorities != null && mAuthorities.length > 0 && accountAuths != null) { + addAccountPref = false; + for (int k = 0; k < mAuthorities.length; k++) { + if (accountAuths.contains(mAuthorities[k])) { + addAccountPref = true; + break; + } + } + } + if (addAccountPref && mAccountTypesFilter != null + && !mAccountTypesFilter.contains(accountType)) { + addAccountPref = false; + } + if (addAccountPref) { + mProviderList.add(new ProviderEntry(providerName, accountType)); + } else { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "Skipped pref " + providerName + ": has no authority we need"); + } + } + } + + if (mProviderList.size() == 1) { + // If there's only one provider that matches, just run it. + finishWithAccountType(mProviderList.get(0).type); + } else if (mProviderList.size() > 0) { + Collections.sort(mProviderList); + mAddAccountGroup.removeAll(); + for (ProviderEntry pref : mProviderList) { + Drawable drawable = getDrawableForType(pref.type); + ProviderPreference p = + new ProviderPreference(this, pref.type, drawable, pref.name); + mAddAccountGroup.addPreference(p); + } + } else { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + final StringBuilder auths = new StringBuilder(); + for (String a : mAuthorities) { + auths.append(a); + auths.append(' '); + } + Log.v(TAG, "No providers found for authorities: " + auths); + } + setResult(RESULT_CANCELED); + finish(); + } + } + + public ArrayList<String> getAuthoritiesForAccountType(String type) { + if (mAccountTypeToAuthorities == null) { + mAccountTypeToAuthorities = Maps.newHashMap(); + SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypes(); + for (int i = 0, n = syncAdapters.length; i < n; i++) { + final SyncAdapterType sa = syncAdapters[i]; + ArrayList<String> authorities = mAccountTypeToAuthorities.get(sa.accountType); + if (authorities == null) { + authorities = new ArrayList<String>(); + mAccountTypeToAuthorities.put(sa.accountType, authorities); + } + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.d(TAG, "added authority " + sa.authority + " to accountType " + + sa.accountType); + } + authorities.add(sa.authority); + } + } + return mAccountTypeToAuthorities.get(type); + } + + /** + * Gets an icon associated with a particular account type. If none found, return null. + * @param accountType the type of account + * @return a drawable for the icon or null if one cannot be found. + */ + protected Drawable getDrawableForType(final String accountType) { + Drawable icon = null; + if (mTypeToAuthDescription.containsKey(accountType)) { + try { + AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); + Context authContext = createPackageContext(desc.packageName, 0); + icon = authContext.getResources().getDrawable(desc.iconId); + } catch (PackageManager.NameNotFoundException e) { + // TODO: place holder icon for missing account icons? + Log.w(TAG, "No icon name for account type " + accountType); + } catch (Resources.NotFoundException e) { + // TODO: place holder icon for missing account icons? + Log.w(TAG, "No icon resource for account type " + accountType); + } + } + return icon; + } + + /** + * Gets the label associated with a particular account type. If none found, return null. + * @param accountType the type of account + * @return a CharSequence for the label or null if one cannot be found. + */ + protected CharSequence getLabelForType(final String accountType) { + CharSequence label = null; + if (mTypeToAuthDescription.containsKey(accountType)) { + try { + AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); + Context authContext = createPackageContext(desc.packageName, 0); + label = authContext.getResources().getText(desc.labelId); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "No label name for account type " + accountType); + } catch (Resources.NotFoundException e) { + Log.w(TAG, "No label resource for account type " + accountType); + } + } + return label; + } + + @Override + public boolean onPreferenceTreeClick(PreferenceScreen preferences, Preference preference) { + if (preference instanceof ProviderPreference) { + ProviderPreference pref = (ProviderPreference) preference; + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "Attempting to add account of type " + pref.getAccountType()); + } + finishWithAccountType(pref.getAccountType()); + } + return true; + } + + private void finishWithAccountType(String accountType) { + Intent intent = new Intent(); + intent.putExtra(AddAccountSettings.EXTRA_SELECTED_ACCOUNT, accountType); + setResult(RESULT_OK, intent); + finish(); + } +} |