summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java3
-rw-r--r--java/src/com/android/intentresolver/TargetPresentationGetter.java11
-rw-r--r--java/src/com/android/intentresolver/icons/BaseLoadIconTask.java17
-rw-r--r--java/src/com/android/intentresolver/icons/CachingTargetDataLoader.kt33
-rw-r--r--java/src/com/android/intentresolver/icons/DefaultTargetDataLoader.kt21
-rw-r--r--java/src/com/android/intentresolver/icons/LoadDirectShareIconTask.java20
-rw-r--r--java/src/com/android/intentresolver/icons/LoadIconTask.java19
-rw-r--r--java/src/com/android/intentresolver/icons/TargetDataLoader.kt10
-rw-r--r--java/src/com/android/intentresolver/icons/TargetDataLoaderModule.kt6
-rw-r--r--tests/activity/src/com/android/intentresolver/ResolverWrapperActivity.java2
-rw-r--r--tests/unit/src/com/android/intentresolver/icons/CachingTargetDataLoaderTest.kt61
11 files changed, 131 insertions, 72 deletions
diff --git a/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java b/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java
index ae80fad4..ff0bda01 100644
--- a/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java
+++ b/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java
@@ -33,6 +33,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -136,7 +137,7 @@ public class ChooserTargetActionsDialogFragment extends DialogFragment
final TargetPresentationGetter pg = getProvidingAppPresentationGetter();
title.setText(isShortcutTarget() ? mShortcutTitle : pg.getLabel());
- icon.setImageDrawable(pg.getIcon(mUserHandle));
+ icon.setImageDrawable(new BitmapDrawable(getResources(), pg.getIconBitmap(mUserHandle)));
rv.setAdapter(new VHAdapter(items));
return v;
diff --git a/java/src/com/android/intentresolver/TargetPresentationGetter.java b/java/src/com/android/intentresolver/TargetPresentationGetter.java
index 910c65c9..ac74366e 100644
--- a/java/src/com/android/intentresolver/TargetPresentationGetter.java
+++ b/java/src/com/android/intentresolver/TargetPresentationGetter.java
@@ -23,7 +23,6 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -77,7 +76,7 @@ public abstract class TargetPresentationGetter {
@Nullable
protected abstract String getAppLabelForSubstitutePermission();
- private Context mContext;
+ private final Context mContext;
private final int mIconDpi;
private final boolean mHasSubstitutePermission;
private final ApplicationInfo mAppInfo;
@@ -88,14 +87,6 @@ public abstract class TargetPresentationGetter {
* Retrieve the image that should be displayed as the icon when this target is presented to the
* specified {@code userHandle}.
*/
- public Drawable getIcon(UserHandle userHandle) {
- return new BitmapDrawable(mContext.getResources(), getIconBitmap(userHandle));
- }
-
- /**
- * Retrieve the image that should be displayed as the icon when this target is presented to the
- * specified {@code userHandle}.
- */
public Bitmap getIconBitmap(@Nullable UserHandle userHandle) {
Drawable drawable = null;
if (mHasSubstitutePermission) {
diff --git a/java/src/com/android/intentresolver/icons/BaseLoadIconTask.java b/java/src/com/android/intentresolver/icons/BaseLoadIconTask.java
index 2eceb89c..f09fcfc5 100644
--- a/java/src/com/android/intentresolver/icons/BaseLoadIconTask.java
+++ b/java/src/com/android/intentresolver/icons/BaseLoadIconTask.java
@@ -17,34 +17,31 @@
package com.android.intentresolver.icons;
import android.content.Context;
-import android.graphics.drawable.Drawable;
+import android.graphics.Bitmap;
import android.os.AsyncTask;
-import com.android.intentresolver.R;
+import androidx.annotation.Nullable;
+
import com.android.intentresolver.TargetPresentationGetter;
import java.util.function.Consumer;
-abstract class BaseLoadIconTask extends AsyncTask<Void, Void, Drawable> {
+abstract class BaseLoadIconTask extends AsyncTask<Void, Void, Bitmap> {
protected final Context mContext;
protected final TargetPresentationGetter.Factory mPresentationFactory;
- private final Consumer<Drawable> mCallback;
+ private final Consumer<Bitmap> mCallback;
BaseLoadIconTask(
Context context,
TargetPresentationGetter.Factory presentationFactory,
- Consumer<Drawable> callback) {
+ Consumer<Bitmap> callback) {
mContext = context;
mPresentationFactory = presentationFactory;
mCallback = callback;
}
- protected final Drawable loadIconPlaceholder() {
- return mContext.getDrawable(R.drawable.resolver_icon_placeholder);
- }
-
@Override
- protected final void onPostExecute(Drawable d) {
+ protected final void onPostExecute(@Nullable Bitmap d) {
mCallback.accept(d);
}
}
diff --git a/java/src/com/android/intentresolver/icons/CachingTargetDataLoader.kt b/java/src/com/android/intentresolver/icons/CachingTargetDataLoader.kt
index 8474b4c3..b0c26777 100644
--- a/java/src/com/android/intentresolver/icons/CachingTargetDataLoader.kt
+++ b/java/src/com/android/intentresolver/icons/CachingTargetDataLoader.kt
@@ -17,6 +17,9 @@
package com.android.intentresolver.icons
import android.content.ComponentName
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.UserHandle
import androidx.collection.LruCache
@@ -28,23 +31,26 @@ import javax.inject.Qualifier
@Qualifier @MustBeDocumented @Retention(AnnotationRetention.BINARY) annotation class Caching
-private typealias IconCache = LruCache<String, Drawable>
+private typealias IconCache = LruCache<String, Bitmap>
class CachingTargetDataLoader(
+ private val context: Context,
private val targetDataLoader: TargetDataLoader,
private val cacheSize: Int = 100,
-) : TargetDataLoader() {
+) : TargetDataLoader {
@GuardedBy("self") private val perProfileIconCache = HashMap<UserHandle, IconCache>()
override fun getOrLoadAppTargetIcon(
info: DisplayResolveInfo,
userHandle: UserHandle,
- callback: Consumer<Drawable>
+ callback: Consumer<Drawable>,
): Drawable? {
val cacheKey = info.toCacheKey()
- return getCachedAppIcon(cacheKey, userHandle)
+ return getCachedAppIcon(cacheKey, userHandle)?.let { BitmapDrawable(context.resources, it) }
?: targetDataLoader.getOrLoadAppTargetIcon(info, userHandle) { drawable ->
- getProfileIconCache(userHandle).put(cacheKey, drawable)
+ (drawable as? BitmapDrawable)?.bitmap?.let {
+ getProfileIconCache(userHandle).put(cacheKey, it)
+ }
callback.accept(drawable)
}
}
@@ -52,13 +58,17 @@ class CachingTargetDataLoader(
override fun getOrLoadDirectShareIcon(
info: SelectableTargetInfo,
userHandle: UserHandle,
- callback: Consumer<Drawable>
+ callback: Consumer<Drawable>,
): Drawable? {
val cacheKey = info.toCacheKey()
- return cacheKey?.let { getCachedAppIcon(it, userHandle) }
+ return cacheKey
+ ?.let { getCachedAppIcon(it, userHandle) }
+ ?.let { BitmapDrawable(context.resources, it) }
?: targetDataLoader.getOrLoadDirectShareIcon(info, userHandle) { drawable ->
if (cacheKey != null) {
- getProfileIconCache(userHandle).put(cacheKey, drawable)
+ (drawable as? BitmapDrawable)?.bitmap?.let {
+ getProfileIconCache(userHandle).put(cacheKey, it)
+ }
}
callback.accept(drawable)
}
@@ -69,7 +79,7 @@ class CachingTargetDataLoader(
override fun getOrLoadLabel(info: DisplayResolveInfo) = targetDataLoader.getOrLoadLabel(info)
- private fun getCachedAppIcon(component: String, userHandle: UserHandle): Drawable? =
+ private fun getCachedAppIcon(component: String, userHandle: UserHandle): Bitmap? =
getProfileIconCache(userHandle)[component]
private fun getProfileIconCache(userHandle: UserHandle): IconCache =
@@ -78,10 +88,7 @@ class CachingTargetDataLoader(
}
private fun DisplayResolveInfo.toCacheKey() =
- ComponentName(
- resolveInfo.activityInfo.packageName,
- resolveInfo.activityInfo.name,
- )
+ ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name)
.flattenToString()
private fun SelectableTargetInfo.toCacheKey(): String? =
diff --git a/java/src/com/android/intentresolver/icons/DefaultTargetDataLoader.kt b/java/src/com/android/intentresolver/icons/DefaultTargetDataLoader.kt
index e7392f58..117c769d 100644
--- a/java/src/com/android/intentresolver/icons/DefaultTargetDataLoader.kt
+++ b/java/src/com/android/intentresolver/icons/DefaultTargetDataLoader.kt
@@ -18,6 +18,7 @@ package com.android.intentresolver.icons
import android.app.ActivityManager
import android.content.Context
+import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.AsyncTask
import android.os.UserHandle
@@ -26,6 +27,7 @@ import androidx.annotation.GuardedBy
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
+import com.android.intentresolver.R
import com.android.intentresolver.TargetPresentationGetter
import com.android.intentresolver.chooser.DisplayResolveInfo
import com.android.intentresolver.chooser.SelectableTargetInfo
@@ -40,12 +42,12 @@ class DefaultTargetDataLoader(
private val context: Context,
private val lifecycle: Lifecycle,
private val isAudioCaptureDevice: Boolean,
-) : TargetDataLoader() {
+) : TargetDataLoader {
private val presentationFactory =
TargetPresentationGetter.Factory(
context,
context.getSystemService(ActivityManager::class.java)?.launcherLargeIconDensity
- ?: error("Unable to access ActivityManager")
+ ?: error("Unable to access ActivityManager"),
)
private val nextTaskId = AtomicInteger(0)
@GuardedBy("self") private val activeTasks = SparseArray<AsyncTask<*, *, *>>()
@@ -68,9 +70,11 @@ class DefaultTargetDataLoader(
callback: Consumer<Drawable>,
): Drawable? {
val taskId = nextTaskId.getAndIncrement()
- LoadIconTask(context, info, userHandle, presentationFactory) { result ->
+ LoadIconTask(context, info, presentationFactory) { bitmap ->
removeTask(taskId)
- callback.accept(result)
+ callback.accept(
+ bitmap?.let { BitmapDrawable(context.resources, it) } ?: loadIconPlaceholder()
+ )
}
.also { addTask(taskId, it) }
.executeOnExecutor(executor)
@@ -87,9 +91,11 @@ class DefaultTargetDataLoader(
context.createContextAsUser(userHandle, 0),
info,
presentationFactory,
- ) { result ->
+ ) { bitmap ->
removeTask(taskId)
- callback.accept(result)
+ callback.accept(
+ bitmap?.let { BitmapDrawable(context.resources, it) } ?: loadIconPlaceholder()
+ )
}
.also { addTask(taskId, it) }
.executeOnExecutor(executor)
@@ -123,6 +129,9 @@ class DefaultTargetDataLoader(
synchronized(activeTasks) { activeTasks.remove(id) }
}
+ private fun loadIconPlaceholder(): Drawable =
+ requireNotNull(context.getDrawable(R.drawable.resolver_icon_placeholder))
+
private fun destroy() {
synchronized(activeTasks) {
for (i in 0 until activeTasks.size()) {
diff --git a/java/src/com/android/intentresolver/icons/LoadDirectShareIconTask.java b/java/src/com/android/intentresolver/icons/LoadDirectShareIconTask.java
index e2c0362d..641a0d6a 100644
--- a/java/src/com/android/intentresolver/icons/LoadDirectShareIconTask.java
+++ b/java/src/com/android/intentresolver/icons/LoadDirectShareIconTask.java
@@ -23,7 +23,6 @@ import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Trace;
@@ -50,19 +49,20 @@ class LoadDirectShareIconTask extends BaseLoadIconTask {
Context context,
SelectableTargetInfo targetInfo,
TargetPresentationGetter.Factory presentationFactory,
- Consumer<Drawable> callback) {
+ Consumer<Bitmap> callback) {
super(context, presentationFactory, callback);
mTargetInfo = targetInfo;
}
@Override
- protected Drawable doInBackground(Void... voids) {
- Drawable drawable = null;
+ @Nullable
+ protected Bitmap doInBackground(Void... voids) {
+ Bitmap iconBitmap = null;
Trace.beginSection("shortcut-icon");
try {
final Icon icon = mTargetInfo.getChooserTargetIcon();
if (icon == null || UriFilters.hasValidIcon(icon)) {
- drawable = getChooserTargetIconDrawable(
+ iconBitmap = getChooserTargetIconBitmap(
mContext,
icon,
mTargetInfo.getChooserTargetComponentName(),
@@ -71,25 +71,21 @@ class LoadDirectShareIconTask extends BaseLoadIconTask {
Log.e(TAG, "Failed to load shortcut icon for "
+ mTargetInfo.getChooserTargetComponentName() + "; no access");
}
- if (drawable == null) {
- drawable = loadIconPlaceholder();
- }
} catch (Exception e) {
Log.e(
TAG,
"Failed to load shortcut icon for "
+ mTargetInfo.getChooserTargetComponentName(),
e);
- drawable = loadIconPlaceholder();
} finally {
Trace.endSection();
}
- return drawable;
+ return iconBitmap;
}
@WorkerThread
@Nullable
- private Drawable getChooserTargetIconDrawable(
+ private Bitmap getChooserTargetIconBitmap(
Context context,
@Nullable Icon icon,
ComponentName targetComponentName,
@@ -129,6 +125,6 @@ class LoadDirectShareIconTask extends BaseLoadIconTask {
Bitmap directShareBadgedIcon = sif.createAppBadgedIconBitmap(directShareIcon, appIcon);
sif.recycle();
- return new BitmapDrawable(context.getResources(), directShareBadgedIcon);
+ return directShareBadgedIcon;
}
}
diff --git a/java/src/com/android/intentresolver/icons/LoadIconTask.java b/java/src/com/android/intentresolver/icons/LoadIconTask.java
index 75132208..4573fadf 100644
--- a/java/src/com/android/intentresolver/icons/LoadIconTask.java
+++ b/java/src/com/android/intentresolver/icons/LoadIconTask.java
@@ -19,11 +19,12 @@ package com.android.intentresolver.icons;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Drawable;
+import android.graphics.Bitmap;
import android.os.Trace;
-import android.os.UserHandle;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.intentresolver.TargetPresentationGetter;
import com.android.intentresolver.chooser.DisplayResolveInfo;
@@ -32,38 +33,36 @@ import java.util.function.Consumer;
class LoadIconTask extends BaseLoadIconTask {
private static final String TAG = "IconTask";
protected final DisplayResolveInfo mDisplayResolveInfo;
- private final UserHandle mUserHandle;
private final ResolveInfo mResolveInfo;
LoadIconTask(
Context context, DisplayResolveInfo dri,
- UserHandle userHandle,
TargetPresentationGetter.Factory presentationFactory,
- Consumer<Drawable> callback) {
+ Consumer<Bitmap> callback) {
super(context, presentationFactory, callback);
- mUserHandle = userHandle;
mDisplayResolveInfo = dri;
mResolveInfo = dri.getResolveInfo();
}
@Override
- protected Drawable doInBackground(Void... params) {
+ @Nullable
+ protected Bitmap doInBackground(Void... params) {
Trace.beginSection("app-icon");
try {
return loadIconForResolveInfo(mResolveInfo);
} catch (Exception e) {
ComponentName componentName = mDisplayResolveInfo.getResolvedComponentName();
Log.e(TAG, "Failed to load app icon for " + componentName, e);
- return loadIconPlaceholder();
+ return null;
} finally {
Trace.endSection();
}
}
- protected final Drawable loadIconForResolveInfo(ResolveInfo ri) {
+ protected final Bitmap loadIconForResolveInfo(ResolveInfo ri) {
// Load icons based on userHandle from ResolveInfo. If in work profile/clone profile, icons
// should be badged.
- return mPresentationFactory.makePresentationGetter(ri).getIcon(ri.userHandle);
+ return mPresentationFactory.makePresentationGetter(ri).getIconBitmap(ri.userHandle);
}
}
diff --git a/java/src/com/android/intentresolver/icons/TargetDataLoader.kt b/java/src/com/android/intentresolver/icons/TargetDataLoader.kt
index 935b527a..7cbd040e 100644
--- a/java/src/com/android/intentresolver/icons/TargetDataLoader.kt
+++ b/java/src/com/android/intentresolver/icons/TargetDataLoader.kt
@@ -23,24 +23,24 @@ import com.android.intentresolver.chooser.SelectableTargetInfo
import java.util.function.Consumer
/** A target data loader contract. Added to support testing. */
-abstract class TargetDataLoader {
+interface TargetDataLoader {
/** Load an app target icon */
- abstract fun getOrLoadAppTargetIcon(
+ fun getOrLoadAppTargetIcon(
info: DisplayResolveInfo,
userHandle: UserHandle,
callback: Consumer<Drawable>,
): Drawable?
/** Load a shortcut icon */
- abstract fun getOrLoadDirectShareIcon(
+ fun getOrLoadDirectShareIcon(
info: SelectableTargetInfo,
userHandle: UserHandle,
callback: Consumer<Drawable>,
): Drawable?
/** Load target label */
- abstract fun loadLabel(info: DisplayResolveInfo, callback: Consumer<LabelInfo>)
+ fun loadLabel(info: DisplayResolveInfo, callback: Consumer<LabelInfo>)
/** Loads DisplayResolveInfo's display label synchronously, if needed */
- abstract fun getOrLoadLabel(info: DisplayResolveInfo)
+ fun getOrLoadLabel(info: DisplayResolveInfo)
}
diff --git a/java/src/com/android/intentresolver/icons/TargetDataLoaderModule.kt b/java/src/com/android/intentresolver/icons/TargetDataLoaderModule.kt
index 9c0acb11..86ebb9d9 100644
--- a/java/src/com/android/intentresolver/icons/TargetDataLoaderModule.kt
+++ b/java/src/com/android/intentresolver/icons/TargetDataLoaderModule.kt
@@ -39,6 +39,8 @@ object TargetDataLoaderModule {
@Provides
@ActivityScoped
@Caching
- fun cachingTargetDataLoader(targetDataLoader: TargetDataLoader): TargetDataLoader =
- CachingTargetDataLoader(targetDataLoader)
+ fun cachingTargetDataLoader(
+ @ActivityContext context: Context,
+ targetDataLoader: TargetDataLoader,
+ ): TargetDataLoader = CachingTargetDataLoader(context, targetDataLoader)
}
diff --git a/tests/activity/src/com/android/intentresolver/ResolverWrapperActivity.java b/tests/activity/src/com/android/intentresolver/ResolverWrapperActivity.java
index 22633085..0d317dc3 100644
--- a/tests/activity/src/com/android/intentresolver/ResolverWrapperActivity.java
+++ b/tests/activity/src/com/android/intentresolver/ResolverWrapperActivity.java
@@ -160,7 +160,7 @@ public class ResolverWrapperActivity extends ResolverActivity {
}
}
- private static class TargetDataLoaderWrapper extends TargetDataLoader {
+ private static class TargetDataLoaderWrapper implements TargetDataLoader {
private final TargetDataLoader mTargetDataLoader;
private final CountingIdlingResource mLabelIdlingResource;
diff --git a/tests/unit/src/com/android/intentresolver/icons/CachingTargetDataLoaderTest.kt b/tests/unit/src/com/android/intentresolver/icons/CachingTargetDataLoaderTest.kt
index a36b512b..c5063eed 100644
--- a/tests/unit/src/com/android/intentresolver/icons/CachingTargetDataLoaderTest.kt
+++ b/tests/unit/src/com/android/intentresolver/icons/CachingTargetDataLoaderTest.kt
@@ -21,11 +21,16 @@ import android.content.Context
import android.content.Intent
import android.content.pm.ShortcutInfo
import android.graphics.Bitmap
+import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.os.UserHandle
+import com.android.intentresolver.ResolverDataProvider.createResolveInfo
+import com.android.intentresolver.chooser.DisplayResolveInfo
import com.android.intentresolver.chooser.SelectableTargetInfo
+import com.android.intentresolver.chooser.TargetInfo
import java.util.function.Consumer
import org.junit.Test
import org.mockito.kotlin.any
@@ -37,6 +42,7 @@ import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
class CachingTargetDataLoaderTest {
+ private val context = mock<Context>()
private val userHandle = UserHandle.of(1)
@Test
@@ -61,7 +67,7 @@ class CachingTargetDataLoaderTest {
on { getOrLoadDirectShareIcon(eq(callerTarget), eq(userHandle), any()) } doReturn
null
}
- val testSubject = CachingTargetDataLoader(targetDataLoader)
+ val testSubject = CachingTargetDataLoader(context, targetDataLoader)
val callback = Consumer<Drawable> {}
testSubject.getOrLoadDirectShareIcon(callerTarget, userHandle, callback)
@@ -102,7 +108,7 @@ class CachingTargetDataLoaderTest {
}
.whenever(targetDataLoader)
.getOrLoadDirectShareIcon(eq(targetInfo), eq(userHandle), any())
- val testSubject = CachingTargetDataLoader(targetDataLoader)
+ val testSubject = CachingTargetDataLoader(context, targetDataLoader)
val callback = Consumer<Drawable> {}
testSubject.getOrLoadDirectShareIcon(targetInfo, userHandle, callback)
@@ -112,6 +118,57 @@ class CachingTargetDataLoaderTest {
1 * { getOrLoadDirectShareIcon(eq(targetInfo), eq(userHandle), any()) }
}
}
+
+ @Test
+ fun onlyBitmapsAreCached() {
+ val context =
+ mock<Context> {
+ on { userId } doReturn 1
+ on { packageName } doReturn "package"
+ }
+ val colorTargetInfo =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ Intent(),
+ createResolveInfo(1, userHandle.identifier),
+ Intent(),
+ ) as DisplayResolveInfo
+ val bitmapTargetInfo =
+ DisplayResolveInfo.newDisplayResolveInfo(
+ Intent(),
+ createResolveInfo(2, userHandle.identifier),
+ Intent(),
+ ) as DisplayResolveInfo
+
+ val targetDataLoader = mock<TargetDataLoader>()
+ doAnswer {
+ val target = it.arguments[0] as TargetInfo
+ val callback = it.arguments[2] as Consumer<Drawable>
+ val drawable =
+ if (target === bitmapTargetInfo) {
+ BitmapDrawable(createBitmap())
+ } else {
+ ColorDrawable(Color.RED)
+ }
+ callback.accept(drawable)
+ null
+ }
+ .whenever(targetDataLoader)
+ .getOrLoadAppTargetIcon(any(), eq(userHandle), any())
+ val testSubject = CachingTargetDataLoader(context, targetDataLoader)
+ val callback = Consumer<Drawable> {}
+
+ testSubject.getOrLoadAppTargetIcon(colorTargetInfo, userHandle, callback)
+ testSubject.getOrLoadAppTargetIcon(colorTargetInfo, userHandle, callback)
+ testSubject.getOrLoadAppTargetIcon(bitmapTargetInfo, userHandle, callback)
+ testSubject.getOrLoadAppTargetIcon(bitmapTargetInfo, userHandle, callback)
+
+ verify(targetDataLoader) {
+ 2 * { getOrLoadAppTargetIcon(eq(colorTargetInfo), eq(userHandle), any()) }
+ }
+ verify(targetDataLoader) {
+ 1 * { getOrLoadAppTargetIcon(eq(bitmapTargetInfo), eq(userHandle), any()) }
+ }
+ }
}
private fun createBitmap() = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)