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.Context;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
import android.credentials.SetEnabledProvidersException;
@@ -32,6 +34,7 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.OutcomeReceiver;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
@@ -162,22 +165,64 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
PreferenceGroup group = screen.findPreference(getPreferenceKey());
Context context = screen.getContext();
for (CredentialProviderInfo service : mServices) {
group.addPreference(createPreference(context, service));
mPrefs.putAll(buildPreferenceList(context, group));
}
/** 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. */
@VisibleForTesting
public SwitchPreference createPreference(Context context, CredentialProviderInfo service) {
CharSequence label = service.getLabel(context);
public @Nullable SwitchPreference createPreference(
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(
context,
label == null ? "" : label,
service.getServiceIcon(mContext),
service.getServiceInfo().packageName,
service.getSettingsSubtitle());
context, title, icon, packageName, firstInfo.getSettingsSubtitle());
}
/**
@@ -240,7 +285,6 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
final SwitchPreference pref = new SwitchPreference(prefContext);
pref.setTitle(title);
pref.setChecked(mEnabledPackageNames.contains(packageName));
mPrefs.put(packageName, pref);
if (icon != null) {
pref.setIcon(Utils.getSafeIcon(icon));

View File

@@ -44,8 +44,10 @@ import org.junit.Before;
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.Set;
@RunWith(AndroidJUnit4.class)
@@ -55,6 +57,13 @@ public class CredentialManagerPreferenceControllerTest {
private PreferenceScreen mScreen;
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
public void setUp() {
mContext = spy(ApplicationProvider.getApplicationContext());
@@ -114,11 +123,11 @@ public class CredentialManagerPreferenceControllerTest {
@Test
public void buildSwitchPreference() {
CredentialProviderInfo providerInfo1 =
createCredentialProviderInfo(
"com.android.provider1", "ClassA", "Service Title", false, null);
createCredentialProviderInfoWithSettingsSubtitle(
"com.android.provider1", "ClassA", "Service Title", null);
CredentialProviderInfo providerInfo2 =
createCredentialProviderInfo(
"com.android.provider2", "ClassA", "Service Title", false, "Summary Text");
createCredentialProviderInfoWithSettingsSubtitle(
"com.android.provider2", "ClassA", "Service Title", "Summary Text");
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
@@ -136,13 +145,14 @@ public class CredentialManagerPreferenceControllerTest {
assertThat(enabledProviders.contains("com.android.provider1")).isTrue();
// 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.isChecked()).isTrue();
assertThat(pref.getSummary()).isNull();
// 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.isChecked()).isFalse();
assertThat(pref2.getSummary().toString()).isEqualTo("Summary Text");
@@ -219,10 +229,10 @@ public class CredentialManagerPreferenceControllerTest {
@Test
public void handlesCredentialProviderInfoEnabledDisabled() {
CredentialProviderInfo providerInfo1 =
createCredentialProviderInfo(
createCredentialProviderInfoWithIsEnabled(
"com.android.provider1", "ClassA", "Service Title", false);
CredentialProviderInfo providerInfo2 =
createCredentialProviderInfo(
createCredentialProviderInfoWithIsEnabled(
"com.android.provider2", "ClassA", "Service Title", true);
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
@@ -246,6 +256,66 @@ public class CredentialManagerPreferenceControllerTest {
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(
List<CredentialProviderInfo> availableServices) {
CredentialManagerPreferenceController controller =
@@ -261,7 +331,8 @@ public class CredentialManagerPreferenceControllerTest {
private CredentialProviderInfo createCredentialProviderInfo(
String packageName, String className) {
return createCredentialProviderInfo(packageName, className, null, false);
return createCredentialProviderInfoBuilder(packageName, className, null, "App Name")
.build();
}
private CredentialProviderInfo createCredentialProviderInfo(
@@ -286,8 +357,41 @@ public class CredentialManagerPreferenceControllerTest {
return new CredentialProviderInfo.Builder(si)
.setOverrideLabel(label)
.setEnabled(isEnabled)
.setSettingsSubtitle(subtitle)
.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);
}
}