• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<lambda>null1 package com.android.launcher3.model
2 
3 import android.appwidget.AppWidgetManager
4 import android.content.ComponentName
5 import android.content.Intent
6 import android.content.pm.ApplicationInfo
7 import android.content.pm.LauncherActivityInfo
8 import android.database.sqlite.SQLiteDatabase
9 import android.os.Process
10 import android.os.UserHandle
11 import android.platform.test.annotations.DisableFlags
12 import android.platform.test.annotations.EnableFlags
13 import android.platform.test.flag.junit.SetFlagsRule
14 import android.provider.Settings
15 import androidx.test.ext.junit.runners.AndroidJUnit4
16 import androidx.test.filters.SmallTest
17 import com.android.dx.mockito.inline.extended.ExtendedMockito
18 import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
19 import com.android.launcher3.Flags
20 import com.android.launcher3.LauncherModel
21 import com.android.launcher3.LauncherModel.LoaderTransaction
22 import com.android.launcher3.LauncherPrefs
23 import com.android.launcher3.LauncherPrefs.Companion.IS_FIRST_LOAD_AFTER_RESTORE
24 import com.android.launcher3.LauncherPrefs.Companion.RESTORE_DEVICE
25 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
26 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
27 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR
28 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
29 import com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME
30 import com.android.launcher3.dagger.LauncherAppComponent
31 import com.android.launcher3.dagger.LauncherAppSingleton
32 import com.android.launcher3.icons.IconCache
33 import com.android.launcher3.icons.cache.CachingLogic
34 import com.android.launcher3.icons.cache.IconCacheUpdateHandler
35 import com.android.launcher3.model.LoaderTask.LoaderTaskFactory
36 import com.android.launcher3.model.data.AppInfo
37 import com.android.launcher3.model.data.IconRequestInfo
38 import com.android.launcher3.model.data.WorkspaceItemInfo
39 import com.android.launcher3.pm.UserCache
40 import com.android.launcher3.provider.RestoreDbTask
41 import com.android.launcher3.ui.TestViewHelpers
42 import com.android.launcher3.util.AllModulesForTest
43 import com.android.launcher3.util.Executors.MODEL_EXECUTOR
44 import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
45 import com.android.launcher3.util.LooperIdleLock
46 import com.android.launcher3.util.ModelTestExtensions
47 import com.android.launcher3.util.TestUtil
48 import com.android.launcher3.util.UserIconInfo
49 import com.google.common.truth.Truth.assertThat
50 import dagger.BindsInstance
51 import dagger.Component
52 import java.util.concurrent.CountDownLatch
53 import junit.framework.Assert.assertEquals
54 import org.junit.After
55 import org.junit.Before
56 import org.junit.Rule
57 import org.junit.Test
58 import org.junit.runner.RunWith
59 import org.mockito.ArgumentCaptor
60 import org.mockito.Mock
61 import org.mockito.Mockito
62 import org.mockito.Mockito.times
63 import org.mockito.Mockito.`when`
64 import org.mockito.MockitoAnnotations
65 import org.mockito.MockitoSession
66 import org.mockito.Spy
67 import org.mockito.kotlin.any
68 import org.mockito.kotlin.anyOrNull
69 import org.mockito.kotlin.doAnswer
70 import org.mockito.kotlin.doReturn
71 import org.mockito.kotlin.mock
72 import org.mockito.kotlin.verify
73 import org.mockito.kotlin.whenever
74 import org.mockito.quality.Strictness
75 
76 private const val INSERTION_STATEMENT_FILE = "databases/workspace_items.sql"
77 
78 @SmallTest
79 @RunWith(AndroidJUnit4::class)
80 class LoaderTaskTest {
81     private var context = SandboxModelContext()
82     private val expectedBroadcastModel =
83         FirstScreenBroadcastModel(
84             installerPackage = "installerPackage",
85             pendingCollectionItems = mutableSetOf("pendingCollectionItem"),
86             pendingWidgetItems = mutableSetOf("pendingWidgetItem"),
87             pendingHotseatItems = mutableSetOf("pendingHotseatItem"),
88             pendingWorkspaceItems = mutableSetOf("pendingWorkspaceItem"),
89             installedHotseatItems = mutableSetOf("installedHotseatItem"),
90             installedWorkspaceItems = mutableSetOf("installedWorkspaceItem"),
91             firstScreenInstalledWidgets = mutableSetOf("installedFirstScreenWidget"),
92             secondaryScreenInstalledWidgets = mutableSetOf("installedSecondaryScreenWidget"),
93         )
94     private lateinit var mockitoSession: MockitoSession
95 
96     @Mock private lateinit var bgAllAppsList: AllAppsList
97     @Mock private lateinit var modelDelegate: ModelDelegate
98     @Mock private lateinit var launcherModel: LauncherModel
99     @Mock private lateinit var iconCache: IconCache
100     @Mock private lateinit var userCache: UserCache
101     @Mock private lateinit var modelDbController: ModelDbController
102 
103     @Mock private lateinit var launcherBinder: BaseLauncherBinder
104     @Mock private lateinit var transaction: LoaderTransaction
105     @Mock private lateinit var idleLock: LooperIdleLock
106     @Mock private lateinit var iconCacheUpdateHandler: IconCacheUpdateHandler
107 
108     @Spy private var userManagerState: UserManagerState = UserManagerState()
109 
110     @get:Rule val setFlagsRule = SetFlagsRule()
111 
112     private val testComponent: TestComponent
113         get() = context.appComponent as TestComponent
114 
115     private val bgDataModel: BgDataModel
116         get() = testComponent.getDataModel()
117 
118     private val inMemoryDb: SQLiteDatabase by lazy {
119         ModelTestExtensions.createInMemoryDb(INSERTION_STATEMENT_FILE)
120     }
121 
122     @Before
123     fun setup() {
124         MockitoAnnotations.initMocks(this)
125         mockitoSession =
126             ExtendedMockito.mockitoSession()
127                 .strictness(Strictness.LENIENT)
128                 .mockStatic(FirstScreenBroadcastHelper::class.java)
129                 .startMocking()
130         doReturn(TestViewHelpers.findWidgetProvider(false))
131             .`when`(context.spyService(AppWidgetManager::class.java))
132             .getAppWidgetInfo(any())
133 
134         `when`(launcherModel.beginLoader(any())).thenReturn(transaction)
135 
136         `when`(launcherModel.modelDbController).thenReturn(modelDbController)
137         doAnswer {}.whenever(modelDbController).loadDefaultFavoritesIfNecessary()
138         doAnswer { i ->
139                 inMemoryDb.query(
140                     TABLE_NAME,
141                     i.getArgument(0),
142                     i.getArgument(1),
143                     i.getArgument(2),
144                     null,
145                     null,
146                     i.getArgument(3),
147                 )
148             }
149             .whenever(modelDbController)
150             .query(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())
151 
152         `when`(launcherModel.modelDelegate).thenReturn(modelDelegate)
153         `when`(launcherBinder.newIdleLock(any())).thenReturn(idleLock)
154         `when`(idleLock.awaitLocked(1000)).thenReturn(false)
155         `when`(iconCache.getUpdateHandler()).thenReturn(iconCacheUpdateHandler)
156 
157         context.initDaggerComponent(
158             DaggerLoaderTaskTest_TestComponent.builder()
159                 .bindUserCache(userCache)
160                 .bindIconCache(iconCache)
161                 .bindLauncherModel(launcherModel)
162                 .bindAllAppsList(bgAllAppsList)
163         )
164         context.appComponent.idp.apply {
165             numRows = 5
166             numColumns = 6
167             numDatabaseHotseatIcons = 5
168         }
169         TestUtil.grantWriteSecurePermission()
170     }
171 
172     @After
173     fun tearDown() {
174         LauncherPrefs.get(context).removeSync(RESTORE_DEVICE)
175         LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false))
176         inMemoryDb.close()
177         context.onDestroy()
178         mockitoSession.finishMocking()
179     }
180 
181     @Test
182     fun loadsDataProperly() =
183         with(bgDataModel) {
184             val MAIN_HANDLE = Process.myUserHandle()
185             val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
186             `when`(userCache.userProfiles).thenReturn(mockUserHandles)
187             `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 1))
188             testComponent
189                 .getLoaderTaskFactory()
190                 .newLoaderTask(launcherBinder, userManagerState)
191                 .runSyncOnBackgroundThread()
192             assertThat(
193                     itemsIdMap
194                         .filter {
195                             it.container == CONTAINER_DESKTOP || it.container == CONTAINER_HOTSEAT
196                         }
197                         .size
198                 )
199                 .isAtLeast(32)
200             assertThat(itemsIdMap.filter { ModelUtils.WIDGET_FILTER.test(it) }.size).isAtLeast(7)
201             assertThat(
202                     itemsIdMap
203                         .filter {
204                             it.itemType == ITEM_TYPE_FOLDER || it.itemType == ITEM_TYPE_APP_PAIR
205                         }
206                         .size
207                 )
208                 .isAtLeast(8)
209             assertThat(itemsIdMap.size()).isAtLeast(40)
210         }
211 
212     @Test
213     fun bindsLoadedDataCorrectly() {
214         testComponent
215             .getLoaderTaskFactory()
216             .newLoaderTask(launcherBinder, userManagerState)
217             .runSyncOnBackgroundThread()
218 
219         verify(launcherBinder).bindWorkspace(true, false)
220         verify(modelDelegate).workspaceLoadComplete()
221         verify(modelDelegate).loadAndBindAllAppsItems(any(), anyOrNull(), any())
222         verify(launcherBinder).bindAllApps()
223         verify(iconCacheUpdateHandler, times(4)).updateIcons(any(), any<CachingLogic<Any>>(), any())
224         verify(launcherBinder).bindDeepShortcuts()
225         verify(launcherBinder).bindWidgets()
226         verify(modelDelegate).loadAndBindOtherItems(anyOrNull())
227         verify(iconCacheUpdateHandler).finish()
228         verify(modelDelegate).modelLoadComplete()
229         verify(transaction).commit()
230     }
231 
232     @Test
233     fun setsQuietModeFlagCorrectlyForWorkProfile() =
234         with(bgDataModel) {
235             setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE)
236             val MAIN_HANDLE = Process.myUserHandle()
237             val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
238             `when`(userCache.userProfiles).thenReturn(mockUserHandles)
239             `when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true)
240             `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 1))
241 
242             testComponent
243                 .getLoaderTaskFactory()
244                 .newLoaderTask(launcherBinder, userManagerState)
245                 .runSyncOnBackgroundThread()
246 
247             verify(bgAllAppsList)
248                 .setFlags(BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED, true)
249             verify(bgAllAppsList)
250                 .setFlags(BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED, false)
251             verify(bgAllAppsList, Mockito.never())
252                 .setFlags(BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED, true)
253         }
254 
255     @Test
256     fun setsQuietModeFlagCorrectlyForPrivateProfile() =
257         with(bgDataModel) {
258             setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE)
259             val MAIN_HANDLE = Process.myUserHandle()
260             val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
261             `when`(userCache.userProfiles).thenReturn(mockUserHandles)
262             `when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true)
263             `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 3))
264 
265             testComponent
266                 .getLoaderTaskFactory()
267                 .newLoaderTask(launcherBinder, userManagerState)
268                 .runSyncOnBackgroundThread()
269 
270             verify(bgAllAppsList)
271                 .setFlags(BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED, false)
272             verify(bgAllAppsList)
273                 .setFlags(BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED, true)
274             verify(bgAllAppsList, Mockito.never())
275                 .setFlags(BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED, true)
276         }
277 
278     @Test
279     @EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
280     fun `When broadcast flag on and is restore and secure setting off then send new broadcast`() {
281         // Given
282         spyOn(context)
283         val spyContext = context
284         whenever(
285                 FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
286                     any(),
287                     any(),
288                     any(),
289                     any(),
290                 )
291             )
292             .thenReturn(listOf(expectedBroadcastModel))
293 
294         whenever(
295                 FirstScreenBroadcastHelper.sendBroadcastsForModels(
296                     spyContext,
297                     listOf(expectedBroadcastModel),
298                 )
299             )
300             .thenCallRealMethod()
301 
302         Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0)
303         RestoreDbTask.setPending(spyContext)
304 
305         // When
306         testComponent
307             .getLoaderTaskFactory()
308             .newLoaderTask(launcherBinder, userManagerState)
309             .runSyncOnBackgroundThread()
310 
311         // Then
312         val argumentCaptor = ArgumentCaptor.forClass(Intent::class.java)
313         verify(spyContext).sendBroadcast(argumentCaptor.capture())
314         val actualBroadcastIntent = argumentCaptor.value
315         assertEquals(expectedBroadcastModel.installerPackage, actualBroadcastIntent.`package`)
316         assertEquals(
317             ArrayList(expectedBroadcastModel.installedWorkspaceItems),
318             actualBroadcastIntent.getStringArrayListExtra("workspaceInstalledItems"),
319         )
320         assertEquals(
321             ArrayList(expectedBroadcastModel.installedHotseatItems),
322             actualBroadcastIntent.getStringArrayListExtra("hotseatInstalledItems"),
323         )
324         assertEquals(
325             ArrayList(
326                 expectedBroadcastModel.firstScreenInstalledWidgets +
327                     expectedBroadcastModel.secondaryScreenInstalledWidgets
328             ),
329             actualBroadcastIntent.getStringArrayListExtra("widgetInstalledItems"),
330         )
331         assertEquals(
332             ArrayList(expectedBroadcastModel.pendingCollectionItems),
333             actualBroadcastIntent.getStringArrayListExtra("folderItem"),
334         )
335         assertEquals(
336             ArrayList(expectedBroadcastModel.pendingWorkspaceItems),
337             actualBroadcastIntent.getStringArrayListExtra("workspaceItem"),
338         )
339         assertEquals(
340             ArrayList(expectedBroadcastModel.pendingHotseatItems),
341             actualBroadcastIntent.getStringArrayListExtra("hotseatItem"),
342         )
343         assertEquals(
344             ArrayList(expectedBroadcastModel.pendingWidgetItems),
345             actualBroadcastIntent.getStringArrayListExtra("widgetItem"),
346         )
347     }
348 
349     @Test
350     @EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
351     fun `When not a restore then installed item broadcast not sent`() {
352         // Given
353         spyOn(context)
354         val spyContext = context
355         whenever(
356                 FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
357                     any(),
358                     any(),
359                     any(),
360                     any(),
361                 )
362             )
363             .thenReturn(listOf(expectedBroadcastModel))
364 
365         whenever(
366                 FirstScreenBroadcastHelper.sendBroadcastsForModels(
367                     spyContext,
368                     listOf(expectedBroadcastModel),
369                 )
370             )
371             .thenCallRealMethod()
372 
373         Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0)
374 
375         // When
376         testComponent
377             .getLoaderTaskFactory()
378             .newLoaderTask(launcherBinder, userManagerState)
379             .runSyncOnBackgroundThread()
380 
381         // Then
382         verify(spyContext, times(0)).sendBroadcast(any())
383     }
384 
385     @Test
386     @DisableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
387     fun `When broadcast flag off then installed item broadcast not sent`() {
388         // Given
389         spyOn(context)
390         val spyContext = context
391         whenever(
392                 FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
393                     any(),
394                     any(),
395                     any(),
396                     any(),
397                 )
398             )
399             .thenReturn(listOf(expectedBroadcastModel))
400 
401         whenever(
402                 FirstScreenBroadcastHelper.sendBroadcastsForModels(
403                     spyContext,
404                     listOf(expectedBroadcastModel),
405                 )
406             )
407             .thenCallRealMethod()
408 
409         Settings.Secure.putInt(
410             spyContext.contentResolver,
411             "disable_launcher_broadcast_installed_apps",
412             0,
413         )
414         RestoreDbTask.setPending(spyContext)
415 
416         // When
417         testComponent
418             .getLoaderTaskFactory()
419             .newLoaderTask(launcherBinder, userManagerState)
420             .runSyncOnBackgroundThread()
421 
422         // Then
423         verify(spyContext, times(0)).sendBroadcast(any())
424     }
425 
426     @Test
427     @EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
428     fun `When failsafe secure setting on then installed item broadcast not sent`() {
429         // Given
430         spyOn(context)
431         val spyContext = context
432         whenever(
433                 FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
434                     any(),
435                     any(),
436                     any(),
437                     any(),
438                 )
439             )
440             .thenReturn(listOf(expectedBroadcastModel))
441 
442         whenever(
443                 FirstScreenBroadcastHelper.sendBroadcastsForModels(
444                     spyContext,
445                     listOf(expectedBroadcastModel),
446                 )
447             )
448             .thenCallRealMethod()
449 
450         Settings.Secure.putInt(
451             spyContext.contentResolver,
452             "disable_launcher_broadcast_installed_apps",
453             1,
454         )
455         RestoreDbTask.setPending(spyContext)
456 
457         // When
458         testComponent
459             .getLoaderTaskFactory()
460             .newLoaderTask(launcherBinder, userManagerState)
461             .runSyncOnBackgroundThread()
462 
463         // Then
464         verify(spyContext, times(0)).sendBroadcast(any())
465     }
466 
467     @Test
468     @EnableFlags(Flags.FLAG_RESTORE_ARCHIVED_APP_ICONS_FROM_DB)
469     fun `When flag on and restore then archived AllApps icons on Workspace load from db`() {
470         // Given
471         val activityInfo: LauncherActivityInfo = mock()
472         val applicationInfo: ApplicationInfo = mock<ApplicationInfo>().apply { isArchived = true }
473         whenever(activityInfo.applicationInfo).thenReturn(applicationInfo)
474         val expectedIconBlob = byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08)
475         val expectedComponent = ComponentName("package", "class")
476         val workspaceIconRequests =
477             listOf(
478                 IconRequestInfo<WorkspaceItemInfo>(
479                     WorkspaceItemInfo().apply {
480                         intent = Intent().apply { component = expectedComponent }
481                     },
482                     activityInfo,
483                     expectedIconBlob,
484                     false, /* useLowResIcon */
485                 )
486             )
487         val expectedAppInfo = AppInfo().apply { componentName = expectedComponent }
488         // When
489         val loader =
490             testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState)
491         val actualIconRequest =
492             loader.getAppInfoIconRequestInfo(
493                 expectedAppInfo,
494                 activityInfo,
495                 workspaceIconRequests,
496                 /* isRestoreFromBackup */ true,
497             )
498         // Then
499         assertThat(actualIconRequest.iconBlob).isEqualTo(expectedIconBlob)
500         assertThat(actualIconRequest.itemInfo).isEqualTo(expectedAppInfo)
501     }
502 
503     @Test
504     @EnableFlags(Flags.FLAG_RESTORE_ARCHIVED_APP_ICONS_FROM_DB)
505     fun `When flag on and not restore then archived AllApps icons do not load from db`() {
506         // Given
507         val activityInfo: LauncherActivityInfo = mock()
508         val applicationInfo: ApplicationInfo = mock<ApplicationInfo>().apply { isArchived = true }
509         whenever(activityInfo.applicationInfo).thenReturn(applicationInfo)
510         val expectedIconBlob = byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08)
511         val expectedComponent = ComponentName("package", "class")
512         val workspaceIconRequests =
513             listOf(
514                 IconRequestInfo<WorkspaceItemInfo>(
515                     WorkspaceItemInfo().apply {
516                         intent = Intent().apply { component = expectedComponent }
517                     },
518                     activityInfo,
519                     expectedIconBlob,
520                     false, /* useLowResIcon */
521                 )
522             )
523         val expectedAppInfo = AppInfo().apply { componentName = expectedComponent }
524         // When
525         val loader =
526             testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState)
527         val actualIconRequest =
528             loader.getAppInfoIconRequestInfo(
529                 expectedAppInfo,
530                 activityInfo,
531                 workspaceIconRequests,
532                 /* isRestoreFromBackup */ false,
533             )
534         // Then
535         assertThat(actualIconRequest.iconBlob).isNull()
536         assertThat(actualIconRequest.itemInfo).isEqualTo(expectedAppInfo)
537     }
538 
539     @Test
540     @EnableFlags(Flags.FLAG_RESTORE_ARCHIVED_APP_ICONS_FROM_DB)
541     fun `When flag on and restore then unarchived AllApps icons not loaded from db`() {
542         // Given
543         val activityInfo: LauncherActivityInfo = mock()
544         val applicationInfo: ApplicationInfo = mock<ApplicationInfo>().apply { isArchived = false }
545         whenever(activityInfo.applicationInfo).thenReturn(applicationInfo)
546         val expectedIconBlob = byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08)
547         val expectedComponent = ComponentName("package", "class")
548         val workspaceIconRequests =
549             listOf(
550                 IconRequestInfo<WorkspaceItemInfo>(
551                     WorkspaceItemInfo().apply {
552                         intent = Intent().apply { component = expectedComponent }
553                     },
554                     activityInfo,
555                     expectedIconBlob,
556                     false, /* useLowResIcon */
557                 )
558             )
559         val expectedAppInfo = AppInfo().apply { componentName = expectedComponent }
560         // When
561         val loader =
562             testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState)
563         val actualIconRequest =
564             loader.getAppInfoIconRequestInfo(
565                 expectedAppInfo,
566                 activityInfo,
567                 workspaceIconRequests,
568                 /* isRestoreFromBackup */ true,
569             )
570         // Then
571         assertThat(actualIconRequest.iconBlob).isNull()
572         assertThat(actualIconRequest.itemInfo).isEqualTo(expectedAppInfo)
573     }
574 
575     @Test
576     @EnableFlags(Flags.FLAG_RESTORE_ARCHIVED_APP_ICONS_FROM_DB)
577     fun `When flag on and restore then all apps icon not on workspace is not loaded from db`() {
578         // Given
579         val activityInfo: LauncherActivityInfo = mock()
580         val applicationInfo: ApplicationInfo = mock<ApplicationInfo>().apply { isArchived = true }
581         whenever(activityInfo.applicationInfo).thenReturn(applicationInfo)
582         val expectedIconBlob = byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08)
583         val expectedComponent = ComponentName("package", "class")
584         val workspaceIconRequests =
585             listOf(
586                 IconRequestInfo<WorkspaceItemInfo>(
587                     WorkspaceItemInfo().apply {
588                         intent = Intent().apply { component = expectedComponent }
589                     },
590                     activityInfo,
591                     expectedIconBlob,
592                     false, /* useLowResIcon */
593                 )
594             )
595         val expectedAppInfo =
596             AppInfo().apply { componentName = ComponentName("differentPkg", "differentClass") }
597         // When
598         val loader =
599             testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState)
600         val actualIconRequest =
601             loader.getAppInfoIconRequestInfo(
602                 expectedAppInfo,
603                 activityInfo,
604                 workspaceIconRequests,
605                 /* isRestoreFromBackup */ true,
606             )
607         // Then
608         assertThat(actualIconRequest.iconBlob).isNull()
609         assertThat(actualIconRequest.itemInfo).isEqualTo(expectedAppInfo)
610     }
611 
612     @Test
613     @DisableFlags(Flags.FLAG_RESTORE_ARCHIVED_APP_ICONS_FROM_DB)
614     fun `When flag off and restore then archived AllApps icons not loaded from db`() {
615         // Given
616         val activityInfo: LauncherActivityInfo = mock()
617         val applicationInfo: ApplicationInfo = mock<ApplicationInfo>().apply { isArchived = true }
618         whenever(activityInfo.applicationInfo).thenReturn(applicationInfo)
619         val expectedIconBlob = byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08)
620         val workspaceIconRequests =
621             listOf(
622                 IconRequestInfo<WorkspaceItemInfo>(
623                     WorkspaceItemInfo(),
624                     activityInfo,
625                     expectedIconBlob,
626                     false, /* useLowResIcon */
627                 )
628             )
629         val expectedAppInfo = AppInfo()
630         // When
631         val loader =
632             testComponent.getLoaderTaskFactory().newLoaderTask(launcherBinder, userManagerState)
633         val actualIconRequest =
634             loader.getAppInfoIconRequestInfo(
635                 expectedAppInfo,
636                 activityInfo,
637                 workspaceIconRequests,
638                 /* isRestoreFromBackup */ true,
639             )
640         // Then
641         assertThat(actualIconRequest.iconBlob).isNull()
642         assertThat(actualIconRequest.itemInfo).isEqualTo(expectedAppInfo)
643     }
644 
645     @LauncherAppSingleton
646     @Component(modules = [AllModulesForTest::class])
647     interface TestComponent : LauncherAppComponent {
648 
649         fun getLoaderTaskFactory(): LoaderTaskFactory
650 
651         fun getDataModel(): BgDataModel
652 
653         @Component.Builder
654         interface Builder : LauncherAppComponent.Builder {
655             @BindsInstance fun bindUserCache(userCache: UserCache): Builder
656 
657             @BindsInstance fun bindLauncherModel(model: LauncherModel): Builder
658 
659             @BindsInstance fun bindIconCache(iconCache: IconCache): Builder
660 
661             @BindsInstance fun bindAllAppsList(list: AllAppsList): Builder
662 
663             override fun build(): TestComponent
664         }
665     }
666 }
667 
runSyncOnBackgroundThreadnull668 private fun LoaderTask.runSyncOnBackgroundThread() {
669     val latch = CountDownLatch(1)
670     MODEL_EXECUTOR.execute {
671         run()
672         latch.countDown()
673     }
674     latch.await()
675 }
676