• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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.launcher3.model
18 
19 import android.content.ComponentName
20 import android.content.pm.ActivityInfo
21 import android.content.pm.ApplicationInfo
22 import android.content.pm.LauncherActivityInfo
23 import android.content.pm.LauncherApps
24 import android.os.Process.myUserHandle
25 import android.platform.test.annotations.EnableFlags
26 import android.platform.test.flag.junit.SetFlagsRule
27 import androidx.test.ext.junit.runners.AndroidJUnit4
28 import com.android.launcher3.AppFilter
29 import com.android.launcher3.Flags.FLAG_ENABLE_PRIVATE_SPACE
30 import com.android.launcher3.LauncherSettings
31 import com.android.launcher3.dagger.LauncherAppComponent
32 import com.android.launcher3.dagger.LauncherAppSingleton
33 import com.android.launcher3.icons.IconCache
34 import com.android.launcher3.model.PackageUpdatedTask.OP_ADD
35 import com.android.launcher3.model.PackageUpdatedTask.OP_REMOVE
36 import com.android.launcher3.model.PackageUpdatedTask.OP_SUSPEND
37 import com.android.launcher3.model.PackageUpdatedTask.OP_UNAVAILABLE
38 import com.android.launcher3.model.PackageUpdatedTask.OP_UNSUSPEND
39 import com.android.launcher3.model.PackageUpdatedTask.OP_UPDATE
40 import com.android.launcher3.model.PackageUpdatedTask.OP_USER_AVAILABILITY_CHANGE
41 import com.android.launcher3.model.data.AppInfo
42 import com.android.launcher3.model.data.WorkspaceItemInfo
43 import com.android.launcher3.util.AllModulesForTest
44 import com.android.launcher3.util.Executors
45 import com.android.launcher3.util.LauncherModelHelper
46 import com.android.launcher3.util.TestUtil
47 import com.google.common.truth.Truth.assertThat
48 import dagger.BindsInstance
49 import dagger.Component
50 import org.junit.After
51 import org.junit.Before
52 import org.junit.Rule
53 import org.junit.Test
54 import org.junit.runner.RunWith
55 import org.mockito.kotlin.any
56 import org.mockito.kotlin.doAnswer
57 import org.mockito.kotlin.mock
58 import org.mockito.kotlin.spy
59 import org.mockito.kotlin.verify
60 import org.mockito.kotlin.whenever
61 
62 @RunWith(AndroidJUnit4::class)
63 class PackageUpdatedTaskTest {
64 
65     @get:Rule val setFlagsRule = SetFlagsRule()
66 
67     private val mUser = myUserHandle()
68     private val mLauncherModelHelper = LauncherModelHelper()
69     private val mContext = mLauncherModelHelper.sandboxContext
70 
71     private val expectedPackage = "Test.Package"
72     private val expectedComponent = ComponentName(expectedPackage, "TestClass")
73     private val expectedActivityInfo: LauncherActivityInfo = mock<LauncherActivityInfo>()
74     private val expectedWorkspaceItem = spy(WorkspaceItemInfo())
75 
76     private val mockIconCache: IconCache = mock()
77     private val mockAppFilter: AppFilter = mock<AppFilter>()
78     private lateinit var mAllAppsList: AllAppsList
79 
80     private val mockApplicationInfo: ApplicationInfo = mock<ApplicationInfo>()
81     private val mockActivityInfo: ActivityInfo = mock<ActivityInfo>()
82 
83     private lateinit var mDataModel: BgDataModel
84     private lateinit var mockTaskController: ModelTaskController
85 
86     @Before
setupnull87     fun setup() {
88         mAllAppsList = spy(AllAppsList(mockIconCache, mockAppFilter))
89         mContext.initDaggerComponent(
90             DaggerPackageUpdatedTaskTest_TestComponent.builder()
91                 .bindAllAppsList(mAllAppsList)
92                 .bindAppFilter(mockAppFilter)
93                 .bindIconCache(mockIconCache)
94         )
95 
96         mContext.spyService(LauncherApps::class.java).apply {
97             whenever(getActivityList(expectedPackage, mUser))
98                 .thenReturn(listOf(expectedActivityInfo))
99         }
100 
101         mockTaskController = spy((mContext.appComponent as TestComponent).getTaskController())
102         mDataModel = (mContext.appComponent as TestComponent).getDataModel()
103 
104         whenever(mockAppFilter.shouldShowApp(expectedComponent)).thenReturn(true)
105         mockApplicationInfo.apply {
106             uid = 1
107             isArchived = false
108         }
109         mockActivityInfo.isArchived = false
110         expectedActivityInfo.apply {
111             whenever(applicationInfo).thenReturn(mockApplicationInfo)
112             whenever(activityInfo).thenReturn(mockActivityInfo)
113             whenever(componentName).thenReturn(expectedComponent)
114         }
115         expectedWorkspaceItem.apply {
116             itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
117             container = LauncherSettings.Favorites.CONTAINER_DESKTOP
118             user = mUser
119             whenever(targetPackage).thenReturn(expectedPackage)
120             whenever(targetComponent).thenReturn(expectedComponent)
121         }
122     }
123 
124     @After
tearDownnull125     fun tearDown() {
126         mLauncherModelHelper.destroy()
127     }
128 
129     @Test
OP_ADD triggers model callbacks and adds new items to AllAppsListnull130     fun `OP_ADD triggers model callbacks and adds new items to AllAppsList`() {
131         // Given
132         val taskUnderTest = PackageUpdatedTask(OP_ADD, mUser, expectedPackage)
133         // When
134         mDataModel.addItem(mContext, expectedWorkspaceItem, true)
135         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
136             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
137         }
138         // Then
139         verify(mockIconCache).updateIconsForPkg(expectedPackage, mUser)
140         verify(mAllAppsList).addPackage(mContext, expectedPackage, mUser)
141         verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWorkspaceItem))
142         verify(mockTaskController).bindUpdatedWidgets(mDataModel)
143         assertThat(mAllAppsList.data.firstOrNull()?.componentName)
144             .isEqualTo(AppInfo(mContext, expectedActivityInfo, mUser).componentName)
145     }
146 
147     @Test
OP_UPDATE triggers model callbacks and updates items in AllAppsListnull148     fun `OP_UPDATE triggers model callbacks and updates items in AllAppsList`() {
149         // Given
150         val taskUnderTest = PackageUpdatedTask(OP_UPDATE, mUser, expectedPackage)
151         // When
152         mDataModel.addItem(mContext, expectedWorkspaceItem, true)
153         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
154             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
155         }
156         // Then
157         verify(mockIconCache).updateIconsForPkg(expectedPackage, mUser)
158         verify(mAllAppsList).updatePackage(mContext, expectedPackage, mUser)
159         verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWorkspaceItem))
160         assertThat(mAllAppsList.data.firstOrNull()?.componentName)
161             .isEqualTo(AppInfo(mContext, expectedActivityInfo, mUser).componentName)
162     }
163 
164     @Test
OP_REMOVE triggers model callbacks and removes packages and iconsnull165     fun `OP_REMOVE triggers model callbacks and removes packages and icons`() {
166         // Given
167         val taskUnderTest = PackageUpdatedTask(OP_REMOVE, mUser, expectedPackage)
168         // When
169         mDataModel.addItem(mContext, expectedWorkspaceItem, true)
170         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
171             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
172         }
173         // Then
174         verify(mockIconCache).removeIconsForPkg(expectedPackage, mUser)
175         verify(mAllAppsList).removePackage(expectedPackage, mUser)
176         verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWorkspaceItem))
177         assertThat(mAllAppsList.data).isEmpty()
178     }
179 
180     @Test
OP_UNAVAILABLE triggers model callbacks and removes package from AllAppsListnull181     fun `OP_UNAVAILABLE triggers model callbacks and removes package from AllAppsList`() {
182         // Given
183         val taskUnderTest = PackageUpdatedTask(OP_UNAVAILABLE, mUser, expectedPackage)
184         // When
185         mDataModel.addItem(mContext, expectedWorkspaceItem, true)
186         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
187             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
188         }
189         // Then
190         verify(mAllAppsList).removePackage(expectedPackage, mUser)
191         verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWorkspaceItem))
192         assertThat(mAllAppsList.data).isEmpty()
193     }
194 
195     @Test
OP_SUSPEND triggers model callbacks and updates flags in AllAppsListnull196     fun `OP_SUSPEND triggers model callbacks and updates flags in AllAppsList`() {
197         // Given
198         val taskUnderTest = PackageUpdatedTask(OP_SUSPEND, mUser, expectedPackage)
199         // When
200         mDataModel.addItem(mContext, expectedWorkspaceItem, true)
201         mAllAppsList.add(AppInfo(mContext, expectedActivityInfo, mUser), expectedActivityInfo)
202         mAllAppsList.getAndResetChangeFlag()
203         doAnswer {}.whenever(mockTaskController).bindApplicationsIfNeeded()
204         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
205             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
206         }
207         // Then
208         verify(mAllAppsList).updateDisabledFlags(any(), any())
209         verify(mockTaskController).bindUpdatedWorkspaceItems(listOf(expectedWorkspaceItem))
210         assertThat(mAllAppsList.getAndResetChangeFlag()).isTrue()
211     }
212 
213     @Test
OP_UNSUSPEND triggers no callbacks when app not suspendednull214     fun `OP_UNSUSPEND triggers no callbacks when app not suspended`() {
215         // Given
216         val taskUnderTest = PackageUpdatedTask(OP_UNSUSPEND, mUser, expectedPackage)
217         // When
218         mDataModel.addItem(mContext, expectedWorkspaceItem, true)
219         mAllAppsList.getAndResetChangeFlag()
220         doAnswer {}.whenever(mockTaskController).bindApplicationsIfNeeded()
221         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
222             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
223         }
224         // Then
225         verify(mAllAppsList).updateDisabledFlags(any(), any())
226         verify(mockTaskController).bindUpdatedWorkspaceItems(emptyList())
227         assertThat(mAllAppsList.getAndResetChangeFlag()).isFalse()
228     }
229 
230     @EnableFlags(FLAG_ENABLE_PRIVATE_SPACE)
231     @Test
OP_USER_AVAILABILITY_CHANGE triggers no callbacks if current user not work or privatenull232     fun `OP_USER_AVAILABILITY_CHANGE triggers no callbacks if current user not work or private`() {
233         // Given
234         val taskUnderTest = PackageUpdatedTask(OP_USER_AVAILABILITY_CHANGE, mUser, expectedPackage)
235         // When
236         mDataModel.addItem(mContext, expectedWorkspaceItem, true)
237         TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
238             taskUnderTest.execute(mockTaskController, mDataModel, mAllAppsList)
239         }
240         // Then
241         verify(mAllAppsList).updateDisabledFlags(any(), any())
242         verify(mockTaskController).bindUpdatedWorkspaceItems(emptyList())
243         assertThat(mAllAppsList.data).isEmpty()
244     }
245 
246     @LauncherAppSingleton
247     @Component(modules = [AllModulesForTest::class])
248     interface TestComponent : LauncherAppComponent {
249 
getDataModelnull250         fun getDataModel(): BgDataModel
251 
252         fun getTaskController(): ModelTaskController
253 
254         @Component.Builder
255         interface Builder : LauncherAppComponent.Builder {
256             @BindsInstance fun bindAppFilter(appFilter: AppFilter): Builder
257 
258             @BindsInstance fun bindIconCache(iconCache: IconCache): Builder
259 
260             @BindsInstance fun bindAllAppsList(list: AllAppsList): Builder
261 
262             override fun build(): TestComponent
263         }
264     }
265 }
266