1 /*
2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.android.intentresolver.icons
18
19 import android.content.ComponentName
20 import android.content.Context
21 import android.content.Intent
22 import android.content.pm.ShortcutInfo
23 import android.graphics.Bitmap
24 import android.graphics.Color
25 import android.graphics.drawable.BitmapDrawable
26 import android.graphics.drawable.ColorDrawable
27 import android.graphics.drawable.Drawable
28 import android.graphics.drawable.Icon
29 import android.os.UserHandle
30 import com.android.intentresolver.ResolverDataProvider.createResolveInfo
31 import com.android.intentresolver.chooser.DisplayResolveInfo
32 import com.android.intentresolver.chooser.SelectableTargetInfo
33 import com.android.intentresolver.chooser.TargetInfo
34 import java.util.function.Consumer
35 import org.junit.Test
36 import org.mockito.kotlin.any
37 import org.mockito.kotlin.doAnswer
38 import org.mockito.kotlin.doReturn
39 import org.mockito.kotlin.eq
40 import org.mockito.kotlin.mock
41 import org.mockito.kotlin.verify
42 import org.mockito.kotlin.whenever
43
44 class CachingTargetDataLoaderTest {
45 private val context = mock<Context>()
46 private val userHandle = UserHandle.of(1)
47
48 @Test
doNotCacheCallerProvidedShortcutsnull49 fun doNotCacheCallerProvidedShortcuts() {
50 val callerTarget =
51 SelectableTargetInfo.newSelectableTargetInfo(
52 /* sourceInfo = */ null,
53 /* backupResolveInfo = */ null,
54 /* resolvedIntent = */ Intent(),
55 /* chooserTargetComponentName =*/ ComponentName("package", "Activity"),
56 "chooserTargetUninitializedTitle",
57 /* chooserTargetIcon =*/ Icon.createWithContentUri("content://package/icon.png"),
58 /* chooserTargetIntentExtras =*/ null,
59 /* modifiedScore =*/ 1f,
60 /* shortcutInfo = */ null,
61 /* appTarget = */ null,
62 /* referrerFillInIntent = */ Intent(),
63 ) as SelectableTargetInfo
64
65 val targetDataLoader =
66 mock<TargetDataLoader> {
67 on { getOrLoadDirectShareIcon(eq(callerTarget), eq(userHandle), any()) } doReturn
68 null
69 }
70 val testSubject = CachingTargetDataLoader(context, targetDataLoader)
71 val callback = Consumer<Drawable> {}
72
73 testSubject.getOrLoadDirectShareIcon(callerTarget, userHandle, callback)
74 testSubject.getOrLoadDirectShareIcon(callerTarget, userHandle, callback)
75
76 verify(targetDataLoader) {
77 2 * { getOrLoadDirectShareIcon(eq(callerTarget), eq(userHandle), any()) }
78 }
79 }
80
81 @Test
serviceShortcutsAreCachednull82 fun serviceShortcutsAreCached() {
83 val context =
84 mock<Context> {
85 on { userId } doReturn 1
86 on { packageName } doReturn "package"
87 }
88 val targetInfo =
89 SelectableTargetInfo.newSelectableTargetInfo(
90 /* sourceInfo = */ null,
91 /* backupResolveInfo = */ null,
92 /* resolvedIntent = */ Intent(),
93 /* chooserTargetComponentName =*/ ComponentName("package", "Activity"),
94 "chooserTargetUninitializedTitle",
95 /* chooserTargetIcon =*/ null,
96 /* chooserTargetIntentExtras =*/ null,
97 /* modifiedScore =*/ 1f,
98 /* shortcutInfo = */ ShortcutInfo.Builder(context, "1").build(),
99 /* appTarget = */ null,
100 /* referrerFillInIntent = */ Intent(),
101 ) as SelectableTargetInfo
102
103 val targetDataLoader = mock<TargetDataLoader>()
104 doAnswer {
105 val callback = it.arguments[2] as Consumer<Drawable>
106 callback.accept(BitmapDrawable(createBitmap()))
107 null
108 }
109 .whenever(targetDataLoader)
110 .getOrLoadDirectShareIcon(eq(targetInfo), eq(userHandle), any())
111 val testSubject = CachingTargetDataLoader(context, targetDataLoader)
112 val callback = Consumer<Drawable> {}
113
114 testSubject.getOrLoadDirectShareIcon(targetInfo, userHandle, callback)
115 testSubject.getOrLoadDirectShareIcon(targetInfo, userHandle, callback)
116
117 verify(targetDataLoader) {
118 1 * { getOrLoadDirectShareIcon(eq(targetInfo), eq(userHandle), any()) }
119 }
120 }
121
122 @Test
onlyBitmapsAreCachednull123 fun onlyBitmapsAreCached() {
124 val context =
125 mock<Context> {
126 on { userId } doReturn 1
127 on { packageName } doReturn "package"
128 }
129 val colorTargetInfo =
130 DisplayResolveInfo.newDisplayResolveInfo(
131 Intent(),
132 createResolveInfo(1, userHandle.identifier),
133 Intent(),
134 ) as DisplayResolveInfo
135 val bitmapTargetInfo =
136 DisplayResolveInfo.newDisplayResolveInfo(
137 Intent(),
138 createResolveInfo(2, userHandle.identifier),
139 Intent(),
140 ) as DisplayResolveInfo
141 val hoverBitmapTargetInfo =
142 DisplayResolveInfo.newDisplayResolveInfo(
143 Intent(),
144 createResolveInfo(3, userHandle.identifier),
145 Intent(),
146 ) as DisplayResolveInfo
147
148 val targetDataLoader = mock<TargetDataLoader>()
149 doAnswer {
150 val target = it.arguments[0] as TargetInfo
151 val callback = it.arguments[2] as Consumer<Drawable>
152 val drawable =
153 if (target === bitmapTargetInfo) {
154 BitmapDrawable(createBitmap())
155 } else if (target === hoverBitmapTargetInfo) {
156 HoverBitmapDrawable(createBitmap())
157 } else {
158 ColorDrawable(Color.RED)
159 }
160 callback.accept(drawable)
161 null
162 }
163 .whenever(targetDataLoader)
164 .getOrLoadAppTargetIcon(any(), eq(userHandle), any())
165 val testSubject = CachingTargetDataLoader(context, targetDataLoader)
166 val callback = Consumer<Drawable> {}
167
168 testSubject.getOrLoadAppTargetIcon(colorTargetInfo, userHandle, callback)
169 testSubject.getOrLoadAppTargetIcon(colorTargetInfo, userHandle, callback)
170 testSubject.getOrLoadAppTargetIcon(bitmapTargetInfo, userHandle, callback)
171 testSubject.getOrLoadAppTargetIcon(bitmapTargetInfo, userHandle, callback)
172 testSubject.getOrLoadAppTargetIcon(hoverBitmapTargetInfo, userHandle, callback)
173 testSubject.getOrLoadAppTargetIcon(hoverBitmapTargetInfo, userHandle, callback)
174
175 verify(targetDataLoader) {
176 2 * { getOrLoadAppTargetIcon(eq(colorTargetInfo), eq(userHandle), any()) }
177 }
178 verify(targetDataLoader) {
179 1 * { getOrLoadAppTargetIcon(eq(bitmapTargetInfo), eq(userHandle), any()) }
180 }
181 verify(targetDataLoader) {
182 1 * { getOrLoadAppTargetIcon(eq(hoverBitmapTargetInfo), eq(userHandle), any()) }
183 }
184 }
185 }
186
createBitmapnull187 private fun createBitmap() = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
188