Merge "Fix bug where accounts are duplicated in user&account list." into oc-dev
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index a782a7d..6ed2c34 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -123,9 +123,9 @@
          */
         public boolean pendingRemoval;
         /**
-         * The map from account name to account preference
+         * The map from account key to account preference
          */
-        public ArrayMap<CharSequence, AccountTypePreference> accountPreferences = new ArrayMap<>();
+        public ArrayMap<String, AccountTypePreference> accountPreferences = new ArrayMap<>();
     }
 
     public AccountPreferenceController(Context context, SettingsPreferenceFragment parent,
@@ -426,7 +426,7 @@
             return;
         }
         if (profileData.userInfo.isEnabled()) {
-            final ArrayMap<CharSequence, AccountTypePreference> preferenceToRemove =
+            final ArrayMap<String, AccountTypePreference> preferenceToRemove =
                     new ArrayMap<>(profileData.accountPreferences);
             final ArrayList<AccountTypePreference> preferences = getAccountTypePreferences(
                     profileData.authenticatorHelper, profileData.userInfo.getUserHandle(),
@@ -435,18 +435,19 @@
             for (int i = 0; i < count; i++) {
                 final AccountTypePreference preference = preferences.get(i);
                 preference.setOrder(i);
-                if (!profileData.accountPreferences.containsValue(preference)) {
-                    profileData.preferenceGroup.addPreference(preferences.get(i));
-                    profileData.accountPreferences.put(preference.getTitle(), preference);
+                final String key = preference.getKey();
+                if (!profileData.accountPreferences.containsKey(key)) {
+                    profileData.preferenceGroup.addPreference(preference);
+                    profileData.accountPreferences.put(key, preference);
                 }
             }
             if (profileData.addAccountPreference != null) {
                 profileData.preferenceGroup.addPreference(profileData.addAccountPreference);
             }
-            for (CharSequence name : preferenceToRemove.keySet()) {
+            for (String key : preferenceToRemove.keySet()) {
                 profileData.preferenceGroup.removePreference(
-                    profileData.accountPreferences.get(name));
-                profileData.accountPreferences.remove(name);
+                    profileData.accountPreferences.get(key));
+                profileData.accountPreferences.remove(key);
             }
         } else {
             profileData.preferenceGroup.removeAll();
@@ -471,8 +472,7 @@
     }
 
     private ArrayList<AccountTypePreference> getAccountTypePreferences(AuthenticatorHelper helper,
-            UserHandle userHandle,
-            ArrayMap<CharSequence, AccountTypePreference> preferenceToRemove) {
+            UserHandle userHandle, ArrayMap<String, AccountTypePreference> preferenceToRemove) {
         final String[] accountTypes = helper.getEnabledAccountTypes();
         final ArrayList<AccountTypePreference> accountTypePreferences =
                 new ArrayList<>(accountTypes.length);
@@ -497,7 +497,8 @@
 
             // Add a preference row for each individual account
             for (Account account : accounts) {
-                final AccountTypePreference preference = preferenceToRemove.remove(account.name);
+                final AccountTypePreference preference =
+                        preferenceToRemove.remove(AccountTypePreference.buildKey(account));
                 if (preference != null) {
                     accountTypePreferences.add(preference);
                     continue;
@@ -521,7 +522,7 @@
                 fragmentArguments.putParcelable(EXTRA_USER, userHandle);
                 accountTypePreferences.add(new AccountTypePreference(
                     prefContext, mMetricsFeatureProvider.getMetricsCategory(mParent),
-                    account.name, titleResPackageName, titleResId, label,
+                    account, titleResPackageName, titleResId, label,
                     AccountDetailDashboardFragment.class.getName(), fragmentArguments, icon));
             }
             helper.preloadDrawableForType(mContext, accountType);
diff --git a/src/com/android/settings/accounts/AccountTypePreference.java b/src/com/android/settings/accounts/AccountTypePreference.java
index 0abfb50..4f92829 100644
--- a/src/com/android/settings/accounts/AccountTypePreference.java
+++ b/src/com/android/settings/accounts/AccountTypePreference.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.accounts;
 
+import android.accounts.Account;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -67,18 +68,11 @@
 
     private final int mMetricsCategory;
 
-    public AccountTypePreference(Context context, int metricsCategory, CharSequence title,
-            String titleResPackageName, int titleResId, String fragment, Bundle fragmentArguments,
-            Drawable icon) {
-        this(context, metricsCategory, title, titleResPackageName, titleResId, null, fragment,
-                fragmentArguments, icon);
-    }
-
-    public AccountTypePreference(Context context, int metricsCategory, CharSequence title,
+    public AccountTypePreference(Context context, int metricsCategory, Account account,
             String titleResPackageName, int titleResId, CharSequence summary, String fragment,
             Bundle fragmentArguments, Drawable icon) {
         super(context);
-        mTitle = title;
+        mTitle = account.name;
         mTitleResPackageName = titleResPackageName;
         mTitleResId = titleResId;
         mSummary = summary;
@@ -87,7 +81,8 @@
         mMetricsCategory = metricsCategory;
         setWidgetLayoutResource(R.layout.account_type_preference);
 
-        setTitle(title);
+        setKey(buildKey(account));
+        setTitle(mTitle);
         setSummary(summary);
         setIcon(icon);
 
@@ -115,6 +110,13 @@
         return false;
     }
 
+    /**
+     * Build a unique preference key based on account.
+     */
+    public static String buildKey(Account account) {
+        return String.valueOf(account.hashCode());
+    }
+
     public CharSequence getTitle() {
         return mTitle;
     }
@@ -122,5 +124,4 @@
     public CharSequence getSummary() {
         return mSummary;
     }
-
 }
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
index 8453da5..66f5549 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
@@ -26,8 +26,8 @@
 import android.support.v7.preference.PreferenceGroup;
 import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceScreen;
-
 import android.text.TextUtils;
+
 import com.android.settings.AccessiblePreferenceCategory;
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
@@ -92,7 +92,7 @@
         when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
         when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
         when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(
-            new AuthenticatorDescription[0]);
+                new AuthenticatorDescription[0]);
         when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
         mController = new AccountPreferenceController(mContext, mFragment, null, mAccountHelper);
     }
@@ -367,6 +367,51 @@
 
     @Test
     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
+    public void onResume_twoAccountsOfSameName_shouldAddFivePreferences() {
+        final List<UserInfo> infos = new ArrayList<>();
+        infos.add(new UserInfo(1, "user 1", 0));
+        when(mUserManager.isManagedProfile()).thenReturn(false);
+        when(mUserManager.isLinkedUser()).thenReturn(false);
+        when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
+
+        final Account[] accountType1 = new Account[2];
+        accountType1[0] = new Account("Account1", "com.acct1");
+        accountType1[1] = new Account("Account2", "com.acct1");
+        final Account[] accountType2 = new Account[2];
+        accountType2[0] = new Account("Account1", "com.acct2");
+        accountType2[1] = new Account("Account2", "com.acct2");
+        final Account[] allAccounts = new Account[4];
+        allAccounts[0] = accountType1[0];
+        allAccounts[1] = accountType1[1];
+        allAccounts[2] = accountType2[0];
+        allAccounts[3] = accountType2[1];
+        final AuthenticatorDescription[] authDescs = {
+                new AuthenticatorDescription("com.acct1", "com.android.settings",
+                        R.string.account_settings_title, 0, 0, 0, false),
+                new AuthenticatorDescription("com.acct2", "com.android.settings",
+                        R.string.account_settings_title, 0, 0, 0, false)
+        };
+
+        when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(allAccounts);
+        when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
+                .thenReturn(accountType1);
+        when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct2"), any(UserHandle.class)))
+                .thenReturn(accountType2);
+        when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
+
+        AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
+        when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
+        when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
+                preferenceGroup);
+
+        mController.onResume();
+
+        // should add 4 individual account and the Add account preference
+        verify(preferenceGroup, times(5)).addPreference(any(Preference.class));
+    }
+
+    @Test
+    @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
     public void onResume_noAccountChange_shouldNotAddAccountPreference() {
         final List<UserInfo> infos = new ArrayList<>();
         infos.add(new UserInfo(1, "user 1", 0));