Merge credential manager providers by package name
As part of the spec'd design we should merge providers by package name this means that if there are multiple providers they will be all turned on/off together. Bug: 266772233 Test: make & atest Change-Id: If7eec7d9a79a97ac3ec4f55b7cbcfaf7748d5750 Merged-In: Id48f27e96cabdd8ab0e8cbafc8eb760b7bbbf928
This commit is contained in:
@@ -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,10 +165,54 @@ 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) {
|
/** Aggregates the list of services and builds a list of UI prefs to show. */
|
||||||
group.addPreference(createPreference(context, service));
|
@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);
|
||||||
|
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 don't show anything.
|
||||||
|
if (TextUtils.isEmpty(title)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the pref and add it to the output & group.
|
||||||
|
SwitchPreference pref = addProviderPreference(context, title, icon, packageName);
|
||||||
|
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. */
|
||||||
@@ -238,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));
|
||||||
|
@@ -46,6 +46,7 @@ import org.junit.runner.RunWith;
|
|||||||
|
|
||||||
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 +56,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,10 +122,10 @@ public class CredentialManagerPreferenceControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void buildSwitchPreference() {
|
public void buildSwitchPreference() {
|
||||||
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", false);
|
"com.android.provider2", "ClassA", "Service Title", false);
|
||||||
CredentialManagerPreferenceController controller =
|
CredentialManagerPreferenceController controller =
|
||||||
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
|
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
|
||||||
@@ -217,10 +225,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));
|
||||||
@@ -244,6 +252,63 @@ 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);
|
||||||
|
assertThat(prefs.containsKey(TEST_PACKAGE_NAME_A));
|
||||||
|
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));
|
||||||
|
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));
|
||||||
|
assertThat(prefs.get(TEST_PACKAGE_NAME_C).getTitle()).isEqualTo(TEST_TITLE_SERVICE_C);
|
||||||
|
assertThat(prefs.get(TEST_PACKAGE_NAME_C).isChecked()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
private CredentialManagerPreferenceController createControllerWithServices(
|
private CredentialManagerPreferenceController createControllerWithServices(
|
||||||
List<CredentialProviderInfo> availableServices) {
|
List<CredentialProviderInfo> availableServices) {
|
||||||
CredentialManagerPreferenceController controller =
|
CredentialManagerPreferenceController controller =
|
||||||
@@ -259,23 +324,34 @@ 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 createCredentialProviderInfoWithIsEnabled(
|
||||||
String packageName, String className, CharSequence label, boolean isEnabled) {
|
String packageName, String className, CharSequence serviceLabel, boolean isEnabled) {
|
||||||
ServiceInfo si = new ServiceInfo();
|
return createCredentialProviderInfoBuilder(packageName, className, serviceLabel, "App Name")
|
||||||
si.packageName = packageName;
|
|
||||||
si.name = className;
|
|
||||||
si.nonLocalizedLabel = "test";
|
|
||||||
|
|
||||||
si.applicationInfo = new ApplicationInfo();
|
|
||||||
si.applicationInfo.packageName = packageName;
|
|
||||||
si.applicationInfo.nonLocalizedLabel = "test";
|
|
||||||
|
|
||||||
return new CredentialProviderInfo.Builder(si)
|
|
||||||
.setOverrideLabel(label)
|
|
||||||
.setEnabled(isEnabled)
|
.setEnabled(isEnabled)
|
||||||
.build();
|
.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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user