diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index a5bc8bb2a1e..da7cb983cc7 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -127,7 +127,8 @@ public class SettingsActivity extends Activity PreferenceFragment.OnPreferenceStartFragmentCallback, ButtonBarHandler, OnAccountsUpdateListener, FragmentManager.OnBackStackChangedListener, SearchView.OnQueryTextListener, SearchView.OnCloseListener, - MenuItem.OnActionExpandListener { + MenuItem.OnActionExpandListener, + AuthenticatorHelper.OnAccountsUpdateListener { private static final String LOG_TAG = "Settings"; @@ -466,10 +467,13 @@ public class SettingsActivity extends Activity if (intent.hasExtra(EXTRA_UI_OPTIONS)) { getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0)); } - - mAuthenticatorHelper = new AuthenticatorHelper(); + // TODO: Delete accounts tile once we have the new screen working + // See: http://b/15815948 + final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); + mAuthenticatorHelper = new AuthenticatorHelper( + this, UserHandle.getCallingUserHandle(), um, this); mAuthenticatorHelper.updateAuthDescriptions(this); - mAuthenticatorHelper.onAccountsUpdated(this, null); + mAuthenticatorHelper.onAccountsUpdated(null); mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE, Context.MODE_PRIVATE); @@ -1263,7 +1267,11 @@ public class SettingsActivity extends Activity public void onAccountsUpdated(Account[] accounts) { // TODO: watch for package upgrades to invalidate cache; see 7206643 mAuthenticatorHelper.updateAuthDescriptions(this); - mAuthenticatorHelper.onAccountsUpdated(this, accounts); + invalidateCategories(); + } + + @Override + public void onAccountsUpdate(UserHandle userHandle) { invalidateCategories(); } diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 5f904424196..26750e7e1f0 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -56,12 +56,14 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import android.widget.TabWidget; + import com.android.settings.dashboard.DashboardCategory; import com.android.settings.dashboard.DashboardTile; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -579,4 +581,31 @@ public final class Utils { intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, isShortcut); return intent; } + + /** + * Returns the managed profile of the current user or null if none found. + */ + public static UserHandle getManagedProfile(UserManager userManager) { + List userProfiles = userManager.getUserProfiles(); + final int count = userProfiles.size(); + for (int i = 0; i < count; i++) { + final UserHandle profile = userProfiles.get(i); + if (profile.getIdentifier() == userManager.getUserHandle()) { + continue; + } + final UserInfo userInfo = userManager.getUserInfo(profile.getIdentifier()); + if (userInfo.isManagedProfile()) { + return profile; + } + } + return null; + } + + /** + * Returns true if the current profile is a managed one. + */ + public static boolean isManagedProfile(UserManager userManager) { + UserInfo currentUser = userManager.getUserInfo(userManager.getUserHandle()); + return currentUser.isManagedProfile(); + } } diff --git a/src/com/android/settings/accounts/AccountPreferenceBase.java b/src/com/android/settings/accounts/AccountPreferenceBase.java index 37dffca9674..c25831d5d23 100644 --- a/src/com/android/settings/accounts/AccountPreferenceBase.java +++ b/src/com/android/settings/accounts/AccountPreferenceBase.java @@ -16,19 +16,9 @@ package com.android.settings.accounts; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import com.android.settings.SettingsPreferenceFragment; - import com.google.android.collect.Maps; -import android.accounts.Account; -import android.accounts.AccountManager; import android.accounts.AuthenticatorDescription; -import android.accounts.OnAccountsUpdateListener; import android.app.Activity; import android.content.ContentResolver; import android.content.Context; @@ -40,28 +30,47 @@ import android.content.res.Resources.Theme; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; +import android.os.UserHandle; +import android.os.UserManager; import android.preference.PreferenceScreen; import android.text.format.DateFormat; import android.util.Log; import android.view.ContextThemeWrapper; +import com.android.settings.SettingsPreferenceFragment; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; + class AccountPreferenceBase extends SettingsPreferenceFragment - implements OnAccountsUpdateListener { + implements AuthenticatorHelper.OnAccountsUpdateListener { protected static final String TAG = "AccountSettings"; public static final String AUTHORITIES_FILTER_KEY = "authorities"; public static final String ACCOUNT_TYPES_FILTER_KEY = "account_types"; private final Handler mHandler = new Handler(); + private UserManager mUm; private Object mStatusChangeListenerHandle; private HashMap> mAccountTypeToAuthorities = null; - private AuthenticatorHelper mAuthenticatorHelper = new AuthenticatorHelper(); + protected AuthenticatorHelper mAuthenticatorHelper; private java.text.DateFormat mDateFormat; private java.text.DateFormat mTimeFormat; + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + // TODO: This needs to handle different users, get the user id from the intent + mUm = (UserManager) getSystemService(Context.USER_SERVICE); + mAuthenticatorHelper = new AuthenticatorHelper( + getActivity(), UserHandle.getCallingUserHandle(), mUm, this); + } + /** * Overload to handle account updates. */ - public void onAccountsUpdated(Account[] accounts) { + @Override + public void onAccountsUpdate(UserHandle userHandle) { } diff --git a/src/com/android/settings/accounts/AccountSettings.java b/src/com/android/settings/accounts/AccountSettings.java index bb06b2f81ef..e60bed93fa3 100644 --- a/src/com/android/settings/accounts/AccountSettings.java +++ b/src/com/android/settings/accounts/AccountSettings.java @@ -19,11 +19,17 @@ package com.android.settings.accounts; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.OnAccountsUpdateListener; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.UserInfo; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.UserHandle; import android.os.UserManager; +import android.util.Log; +import android.util.SparseArray; import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceGroup; @@ -33,16 +39,17 @@ import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.List; /** * Settings screen for the account types on the device. * This shows all account types available for personal and work profiles. */ public class AccountSettings extends SettingsPreferenceFragment - implements OnAccountsUpdateListener, OnPreferenceClickListener { + implements AuthenticatorHelper.OnAccountsUpdateListener, + OnPreferenceClickListener { public static final String TAG = "AccountSettings"; private static final String KEY_ACCOUNT = "account"; @@ -51,128 +58,183 @@ public class AccountSettings extends SettingsPreferenceFragment private static final String KEY_CATEGORY_PERSONAL = "account_personal"; private static final String KEY_ADD_ACCOUNT_PERSONAL = "add_account_personal"; private static final String KEY_CATEGORY_WORK = "account_work"; + private static final String KEY_ADD_ACCOUNT_WORK = "add_account_work"; - private AuthenticatorHelper mAuthenticatorHelper; - private boolean mListeningToAccountUpdates; - - private PreferenceGroup mAccountTypesForUser; - private Preference mAddAccountForUser; + private static final String ADD_ACCOUNT_ACTION = "android.settings.ADD_ACCOUNT_SETTINGS"; private UserManager mUm; + private SparseArray mProfiles; + private ManagedProfileBroadcastReceiver mManagedProfileBroadcastReceiver; + + /** + * Holds data related to the accounts belonging to one profile. + */ + private static class ProfileData { + /** + * The preference that displays the accounts. + */ + public PreferenceGroup preferenceGroup; + /** + * The preference that displays the add account button. + */ + public Preference addAccountPreference; + /** + * The user handle of the user that these accounts belong to. + */ + public UserHandle userHandle; + /** + * The {@link AuthenticatorHelper} that holds accounts data for this profile. + */ + public AuthenticatorHelper authenticatorHelper; + } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mUm = (UserManager) getSystemService(Context.USER_SERVICE); + mProfiles = new SparseArray(2); + updateUi(); + } - mAuthenticatorHelper = new AuthenticatorHelper(); - mAuthenticatorHelper.updateAuthDescriptions(getActivity()); - mAuthenticatorHelper.onAccountsUpdated(getActivity(), null); - + void updateUi() { // Load the preferences from an XML resource addPreferencesFromResource(R.xml.account_settings); if(mUm.isLinkedUser()) { // Restricted user or similar - // TODO: Do we disallow modifying accounts for restricted profiles? - mAccountTypesForUser = (PreferenceGroup) findPreference(KEY_ACCOUNT); - if (mUm.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) { - removePreference(KEY_ADD_ACCOUNT); - } else { - mAddAccountForUser = findPreference(KEY_ADD_ACCOUNT); - mAddAccountForUser.setOnPreferenceClickListener(this); - } - removePreference(KEY_CATEGORY_PERSONAL); - removePreference(KEY_CATEGORY_WORK); + updateSingleProfileUi(); } else { - mAccountTypesForUser = (PreferenceGroup) findPreference(KEY_CATEGORY_PERSONAL); - mAddAccountForUser = findPreference(KEY_ADD_ACCOUNT_PERSONAL); - mAddAccountForUser.setOnPreferenceClickListener(this); - - // TODO: Show the work accounts also - // TODO: Handle the case where there is only one account - removePreference(KEY_CATEGORY_WORK); - removePreference(KEY_ADD_ACCOUNT); + if (Utils.isManagedProfile(mUm)) { + // This should not happen + Log.w(TAG, "We should not be showing settings for a managed profile"); + updateSingleProfileUi(); + } + final UserHandle currentProfile = UserHandle.getCallingUserHandle(); + final UserHandle managedProfile = Utils.getManagedProfile(mUm); + if (managedProfile == null) { + updateSingleProfileUi(); + } else { + updateProfileUi(currentProfile, + KEY_CATEGORY_PERSONAL, KEY_ADD_ACCOUNT_PERSONAL, new ArrayList()); + final ArrayList unusedPreferences = new ArrayList(1); + unusedPreferences.add(KEY_ADD_ACCOUNT); + updateProfileUi(managedProfile, + KEY_CATEGORY_WORK, KEY_ADD_ACCOUNT_WORK, unusedPreferences); + mManagedProfileBroadcastReceiver = new ManagedProfileBroadcastReceiver(); + mManagedProfileBroadcastReceiver.register(getActivity()); + } } - updateAccountTypes(mAccountTypesForUser); + final int count = mProfiles.size(); + for (int i = 0; i < count; i++) { + updateAccountTypes(mProfiles.valueAt(i)); + } + } + + private void updateSingleProfileUi() { + final ArrayList unusedPreferences = new ArrayList(2); + unusedPreferences.add(KEY_CATEGORY_PERSONAL); + unusedPreferences.add(KEY_CATEGORY_WORK); + updateProfileUi(UserHandle.getCallingUserHandle(), KEY_ACCOUNT, KEY_ADD_ACCOUNT, + unusedPreferences); + } + + private void updateProfileUi(UserHandle userHandle, String categoryKey, String addAccountKey, + ArrayList unusedPreferences) { + final int count = unusedPreferences.size(); + for (int i = 0; i < count; i++) { + removePreference(unusedPreferences.get(i)); + } + final ProfileData profileData = new ProfileData(); + profileData.preferenceGroup = (PreferenceGroup) findPreference(categoryKey); + if (mUm.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) { + removePreference(addAccountKey); + } else { + profileData.addAccountPreference = findPreference(addAccountKey); + profileData.addAccountPreference.setOnPreferenceClickListener(this); + } + profileData.userHandle = userHandle; + profileData.authenticatorHelper = new AuthenticatorHelper( + getActivity(), userHandle, mUm, this); + mProfiles.put(userHandle.getIdentifier(), profileData); + + profileData.authenticatorHelper.listenToAccountUpdates(); } @Override public void onDestroy() { super.onDestroy(); - stopListeningToAccountUpdates(); + cleanUp(); + } + + void cleanUp() { + if (mManagedProfileBroadcastReceiver != null) { + mManagedProfileBroadcastReceiver.unregister(getActivity()); + } + final int count = mProfiles.size(); + for (int i = 0; i < count; i++) { + mProfiles.valueAt(i).authenticatorHelper.stopListeningToAccountUpdates(); + } } @Override - public void onAccountsUpdated(Account[] accounts) { - // TODO: watch for package upgrades to invalidate cache; see 7206643 - mAuthenticatorHelper.updateAuthDescriptions(getActivity()); - mAuthenticatorHelper.onAccountsUpdated(getActivity(), accounts); - listenToAccountUpdates(); - updateAccountTypes(mAccountTypesForUser); - } - - @Override - public boolean onPreferenceClick(Preference preference) { - // Check the preference - if (preference == mAddAccountForUser) { - Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); - startActivity(intent); - return true; - } - return false; - } - - private void updateAccountTypes(PreferenceGroup preferenceGroup) { - preferenceGroup.removeAll(); - preferenceGroup.setOrderingAsAdded(true); - for (AccountPreference preference : getAccountTypePreferences()) { - preferenceGroup.addPreference(preference); - } - if (mAddAccountForUser != null) { - preferenceGroup.addPreference(mAddAccountForUser); + public void onAccountsUpdate(UserHandle userHandle) { + final ProfileData profileData = mProfiles.get(userHandle.getIdentifier()); + if (profileData != null) { + updateAccountTypes(profileData); + } else { + Log.w(TAG, "Missing Settings screen for: " + userHandle.getIdentifier()); } } - private List getAccountTypePreferences() { - String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes(); - List accountTypePreferences = + private void updateAccountTypes(ProfileData profileData) { + profileData.preferenceGroup.removeAll(); + final ArrayList preferences = getAccountTypePreferences( + profileData.authenticatorHelper); + final int count = preferences.size(); + for (int i = 0; i < count; i++) { + profileData.preferenceGroup.addPreference(preferences.get(i)); + } + if (profileData.addAccountPreference != null) { + profileData.preferenceGroup.addPreference(profileData.addAccountPreference); + } + } + + private ArrayList getAccountTypePreferences(AuthenticatorHelper helper) { + final String[] accountTypes = helper.getEnabledAccountTypes(); + final ArrayList accountTypePreferences = new ArrayList(accountTypes.length); - for (String accountType : accountTypes) { - CharSequence label = mAuthenticatorHelper.getLabelForType(getActivity(), accountType); + + for (int i = 0; i < accountTypes.length; i++) { + final String accountType = accountTypes[i]; + final CharSequence label = helper.getLabelForType(getActivity(), accountType); if (label == null) { continue; } - Account[] accounts = AccountManager.get(getActivity()).getAccountsByType(accountType); - boolean skipToAccount = accounts.length == 1 - && !mAuthenticatorHelper.hasAccountPreferences(accountType); + final Account[] accounts = AccountManager.get(getActivity()) + .getAccountsByType(accountType); + final boolean skipToAccount = accounts.length == 1 + && !helper.hasAccountPreferences(accountType); if (skipToAccount) { - Bundle fragmentArguments = new Bundle(); + final Bundle fragmentArguments = new Bundle(); fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]); - accountTypePreferences.add(new AccountPreference( - getActivity(), - label, - accountType, - AccountSyncSettings.class.getName(), - fragmentArguments)); + accountTypePreferences.add(new AccountPreference(getActivity(), label, + AccountSyncSettings.class.getName(), fragmentArguments, + helper.getDrawableForType(getActivity(), accountType))); } else { - Bundle fragmentArguments = new Bundle(); + final Bundle fragmentArguments = new Bundle(); fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType); fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL, label.toString()); - accountTypePreferences.add(new AccountPreference( - getActivity(), - label, - accountType, - ManageAccountsSettings.class.getName(), - fragmentArguments)); + accountTypePreferences.add(new AccountPreference(getActivity(), label, + ManageAccountsSettings.class.getName(), fragmentArguments, + helper.getDrawableForType(getActivity(), accountType))); } - mAuthenticatorHelper.preloadDrawableForType(getActivity(), accountType); + helper.preloadDrawableForType(getActivity(), accountType); } // Sort by label Collections.sort(accountTypePreferences, new Comparator() { @@ -184,18 +246,20 @@ public class AccountSettings extends SettingsPreferenceFragment return accountTypePreferences; } - private void listenToAccountUpdates() { - if (!mListeningToAccountUpdates) { - AccountManager.get(getActivity()).addOnAccountsUpdatedListener(this, null, true); - mListeningToAccountUpdates = true; - } - } - - private void stopListeningToAccountUpdates() { - if (mListeningToAccountUpdates) { - AccountManager.get(getActivity()).removeOnAccountsUpdatedListener(this); - mListeningToAccountUpdates = false; + @Override + public boolean onPreferenceClick(Preference preference) { + // Check the preference + final int count = mProfiles.size(); + for (int i = 0; i < count; i++) { + ProfileData profileData = mProfiles.valueAt(i); + if (preference == profileData.addAccountPreference) { + Intent intent = new Intent(ADD_ACCOUNT_ACTION); + intent.putExtra(Intent.EXTRA_USER_HANDLE, profileData.userHandle); + startActivity(intent); + return true; + } } + return false; } private class AccountPreference extends Preference implements OnPreferenceClickListener { @@ -218,18 +282,16 @@ public class AccountSettings extends SettingsPreferenceFragment */ private final Bundle mFragmentArguments; - - public AccountPreference(Context context, CharSequence title, - String accountType, String fragment, Bundle fragmentArguments) { + public AccountPreference(Context context, CharSequence title, String fragment, + Bundle fragmentArguments, Drawable icon) { super(context); mTitle = title; mFragment = fragment; mFragmentArguments = fragmentArguments; setWidgetLayoutResource(R.layout.account_type_preference); - Drawable drawable = mAuthenticatorHelper.getDrawableForType(context, accountType); setTitle(title); - setIcon(drawable); + setIcon(icon); setOnPreferenceClickListener(this); } @@ -244,6 +306,39 @@ public class AccountSettings extends SettingsPreferenceFragment return false; } } + + private class ManagedProfileBroadcastReceiver extends BroadcastReceiver { + private boolean listeningToManagedProfileEvents; + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_MANAGED_PROFILE_REMOVED) + || intent.getAction().equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) { + Log.v(TAG, "Received broadcast: " + intent.getAction()); + cleanUp(); + updateUi(); + return; + } + Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction()); + } + + public void register(Context context) { + if (!listeningToManagedProfileEvents) { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); + intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); + context.registerReceiver(this, intentFilter); + listeningToManagedProfileEvents = true; + } + } + + public void unregister(Context context) { + if (listeningToManagedProfileEvents) { + context.unregisterReceiver(this); + listeningToManagedProfileEvents = false; + } + } + } // TODO Implement a {@link SearchIndexProvider} to allow Indexing and Search of account types // See http://b/15403806 } diff --git a/src/com/android/settings/accounts/AccountSyncSettings.java b/src/com/android/settings/accounts/AccountSyncSettings.java index c14dbbe1fc9..e33e37a8f6a 100644 --- a/src/com/android/settings/accounts/AccountSyncSettings.java +++ b/src/com/android/settings/accounts/AccountSyncSettings.java @@ -16,13 +16,15 @@ package com.android.settings.accounts; +import com.google.android.collect.Lists; +import com.google.android.collect.Maps; + import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerCallback; import android.accounts.AccountManagerFuture; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; -import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.ContentResolver; @@ -34,6 +36,7 @@ import android.content.SyncStatusInfo; import android.content.pm.ProviderInfo; import android.net.ConnectivityManager; import android.os.Bundle; +import android.os.UserHandle; import android.os.UserManager; import android.preference.Preference; import android.preference.PreferenceScreen; @@ -51,8 +54,6 @@ import android.widget.TextView; import com.android.settings.R; import com.android.settings.Utils; -import com.google.android.collect.Lists; -import com.google.android.collect.Maps; import java.io.IOException; import java.util.ArrayList; @@ -193,10 +194,9 @@ public class AccountSyncSettings extends AccountPreferenceBase { @Override public void onResume() { - final Activity activity = getActivity(); - AccountManager.get(activity).addOnAccountsUpdatedListener(this, null, false); + mAuthenticatorHelper.listenToAccountUpdates(); updateAuthDescriptions(); - onAccountsUpdated(AccountManager.get(activity).getAccounts()); + onAccountsUpdate(UserHandle.getCallingUserHandle()); super.onResume(); } @@ -204,7 +204,7 @@ public class AccountSyncSettings extends AccountPreferenceBase { @Override public void onPause() { super.onPause(); - AccountManager.get(getActivity()).removeOnAccountsUpdatedListener(this); + mAuthenticatorHelper.stopListeningToAccountUpdates(); } private void addSyncStateCheckBox(Account account, String authority) { @@ -436,10 +436,10 @@ public class AccountSyncSettings extends AccountPreferenceBase { } @Override - public void onAccountsUpdated(Account[] accounts) { - super.onAccountsUpdated(accounts); - mAccounts = accounts; - updateAccountCheckboxes(accounts); + public void onAccountsUpdate(final UserHandle userHandle) { + super.onAccountsUpdate(userHandle); + mAccounts = AccountManager.get(getActivity()).getAccounts(); + updateAccountCheckboxes(mAccounts); onSyncStateUpdated(); } diff --git a/src/com/android/settings/accounts/AuthenticatorHelper.java b/src/com/android/settings/accounts/AuthenticatorHelper.java index a164b8be10e..0ecf43826b4 100644 --- a/src/com/android/settings/accounts/AuthenticatorHelper.java +++ b/src/com/android/settings/accounts/AuthenticatorHelper.java @@ -19,27 +19,58 @@ package com.android.settings.accounts; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorDescription; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.AsyncTask; +import android.os.UserHandle; +import android.os.UserManager; import android.util.Log; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -public class AuthenticatorHelper { - +/** + * Helper class for monitoring accounts on the device for a given user. + * + * Classes using this helper should implement {@link OnAccountsUpdateListener}. + * {@link OnAccountsUpdateListener#onAccountsUpdate(UserHandle)} will then be + * called once accounts get updated. For setting up listening for account + * updates, {@link #listenToAccountUpdates()} and + * {@link #stopListeningToAccountUpdates()} should be used. + */ +final public class AuthenticatorHelper extends BroadcastReceiver { private static final String TAG = "AuthenticatorHelper"; + private Map mTypeToAuthDescription = new HashMap(); private AuthenticatorDescription[] mAuthDescs; private ArrayList mEnabledAccountTypes = new ArrayList(); private Map mAccTypeIconCache = new HashMap(); - public AuthenticatorHelper() { + private final UserHandle mUserHandle; + private final UserManager mUm; + private final Context mContext; + private final OnAccountsUpdateListener mListener; + private boolean mListeningToAccountUpdates; + + public interface OnAccountsUpdateListener { + void onAccountsUpdate(UserHandle userHandle); + } + + public AuthenticatorHelper(Context context, UserHandle userHandle, UserManager userManager, + OnAccountsUpdateListener listener) { + mContext = context; + mUm = userManager; + mUserHandle = userHandle; + mListener = listener; + // This guarantees that the helper is ready to use once constructed + onAccountsUpdated(null); } public String[] getEnabledAccountTypes() { @@ -72,7 +103,8 @@ public class AuthenticatorHelper { try { AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); Context authContext = context.createPackageContext(desc.packageName, 0); - icon = authContext.getResources().getDrawable(desc.iconId); + icon = mUm.getBadgedDrawableForUser( + authContext.getResources().getDrawable(desc.iconId), mUserHandle); synchronized (mAccTypeIconCache) { mAccTypeIconCache.put(accountType, icon); } @@ -112,25 +144,13 @@ public class AuthenticatorHelper { * and update any UI that depends on AuthenticatorDescriptions in onAuthDescriptionsUpdated(). */ public void updateAuthDescriptions(Context context) { - mAuthDescs = AccountManager.get(context).getAuthenticatorTypes(); + mAuthDescs = AccountManager.get(context) + .getAuthenticatorTypesAsUser(mUserHandle.getIdentifier()); for (int i = 0; i < mAuthDescs.length; i++) { mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]); } } - public void onAccountsUpdated(Context context, Account[] accounts) { - if (accounts == null) { - accounts = AccountManager.get(context).getAccounts(); - } - mEnabledAccountTypes.clear(); - mAccTypeIconCache.clear(); - for (Account account: accounts) { - if (!mEnabledAccountTypes.contains(account.type)) { - mEnabledAccountTypes.add(account.type); - } - } - } - public boolean containsAccountType(String accountType) { return mTypeToAuthDescription.containsKey(accountType); } @@ -148,4 +168,50 @@ public class AuthenticatorHelper { } return false; } + + public void onAccountsUpdated(Account[] accounts) { + // TODO: Revert to non-public once no longer needed in SettingsActivity + // See http://b/15819268 + updateAuthDescriptions(mContext); + if (accounts == null) { + accounts = AccountManager.get(mContext).getAccounts(); + } + mEnabledAccountTypes.clear(); + mAccTypeIconCache.clear(); + for (int i = 0; i < accounts.length; i++) { + final Account account = accounts[i]; + if (!mEnabledAccountTypes.contains(account.type)) { + mEnabledAccountTypes.add(account.type); + } + } + if (mListeningToAccountUpdates) { + mListener.onAccountsUpdate(mUserHandle); + } + } + + @Override + public void onReceive(final Context context, final Intent intent) { + final Account[] accounts = AccountManager.get(mContext) + .getAccountsAsUser(mUserHandle.getIdentifier()); + onAccountsUpdated(accounts); + } + + public void listenToAccountUpdates() { + if (!mListeningToAccountUpdates) { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION); + // At disk full, certain actions are blocked (such as writing the accounts to storage). + // It is useful to also listen for recovery from disk full to avoid bugs. + intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); + mContext.registerReceiverAsUser(this, mUserHandle, intentFilter, null, null); + mListeningToAccountUpdates = true; + } + } + + public void stopListeningToAccountUpdates() { + if (mListeningToAccountUpdates) { + mContext.unregisterReceiver(this); + mListeningToAccountUpdates = false; + } + } }