Merge "Merge credential manager providers by package name"

This commit is contained in:
Becca Hughes
2023-03-14 17:14:49 +00:00
committed by Android (Google) Code Review
2 changed files with 168 additions and 20 deletions

View File

@@ -24,7 +24,9 @@ import android.app.Dialog;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.credentials.CredentialManager; import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo; import android.credentials.CredentialProviderInfo;
import android.credentials.SetEnabledProvidersException; import android.credentials.SetEnabledProvidersException;
@@ -32,6 +34,7 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.os.OutcomeReceiver; import android.os.OutcomeReceiver;
import android.os.UserHandle; import android.os.UserHandle;
import android.text.TextUtils;
import android.util.IconDrawableFactory; import android.util.IconDrawableFactory;
import android.util.Log; import android.util.Log;
@@ -162,22 +165,64 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
PreferenceGroup group = screen.findPreference(getPreferenceKey()); PreferenceGroup group = screen.findPreference(getPreferenceKey());
Context context = screen.getContext(); Context context = screen.getContext();
mPrefs.putAll(buildPreferenceList(context, group));
for (CredentialProviderInfo service : mServices) {
group.addPreference(createPreference(context, service));
} }
/** Aggregates the list of services and builds a list of UI prefs to show. */
@VisibleForTesting
public Map<String, SwitchPreference> buildPreferenceList(
Context context, PreferenceGroup group) {
// Group the services by package name.
Map<String, List<CredentialProviderInfo>> groupedInfos = new HashMap<>();
for (CredentialProviderInfo cpi : mServices) {
String packageName = cpi.getServiceInfo().packageName;
if (!groupedInfos.containsKey(packageName)) {
groupedInfos.put(packageName, new ArrayList<>());
}
groupedInfos.get(packageName).add(cpi);
}
// Build the pref list.
Map<String, SwitchPreference> output = new HashMap<>();
for (String packageName : groupedInfos.keySet()) {
List<CredentialProviderInfo> infos = groupedInfos.get(packageName);
SwitchPreference pref = createPreference(context, groupedInfos.get(packageName));
if (pref != null) {
output.put(packageName, pref);
group.addPreference(pref);
}
}
return output;
} }
/** Creates a preference object based on the provider info. */ /** Creates a preference object based on the provider info. */
@VisibleForTesting @VisibleForTesting
public SwitchPreference createPreference(Context context, CredentialProviderInfo service) { public @Nullable SwitchPreference createPreference(
CharSequence label = service.getLabel(context); Context context, List<CredentialProviderInfo> infos) {
final CredentialProviderInfo firstInfo = infos.get(0);
final ServiceInfo firstServiceInfo = firstInfo.getServiceInfo();
final String packageName = firstServiceInfo.packageName;
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 don't show anything.
if (TextUtils.isEmpty(title)) {
return null;
}
return addProviderPreference( return addProviderPreference(
context, context, title, icon, packageName, firstInfo.getSettingsSubtitle());
label == null ? "" : label,
service.getServiceIcon(mContext),
service.getServiceInfo().packageName,
service.getSettingsSubtitle());
} }
/** /**
@@ -240,7 +285,6 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
final SwitchPreference pref = new SwitchPreference(prefContext); final SwitchPreference pref = new SwitchPreference(prefContext);
pref.setTitle(title); pref.setTitle(title);
pref.setChecked(mEnabledPackageNames.contains(packageName)); pref.setChecked(mEnabledPackageNames.contains(packageName));
mPrefs.put(packageName, pref);
if (icon != null) { if (icon != null) {
pref.setIcon(Utils.getSafeIcon(icon)); pref.setIcon(Utils.getSafeIcon(icon));

View File

@@ -44,8 +44,10 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@@ -55,6 +57,13 @@ public class CredentialManagerPreferenceControllerTest {
private PreferenceScreen mScreen; private PreferenceScreen mScreen;
private PreferenceCategory mCredentialsPreferenceCategory; private PreferenceCategory mCredentialsPreferenceCategory;
private static final String TEST_PACKAGE_NAME_A = "com.android.providerA";
private static final String TEST_PACKAGE_NAME_B = "com.android.providerB";
private static final String TEST_PACKAGE_NAME_C = "com.android.providerC";
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";
@Before @Before
public void setUp() { public void setUp() {
mContext = spy(ApplicationProvider.getApplicationContext()); mContext = spy(ApplicationProvider.getApplicationContext());
@@ -114,11 +123,11 @@ public class CredentialManagerPreferenceControllerTest {
@Test @Test
public void buildSwitchPreference() { public void buildSwitchPreference() {
CredentialProviderInfo providerInfo1 = CredentialProviderInfo providerInfo1 =
createCredentialProviderInfo( createCredentialProviderInfoWithSettingsSubtitle(
"com.android.provider1", "ClassA", "Service Title", false, null); "com.android.provider1", "ClassA", "Service Title", null);
CredentialProviderInfo providerInfo2 = CredentialProviderInfo providerInfo2 =
createCredentialProviderInfo( createCredentialProviderInfoWithSettingsSubtitle(
"com.android.provider2", "ClassA", "Service Title", false, "Summary Text"); "com.android.provider2", "ClassA", "Service Title", "Summary Text");
CredentialManagerPreferenceController controller = CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2)); createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
@@ -136,13 +145,14 @@ public class CredentialManagerPreferenceControllerTest {
assertThat(enabledProviders.contains("com.android.provider1")).isTrue(); assertThat(enabledProviders.contains("com.android.provider1")).isTrue();
// Create the pref (checked). // Create the pref (checked).
SwitchPreference pref = controller.createPreference(mContext, providerInfo1); SwitchPreference pref = controller.createPreference(mContext, Arrays.asList(providerInfo1));
assertThat(pref.getTitle().toString()).isEqualTo("Service Title"); assertThat(pref.getTitle().toString()).isEqualTo("Service Title");
assertThat(pref.isChecked()).isTrue(); assertThat(pref.isChecked()).isTrue();
assertThat(pref.getSummary()).isNull(); assertThat(pref.getSummary()).isNull();
// Create the pref (not checked). // Create the pref (not checked).
SwitchPreference pref2 = controller.createPreference(mContext, providerInfo2); SwitchPreference pref2 =
controller.createPreference(mContext, Arrays.asList(providerInfo2));
assertThat(pref2.getTitle().toString()).isEqualTo("Service Title"); assertThat(pref2.getTitle().toString()).isEqualTo("Service Title");
assertThat(pref2.isChecked()).isFalse(); assertThat(pref2.isChecked()).isFalse();
assertThat(pref2.getSummary().toString()).isEqualTo("Summary Text"); assertThat(pref2.getSummary().toString()).isEqualTo("Summary Text");
@@ -219,10 +229,10 @@ public class CredentialManagerPreferenceControllerTest {
@Test @Test
public void handlesCredentialProviderInfoEnabledDisabled() { public void handlesCredentialProviderInfoEnabledDisabled() {
CredentialProviderInfo providerInfo1 = CredentialProviderInfo providerInfo1 =
createCredentialProviderInfo( createCredentialProviderInfoWithIsEnabled(
"com.android.provider1", "ClassA", "Service Title", false); "com.android.provider1", "ClassA", "Service Title", false);
CredentialProviderInfo providerInfo2 = CredentialProviderInfo providerInfo2 =
createCredentialProviderInfo( createCredentialProviderInfoWithIsEnabled(
"com.android.provider2", "ClassA", "Service Title", true); "com.android.provider2", "ClassA", "Service Title", true);
CredentialManagerPreferenceController controller = CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2)); createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
@@ -246,6 +256,66 @@ public class CredentialManagerPreferenceControllerTest {
assertThat(enabledServices.contains("com.android.provider2/ClassA")).isTrue(); assertThat(enabledServices.contains("com.android.provider2/ClassA")).isTrue();
} }
@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.size()).isEqualTo(3);
SwitchPreference pref1 = prefs.get(TEST_PACKAGE_NAME_C);
assertThat(pref1).isNotNull();
assertThat(pref1.getTitle()).isEqualTo(TEST_TITLE_APP_A);
assertThat(pref1.isChecked()).isFalse();
SwitchPreference pref2 = prefs.get(TEST_PACKAGE_NAME_C);
assertThat(pref2).isNotNull();
assertThat(pref2.getTitle()).isEqualTo(TEST_TITLE_APP_B);
assertThat(pref2.isChecked()).isFalse();
SwitchPreference pref3 = prefs.get(TEST_PACKAGE_NAME_C);
assertThat(pref3).isNotNull();
assertThat(pref3.getTitle()).isEqualTo(TEST_TITLE_SERVICE_C);
assertThat(pref3.isChecked()).isTrue();
}
private CredentialManagerPreferenceController createControllerWithServices( private CredentialManagerPreferenceController createControllerWithServices(
List<CredentialProviderInfo> availableServices) { List<CredentialProviderInfo> availableServices) {
CredentialManagerPreferenceController controller = CredentialManagerPreferenceController controller =
@@ -261,7 +331,8 @@ public class CredentialManagerPreferenceControllerTest {
private CredentialProviderInfo createCredentialProviderInfo( private CredentialProviderInfo createCredentialProviderInfo(
String packageName, String className) { String packageName, String className) {
return createCredentialProviderInfo(packageName, className, null, false); return createCredentialProviderInfoBuilder(packageName, className, null, "App Name")
.build();
} }
private CredentialProviderInfo createCredentialProviderInfo( private CredentialProviderInfo createCredentialProviderInfo(
@@ -286,8 +357,41 @@ public class CredentialManagerPreferenceControllerTest {
return new CredentialProviderInfo.Builder(si) return new CredentialProviderInfo.Builder(si)
.setOverrideLabel(label) .setOverrideLabel(label)
.setEnabled(isEnabled)
.setSettingsSubtitle(subtitle) .setSettingsSubtitle(subtitle)
.build(); .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)
.build();
}
private CredentialProviderInfo.Builder createCredentialProviderInfoBuilder(
String packageName, String className, CharSequence serviceLabel, String appLabel) {
ServiceInfo si = new ServiceInfo();
si.packageName = packageName;
si.name = className;
si.nonLocalizedLabel = serviceLabel;
si.applicationInfo = new ApplicationInfo();
si.applicationInfo.packageName = packageName;
si.applicationInfo.nonLocalizedLabel = appLabel;
return new CredentialProviderInfo.Builder(si).setOverrideLabel(serviceLabel);
}
} }