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.taskbar 18 19 import android.app.ActivityManager.RunningTaskInfo 20 import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM 21 import android.content.ComponentName 22 import android.content.Intent 23 import android.os.Process 24 import android.os.UserHandle 25 import android.testing.AndroidTestingRunner 26 import com.android.launcher3.model.data.AppInfo 27 import com.android.launcher3.model.data.ItemInfo 28 import com.android.launcher3.statehandlers.DesktopVisibilityController 29 import com.android.quickstep.RecentsModel 30 import com.google.common.truth.Truth.assertThat 31 import org.junit.Before 32 import org.junit.Rule 33 import org.junit.Test 34 import org.junit.runner.RunWith 35 import org.mockito.Mock 36 import org.mockito.junit.MockitoJUnit 37 import org.mockito.kotlin.whenever 38 39 @RunWith(AndroidTestingRunner::class) 40 class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { 41 42 @get:Rule val mockitoRule = MockitoJUnit.rule() 43 44 @Mock private lateinit var mockRecentsModel: RecentsModel 45 @Mock private lateinit var mockDesktopVisibilityController: DesktopVisibilityController 46 47 private var nextTaskId: Int = 500 48 49 private lateinit var recentAppsController: TaskbarRecentAppsController 50 private lateinit var userHandle: UserHandle 51 52 @Before setUpnull53 fun setUp() { 54 super.setup() 55 userHandle = Process.myUserHandle() 56 recentAppsController = 57 TaskbarRecentAppsController(mockRecentsModel) { mockDesktopVisibilityController } 58 recentAppsController.init(taskbarControllers) 59 recentAppsController.isEnabled = true 60 recentAppsController.setApps( 61 ALL_APP_PACKAGES.map { createTestAppInfo(packageName = it) }.toTypedArray() 62 ) 63 } 64 65 @Test updateHotseatItemInfos_notInDesktopMode_returnsExistingHotseatItemsnull66 fun updateHotseatItemInfos_notInDesktopMode_returnsExistingHotseatItems() { 67 setInDesktopMode(false) 68 val hotseatItems = 69 createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)) 70 71 assertThat(recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())) 72 .isEqualTo(hotseatItems.toTypedArray()) 73 } 74 75 @Test updateHotseatItemInfos_notInDesktopMode_runningApps_returnsExistingHotseatItemsnull76 fun updateHotseatItemInfos_notInDesktopMode_runningApps_returnsExistingHotseatItems() { 77 setInDesktopMode(false) 78 val hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2) 79 val hotseatItems = createHotseatItemsFromPackageNames(hotseatPackages) 80 val runningTasks = 81 createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)) 82 whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) 83 recentAppsController.updateRunningApps() 84 85 val newHotseatItems = 86 recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()) 87 88 assertThat(newHotseatItems.map { it?.targetPackage }) 89 .containsExactlyElementsIn(hotseatPackages) 90 } 91 92 @Test updateHotseatItemInfos_noRunningApps_returnsExistingHotseatItemsnull93 fun updateHotseatItemInfos_noRunningApps_returnsExistingHotseatItems() { 94 setInDesktopMode(true) 95 val hotseatItems = 96 createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)) 97 98 assertThat(recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())) 99 .isEqualTo(hotseatItems.toTypedArray()) 100 } 101 102 @Test updateHotseatItemInfos_returnsExistingHotseatItemsAndRunningAppsnull103 fun updateHotseatItemInfos_returnsExistingHotseatItemsAndRunningApps() { 104 setInDesktopMode(true) 105 val hotseatItems = 106 createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)) 107 val runningTasks = 108 createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)) 109 whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) 110 recentAppsController.updateRunningApps() 111 112 val newHotseatItems = 113 recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()) 114 115 val expectedPackages = 116 listOf( 117 HOTSEAT_PACKAGE_1, 118 HOTSEAT_PACKAGE_2, 119 RUNNING_APP_PACKAGE_1, 120 RUNNING_APP_PACKAGE_2, 121 ) 122 assertThat(newHotseatItems.map { it?.targetPackage }) 123 .containsExactlyElementsIn(expectedPackages) 124 } 125 126 @Test updateHotseatItemInfos_runningAppIsHotseatItem_returnsDistinctItemsnull127 fun updateHotseatItemInfos_runningAppIsHotseatItem_returnsDistinctItems() { 128 setInDesktopMode(true) 129 val hotseatItems = 130 createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)) 131 val runningTasks = 132 createDesktopTasksFromPackageNames( 133 listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) 134 ) 135 whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) 136 recentAppsController.updateRunningApps() 137 138 val newHotseatItems = 139 recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()) 140 141 val expectedPackages = 142 listOf( 143 HOTSEAT_PACKAGE_1, 144 HOTSEAT_PACKAGE_2, 145 RUNNING_APP_PACKAGE_1, 146 RUNNING_APP_PACKAGE_2, 147 ) 148 assertThat(newHotseatItems.map { it?.targetPackage }) 149 .containsExactlyElementsIn(expectedPackages) 150 } 151 152 @Test getRunningApps_notInDesktopMode_returnsEmptySetnull153 fun getRunningApps_notInDesktopMode_returnsEmptySet() { 154 setInDesktopMode(false) 155 val runningTasks = 156 createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)) 157 whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) 158 recentAppsController.updateRunningApps() 159 160 assertThat(recentAppsController.runningApps).isEmpty() 161 assertThat(recentAppsController.minimizedApps).isEmpty() 162 } 163 164 @Test getRunningApps_inDesktopMode_returnsRunningAppsnull165 fun getRunningApps_inDesktopMode_returnsRunningApps() { 166 setInDesktopMode(true) 167 val runningTasks = 168 createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)) 169 whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) 170 recentAppsController.updateRunningApps() 171 172 assertThat(recentAppsController.runningApps) 173 .containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) 174 assertThat(recentAppsController.minimizedApps).isEmpty() 175 } 176 177 @Test getMinimizedApps_inDesktopMode_returnsAllAppsRunningAndInvisibleAppsMinimizednull178 fun getMinimizedApps_inDesktopMode_returnsAllAppsRunningAndInvisibleAppsMinimized() { 179 setInDesktopMode(true) 180 val runningTasks = 181 ArrayList( 182 listOf( 183 createDesktopTaskInfo(RUNNING_APP_PACKAGE_1) { isVisible = true }, 184 createDesktopTaskInfo(RUNNING_APP_PACKAGE_2) { isVisible = true }, 185 createDesktopTaskInfo(RUNNING_APP_PACKAGE_3) { isVisible = false }, 186 ) 187 ) 188 whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks) 189 recentAppsController.updateRunningApps() 190 191 assertThat(recentAppsController.runningApps) 192 .containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3) 193 assertThat(recentAppsController.minimizedApps).containsExactly(RUNNING_APP_PACKAGE_3) 194 } 195 createHotseatItemsFromPackageNamesnull196 private fun createHotseatItemsFromPackageNames(packageNames: List<String>): List<ItemInfo> { 197 return packageNames.map { createTestAppInfo(packageName = it) } 198 } 199 createDesktopTasksFromPackageNamesnull200 private fun createDesktopTasksFromPackageNames( 201 packageNames: List<String> 202 ): ArrayList<RunningTaskInfo> { 203 return ArrayList(packageNames.map { createDesktopTaskInfo(packageName = it) }) 204 } 205 createDesktopTaskInfonull206 private fun createDesktopTaskInfo( 207 packageName: String, 208 init: RunningTaskInfo.() -> Unit = { isVisible = true }, 209 ): RunningTaskInfo { <lambda>null210 return RunningTaskInfo().apply { 211 taskId = nextTaskId++ 212 configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM 213 realActivity = ComponentName(packageName, "TestActivity") 214 init() 215 } 216 } 217 createTestAppInfonull218 private fun createTestAppInfo( 219 packageName: String = "testPackageName", 220 className: String = "testClassName" 221 ) = AppInfo(ComponentName(packageName, className), className /* title */, userHandle, Intent()) 222 223 private fun setInDesktopMode(inDesktopMode: Boolean) { 224 whenever(mockDesktopVisibilityController.areDesktopTasksVisible()).thenReturn(inDesktopMode) 225 } 226 227 private companion object { 228 const val HOTSEAT_PACKAGE_1 = "hotseat1" 229 const val HOTSEAT_PACKAGE_2 = "hotseat2" 230 const val RUNNING_APP_PACKAGE_1 = "running1" 231 const val RUNNING_APP_PACKAGE_2 = "running2" 232 const val RUNNING_APP_PACKAGE_3 = "running3" 233 val ALL_APP_PACKAGES = 234 listOf( 235 HOTSEAT_PACKAGE_1, 236 HOTSEAT_PACKAGE_2, 237 RUNNING_APP_PACKAGE_1, 238 RUNNING_APP_PACKAGE_2, 239 RUNNING_APP_PACKAGE_3, 240 ) 241 } 242 } 243