• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.launcher3.model
2 
3 import android.appwidget.AppWidgetManager
4 import android.content.Intent
5 import android.os.UserHandle
6 import android.platform.test.flag.junit.SetFlagsRule
7 import android.provider.Settings
8 import androidx.test.ext.junit.runners.AndroidJUnit4
9 import androidx.test.filters.SmallTest
10 import com.android.dx.mockito.inline.extended.ExtendedMockito
11 import com.android.launcher3.Flags
12 import com.android.launcher3.InvariantDeviceProfile
13 import com.android.launcher3.LauncherAppState
14 import com.android.launcher3.LauncherModel
15 import com.android.launcher3.LauncherModel.LoaderTransaction
16 import com.android.launcher3.icons.IconCache
17 import com.android.launcher3.icons.cache.CachingLogic
18 import com.android.launcher3.icons.cache.IconCacheUpdateHandler
19 import com.android.launcher3.pm.UserCache
20 import com.android.launcher3.provider.RestoreDbTask
21 import com.android.launcher3.ui.TestViewHelpers
22 import com.android.launcher3.util.Executors.MODEL_EXECUTOR
23 import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
24 import com.android.launcher3.util.LooperIdleLock
25 import com.android.launcher3.util.UserIconInfo
26 import com.google.common.truth.Truth
27 import java.util.concurrent.CountDownLatch
28 import junit.framework.Assert.assertEquals
29 import org.junit.After
30 import org.junit.Before
31 import org.junit.Rule
32 import org.junit.Test
33 import org.junit.runner.RunWith
34 import org.mockito.ArgumentCaptor
35 import org.mockito.ArgumentMatchers.any
36 import org.mockito.ArgumentMatchers.anyInt
37 import org.mockito.ArgumentMatchers.anyList
38 import org.mockito.ArgumentMatchers.anyMap
39 import org.mockito.Mock
40 import org.mockito.Mockito
41 import org.mockito.Mockito.times
42 import org.mockito.Mockito.`when`
43 import org.mockito.MockitoAnnotations
44 import org.mockito.MockitoSession
45 import org.mockito.Spy
46 import org.mockito.kotlin.anyOrNull
47 import org.mockito.kotlin.doReturn
48 import org.mockito.kotlin.spy
49 import org.mockito.kotlin.verify
50 import org.mockito.kotlin.whenever
51 import org.mockito.quality.Strictness
52 
53 private const val INSERTION_STATEMENT_FILE = "databases/workspace_items.sql"
54 
55 @SmallTest
56 @RunWith(AndroidJUnit4::class)
57 class LoaderTaskTest {
58     private var context = SandboxModelContext()
59     private val expectedBroadcastModel =
60         FirstScreenBroadcastModel(
61             installerPackage = "installerPackage",
62             pendingCollectionItems = mutableSetOf("pendingCollectionItem"),
63             pendingWidgetItems = mutableSetOf("pendingWidgetItem"),
64             pendingHotseatItems = mutableSetOf("pendingHotseatItem"),
65             pendingWorkspaceItems = mutableSetOf("pendingWorkspaceItem"),
66             installedHotseatItems = mutableSetOf("installedHotseatItem"),
67             installedWorkspaceItems = mutableSetOf("installedWorkspaceItem"),
68             firstScreenInstalledWidgets = mutableSetOf("installedFirstScreenWidget"),
69             secondaryScreenInstalledWidgets = mutableSetOf("installedSecondaryScreenWidget")
70         )
71     private lateinit var mockitoSession: MockitoSession
72 
73     @Mock private lateinit var app: LauncherAppState
74     @Mock private lateinit var bgAllAppsList: AllAppsList
75     @Mock private lateinit var modelDelegate: ModelDelegate
76     @Mock private lateinit var launcherBinder: BaseLauncherBinder
77     @Mock private lateinit var launcherModel: LauncherModel
78     @Mock private lateinit var transaction: LoaderTransaction
79     @Mock private lateinit var iconCache: IconCache
80     @Mock private lateinit var idleLock: LooperIdleLock
81     @Mock private lateinit var iconCacheUpdateHandler: IconCacheUpdateHandler
82     @Mock private lateinit var userCache: UserCache
83 
84     @Spy private var userManagerState: UserManagerState? = UserManagerState()
85 
86     @get:Rule val setFlagsRule = SetFlagsRule()
87 
88     @Before
setupnull89     fun setup() {
90         MockitoAnnotations.initMocks(this)
91         mockitoSession =
92             ExtendedMockito.mockitoSession()
93                 .strictness(Strictness.LENIENT)
94                 .mockStatic(FirstScreenBroadcastHelper::class.java)
95                 .startMocking()
96         val idp =
97             InvariantDeviceProfile().apply {
98                 numRows = 5
99                 numColumns = 6
100                 numDatabaseHotseatIcons = 5
101             }
102         context.putObject(InvariantDeviceProfile.INSTANCE, idp)
103         context.putObject(LauncherAppState.INSTANCE, app)
104 
105         doReturn(TestViewHelpers.findWidgetProvider(false))
106             .`when`(context.spyService(AppWidgetManager::class.java))
107             .getAppWidgetInfo(anyInt())
108         `when`(app.context).thenReturn(context)
109         `when`(app.model).thenReturn(launcherModel)
110         `when`(launcherModel.beginLoader(any(LoaderTask::class.java))).thenReturn(transaction)
111         `when`(app.iconCache).thenReturn(iconCache)
112         `when`(launcherModel.modelDbController)
113             .thenReturn(FactitiousDbController(context, INSERTION_STATEMENT_FILE))
114         `when`(app.invariantDeviceProfile).thenReturn(idp)
115         `when`(launcherBinder.newIdleLock(any(LoaderTask::class.java))).thenReturn(idleLock)
116         `when`(idleLock.awaitLocked(1000)).thenReturn(false)
117         `when`(iconCache.updateHandler).thenReturn(iconCacheUpdateHandler)
118         context.putObject(UserCache.INSTANCE, userCache)
119     }
120 
121     @After
tearDownnull122     fun tearDown() {
123         context.onDestroy()
124         mockitoSession.finishMocking()
125     }
126 
127     @Test
loadsDataProperlynull128     fun loadsDataProperly() =
129         with(BgDataModel()) {
130             val MAIN_HANDLE = UserHandle.of(0)
131             val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
132             `when`(userCache.userProfiles).thenReturn(mockUserHandles)
133             `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 1))
134             LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder)
135                 .runSyncOnBackgroundThread()
136             Truth.assertThat(workspaceItems.size).isAtLeast(25)
137             Truth.assertThat(appWidgets.size).isAtLeast(7)
138             Truth.assertThat(collections.size()).isAtLeast(8)
139             Truth.assertThat(itemsIdMap.size()).isAtLeast(40)
140         }
141 
142     @Test
bindsLoadedDataCorrectlynull143     fun bindsLoadedDataCorrectly() {
144         LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
145             .runSyncOnBackgroundThread()
146 
147         verify(launcherBinder).bindWorkspace(true, false)
148         verify(modelDelegate).workspaceLoadComplete()
149         verify(modelDelegate).loadAndBindAllAppsItems(any(), any(), any())
150         verify(launcherBinder).bindAllApps()
151         verify(iconCacheUpdateHandler, times(4)).updateIcons(any(), any<CachingLogic<Any>>(), any())
152         verify(launcherBinder).bindDeepShortcuts()
153         verify(launcherBinder).bindWidgets()
154         verify(modelDelegate).loadAndBindOtherItems(any())
155         verify(iconCacheUpdateHandler).finish()
156         verify(modelDelegate).modelLoadComplete()
157         verify(transaction).commit()
158     }
159 
160     @Test
setsQuietModeFlagCorrectlyForWorkProfilenull161     fun setsQuietModeFlagCorrectlyForWorkProfile() =
162         with(BgDataModel()) {
163             setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE)
164             val MAIN_HANDLE = UserHandle.of(0)
165             val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
166             `when`(userCache.userProfiles).thenReturn(mockUserHandles)
167             `when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true)
168             `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 1))
169 
170             LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder, userManagerState)
171                 .runSyncOnBackgroundThread()
172 
173             verify(bgAllAppsList)
174                 .setFlags(BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED, true)
175             verify(bgAllAppsList)
176                 .setFlags(BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED, false)
177             verify(bgAllAppsList, Mockito.never())
178                 .setFlags(BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED, true)
179         }
180 
181     @Test
setsQuietModeFlagCorrectlyForPrivateProfilenull182     fun setsQuietModeFlagCorrectlyForPrivateProfile() =
183         with(BgDataModel()) {
184             setFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE)
185             val MAIN_HANDLE = UserHandle.of(0)
186             val mockUserHandles = arrayListOf<UserHandle>(MAIN_HANDLE)
187             `when`(userCache.userProfiles).thenReturn(mockUserHandles)
188             `when`(userManagerState?.isUserQuiet(MAIN_HANDLE)).thenReturn(true)
189             `when`(userCache.getUserInfo(MAIN_HANDLE)).thenReturn(UserIconInfo(MAIN_HANDLE, 3))
190 
191             LoaderTask(app, bgAllAppsList, this, modelDelegate, launcherBinder, userManagerState)
192                 .runSyncOnBackgroundThread()
193 
194             verify(bgAllAppsList)
195                 .setFlags(BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED, false)
196             verify(bgAllAppsList)
197                 .setFlags(BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED, true)
198             verify(bgAllAppsList, Mockito.never())
199                 .setFlags(BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED, true)
200         }
201 
202     @Test
When launcher_broadcast_installed_apps and is restore then send installed item broadcastnull203     fun `When launcher_broadcast_installed_apps and is restore then send installed item broadcast`() {
204         // Given
205         val spyContext = spy(context)
206         `when`(app.context).thenReturn(spyContext)
207         whenever(
208                 FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
209                     anyOrNull(),
210                     anyList(),
211                     anyMap(),
212                     anyList()
213                 )
214             )
215             .thenReturn(listOf(expectedBroadcastModel))
216 
217         whenever(
218                 FirstScreenBroadcastHelper.sendBroadcastsForModels(
219                     spyContext,
220                     listOf(expectedBroadcastModel)
221                 )
222             )
223             .thenCallRealMethod()
224 
225         Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 1)
226         RestoreDbTask.setPending(spyContext)
227 
228         // When
229         LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
230             .runSyncOnBackgroundThread()
231 
232         // Then
233         val argumentCaptor = ArgumentCaptor.forClass(Intent::class.java)
234         verify(spyContext).sendBroadcast(argumentCaptor.capture())
235         val actualBroadcastIntent = argumentCaptor.value
236         assertEquals(expectedBroadcastModel.installerPackage, actualBroadcastIntent.`package`)
237         assertEquals(
238             ArrayList(expectedBroadcastModel.installedWorkspaceItems),
239             actualBroadcastIntent.getStringArrayListExtra("workspaceInstalledItems")
240         )
241         assertEquals(
242             ArrayList(expectedBroadcastModel.installedHotseatItems),
243             actualBroadcastIntent.getStringArrayListExtra("hotseatInstalledItems")
244         )
245         assertEquals(
246             ArrayList(
247                 expectedBroadcastModel.firstScreenInstalledWidgets +
248                     expectedBroadcastModel.secondaryScreenInstalledWidgets
249             ),
250             actualBroadcastIntent.getStringArrayListExtra("widgetInstalledItems")
251         )
252         assertEquals(
253             ArrayList(expectedBroadcastModel.pendingCollectionItems),
254             actualBroadcastIntent.getStringArrayListExtra("folderItem")
255         )
256         assertEquals(
257             ArrayList(expectedBroadcastModel.pendingWorkspaceItems),
258             actualBroadcastIntent.getStringArrayListExtra("workspaceItem")
259         )
260         assertEquals(
261             ArrayList(expectedBroadcastModel.pendingHotseatItems),
262             actualBroadcastIntent.getStringArrayListExtra("hotseatItem")
263         )
264         assertEquals(
265             ArrayList(expectedBroadcastModel.pendingWidgetItems),
266             actualBroadcastIntent.getStringArrayListExtra("widgetItem")
267         )
268     }
269 
270     @Test
When not a restore then installed item broadcast not sentnull271     fun `When not a restore then installed item broadcast not sent`() {
272         // Given
273         val spyContext = spy(context)
274         `when`(app.context).thenReturn(spyContext)
275         whenever(
276                 FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
277                     anyOrNull(),
278                     anyList(),
279                     anyMap(),
280                     anyList()
281                 )
282             )
283             .thenReturn(listOf(expectedBroadcastModel))
284 
285         whenever(
286                 FirstScreenBroadcastHelper.sendBroadcastsForModels(
287                     spyContext,
288                     listOf(expectedBroadcastModel)
289                 )
290             )
291             .thenCallRealMethod()
292 
293         Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 1)
294 
295         // When
296         LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
297             .runSyncOnBackgroundThread()
298 
299         // Then
300         verify(spyContext, times(0)).sendBroadcast(any(Intent::class.java))
301     }
302 
303     @Test
When launcher_broadcast_installed_apps false then installed item broadcast not sentnull304     fun `When launcher_broadcast_installed_apps false then installed item broadcast not sent`() {
305         // Given
306         val spyContext = spy(context)
307         `when`(app.context).thenReturn(spyContext)
308         whenever(
309                 FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
310                     anyOrNull(),
311                     anyList(),
312                     anyMap(),
313                     anyList()
314                 )
315             )
316             .thenReturn(listOf(expectedBroadcastModel))
317 
318         whenever(
319                 FirstScreenBroadcastHelper.sendBroadcastsForModels(
320                     spyContext,
321                     listOf(expectedBroadcastModel)
322                 )
323             )
324             .thenCallRealMethod()
325 
326         Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0)
327         RestoreDbTask.setPending(spyContext)
328 
329         // When
330         LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
331             .runSyncOnBackgroundThread()
332 
333         // Then
334         verify(spyContext, times(0)).sendBroadcast(any(Intent::class.java))
335     }
336 }
337 
runSyncOnBackgroundThreadnull338 private fun LoaderTask.runSyncOnBackgroundThread() {
339     val latch = CountDownLatch(1)
340     MODEL_EXECUTOR.execute {
341         run()
342         latch.countDown()
343     }
344     latch.await()
345 }
346