Revert "Rollback decision to merge by package name"

This reverts commit ca542c90cd2506daf1c4de72f34de940c8128d76.

Reason for revert: product changed mind

Change-Id: Ic4b9275e8f19bf2b3e3e51f09162fb6d45e6a5bf
diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
index 37c8f4f..157fee1 100644
--- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
@@ -82,15 +83,16 @@
     public static final String ADD_SERVICE_DEVICE_CONFIG = "credential_manager_service_search_uri";
     private static final String TAG = "CredentialManagerPreferenceController";
     private static final String ALTERNATE_INTENT = "android.settings.SYNC_SETTINGS";
+    private static final String PRIMARY_INTENT = "android.settings.CREDENTIAL_PROVIDER";
     private static final int MAX_SELECTABLE_PROVIDERS = 5;
 
     private final PackageManager mPm;
     private final IconDrawableFactory mIconFactory;
     private final List<CredentialProviderInfo> mServices;
-    private final Set<ServiceInfo> mEnabledServiceInfos;
+    private final Set<String> mEnabledPackageNames;
     private final @Nullable CredentialManager mCredentialManager;
     private final Executor mExecutor;
-    private final Map<ServiceInfo, SwitchPreference> mPrefs = new HashMap<>();
+    private final Map<String, SwitchPreference> mPrefs = new HashMap<>(); // key is package name
     private final List<ServiceInfo> mPendingServiceInfos = new ArrayList<>();
     private final Handler mHandler = new Handler();
 
@@ -104,7 +106,7 @@
         mPm = context.getPackageManager();
         mIconFactory = IconDrawableFactory.newInstance(mContext);
         mServices = new ArrayList<>();
-        mEnabledServiceInfos = new HashSet<>();
+        mEnabledPackageNames = new HashSet<>();
         mExecutor = ContextCompat.getMainExecutor(mContext);
         mCredentialManager =
                 getCredentialManager(context, preferenceKey.equals("credentials_test"));
@@ -161,8 +163,7 @@
         }
 
         final String action = launchIntent.getAction();
-        final boolean isCredProviderAction =
-                TextUtils.equals(action, Settings.ACTION_CREDENTIAL_PROVIDER);
+        final boolean isCredProviderAction = TextUtils.equals(action, PRIMARY_INTENT);
         final boolean isExistingAction = TextUtils.equals(action, ALTERNATE_INTENT);
         final boolean isValid = isCredProviderAction || isExistingAction;
 
@@ -222,18 +223,20 @@
         }
 
         ServiceInfo serviceInfo = pendingServiceInfos.get(0);
-        CharSequence serviceLabel = "";
-        if (serviceInfo.nonLocalizedLabel != null) {
-            serviceLabel = serviceInfo.loadLabel(mPm);
+        ApplicationInfo appInfo = serviceInfo.applicationInfo;
+        CharSequence appName = "";
+        if (appInfo.nonLocalizedLabel != null) {
+            appName = appInfo.loadLabel(mPm);
         }
 
-        // Stop if there is no service label.
-        if (TextUtils.isEmpty(serviceLabel)) {
+        // Stop if there is no name.
+        if (TextUtils.isEmpty(appName)) {
             return;
         }
 
         NewProviderConfirmationDialogFragment fragment =
-                newNewProviderConfirmationDialogFragment(serviceInfo, serviceLabel, /* setActivityResult= */ true);
+                newNewProviderConfirmationDialogFragment(
+                        serviceInfo.packageName, appName, /* setActivityResult= */ true);
         if (fragment == null || mFragmentManager == null) {
             return;
         }
@@ -276,15 +279,15 @@
         // If there is a pending dialog then show it.
         handleIntent();
 
-        mEnabledServiceInfos.clear();
+        mEnabledPackageNames.clear();
         for (CredentialProviderInfo cpi : availableServices) {
             if (cpi.isEnabled()) {
-                mEnabledServiceInfos.add(cpi.getServiceInfo());
+                mEnabledPackageNames.add(cpi.getServiceInfo().packageName);
             }
         }
 
-        for (ServiceInfo serviceInfo : mPrefs.keySet()) {
-            mPrefs.get(serviceInfo).setChecked(mEnabledServiceInfos.contains(serviceInfo));
+        for (String packageName : mPrefs.keySet()) {
+            mPrefs.get(packageName).setChecked(mEnabledPackageNames.contains(packageName));
         }
     }
 
@@ -367,7 +370,7 @@
 
     /** Aggregates the list of services and builds a list of UI prefs to show. */
     @VisibleForTesting
-    public Map<ServiceInfo, SwitchPreference> buildPreferenceList(
+    public Map<String, SwitchPreference> buildPreferenceList(
             Context context, PreferenceGroup group) {
         // Group the services by package name.
         Map<String, List<CredentialProviderInfo>> groupedInfos = new HashMap<>();
@@ -385,11 +388,33 @@
         }
 
         // Build the pref list.
-        Map<ServiceInfo, SwitchPreference> output = new HashMap<>();
-        for (CredentialProviderInfo service : mServices) {
+        Map<String, SwitchPreference> output = new HashMap<>();
+        for (String packageName : groupedInfos.keySet()) {
+            List<CredentialProviderInfo> infos = groupedInfos.get(packageName);
+            CredentialProviderInfo firstInfo = infos.get(0);
+            ServiceInfo firstServiceInfo = firstInfo.getServiceInfo();
+            CharSequence title = firstInfo.getLabel(context);
+            Drawable icon = firstInfo.getServiceIcon(context);
+
+            if (infos.size() > 1) {
+                // If there is more than one then group them under the package.
+                ApplicationInfo appInfo = firstServiceInfo.applicationInfo;
+                if (appInfo.nonLocalizedLabel != null) {
+                    title = appInfo.loadLabel(mPm);
+                }
+                icon = mIconFactory.getBadgedIcon(appInfo, getUser());
+            }
+
+            // If there is no title then show the package manager.
+            if (TextUtils.isEmpty(title)) {
+                title = firstServiceInfo.packageName;
+            }
+
             // Build the pref and add it to the output & group.
-            SwitchPreference pref = createPreference(mContext, service);
-            output.put(service.getServiceInfo(), pref);
+            SwitchPreference pref =
+                    addProviderPreference(
+                            context, title, icon, packageName, firstInfo.getSettingsSubtitle());
+            output.put(packageName, pref);
             group.addPreference(pref);
         }
 
@@ -399,54 +424,46 @@
     /** Creates a preference object based on the provider info. */
     @VisibleForTesting
     public SwitchPreference createPreference(Context context, CredentialProviderInfo service) {
-        final String packageName = service.getServiceInfo().packageName;
         CharSequence label = service.getLabel(context);
-
-        // If there is no label then show the package name.
-        if (label == null || TextUtils.isEmpty(label)) {
-            label = packageName;
-        }
-
         return addProviderPreference(
                 context,
-                label,
+                label == null ? "" : label,
                 service.getServiceIcon(mContext),
-                packageName,
-                service.getSettingsSubtitle(),
-                service.getServiceInfo());
+                service.getServiceInfo().packageName,
+                service.getSettingsSubtitle());
     }
 
     /**
-     * Enables the service as an enabled credential manager provider.
+     * Enables the package name as an enabled credential manager provider.
      *
-     * @param service the service to enable
+     * @param packageName the package name to enable
      */
     @VisibleForTesting
-    public boolean toggleServiceInfoEnabled(ServiceInfo service) {
-        if (mEnabledServiceInfos.size() >= MAX_SELECTABLE_PROVIDERS) {
+    public boolean togglePackageNameEnabled(String packageName) {
+        if (mEnabledPackageNames.size() >= MAX_SELECTABLE_PROVIDERS) {
             return false;
         } else {
-            mEnabledServiceInfos.add(service);
-            commitEnabledServices();
+            mEnabledPackageNames.add(packageName);
+            commitEnabledPackages();
             return true;
         }
     }
 
     /**
-     * Disables the service as a credential manager provider.
+     * Disables the package name as a credential manager provider.
      *
-     * @param service the service to disable
+     * @param packageName the package name to disable
      */
     @VisibleForTesting
-    public void toggleServiceInfoDisabled(ServiceInfo service) {
-        mEnabledServiceInfos.remove(service);
-        commitEnabledServices();
+    public void togglePackageNameDisabled(String packageName) {
+        mEnabledPackageNames.remove(packageName);
+        commitEnabledPackages();
     }
 
     /** Returns the enabled credential manager provider package names. */
     @VisibleForTesting
-    public Set<ServiceInfo> getEnabledProviders() {
-        return mEnabledServiceInfos;
+    public Set<String> getEnabledProviders() {
+        return mEnabledPackageNames;
     }
 
     /**
@@ -457,8 +474,11 @@
     public List<String> getEnabledSettings() {
         // Get all the component names that match the enabled package names.
         List<String> enabledServices = new ArrayList<>();
-        for (ServiceInfo service : mEnabledServiceInfos) {
-            enabledServices.add(service.getComponentName().flattenToString());
+        for (CredentialProviderInfo service : mServices) {
+            ComponentName cn = service.getServiceInfo().getComponentName();
+            if (mEnabledPackageNames.contains(service.getServiceInfo().packageName)) {
+                enabledServices.add(cn.flattenToString());
+            }
         }
 
         return enabledServices;
@@ -469,11 +489,10 @@
             @NonNull CharSequence title,
             @Nullable Drawable icon,
             @NonNull String packageName,
-            @Nullable CharSequence subtitle,
-            @NonNull ServiceInfo service) {
+            @Nullable CharSequence subtitle) {
         final SwitchPreference pref = new SwitchPreference(prefContext);
         pref.setTitle(title);
-        pref.setChecked(mEnabledServiceInfos.contains(service));
+        pref.setChecked(mEnabledPackageNames.contains(packageName));
 
         if (icon != null) {
             pref.setIcon(Utils.getSafeIcon(icon));
@@ -492,7 +511,7 @@
                         // dialog box.
                         NewProviderConfirmationDialogFragment fragment =
                                 newNewProviderConfirmationDialogFragment(
-                                        service, title, /* setActivityResult= */ false);
+                                        packageName, title, /* setActivityResult= */ false);
                         if (fragment == null || mFragmentManager == null) {
                             return true;
                         }
@@ -502,9 +521,9 @@
                         return true;
                     } else {
                         // If we are disabling the last enabled provider then show a warning.
-                        if (mEnabledServiceInfos.size() <= 1) {
+                        if (mEnabledPackageNames.size() <= 1) {
                             final DialogFragment fragment =
-                                    newConfirmationDialogFragment(service, title, pref);
+                                    newConfirmationDialogFragment(packageName, title, pref);
 
                             if (fragment == null || mFragmentManager == null) {
                                 return true;
@@ -512,7 +531,7 @@
 
                             fragment.show(mFragmentManager, ConfirmationDialogFragment.TAG);
                         } else {
-                            toggleServiceInfoDisabled(service);
+                            togglePackageNameDisabled(packageName);
                         }
                     }
 
@@ -522,7 +541,7 @@
         return pref;
     }
 
-    private void commitEnabledServices() {
+    private void commitEnabledPackages() {
         // Commit using the CredMan API.
         if (mCredentialManager == null) {
             return;
@@ -549,18 +568,19 @@
     /** Create the new provider confirmation dialog. */
     private @Nullable NewProviderConfirmationDialogFragment
             newNewProviderConfirmationDialogFragment(
-                    @NonNull ServiceInfo service,
+                    @NonNull String packageName,
                     @NonNull CharSequence appName,
                     boolean setActivityResult) {
         DialogHost host =
                 new DialogHost() {
                     @Override
                     public void onDialogClick(int whichButton) {
-                        completeEnableProviderDialogBox(whichButton, service, setActivityResult);
+                        completeEnableProviderDialogBox(
+                                whichButton, packageName, setActivityResult);
                     }
                 };
 
-        return new NewProviderConfirmationDialogFragment(host, service, appName);
+        return new NewProviderConfirmationDialogFragment(host, packageName, appName);
     }
 
     /** If the provider is also the autofill provider then hide it. */
@@ -581,13 +601,14 @@
     }
 
     @VisibleForTesting
-    void completeEnableProviderDialogBox(int whichButton, ServiceInfo service, boolean setActivityResult) {
+    void completeEnableProviderDialogBox(
+            int whichButton, String packageName, boolean setActivityResult) {
         int activityResult = -1;
         if (whichButton == DialogInterface.BUTTON_POSITIVE) {
-            if (toggleServiceInfoEnabled(service)) {
+            if (togglePackageNameEnabled(packageName)) {
                 // Enable all prefs.
-                if (mPrefs.containsKey(service)) {
-                    mPrefs.get(service).setChecked(true);
+                if (mPrefs.containsKey(packageName)) {
+                    mPrefs.get(packageName).setChecked(true);
                 }
                 activityResult = Activity.RESULT_OK;
             } else {
@@ -626,7 +647,7 @@
     }
 
     private @Nullable ConfirmationDialogFragment newConfirmationDialogFragment(
-            @NonNull ServiceInfo service,
+            @NonNull String packageName,
             @NonNull CharSequence appName,
             @NonNull SwitchPreference pref) {
         DialogHost host =
@@ -636,7 +657,7 @@
                         if (whichButton == DialogInterface.BUTTON_POSITIVE) {
                             // Since the package is now enabled then we
                             // should remove it from the enabled list.
-                            toggleServiceInfoDisabled(service);
+                            togglePackageNameDisabled(packageName);
                         } else if (whichButton == DialogInterface.BUTTON_NEGATIVE) {
                             // Set the checked back to true because we
                             // backed out of turning this off.
@@ -645,7 +666,7 @@
                     }
                 };
 
-        return new ConfirmationDialogFragment(host, service, appName);
+        return new ConfirmationDialogFragment(host, packageName, appName);
     }
 
     private int getUser() {
@@ -730,13 +751,11 @@
     public static class ConfirmationDialogFragment extends CredentialManagerDialogFragment {
 
         ConfirmationDialogFragment(
-                DialogHost dialogHost,
-                @NonNull ServiceInfo serviceInfo,
-                @NonNull CharSequence appName) {
+                DialogHost dialogHost, @NonNull String packageName, @NonNull CharSequence appName) {
             super(dialogHost);
 
             final Bundle argument = new Bundle();
-            argument.putString(PACKAGE_NAME_KEY, serviceInfo.packageName);
+            argument.putString(PACKAGE_NAME_KEY, packageName);
             argument.putCharSequence(APP_NAME_KEY, appName);
             setArguments(argument);
         }
@@ -773,13 +792,11 @@
             extends CredentialManagerDialogFragment {
 
         NewProviderConfirmationDialogFragment(
-                DialogHost dialogHost,
-                @NonNull ServiceInfo service,
-                @NonNull CharSequence appName) {
+                DialogHost dialogHost, @NonNull String packageName, @NonNull CharSequence appName) {
             super(dialogHost);
 
             final Bundle argument = new Bundle();
-            argument.putString(PACKAGE_NAME_KEY, service.packageName);
+            argument.putString(PACKAGE_NAME_KEY, packageName);
             argument.putCharSequence(APP_NAME_KEY, appName);
             setArguments(argument);
         }
@@ -832,4 +849,4 @@
             updateFromExternal();
         }
     }
-}
+}
\ No newline at end of file
diff --git a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
index dd92810..a97d5f7 100644
--- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
@@ -51,9 +51,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 
@@ -72,6 +72,8 @@
     private static final String TEST_TITLE_APP_A = "test app A";
     private static final String TEST_TITLE_APP_B = "test app B";
     private static final String TEST_TITLE_SERVICE_C = "test service C1";
+    private static final String PRIMARY_INTENT = "android.settings.CREDENTIAL_PROVIDER";
+    private static final String ALTERNATE_INTENT = "android.settings.SYNC_SETTINGS";
 
     @Before
     public void setUp() {
@@ -193,10 +195,10 @@
     @Test
     public void buildSwitchPreference() {
         CredentialProviderInfo providerInfo1 =
-                createCredentialProviderInfoWithSettingsSubtitle(
+                createCredentialProviderInfoWithSubtitle(
                         "com.android.provider1", "ClassA", "Service Title", null);
         CredentialProviderInfo providerInfo2 =
-                createCredentialProviderInfoWithSettingsSubtitle(
+                createCredentialProviderInfoWithSubtitle(
                         "com.android.provider2", "ClassA", "Service Title", "Summary Text");
         CredentialManagerPreferenceController controller =
                 createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
@@ -209,10 +211,10 @@
         assertThat(controller.getEnabledProviders().size()).isEqualTo(0);
 
         // Toggle one provider and make sure it worked.
-        assertThat(controller.toggleServiceInfoEnabled(providerInfo1.getServiceInfo())).isTrue();
-        Set<ServiceInfo> enabledProviders = controller.getEnabledProviders();
+        assertThat(controller.togglePackageNameEnabled("com.android.provider1")).isTrue();
+        Set<String> enabledProviders = controller.getEnabledProviders();
         assertThat(enabledProviders.size()).isEqualTo(1);
-        assertThat(enabledProviders.contains(providerInfo1.getServiceInfo())).isTrue();
+        assertThat(enabledProviders.contains("com.android.provider1")).isTrue();
 
         // Create the pref (checked).
         SwitchPreference pref = controller.createPreference(mContext, providerInfo1);
@@ -221,8 +223,7 @@
         assertThat(pref.getSummary()).isNull();
 
         // Create the pref (not checked).
-        SwitchPreference pref2 =
-                controller.createPreference(mContext, providerInfo2);
+        SwitchPreference pref2 = controller.createPreference(mContext, providerInfo2);
         assertThat(pref2.getTitle().toString()).isEqualTo("Service Title");
         assertThat(pref2.isChecked()).isFalse();
         assertThat(pref2.getSummary().toString()).isEqualTo("Summary Text");
@@ -230,14 +231,6 @@
 
     @Test
     public void getAvailabilityStatus_handlesToggleAndSave() {
-        ServiceInfo providerService1a = createServiceInfo("com.android.provider1", "ClassA");
-        ServiceInfo providerService1b = createServiceInfo("com.android.provider1", "ClassB");
-        ServiceInfo providerService2 = createServiceInfo("com.android.provider2", "ClassA");
-        ServiceInfo providerService3 = createServiceInfo("com.android.provider3", "ClassA");
-        ServiceInfo providerService4 = createServiceInfo("com.android.provider4", "ClassA");
-        ServiceInfo providerService5 = createServiceInfo("com.android.provider5", "ClassA");
-        ServiceInfo providerService6 = createServiceInfo("com.android.provider6", "ClassA");
-
         CredentialManagerPreferenceController controller =
                 createControllerWithServices(
                         Lists.newArrayList(
@@ -252,28 +245,28 @@
         assertThat(controller.isConnected()).isFalse();
 
         // Ensure that we stay under 5 providers.
-        assertThat(controller.toggleServiceInfoEnabled(providerService1a)).isTrue();
-        assertThat(controller.toggleServiceInfoEnabled(providerService2)).isTrue();
-        assertThat(controller.toggleServiceInfoEnabled(providerService3)).isTrue();
-        assertThat(controller.toggleServiceInfoEnabled(providerService4)).isTrue();
-        assertThat(controller.toggleServiceInfoEnabled(providerService5)).isTrue();
-        assertThat(controller.toggleServiceInfoEnabled(providerService6)).isFalse();
+        assertThat(controller.togglePackageNameEnabled("com.android.provider1")).isTrue();
+        assertThat(controller.togglePackageNameEnabled("com.android.provider2")).isTrue();
+        assertThat(controller.togglePackageNameEnabled("com.android.provider3")).isTrue();
+        assertThat(controller.togglePackageNameEnabled("com.android.provider4")).isTrue();
+        assertThat(controller.togglePackageNameEnabled("com.android.provider5")).isTrue();
+        assertThat(controller.togglePackageNameEnabled("com.android.provider6")).isFalse();
 
         // Check that they are all actually registered.
-        Set<ServiceInfo> enabledProviders = controller.getEnabledProviders();
+        Set<String> enabledProviders = controller.getEnabledProviders();
         assertThat(enabledProviders.size()).isEqualTo(5);
-        assertThat(enabledProviders.contains(providerService1a)).isTrue();
-        assertThat(enabledProviders.contains(providerService2)).isTrue();
-        assertThat(enabledProviders.contains(providerService3)).isTrue();
-        assertThat(enabledProviders.contains(providerService4)).isTrue();
-        assertThat(enabledProviders.contains(providerService5)).isTrue();
-        assertThat(enabledProviders.contains(providerService6)).isFalse();
+        assertThat(enabledProviders.contains("com.android.provider1")).isTrue();
+        assertThat(enabledProviders.contains("com.android.provider2")).isTrue();
+        assertThat(enabledProviders.contains("com.android.provider3")).isTrue();
+        assertThat(enabledProviders.contains("com.android.provider4")).isTrue();
+        assertThat(enabledProviders.contains("com.android.provider5")).isTrue();
+        assertThat(enabledProviders.contains("com.android.provider6")).isFalse();
 
         // Check that the settings string has the right component names.
         List<String> enabledServices = controller.getEnabledSettings();
-        assertThat(enabledServices.size()).isEqualTo(5);
+        assertThat(enabledServices.size()).isEqualTo(6);
         assertThat(enabledServices.contains("com.android.provider1/ClassA")).isTrue();
-        assertThat(enabledServices.contains("com.android.provider1/ClassB")).isFalse();
+        assertThat(enabledServices.contains("com.android.provider1/ClassB")).isTrue();
         assertThat(enabledServices.contains("com.android.provider2/ClassA")).isTrue();
         assertThat(enabledServices.contains("com.android.provider3/ClassA")).isTrue();
         assertThat(enabledServices.contains("com.android.provider4/ClassA")).isTrue();
@@ -281,24 +274,23 @@
         assertThat(enabledServices.contains("com.android.provider6/ClassA")).isFalse();
 
         // Toggle the provider disabled.
-        controller.toggleServiceInfoDisabled(providerService2);
+        controller.togglePackageNameDisabled("com.android.provider2");
 
         // Check that the provider was removed from the list of providers.
-        Set<ServiceInfo> currentlyEnabledProviders = controller.getEnabledProviders();
+        Set<String> currentlyEnabledProviders = controller.getEnabledProviders();
         assertThat(currentlyEnabledProviders.size()).isEqualTo(4);
-        assertThat(enabledProviders.contains(providerService1a)).isTrue();
-        assertThat(enabledProviders.contains(providerService2)).isFalse();
-        assertThat(enabledProviders.contains(providerService3)).isTrue();
-        assertThat(enabledProviders.contains(providerService4)).isTrue();
-        assertThat(enabledProviders.contains(providerService5)).isTrue();
-        assertThat(enabledProviders.contains(providerService6)).isFalse();
+        assertThat(currentlyEnabledProviders.contains("com.android.provider1")).isTrue();
+        assertThat(currentlyEnabledProviders.contains("com.android.provider2")).isFalse();
+        assertThat(currentlyEnabledProviders.contains("com.android.provider3")).isTrue();
+        assertThat(currentlyEnabledProviders.contains("com.android.provider4")).isTrue();
+        assertThat(currentlyEnabledProviders.contains("com.android.provider5")).isTrue();
+        assertThat(currentlyEnabledProviders.contains("com.android.provider6")).isFalse();
 
         // Check that the provider was removed from the list of services stored in the setting.
         List<String> currentlyEnabledServices = controller.getEnabledSettings();
-        assertThat(currentlyEnabledServices.size()).isEqualTo(4);
+        assertThat(currentlyEnabledServices.size()).isEqualTo(5);
         assertThat(currentlyEnabledServices.contains("com.android.provider1/ClassA")).isTrue();
-        assertThat(currentlyEnabledServices.contains("com.android.provider1/ClassB")).isFalse();
-        assertThat(currentlyEnabledServices.contains("com.android.provider2/ClassA")).isFalse();
+        assertThat(currentlyEnabledServices.contains("com.android.provider1/ClassB")).isTrue();
         assertThat(currentlyEnabledServices.contains("com.android.provider3/ClassA")).isTrue();
         assertThat(currentlyEnabledServices.contains("com.android.provider4/ClassA")).isTrue();
         assertThat(currentlyEnabledServices.contains("com.android.provider5/ClassA")).isTrue();
@@ -307,8 +299,6 @@
 
     @Test
     public void handlesCredentialProviderInfoEnabledDisabled() {
-        ServiceInfo providerService1 = createServiceInfo("com.android.provider1", "ClassA");
-        ServiceInfo providerService2 = createServiceInfo("com.android.provider2", "ClassA");
         CredentialProviderInfo providerInfo1 =
                 createCredentialProviderInfoWithIsEnabled(
                         "com.android.provider1", "ClassA", "Service Title", false);
@@ -325,10 +315,10 @@
         assertThat(providerInfo2.isEnabled()).isTrue();
 
         // Check that they are all actually registered.
-        Set<ServiceInfo> enabledProviders = controller.getEnabledProviders();
+        Set<String> enabledProviders = controller.getEnabledProviders();
         assertThat(enabledProviders.size()).isEqualTo(1);
-        assertThat(enabledProviders.contains(providerInfo1.getServiceInfo())).isFalse();
-        assertThat(enabledProviders.contains(providerInfo2.getServiceInfo())).isTrue();
+        assertThat(enabledProviders.contains("com.android.provider1")).isFalse();
+        assertThat(enabledProviders.contains("com.android.provider2")).isTrue();
 
         // Check that the settings string has the right component names.
         List<String> enabledServices = controller.getEnabledSettings();
@@ -338,13 +328,72 @@
     }
 
     @Test
+    public void displayPreference_withServices_preferencesAdded_sameAppShouldBeMerged() {
+        CredentialProviderInfo serviceA1 =
+                createCredentialProviderInfoWithAppLabel(
+                        TEST_PACKAGE_NAME_A,
+                        "CredManProviderA1",
+                        TEST_TITLE_APP_A,
+                        "test service A1");
+        CredentialProviderInfo serviceB1 =
+                createCredentialProviderInfoWithAppLabel(
+                        TEST_PACKAGE_NAME_B,
+                        "CredManProviderB1",
+                        TEST_TITLE_APP_B,
+                        "test service B");
+        CredentialProviderInfo serviceC1 =
+                createCredentialProviderInfoWithAppLabel(
+                        TEST_PACKAGE_NAME_C,
+                        "CredManProviderC1",
+                        "test app C1",
+                        TEST_TITLE_SERVICE_C);
+        CredentialProviderInfo serviceC2 =
+                createCredentialProviderInfoWithAppLabel(
+                        TEST_PACKAGE_NAME_C,
+                        "CredManProviderC2",
+                        "test app C2",
+                        TEST_TITLE_SERVICE_C);
+        CredentialProviderInfo serviceC3 =
+                createCredentialProviderInfoBuilder(
+                                TEST_PACKAGE_NAME_C,
+                                "CredManProviderC3",
+                                "test app C3",
+                                TEST_TITLE_SERVICE_C)
+                        .setEnabled(true)
+                        .build();
+
+        CredentialManagerPreferenceController controller =
+                createControllerWithServices(
+                        Lists.newArrayList(serviceA1, serviceB1, serviceC1, serviceC2, serviceC3));
+        controller.displayPreference(mScreen);
+
+        assertThat(controller.isConnected()).isFalse();
+        assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(3);
+
+        Map<String, SwitchPreference> prefs =
+                controller.buildPreferenceList(mContext, mCredentialsPreferenceCategory);
+        assertThat(prefs.keySet())
+                .containsExactly(TEST_PACKAGE_NAME_A, TEST_PACKAGE_NAME_B, TEST_PACKAGE_NAME_C);
+        assertThat(prefs.size()).isEqualTo(3);
+        assertThat(prefs.containsKey(TEST_PACKAGE_NAME_A)).isTrue();
+        assertThat(prefs.get(TEST_PACKAGE_NAME_A).getTitle()).isEqualTo(TEST_TITLE_APP_A);
+        assertThat(prefs.get(TEST_PACKAGE_NAME_A).isChecked()).isFalse();
+        assertThat(prefs.containsKey(TEST_PACKAGE_NAME_B)).isTrue();
+        assertThat(prefs.get(TEST_PACKAGE_NAME_B).getTitle()).isEqualTo(TEST_TITLE_APP_B);
+        assertThat(prefs.get(TEST_PACKAGE_NAME_B).isChecked()).isFalse();
+        assertThat(prefs.containsKey(TEST_PACKAGE_NAME_C)).isTrue();
+        assertThat(prefs.get(TEST_PACKAGE_NAME_C).getTitle()).isEqualTo(TEST_TITLE_SERVICE_C);
+        assertThat(prefs.get(TEST_PACKAGE_NAME_C).isChecked()).isTrue();
+    }
+
+    @Test
     public void handleIntentWithProviderServiceInfo_handleBadIntent_missingData() {
         CredentialProviderInfo cpi = createCredentialProviderInfo();
         CredentialManagerPreferenceController controller =
                 createControllerWithServices(Lists.newArrayList(cpi));
 
         // Create an intent with missing data.
-        Intent missingDataIntent = new Intent(Settings.ACTION_CREDENTIAL_PROVIDER);
+        Intent missingDataIntent = new Intent(PRIMARY_INTENT);
         assertThat(controller.verifyReceivedIntent(missingDataIntent)).isFalse();
     }
 
@@ -356,11 +405,10 @@
         String packageName = cpi.getServiceInfo().packageName;
 
         // Create an intent with valid data.
-        Intent intent = new Intent(Settings.ACTION_CREDENTIAL_PROVIDER);
+        Intent intent = new Intent(PRIMARY_INTENT);
         intent.setData(Uri.parse("package:" + packageName));
         assertThat(controller.verifyReceivedIntent(intent)).isTrue();
-        controller.completeEnableProviderDialogBox(
-                DialogInterface.BUTTON_POSITIVE, cpi.getServiceInfo(), true);
+        controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_POSITIVE, packageName, true);
         assertThat(mReceivedResultCode.get()).isEqualTo(Activity.RESULT_OK);
     }
 
@@ -372,10 +420,51 @@
         String packageName = cpi.getServiceInfo().packageName;
 
         // Create an intent with valid data.
-        Intent intent = new Intent(Settings.ACTION_CREDENTIAL_PROVIDER);
+        Intent intent = new Intent(PRIMARY_INTENT);
         intent.setData(Uri.parse("package:" + packageName));
         assertThat(controller.verifyReceivedIntent(intent)).isTrue();
-        controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_NEGATIVE, cpi.getServiceInfo(), true);
+        controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_NEGATIVE, packageName, true);
+        assertThat(mReceivedResultCode.get()).isEqualTo(Activity.RESULT_CANCELED);
+    }
+
+    @Test
+    public void handleOtherIntentWithProviderServiceInfo_handleBadIntent_missingData() {
+        CredentialProviderInfo cpi = createCredentialProviderInfo();
+        CredentialManagerPreferenceController controller =
+                createControllerWithServices(Lists.newArrayList(cpi));
+
+        // Create an intent with missing data.
+        Intent missingDataIntent = new Intent(ALTERNATE_INTENT);
+        assertThat(controller.verifyReceivedIntent(missingDataIntent)).isFalse();
+    }
+
+    @Test
+    public void handleOtherIntentWithProviderServiceInfo_handleBadIntent_successDialog() {
+        CredentialProviderInfo cpi = createCredentialProviderInfo();
+        CredentialManagerPreferenceController controller =
+                createControllerWithServices(Lists.newArrayList(cpi));
+        String packageName = cpi.getServiceInfo().packageName;
+
+        // Create an intent with valid data.
+        Intent intent = new Intent(ALTERNATE_INTENT);
+        intent.setData(Uri.parse("package:" + packageName));
+        assertThat(controller.verifyReceivedIntent(intent)).isTrue();
+        controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_POSITIVE, packageName, true);
+        assertThat(mReceivedResultCode.get()).isEqualTo(Activity.RESULT_OK);
+    }
+
+    @Test
+    public void handleOtherIntentWithProviderServiceInfo_handleIntent_cancelDialog() {
+        CredentialProviderInfo cpi = createCredentialProviderInfo();
+        CredentialManagerPreferenceController controller =
+                createControllerWithServices(Lists.newArrayList(cpi));
+        String packageName = cpi.getServiceInfo().packageName;
+
+        // Create an intent with valid data.
+        Intent intent = new Intent(ALTERNATE_INTENT);
+        intent.setData(Uri.parse("package:" + packageName));
+        assertThat(controller.verifyReceivedIntent(intent)).isTrue();
+        controller.completeEnableProviderDialogBox(DialogInterface.BUTTON_NEGATIVE, packageName, true);
         assertThat(mReceivedResultCode.get()).isEqualTo(Activity.RESULT_CANCELED);
     }
 
@@ -429,17 +518,15 @@
                 .build();
     }
 
-    private CredentialProviderInfo createCredentialProviderInfo(
-            String packageName, String className, CharSequence label, boolean isEnabled) {
-        return createCredentialProviderInfo(packageName, className, label, isEnabled, null);
+    private CredentialProviderInfo createCredentialProviderInfoWithIsEnabled(
+            String packageName, String className, CharSequence serviceLabel, boolean isEnabled) {
+        return createCredentialProviderInfoBuilder(packageName, className, serviceLabel, "App Name")
+                .setEnabled(isEnabled)
+                .build();
     }
 
-    private CredentialProviderInfo createCredentialProviderInfo(
-            String packageName,
-            String className,
-            CharSequence label,
-            boolean isEnabled,
-            CharSequence subtitle) {
+    private CredentialProviderInfo createCredentialProviderInfoWithSubtitle(
+            String packageName, String className, CharSequence label, CharSequence subtitle) {
         ServiceInfo si = new ServiceInfo();
         si.packageName = packageName;
         si.name = className;
@@ -455,20 +542,6 @@
                 .build();
     }
 
-    private CredentialProviderInfo createCredentialProviderInfoWithIsEnabled(
-            String packageName, String className, CharSequence serviceLabel, boolean isEnabled) {
-        return createCredentialProviderInfoBuilder(packageName, className, serviceLabel, "App Name")
-                .setEnabled(isEnabled)
-                .build();
-    }
-
-    private CredentialProviderInfo createCredentialProviderInfoWithSettingsSubtitle(
-            String packageName, String className, CharSequence serviceLabel, String subtitle) {
-        return createCredentialProviderInfoBuilder(packageName, className, serviceLabel, "App Name")
-                .setSettingsSubtitle(subtitle)
-                .build();
-    }
-
     private CredentialProviderInfo createCredentialProviderInfoWithAppLabel(
             String packageName, String className, CharSequence serviceLabel, String appLabel) {
         return createCredentialProviderInfoBuilder(packageName, className, serviceLabel, appLabel)
@@ -488,14 +561,4 @@
 
         return new CredentialProviderInfo.Builder(si).setOverrideLabel(serviceLabel);
     }
-
-    private ServiceInfo createServiceInfo(String packageName, String className) {
-        ServiceInfo si = new ServiceInfo();
-        si.packageName = packageName;
-        si.name = className;
-
-        si.applicationInfo = new ApplicationInfo();
-        si.applicationInfo.packageName = packageName;
-        return si;
-    }
-}
+}
\ No newline at end of file