Loading src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java +26 −51 Original line number Diff line number Diff line Loading @@ -25,14 +25,11 @@ import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.credentials.CredentialManager; import android.credentials.ListEnabledProvidersException; import android.credentials.ListEnabledProvidersResponse; import android.credentials.CredentialProviderInfo; import android.credentials.SetEnabledProvidersException; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.CancellationSignal; import android.os.OutcomeReceiver; import android.os.UserHandle; import android.util.IconDrawableFactory; Loading Loading @@ -71,10 +68,9 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl private final PackageManager mPm; private final IconDrawableFactory mIconFactory; private final List<ServiceInfo> mServices; private final List<CredentialProviderInfo> mServices; private final Set<String> mEnabledPackageNames; private final @Nullable CredentialManager mCredentialManager; private final CancellationSignal mCancellationSignal = new CancellationSignal(); private final Executor mExecutor; private final Map<String, SwitchPreference> mPrefs = new HashMap<>(); // key is package name Loading Loading @@ -132,42 +128,20 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl lifecycleOwner, mCredentialManager.getCredentialProviderServices( getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY)); mCredentialManager.listEnabledProviders( mCancellationSignal, mExecutor, new OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>() { @Override public void onResult(ListEnabledProvidersResponse result) { Set<String> enabledPackages = new HashSet<>(); for (String flattenedComponentName : result.getProviderComponentNames()) { ComponentName cn = ComponentName.unflattenFromString(flattenedComponentName); if (cn != null) { enabledPackages.add(cn.getPackageName()); } } setEnabledPackageNames(enabledPackages); } @Override public void onError(ListEnabledProvidersException e) { Log.e(TAG, "listEnabledProviders error: " + e.toString()); } }); } @VisibleForTesting void setAvailableServices(LifecycleOwner lifecycleOwner, List<ServiceInfo> availableServices) { void setAvailableServices( LifecycleOwner lifecycleOwner, List<CredentialProviderInfo> availableServices) { mServices.clear(); mServices.addAll(availableServices); } @VisibleForTesting void setEnabledPackageNames(Set<String> enabledPackages) { mEnabledPackageNames.clear(); mEnabledPackageNames.addAll(enabledPackages); for (CredentialProviderInfo cpi : availableServices) { if (cpi.isEnabled()) { mEnabledPackageNames.add(cpi.getServiceInfo().packageName); } } for (String packageName : mPrefs.keySet()) { mPrefs.get(packageName).setChecked(mEnabledPackageNames.contains(packageName)); Loading @@ -189,20 +163,20 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl PreferenceGroup group = screen.findPreference(getPreferenceKey()); Context context = screen.getContext(); for (ServiceInfo serviceInfo : mServices) { CharSequence title = ""; if (serviceInfo.nonLocalizedLabel != null) { title = serviceInfo.loadLabel(mPm); for (CredentialProviderInfo service : mServices) { group.addPreference(createPreference(context, service)); } } group.addPreference( addProviderPreference( /** Creates a preference object based on the provider info. */ @VisibleForTesting public SwitchPreference createPreference(Context context, CredentialProviderInfo service) { CharSequence label = service.getLabel(context); return addProviderPreference( context, title, mIconFactory.getBadgedIcon( serviceInfo, serviceInfo.applicationInfo, getUser()), serviceInfo.packageName)); } label == null ? "" : label, service.getServiceIcon(mContext), service.getServiceInfo().packageName); } /** Loading Loading @@ -246,9 +220,10 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl public List<String> getEnabledSettings() { // Get all the component names that match the enabled package names. List<String> enabledServices = new ArrayList<>(); for (ServiceInfo service : mServices) { if (mEnabledPackageNames.contains(service.packageName)) { enabledServices.add(service.getComponentName().flattenToString()); for (CredentialProviderInfo service : mServices) { ComponentName cn = service.getServiceInfo().getComponentName(); if (mEnabledPackageNames.contains(service.getServiceInfo().packageName)) { enabledServices.add(cn.flattenToString()); } } Loading tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java +90 −14 Original line number Diff line number Diff line Loading @@ -27,12 +27,14 @@ import static org.mockito.Mockito.spy; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.ServiceInfo; import android.credentials.CredentialProviderInfo; import android.os.Looper; import androidx.lifecycle.Lifecycle; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; Loading Loading @@ -87,7 +89,7 @@ public class CredentialManagerPreferenceControllerTest { @Test public void getAvailabilityStatus_withServices_returnsAvailable() { CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(createServiceInfo())); createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo())); assertThat(controller.isConnected()).isFalse(); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); } Loading @@ -103,24 +105,59 @@ public class CredentialManagerPreferenceControllerTest { @Test public void displayPreference_withServices_preferencesAdded() { CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(createServiceInfo())); createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo())); controller.displayPreference(mScreen); assertThat(controller.isConnected()).isFalse(); assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1); } @Test public void buildSwitchPreference() { CredentialProviderInfo providerInfo1 = createCredentialProviderInfo( "com.android.provider1", "ClassA", "Service Title", false); CredentialProviderInfo providerInfo2 = createCredentialProviderInfo( "com.android.provider2", "ClassA", "Service Title", false); CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2)); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); assertThat(controller.isConnected()).isFalse(); // Test the data is correct. assertThat(providerInfo1.isEnabled()).isFalse(); assertThat(providerInfo2.isEnabled()).isFalse(); assertThat(controller.getEnabledProviders().size()).isEqualTo(0); // Toggle one provider and make sure it worked. assertThat(controller.togglePackageNameEnabled("com.android.provider1")).isTrue(); Set<String> enabledProviders = controller.getEnabledProviders(); assertThat(enabledProviders.size()).isEqualTo(1); assertThat(enabledProviders.contains("com.android.provider1")).isTrue(); // Create the pref (checked). SwitchPreference pref = controller.createPreference(mContext, providerInfo1); assertThat(pref.getTitle().toString()).isEqualTo("Service Title"); assertThat(pref.isChecked()).isTrue(); // Create the pref (not checked). SwitchPreference pref2 = controller.createPreference(mContext, providerInfo2); assertThat(pref2.getTitle().toString()).isEqualTo("Service Title"); assertThat(pref2.isChecked()).isFalse(); } @Test public void getAvailabilityStatus_handlesToggleAndSave() { CredentialManagerPreferenceController controller = createControllerWithServices( Lists.newArrayList( createServiceInfo("com.android.provider1", "ClassA"), createServiceInfo("com.android.provider1", "ClassB"), createServiceInfo("com.android.provider2", "ClassA"), createServiceInfo("com.android.provider3", "ClassA"), createServiceInfo("com.android.provider4", "ClassA"), createServiceInfo("com.android.provider5", "ClassA"), createServiceInfo("com.android.provider6", "ClassA"))); createCredentialProviderInfo("com.android.provider1", "ClassA"), createCredentialProviderInfo("com.android.provider1", "ClassB"), createCredentialProviderInfo("com.android.provider2", "ClassA"), createCredentialProviderInfo("com.android.provider3", "ClassA"), createCredentialProviderInfo("com.android.provider4", "ClassA"), createCredentialProviderInfo("com.android.provider5", "ClassA"), createCredentialProviderInfo("com.android.provider6", "ClassA"))); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); assertThat(controller.isConnected()).isFalse(); Loading Loading @@ -177,8 +214,38 @@ public class CredentialManagerPreferenceControllerTest { assertThat(currentlyEnabledServices.contains("com.android.provider6/ClassA")).isFalse(); } @Test public void handlesCredentialProviderInfoEnabledDisabled() { CredentialProviderInfo providerInfo1 = createCredentialProviderInfo( "com.android.provider1", "ClassA", "Service Title", false); CredentialProviderInfo providerInfo2 = createCredentialProviderInfo( "com.android.provider2", "ClassA", "Service Title", true); CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2)); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); assertThat(controller.isConnected()).isFalse(); // Test the data is correct. assertThat(providerInfo1.isEnabled()).isFalse(); assertThat(providerInfo2.isEnabled()).isTrue(); // Check that they are all actually registered. Set<String> enabledProviders = controller.getEnabledProviders(); assertThat(enabledProviders.size()).isEqualTo(1); 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(); assertThat(enabledServices.size()).isEqualTo(1); assertThat(enabledServices.contains("com.android.provider1/ClassA")).isFalse(); assertThat(enabledServices.contains("com.android.provider2/ClassA")).isTrue(); } private CredentialManagerPreferenceController createControllerWithServices( List<ServiceInfo> availableServices) { List<CredentialProviderInfo> availableServices) { CredentialManagerPreferenceController controller = new CredentialManagerPreferenceController( mContext, mCredentialsPreferenceCategory.getKey()); Loading @@ -186,11 +253,17 @@ public class CredentialManagerPreferenceControllerTest { return controller; } private ServiceInfo createServiceInfo() { return createServiceInfo("com.android.provider", "CredManProvider"); private CredentialProviderInfo createCredentialProviderInfo() { return createCredentialProviderInfo("com.android.provider", "CredManProvider"); } private CredentialProviderInfo createCredentialProviderInfo( String packageName, String className) { return createCredentialProviderInfo(packageName, className, null, false); } private ServiceInfo createServiceInfo(String packageName, String className) { private CredentialProviderInfo createCredentialProviderInfo( String packageName, String className, CharSequence label, boolean isEnabled) { ServiceInfo si = new ServiceInfo(); si.packageName = packageName; si.name = className; Loading @@ -200,6 +273,9 @@ public class CredentialManagerPreferenceControllerTest { si.applicationInfo.packageName = packageName; si.applicationInfo.nonLocalizedLabel = "test"; return si; return new CredentialProviderInfo.Builder(si) .setOverrideLabel(label) .setEnabled(isEnabled) .build(); } } Loading
src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java +26 −51 Original line number Diff line number Diff line Loading @@ -25,14 +25,11 @@ import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.credentials.CredentialManager; import android.credentials.ListEnabledProvidersException; import android.credentials.ListEnabledProvidersResponse; import android.credentials.CredentialProviderInfo; import android.credentials.SetEnabledProvidersException; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.CancellationSignal; import android.os.OutcomeReceiver; import android.os.UserHandle; import android.util.IconDrawableFactory; Loading Loading @@ -71,10 +68,9 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl private final PackageManager mPm; private final IconDrawableFactory mIconFactory; private final List<ServiceInfo> mServices; private final List<CredentialProviderInfo> mServices; private final Set<String> mEnabledPackageNames; private final @Nullable CredentialManager mCredentialManager; private final CancellationSignal mCancellationSignal = new CancellationSignal(); private final Executor mExecutor; private final Map<String, SwitchPreference> mPrefs = new HashMap<>(); // key is package name Loading Loading @@ -132,42 +128,20 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl lifecycleOwner, mCredentialManager.getCredentialProviderServices( getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY)); mCredentialManager.listEnabledProviders( mCancellationSignal, mExecutor, new OutcomeReceiver<ListEnabledProvidersResponse, ListEnabledProvidersException>() { @Override public void onResult(ListEnabledProvidersResponse result) { Set<String> enabledPackages = new HashSet<>(); for (String flattenedComponentName : result.getProviderComponentNames()) { ComponentName cn = ComponentName.unflattenFromString(flattenedComponentName); if (cn != null) { enabledPackages.add(cn.getPackageName()); } } setEnabledPackageNames(enabledPackages); } @Override public void onError(ListEnabledProvidersException e) { Log.e(TAG, "listEnabledProviders error: " + e.toString()); } }); } @VisibleForTesting void setAvailableServices(LifecycleOwner lifecycleOwner, List<ServiceInfo> availableServices) { void setAvailableServices( LifecycleOwner lifecycleOwner, List<CredentialProviderInfo> availableServices) { mServices.clear(); mServices.addAll(availableServices); } @VisibleForTesting void setEnabledPackageNames(Set<String> enabledPackages) { mEnabledPackageNames.clear(); mEnabledPackageNames.addAll(enabledPackages); for (CredentialProviderInfo cpi : availableServices) { if (cpi.isEnabled()) { mEnabledPackageNames.add(cpi.getServiceInfo().packageName); } } for (String packageName : mPrefs.keySet()) { mPrefs.get(packageName).setChecked(mEnabledPackageNames.contains(packageName)); Loading @@ -189,20 +163,20 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl PreferenceGroup group = screen.findPreference(getPreferenceKey()); Context context = screen.getContext(); for (ServiceInfo serviceInfo : mServices) { CharSequence title = ""; if (serviceInfo.nonLocalizedLabel != null) { title = serviceInfo.loadLabel(mPm); for (CredentialProviderInfo service : mServices) { group.addPreference(createPreference(context, service)); } } group.addPreference( addProviderPreference( /** Creates a preference object based on the provider info. */ @VisibleForTesting public SwitchPreference createPreference(Context context, CredentialProviderInfo service) { CharSequence label = service.getLabel(context); return addProviderPreference( context, title, mIconFactory.getBadgedIcon( serviceInfo, serviceInfo.applicationInfo, getUser()), serviceInfo.packageName)); } label == null ? "" : label, service.getServiceIcon(mContext), service.getServiceInfo().packageName); } /** Loading Loading @@ -246,9 +220,10 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl public List<String> getEnabledSettings() { // Get all the component names that match the enabled package names. List<String> enabledServices = new ArrayList<>(); for (ServiceInfo service : mServices) { if (mEnabledPackageNames.contains(service.packageName)) { enabledServices.add(service.getComponentName().flattenToString()); for (CredentialProviderInfo service : mServices) { ComponentName cn = service.getServiceInfo().getComponentName(); if (mEnabledPackageNames.contains(service.getServiceInfo().packageName)) { enabledServices.add(cn.flattenToString()); } } Loading
tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java +90 −14 Original line number Diff line number Diff line Loading @@ -27,12 +27,14 @@ import static org.mockito.Mockito.spy; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.ServiceInfo; import android.credentials.CredentialProviderInfo; import android.os.Looper; import androidx.lifecycle.Lifecycle; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; Loading Loading @@ -87,7 +89,7 @@ public class CredentialManagerPreferenceControllerTest { @Test public void getAvailabilityStatus_withServices_returnsAvailable() { CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(createServiceInfo())); createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo())); assertThat(controller.isConnected()).isFalse(); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); } Loading @@ -103,24 +105,59 @@ public class CredentialManagerPreferenceControllerTest { @Test public void displayPreference_withServices_preferencesAdded() { CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(createServiceInfo())); createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo())); controller.displayPreference(mScreen); assertThat(controller.isConnected()).isFalse(); assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1); } @Test public void buildSwitchPreference() { CredentialProviderInfo providerInfo1 = createCredentialProviderInfo( "com.android.provider1", "ClassA", "Service Title", false); CredentialProviderInfo providerInfo2 = createCredentialProviderInfo( "com.android.provider2", "ClassA", "Service Title", false); CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2)); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); assertThat(controller.isConnected()).isFalse(); // Test the data is correct. assertThat(providerInfo1.isEnabled()).isFalse(); assertThat(providerInfo2.isEnabled()).isFalse(); assertThat(controller.getEnabledProviders().size()).isEqualTo(0); // Toggle one provider and make sure it worked. assertThat(controller.togglePackageNameEnabled("com.android.provider1")).isTrue(); Set<String> enabledProviders = controller.getEnabledProviders(); assertThat(enabledProviders.size()).isEqualTo(1); assertThat(enabledProviders.contains("com.android.provider1")).isTrue(); // Create the pref (checked). SwitchPreference pref = controller.createPreference(mContext, providerInfo1); assertThat(pref.getTitle().toString()).isEqualTo("Service Title"); assertThat(pref.isChecked()).isTrue(); // Create the pref (not checked). SwitchPreference pref2 = controller.createPreference(mContext, providerInfo2); assertThat(pref2.getTitle().toString()).isEqualTo("Service Title"); assertThat(pref2.isChecked()).isFalse(); } @Test public void getAvailabilityStatus_handlesToggleAndSave() { CredentialManagerPreferenceController controller = createControllerWithServices( Lists.newArrayList( createServiceInfo("com.android.provider1", "ClassA"), createServiceInfo("com.android.provider1", "ClassB"), createServiceInfo("com.android.provider2", "ClassA"), createServiceInfo("com.android.provider3", "ClassA"), createServiceInfo("com.android.provider4", "ClassA"), createServiceInfo("com.android.provider5", "ClassA"), createServiceInfo("com.android.provider6", "ClassA"))); createCredentialProviderInfo("com.android.provider1", "ClassA"), createCredentialProviderInfo("com.android.provider1", "ClassB"), createCredentialProviderInfo("com.android.provider2", "ClassA"), createCredentialProviderInfo("com.android.provider3", "ClassA"), createCredentialProviderInfo("com.android.provider4", "ClassA"), createCredentialProviderInfo("com.android.provider5", "ClassA"), createCredentialProviderInfo("com.android.provider6", "ClassA"))); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); assertThat(controller.isConnected()).isFalse(); Loading Loading @@ -177,8 +214,38 @@ public class CredentialManagerPreferenceControllerTest { assertThat(currentlyEnabledServices.contains("com.android.provider6/ClassA")).isFalse(); } @Test public void handlesCredentialProviderInfoEnabledDisabled() { CredentialProviderInfo providerInfo1 = createCredentialProviderInfo( "com.android.provider1", "ClassA", "Service Title", false); CredentialProviderInfo providerInfo2 = createCredentialProviderInfo( "com.android.provider2", "ClassA", "Service Title", true); CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2)); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); assertThat(controller.isConnected()).isFalse(); // Test the data is correct. assertThat(providerInfo1.isEnabled()).isFalse(); assertThat(providerInfo2.isEnabled()).isTrue(); // Check that they are all actually registered. Set<String> enabledProviders = controller.getEnabledProviders(); assertThat(enabledProviders.size()).isEqualTo(1); 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(); assertThat(enabledServices.size()).isEqualTo(1); assertThat(enabledServices.contains("com.android.provider1/ClassA")).isFalse(); assertThat(enabledServices.contains("com.android.provider2/ClassA")).isTrue(); } private CredentialManagerPreferenceController createControllerWithServices( List<ServiceInfo> availableServices) { List<CredentialProviderInfo> availableServices) { CredentialManagerPreferenceController controller = new CredentialManagerPreferenceController( mContext, mCredentialsPreferenceCategory.getKey()); Loading @@ -186,11 +253,17 @@ public class CredentialManagerPreferenceControllerTest { return controller; } private ServiceInfo createServiceInfo() { return createServiceInfo("com.android.provider", "CredManProvider"); private CredentialProviderInfo createCredentialProviderInfo() { return createCredentialProviderInfo("com.android.provider", "CredManProvider"); } private CredentialProviderInfo createCredentialProviderInfo( String packageName, String className) { return createCredentialProviderInfo(packageName, className, null, false); } private ServiceInfo createServiceInfo(String packageName, String className) { private CredentialProviderInfo createCredentialProviderInfo( String packageName, String className, CharSequence label, boolean isEnabled) { ServiceInfo si = new ServiceInfo(); si.packageName = packageName; si.name = className; Loading @@ -200,6 +273,9 @@ public class CredentialManagerPreferenceControllerTest { si.applicationInfo.packageName = packageName; si.applicationInfo.nonLocalizedLabel = "test"; return si; return new CredentialProviderInfo.Builder(si) .setOverrideLabel(label) .setEnabled(isEnabled) .build(); } }