diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java index e1862065e03..c8432820eaa 100644 --- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java +++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java @@ -32,6 +32,7 @@ import android.content.res.Resources; import android.credentials.CredentialManager; import android.credentials.CredentialProviderInfo; import android.credentials.SetEnabledProvidersException; +import android.credentials.flags.Flags; import android.database.ContentObserver; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -108,6 +109,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl private final List mPendingServiceInfos = new ArrayList<>(); private final Handler mHandler = new Handler(); private final SettingContentObserver mSettingsContentObserver; + private final ImageUtils.IconResizer mIconResizer; private @Nullable FragmentManager mFragmentManager = null; private @Nullable Delegate mDelegate = null; @@ -116,6 +118,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl private boolean mVisibility = false; private boolean mIsWorkProfile = false; + private boolean mSimulateConnectedForTests = false; public CredentialManagerPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); @@ -129,6 +132,13 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl new SettingContentObserver(mHandler, context.getContentResolver()); mSettingsContentObserver.register(); mSettingsPackageMonitor.register(context, context.getMainLooper(), false); + mIconResizer = getResizer(context); + } + + private static ImageUtils.IconResizer getResizer(Context context) { + final Resources resources = context.getResources(); + int size = (int) resources.getDimension(android.R.dimen.app_icon_size); + return new ImageUtils.IconResizer(size, size, resources.getDisplayMetrics()); } private @Nullable CredentialManager getCredentialManager(Context context, boolean isTest) { @@ -147,7 +157,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl @Override public int getAvailabilityStatus() { - if (mCredentialManager == null) { + if (!isConnected()) { return UNSUPPORTED_ON_DEVICE; } @@ -174,7 +184,11 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl @VisibleForTesting public boolean isConnected() { - return mCredentialManager != null; + return mCredentialManager != null || mSimulateConnectedForTests; + } + + public void setSimulateConnectedForTests(boolean simulateConnectedForTests) { + mSimulateConnectedForTests = simulateConnectedForTests; } /** @@ -293,7 +307,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl NewProviderConfirmationDialogFragment fragment = newNewProviderConfirmationDialogFragment( - serviceInfo.packageName, appName, /* setActivityResult= */ true); + serviceInfo.packageName, appName, /* shouldSetActivityResult= */ true); if (fragment == null || mFragmentManager == null) { return; } @@ -365,7 +379,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl } } - private void setVisibility(boolean newVisibility) { + @VisibleForTesting + public void setVisibility(boolean newVisibility) { if (newVisibility == mVisibility) { return; } @@ -376,6 +391,11 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl } } + @VisibleForTesting + public boolean getVisibility() { + return mVisibility; + } + @VisibleForTesting void setAvailableServices( List availableServices, String flagOverrideForTest) { @@ -574,6 +594,17 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl return enabledServices; } + @VisibleForTesting + public @NonNull Drawable processIcon(@Nullable Drawable icon) { + // If we didn't get an icon then we should use the default app icon. + if (icon == null) { + icon = mPm.getDefaultActivityIcon(); + } + + Drawable providerIcon = Utils.getSafeIcon(icon); + return mIconResizer.createIconThumbnail(providerIcon); + } + private CombiPreference addProviderPreference( @NonNull Context prefContext, @NonNull CharSequence title, @@ -584,13 +615,14 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl final CombiPreference pref = new CombiPreference(prefContext, mEnabledPackageNames.contains(packageName)); pref.setTitle(title); + pref.setLayoutResource(R.layout.preference_icon_credman); - if (icon != null) { + if (Flags.newSettingsUi()) { + pref.setIcon(processIcon(icon)); + } else if (icon != null) { pref.setIcon(icon); } - pref.setLayoutResource(R.layout.preference_icon_credman); - if (subtitle != null) { pref.setSummary(subtitle); } @@ -711,13 +743,13 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl newNewProviderConfirmationDialogFragment( @NonNull String packageName, @NonNull CharSequence appName, - boolean setActivityResult) { + boolean shouldSetActivityResult) { DialogHost host = new DialogHost() { @Override public void onDialogClick(int whichButton) { completeEnableProviderDialogBox( - whichButton, packageName, setActivityResult); + whichButton, packageName, shouldSetActivityResult); } @Override @@ -728,8 +760,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl } @VisibleForTesting - void completeEnableProviderDialogBox( - int whichButton, String packageName, boolean setActivityResult) { + int completeEnableProviderDialogBox( + int whichButton, String packageName, boolean shouldSetActivityResult) { int activityResult = -1; if (whichButton == DialogInterface.BUTTON_POSITIVE) { if (togglePackageNameEnabled(packageName)) { @@ -746,7 +778,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl final DialogFragment fragment = newErrorDialogFragment(); if (fragment == null || mFragmentManager == null) { - return; + return activityResult; } fragment.show(mFragmentManager, ErrorDialogFragment.TAG); @@ -758,9 +790,11 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl // If the dialog is being shown because of the intent we should // return a result. - if (activityResult == -1 || !setActivityResult) { + if (activityResult == -1 || !shouldSetActivityResult) { setActivityResult(activityResult); } + + return activityResult; } private @Nullable ErrorDialogFragment newErrorDialogFragment() { @@ -1002,6 +1036,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl } } + @VisibleForTesting public boolean isChecked() { return mChecked; } diff --git a/src/com/android/settings/applications/credentials/ImageUtils.java b/src/com/android/settings/applications/credentials/ImageUtils.java new file mode 100644 index 00000000000..a7803a8eeb8 --- /dev/null +++ b/src/com/android/settings/applications/credentials/ImageUtils.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.applications.credentials; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PaintFlagsDrawFilter; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.PaintDrawable; +import android.util.DisplayMetrics; + +import androidx.annotation.NonNull; + +/** Handles resizing of images for CredMan settings. */ +public class ImageUtils { + + /** + * Utility class to resize icons to match default icon size. Code is mostly borrowed from + * Launcher and ActivityPicker. + */ + public static class IconResizer { + private final int mIconWidth; + private final int mIconHeight; + + private final DisplayMetrics mMetrics; + private final Rect mOldBounds = new Rect(); + private final Canvas mCanvas = new Canvas(); + + public IconResizer(int width, int height, DisplayMetrics metrics) { + mCanvas.setDrawFilter( + new PaintFlagsDrawFilter(Paint.DITHER_FLAG, Paint.FILTER_BITMAP_FLAG)); + + mMetrics = metrics; + mIconWidth = width; + mIconHeight = height; + } + + /** + * Returns a Drawable representing the thumbnail of the specified Drawable. The size of the + * thumbnail is defined by the dimension android.R.dimen.app_icon_size. + * + *

This method is not thread-safe and should be invoked on the UI thread only. + * + * @param icon The icon to get a thumbnail of. + * @return A thumbnail for the specified icon or the icon itself if the thumbnail could not + * be created. + */ + public Drawable createIconThumbnail(Drawable icon) { + int width = mIconWidth; + int height = mIconHeight; + + if (icon == null) { + return new EmptyDrawable(width, height); + } + + try { + if (icon instanceof PaintDrawable) { + PaintDrawable painter = (PaintDrawable) icon; + painter.setIntrinsicWidth(width); + painter.setIntrinsicHeight(height); + } else if (icon instanceof BitmapDrawable) { + // Ensure the bitmap has a density. + BitmapDrawable bitmapDrawable = (BitmapDrawable) icon; + Bitmap bitmap = bitmapDrawable.getBitmap(); + if (bitmap.getDensity() == Bitmap.DENSITY_NONE) { + bitmapDrawable.setTargetDensity(mMetrics); + } + } + int iconWidth = icon.getIntrinsicWidth(); + int iconHeight = icon.getIntrinsicHeight(); + + if (iconWidth > 0 && iconHeight > 0) { + if (width < iconWidth || height < iconHeight) { + final float ratio = (float) iconWidth / iconHeight; + + if (iconWidth > iconHeight) { + height = (int) (width / ratio); + } else if (iconHeight > iconWidth) { + width = (int) (height * ratio); + } + + final Bitmap.Config c = + icon.getOpacity() != PixelFormat.OPAQUE + ? Bitmap.Config.ARGB_8888 + : Bitmap.Config.RGB_565; + final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c); + final Canvas canvas = mCanvas; + canvas.setBitmap(thumb); + + // Copy the old bounds to restore them later + // If we were to do oldBounds = icon.getBounds(), + // the call to setBounds() that follows would + // change the same instance and we would lose the + // old bounds. + mOldBounds.set(icon.getBounds()); + final int x = (mIconWidth - width) / 2; + final int y = (mIconHeight - height) / 2; + icon.setBounds(x, y, x + width, y + height); + icon.draw(canvas); + icon.setBounds(mOldBounds); + + // Create the new resized drawable. + icon = createBitmapDrawable(thumb); + } else if (iconWidth < width && iconHeight < height) { + final Bitmap.Config c = Bitmap.Config.ARGB_8888; + final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c); + final Canvas canvas = mCanvas; + canvas.setBitmap(thumb); + mOldBounds.set(icon.getBounds()); + + // Set the bounds for the new icon. + final int x = (width - iconWidth) / 2; + final int y = (height - iconHeight) / 2; + icon.setBounds(x, y, x + iconWidth, y + iconHeight); + icon.draw(canvas); + icon.setBounds(mOldBounds); + + // Create the new resized drawable. + icon = createBitmapDrawable(thumb); + } + } + + } catch (Throwable t) { + icon = new EmptyDrawable(width, height); + } + + return icon; + } + + private BitmapDrawable createBitmapDrawable(Bitmap thumb) { + BitmapDrawable icon = new BitmapDrawable(thumb); + icon.setTargetDensity(mMetrics); + mCanvas.setBitmap(null); + return icon; + } + } + + public static class EmptyDrawable extends Drawable { + private final int mWidth; + private final int mHeight; + + EmptyDrawable(int width, int height) { + mWidth = width; + mHeight = height; + } + + @Override + public int getIntrinsicWidth() { + return mWidth; + } + + @Override + public int getIntrinsicHeight() { + return mHeight; + } + + @Override + public int getMinimumWidth() { + return mWidth; + } + + @Override + public int getMinimumHeight() { + return mHeight; + } + + @Override + public void draw(@NonNull Canvas canvas) {} + + @Override + public void setAlpha(int alpha) {} + + @Override + public void setColorFilter(@NonNull ColorFilter cf) {} + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + } +} diff --git a/tests/unit/res/drawable/credman_icon_1_1.xml b/tests/unit/res/drawable/credman_icon_1_1.xml new file mode 100644 index 00000000000..49f2d2e3e4d --- /dev/null +++ b/tests/unit/res/drawable/credman_icon_1_1.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/tests/unit/res/drawable/credman_icon_32_32.xml b/tests/unit/res/drawable/credman_icon_32_32.xml new file mode 100644 index 00000000000..2612ed27b67 --- /dev/null +++ b/tests/unit/res/drawable/credman_icon_32_32.xml @@ -0,0 +1,20 @@ + + + + + + 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 7d400ad7405..acf590bf236 100644 --- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java @@ -17,8 +17,10 @@ package com.android.settings.applications.credentials; import static com.android.settings.core.BasePreferenceController.AVAILABLE; -import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.spy; import android.app.Activity; @@ -27,7 +29,9 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.ServiceInfo; +import android.content.res.Resources; import android.credentials.CredentialProviderInfo; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Looper; import android.provider.Settings; @@ -38,6 +42,9 @@ import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.settings.tests.unit.R; import com.google.android.collect.Lists; @@ -48,7 +55,6 @@ import org.junit.runner.RunWith; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; @RunWith(AndroidJUnit4.class) @@ -58,14 +64,13 @@ public class CredentialManagerPreferenceControllerTest { private PreferenceScreen mScreen; private PreferenceCategory mCredentialsPreferenceCategory; private CredentialManagerPreferenceController.Delegate mDelegate; - private Optional mReceivedResultCode; 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"; + private static final String TEST_TITLE_APP_C = "test app C1"; private static final String PRIMARY_INTENT = "android.settings.CREDENTIAL_PROVIDER"; private static final String ALTERNATE_INTENT = "android.settings.SYNC_SETTINGS"; @@ -79,12 +84,9 @@ public class CredentialManagerPreferenceControllerTest { mCredentialsPreferenceCategory = new PreferenceCategory(mContext); mCredentialsPreferenceCategory.setKey("credentials_test"); mScreen.addPreference(mCredentialsPreferenceCategory); - mReceivedResultCode = Optional.empty(); mDelegate = new CredentialManagerPreferenceController.Delegate() { - public void setActivityResult(int resultCode) { - mReceivedResultCode = Optional.of(resultCode); - } + public void setActivityResult(int resultCode) {} public void forceDelegateRefresh() {} }; @@ -94,11 +96,15 @@ public class CredentialManagerPreferenceControllerTest { // Tests that getAvailabilityStatus() does not throw an exception if it's called before the // Controller is initialized (this can happen during indexing). public void getAvailabilityStatus_withoutInit_returnsUnavailable() { + if (Looper.myLooper() == null) { + Looper.prepare(); // needed to create the preference screen + } + CredentialManagerPreferenceController controller = new CredentialManagerPreferenceController( mContext, mCredentialsPreferenceCategory.getKey()); assertThat(controller.isConnected()).isFalse(); - assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } @Test @@ -106,14 +112,17 @@ public class CredentialManagerPreferenceControllerTest { CredentialManagerPreferenceController controller = createControllerWithServices(Collections.emptyList()); assertThat(controller.isConnected()).isFalse(); - assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } @Test public void getAvailabilityStatus_withServices_returnsAvailable() { CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo())); - assertThat(controller.isConnected()).isFalse(); + controller.setSimulateConnectedForTests(true); + assertThat(controller.isConnected()).isTrue(); + controller.setVisibility(true); + assertThat(controller.getVisibility()).isTrue(); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @@ -139,8 +148,11 @@ public class CredentialManagerPreferenceControllerTest { "com.android.provider2", "ClassA", "Service Title", "Summary Text"); CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2)); + controller.setSimulateConnectedForTests(true); + assertThat(controller.isConnected()).isTrue(); + controller.setVisibility(true); + assertThat(controller.getVisibility()).isTrue(); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); - assertThat(controller.isConnected()).isFalse(); // Test the data is correct. assertThat(providerInfo1.isEnabled()).isFalse(); @@ -180,8 +192,11 @@ public class CredentialManagerPreferenceControllerTest { createCredentialProviderInfo("com.android.provider4", "ClassA"), createCredentialProviderInfo("com.android.provider5", "ClassA"), createCredentialProviderInfo("com.android.provider6", "ClassA"))); + controller.setSimulateConnectedForTests(true); + assertThat(controller.isConnected()).isTrue(); + controller.setVisibility(true); + assertThat(controller.getVisibility()).isTrue(); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); - assertThat(controller.isConnected()).isFalse(); // Ensure that we stay under 5 providers. assertThat(controller.togglePackageNameEnabled("com.android.provider1")).isTrue(); @@ -246,8 +261,11 @@ public class CredentialManagerPreferenceControllerTest { "com.android.provider2", "ClassA", "Service Title", true); CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2)); + controller.setSimulateConnectedForTests(true); + assertThat(controller.isConnected()).isTrue(); + controller.setVisibility(true); + assertThat(controller.getVisibility()).isTrue(); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); - assertThat(controller.isConnected()).isFalse(); // Test the data is correct. assertThat(providerInfo1.isEnabled()).isFalse(); @@ -282,22 +300,16 @@ public class CredentialManagerPreferenceControllerTest { "test service B"); CredentialProviderInfo serviceC1 = createCredentialProviderInfoWithAppLabel( - TEST_PACKAGE_NAME_C, - "CredManProviderC1", - "test app C1", - TEST_TITLE_SERVICE_C); + TEST_PACKAGE_NAME_C, "CredManProviderC1", "test app C1", TEST_TITLE_APP_C); CredentialProviderInfo serviceC2 = createCredentialProviderInfoWithAppLabel( - TEST_PACKAGE_NAME_C, - "CredManProviderC2", - "test app C2", - TEST_TITLE_SERVICE_C); + TEST_PACKAGE_NAME_C, "CredManProviderC2", "test app C2", TEST_TITLE_APP_C); CredentialProviderInfo serviceC3 = createCredentialProviderInfoBuilder( TEST_PACKAGE_NAME_C, "CredManProviderC3", "test app C3", - TEST_TITLE_SERVICE_C) + TEST_TITLE_APP_C) .setEnabled(true) .build(); @@ -321,7 +333,7 @@ public class CredentialManagerPreferenceControllerTest { 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).getTitle()).isEqualTo(TEST_TITLE_APP_C); assertThat(prefs.get(TEST_PACKAGE_NAME_C).isChecked()).isTrue(); } @@ -347,9 +359,10 @@ public class CredentialManagerPreferenceControllerTest { Intent intent = new Intent(PRIMARY_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); + int resultCode = + controller.completeEnableProviderDialogBox( + DialogInterface.BUTTON_POSITIVE, packageName, true); + assertThat(resultCode).isEqualTo(Activity.RESULT_OK); } @Test @@ -363,9 +376,10 @@ public class CredentialManagerPreferenceControllerTest { Intent intent = new Intent(PRIMARY_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); + int resultCode = + controller.completeEnableProviderDialogBox( + DialogInterface.BUTTON_NEGATIVE, packageName, true); + assertThat(resultCode).isEqualTo(Activity.RESULT_CANCELED); } @Test @@ -390,9 +404,10 @@ public class CredentialManagerPreferenceControllerTest { 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); + int resultCode = + controller.completeEnableProviderDialogBox( + DialogInterface.BUTTON_POSITIVE, packageName, true); + assertThat(resultCode).isEqualTo(Activity.RESULT_OK); } @Test @@ -406,9 +421,10 @@ public class CredentialManagerPreferenceControllerTest { 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); + int resultCode = + controller.completeEnableProviderDialogBox( + DialogInterface.BUTTON_NEGATIVE, packageName, true); + assertThat(resultCode).isEqualTo(Activity.RESULT_CANCELED); } @Test @@ -422,7 +438,6 @@ public class CredentialManagerPreferenceControllerTest { Intent intent = new Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE); intent.setData(Uri.parse("package:" + packageName)); assertThat(controller.verifyReceivedIntent(intent)).isFalse(); - assertThat(mReceivedResultCode.isPresent()).isFalse(); } @Test @@ -433,7 +448,65 @@ public class CredentialManagerPreferenceControllerTest { // Use a null intent. assertThat(controller.verifyReceivedIntent(null)).isFalse(); - assertThat(mReceivedResultCode.isPresent()).isFalse(); + } + + @Test + public void testIconResizer_resizeLargeImage() throws Throwable { + CredentialProviderInfo cpi = createCredentialProviderInfo(); + CredentialManagerPreferenceController controller = + createControllerWithServices(Lists.newArrayList(cpi)); + + final Drawable d = + InstrumentationRegistry.getInstrumentation() + .getContext() + .getResources() + .getDrawable(R.drawable.credman_icon_32_32); + assertThat(d).isNotNull(); + assertThat(d.getIntrinsicHeight() >= 0).isTrue(); + assertThat(d.getIntrinsicWidth() >= 0).isTrue(); + + Drawable thumbnail = controller.processIcon(d); + assertThat(thumbnail).isNotNull(); + assertThat(thumbnail.getIntrinsicHeight()).isEqualTo(getIconSize()); + assertThat(thumbnail.getIntrinsicWidth()).isEqualTo(getIconSize()); + } + + @Test + public void testIconResizer_resizeNullImage() throws Throwable { + CredentialProviderInfo cpi = createCredentialProviderInfo(); + CredentialManagerPreferenceController controller = + createControllerWithServices(Lists.newArrayList(cpi)); + + Drawable thumbnail = controller.processIcon(null); + assertThat(thumbnail).isNotNull(); + assertThat(thumbnail.getIntrinsicHeight()).isEqualTo(getIconSize()); + assertThat(thumbnail.getIntrinsicWidth()).isEqualTo(getIconSize()); + } + + @Test + public void testIconResizer_resizeSmallImage() throws Throwable { + CredentialProviderInfo cpi = createCredentialProviderInfo(); + CredentialManagerPreferenceController controller = + createControllerWithServices(Lists.newArrayList(cpi)); + + final Drawable d = + InstrumentationRegistry.getInstrumentation() + .getContext() + .getResources() + .getDrawable(R.drawable.credman_icon_1_1); + assertThat(d).isNotNull(); + assertThat(d.getIntrinsicHeight() >= 0).isTrue(); + assertThat(d.getIntrinsicWidth() >= 0).isTrue(); + + Drawable thumbnail = controller.processIcon(null); + assertThat(thumbnail).isNotNull(); + assertThat(thumbnail.getIntrinsicHeight()).isEqualTo(getIconSize()); + assertThat(thumbnail.getIntrinsicWidth()).isEqualTo(getIconSize()); + } + + private int getIconSize() { + final Resources resources = mContext.getResources(); + return (int) resources.getDimension(android.R.dimen.app_icon_size); } private CredentialManagerPreferenceController createControllerWithServices( @@ -443,6 +516,10 @@ public class CredentialManagerPreferenceControllerTest { private CredentialManagerPreferenceController createControllerWithServicesAndAddServiceOverride( List availableServices, String addServiceOverride) { + if (Looper.myLooper() == null) { + Looper.prepare(); // needed to create the preference screen + } + CredentialManagerPreferenceController controller = new CredentialManagerPreferenceController( mContext, mCredentialsPreferenceCategory.getKey());