diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 6c3b4adc09..3fbdc892a1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -95,6 +95,7 @@ import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.TaskItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupDataProvider; @@ -1132,6 +1133,11 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mControllers.uiController.onTaskbarIconLaunched(api); mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true); } + } else if (tag instanceof TaskItemInfo info) { + UI_HELPER_EXECUTOR.execute(() -> + SystemUiProxy.INSTANCE.get(this).showDesktopApp(info.getTaskId())); + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar( + /* stash= */ true); } else if (tag instanceof WorkspaceItemInfo) { // Tapping a launchable icon on Taskbar WorkspaceItemInfo info = (WorkspaceItemInfo) tag; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java index 0b7ae39e41..5024cd8817 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java @@ -196,26 +196,26 @@ public class TaskbarModelCallbacks implements final TaskbarRecentAppsController recentAppsController = mControllers.taskbarRecentAppsController; hotseatItemInfos = recentAppsController.updateHotseatItemInfos(hotseatItemInfos); - Set runningPackages = recentAppsController.getRunningAppPackages(); - Set minimizedPackages = recentAppsController.getMinimizedAppPackages(); + Set runningTaskIds = recentAppsController.getRunningTaskIds(); + Set minimizedTaskIds = recentAppsController.getMinimizedTaskIds(); if (mDeferUpdatesForSUW) { ItemInfo[] finalHotseatItemInfos = hotseatItemInfos; mDeferredUpdates = () -> commitHotseatItemUpdates(finalHotseatItemInfos, - recentAppsController.getShownTasks(), runningPackages, - minimizedPackages); + recentAppsController.getShownTasks(), runningTaskIds, + minimizedTaskIds); } else { commitHotseatItemUpdates(hotseatItemInfos, - recentAppsController.getShownTasks(), runningPackages, minimizedPackages); + recentAppsController.getShownTasks(), runningTaskIds, minimizedTaskIds); } } private void commitHotseatItemUpdates(ItemInfo[] hotseatItemInfos, List recentTasks, - Set runningPackages, Set minimizedPackages) { + Set runningTaskIds, Set minimizedTaskIds) { mContainer.updateHotseatItems(hotseatItemInfos, recentTasks); mControllers.taskbarViewController.updateIconViewsRunningStates( - runningPackages, minimizedPackages); + runningTaskIds, minimizedTaskIds); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt index 36828a8fe9..5c081163cc 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt @@ -18,6 +18,8 @@ package com.android.launcher3.taskbar import androidx.annotation.VisibleForTesting import com.android.launcher3.Flags.enableRecentsInTaskbar import com.android.launcher3.model.data.ItemInfo +import com.android.launcher3.model.data.TaskItemInfo +import com.android.launcher3.model.data.WorkspaceItemInfo import com.android.launcher3.statehandlers.DesktopVisibilityController import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController import com.android.launcher3.util.CancellableTask @@ -58,9 +60,13 @@ class TaskbarRecentAppsController( // Initialized in init. private lateinit var controllers: TaskbarControllers - private var shownHotseatItems: List = emptyList() + var shownHotseatItems: List = emptyList() + private set + private var allRecentTasks: List = emptyList() private var desktopTask: DesktopTask? = null + // Keeps track of the order in which running tasks appear. + private var orderedRunningTaskIds = emptyList() var shownTasks: List = emptyList() private set @@ -70,9 +76,9 @@ class TaskbarRecentAppsController( private val isInDesktopMode: Boolean get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false - val runningAppPackages: Set + val runningTaskIds: Set /** - * Returns the package names of apps that should be indicated as "running" to the user. + * Returns the task IDs of apps that should be indicated as "running" to the user. * Specifically, we return all the open tasks if we are in Desktop mode, else emptySet(). */ get() { @@ -80,22 +86,19 @@ class TaskbarRecentAppsController( return emptySet() } val tasks = desktopTask?.tasks ?: return emptySet() - return tasks.map { task -> task.key.packageName }.toSet() + return tasks.map { task -> task.key.id }.toSet() } - val minimizedAppPackages: Set + val minimizedTaskIds: Set /** - * Returns the package names of apps that should be indicated as "minimized" to the user. - * Specifically, we return all the running packages where all the tasks in that package are - * minimized (not visible). + * Returns the task IDs for the tasks that should be indicated as "minimized" to the user. */ get() { if (!canShowRunningApps || !isInDesktopMode) { return emptySet() } val desktopTasks = desktopTask?.tasks ?: return emptySet() - val packageToTasks = desktopTasks.groupBy { it.key.packageName } - return packageToTasks.filterValues { tasks -> tasks.all { !it.isVisible } }.keys + return desktopTasks.filter { !it.isVisible }.map { task -> task.key.id }.toSet() } private val recentTasksChangedListener = @@ -137,25 +140,39 @@ class TaskbarRecentAppsController( .filter { itemInfo -> !itemInfo.isPredictedItem } .toMutableList() + if (isInDesktopMode && canShowRunningApps) { + shownHotseatItems = + updateHotseatItemsFromRunningTasks( + getOrderedAndWrappedDesktopTasks(), + shownHotseatItems + ) + } + onRecentsOrHotseatChanged() return shownHotseatItems.toTypedArray() } + private fun getOrderedAndWrappedDesktopTasks(): List { + val tasks = desktopTask?.tasks ?: emptyList() + // Kind of hacky, we wrap each single task in the Desktop as a GroupTask. + val orderFromId = orderedRunningTaskIds.withIndex().associate { (index, id) -> id to index } + val sortedTasks = tasks.sortedWith(compareBy(nullsLast()) { orderFromId[it.key.id] }) + return sortedTasks.map { GroupTask(it) } + } + private fun reloadRecentTasksIfNeeded() { if (!recentsModel.isTaskListValid(taskListChangeId)) { taskListChangeId = recentsModel.getTasks { tasks -> allRecentTasks = tasks - val oldRunningPackages = runningAppPackages - val oldMinimizedPackages = minimizedAppPackages + val oldRunningTaskdIds = runningTaskIds + val oldMinimizedTaskIds = minimizedTaskIds desktopTask = allRecentTasks.filterIsInstance().firstOrNull() - val runningPackagesChanged = oldRunningPackages != runningAppPackages - val minimizedPackagessChanged = oldMinimizedPackages != minimizedAppPackages + val runningTasksChanged = oldRunningTaskdIds != runningTaskIds + val minimizedTasksChanged = oldMinimizedTaskIds != minimizedTaskIds if ( - onRecentsOrHotseatChanged() || - runningPackagesChanged || - minimizedPackagessChanged + onRecentsOrHotseatChanged() || runningTasksChanged || minimizedTasksChanged ) { controllers.taskbarViewController.commitRunningAppsToUI() } @@ -170,6 +187,7 @@ class TaskbarRecentAppsController( */ private fun onRecentsOrHotseatChanged(): Boolean { val oldShownTasks = shownTasks + orderedRunningTaskIds = updateOrderedRunningTaskIds() shownTasks = if (isInDesktopMode) { computeShownRunningTasks() @@ -201,22 +219,39 @@ class TaskbarRecentAppsController( return shownTasksChanged } + private fun updateOrderedRunningTaskIds(): MutableList { + val desktopTaskAsList = getOrderedAndWrappedDesktopTasks() + val desktopTaskIds = desktopTaskAsList.map { it.task1.key.id } + var newOrder = + orderedRunningTaskIds + .filter { it in desktopTaskIds } // Only keep the tasks that are still running + .toMutableList() + // Add new tasks not already listed + newOrder.addAll(desktopTaskIds.filter { it !in newOrder }) + return newOrder + } + private fun computeShownRunningTasks(): List { if (!canShowRunningApps) { return emptyList() } - val tasks = desktopTask?.tasks ?: emptyList() - // Kind of hacky, we wrap each single task in the Desktop as a GroupTask. - var desktopTaskAsList = tasks.map { GroupTask(it) } - // TODO(b/315344726 Multi-instance support): dedupe Tasks of the same package too. - desktopTaskAsList = dedupeHotseatTasks(desktopTaskAsList, shownHotseatItems) - val desktopPackages = desktopTaskAsList.map { it.packageNames } - // Remove any missing Tasks. - val newShownTasks = shownTasks.filter { it.packageNames in desktopPackages }.toMutableList() - val newShownPackages = newShownTasks.map { it.packageNames } + val desktopTaskAsList = getOrderedAndWrappedDesktopTasks() + val desktopTaskIds = desktopTaskAsList.map { it.task1.key.id } + val shownTaskIds = shownTasks.map { it.task1.key.id } + // TODO(b/315344726 Multi-instance support): only show one icon per package once we support + // taskbar multi-instance menus + val shownHotseatItemTaskIds = + shownHotseatItems.mapNotNull { it as? TaskItemInfo }.map { it.taskId } + // Remove any newly-missing Tasks, and actual group-tasks + val newShownTasks = + shownTasks + .filter { !it.hasMultipleTasks() } + .filter { it.task1.key.id in desktopTaskIds } + .toMutableList() // Add any new Tasks, maintaining the order from previous shownTasks. - newShownTasks.addAll(desktopTaskAsList.filter { it.packageNames !in newShownPackages }) - return newShownTasks.toList() + newShownTasks.addAll(desktopTaskAsList.filter { it.task1.key.id !in shownTaskIds }) + // Remove any tasks already covered by Hotseat icons + return newShownTasks.filter { it.task1.key.id !in shownHotseatItemTaskIds } } private fun computeShownRecentTasks(): List { @@ -245,6 +280,25 @@ class TaskbarRecentAppsController( } } + /** + * Returns the hotseat items updated so that any item that points to a package with a running + * task also references that task. + */ + private fun updateHotseatItemsFromRunningTasks( + groupTasks: List, + shownHotseatItems: List + ): List = + shownHotseatItems.map { itemInfo -> + if (itemInfo is TaskItemInfo) { + itemInfo + } else { + val foundTask = + groupTasks.find { task -> task.task1.key.packageName == itemInfo.targetPackage } + ?: return@map itemInfo + TaskItemInfo(foundTask.task1.key.id, itemInfo as WorkspaceItemInfo) + } + } + override fun dumpLogs(prefix: String, pw: PrintWriter) { pw.println("$prefix TaskbarRecentAppsController:") pw.println("$prefix\tcanShowRunningApps=$canShowRunningApps") @@ -253,8 +307,8 @@ class TaskbarRecentAppsController( pw.println("$prefix\tallRecentTasks=${allRecentTasks.map { it.packageNames }}") pw.println("$prefix\tdesktopTask=${desktopTask?.packageNames}") pw.println("$prefix\tshownTasks=${shownTasks.map { it.packageNames }}") - pw.println("$prefix\trunningTasks=$runningAppPackages") - pw.println("$prefix\tminimizedTasks=$minimizedAppPackages") + pw.println("$prefix\trunningTaskIds=$runningTaskIds") + pw.println("$prefix\tminimizedTaskIds=$minimizedTaskIds") } private val GroupTask.packageNames: List diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index e59a016e72..527e3a3cc1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -63,6 +63,7 @@ import com.android.launcher3.anim.RevealOutlineAnimation; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.TaskItemInfo; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.LauncherBindableItemsContainer; @@ -515,35 +516,38 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar return mTaskbarView.getTaskbarDividerView(); } - /** Updates which icons are marked as running given the Set of currently running packages. */ - public void updateIconViewsRunningStates(Set runningPackages, - Set minimizedPackages) { + /** + * Updates which icons are marked as running or minimized given the Sets of currently running + * and minimized tasks. + */ + public void updateIconViewsRunningStates(Set runningTaskIds, + Set minimizedTaskIds) { for (View iconView : getIconViews()) { if (iconView instanceof BubbleTextView btv) { btv.updateRunningState( - getRunningAppState(btv, runningPackages, minimizedPackages)); + getRunningAppState(btv, runningTaskIds, minimizedTaskIds)); } } } private BubbleTextView.RunningAppState getRunningAppState( BubbleTextView btv, - Set runningPackages, - Set minimizedPackages) { + Set runningTaskIds, + Set minimizedTaskIds) { Object tag = btv.getTag(); - if (tag instanceof ItemInfo itemInfo) { - if (minimizedPackages.contains(itemInfo.getTargetPackage())) { + if (tag instanceof TaskItemInfo itemInfo) { + if (minimizedTaskIds.contains(itemInfo.getTaskId())) { return BubbleTextView.RunningAppState.MINIMIZED; } - if (runningPackages.contains(itemInfo.getTargetPackage())) { + if (runningTaskIds.contains(itemInfo.getTaskId())) { return BubbleTextView.RunningAppState.RUNNING; } } if (tag instanceof GroupTask groupTask && !groupTask.hasMultipleTasks()) { - if (minimizedPackages.contains(groupTask.task1.key.getPackageName())) { + if (minimizedTaskIds.contains(groupTask.task1.key.id)) { return BubbleTextView.RunningAppState.MINIMIZED; } - if (runningPackages.contains(groupTask.task1.key.getPackageName())) { + if (runningTaskIds.contains(groupTask.task1.key.id)) { return BubbleTextView.RunningAppState.RUNNING; } } diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt index 13c4f72dd9..27e761af01 100644 --- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt +++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt @@ -26,6 +26,7 @@ import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION import com.android.launcher3.model.data.AppInfo import com.android.launcher3.model.data.ItemInfo +import com.android.launcher3.model.data.TaskItemInfo import com.android.launcher3.statehandlers.DesktopVisibilityController import com.android.quickstep.RecentsModel import com.android.quickstep.RecentsModel.RecentTasksChangedListener @@ -78,6 +79,13 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { val listenerCaptor = ArgumentCaptor.forClass(RecentTasksChangedListener::class.java) verify(mockRecentsModel).registerRecentTasksChangedListener(listenerCaptor.capture()) recentTasksChangedListener = listenerCaptor.value + + // Make sure updateHotseatItemInfos() is called after commitRunningAppsToUI() + whenever(taskbarViewController.commitRunningAppsToUI()).then { + recentAppsController.updateHotseatItemInfos( + recentAppsController.shownHotseatItems.toTypedArray() + ) + } } @Test @@ -88,7 +96,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { val newHotseatItems = prepareHotseatAndRunningAndRecentApps( hotseatPackages = hotseatPackages, - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = emptyList() ) assertThat(newHotseatItems.map { it?.targetPackage }) @@ -103,7 +111,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { val newHotseatItems = prepareHotseatAndRunningAndRecentApps( hotseatPackages = hotseatPackages, - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = emptyList() ) assertThat(newHotseatItems.map { it?.targetPackage }) @@ -117,7 +125,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { val newHotseatItems = prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = emptyList() ) val expectedPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2) @@ -125,6 +133,51 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { .containsExactlyElementsIn(expectedPackages) } + @Test + fun updateHotseatItemInfos_inDesktopMode_hotseatPackageHasRunningTask_hotseatItemLinksToTask() { + setInDesktopMode(true) + + val newHotseatItems = + prepareHotseatAndRunningAndRecentApps( + hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2), + runningTasks = listOf(createTask(id = 1, HOTSEAT_PACKAGE_1)), + recentTaskPackages = emptyList() + ) + + assertThat(newHotseatItems).hasLength(2) + assertThat(newHotseatItems[0]).isInstanceOf(TaskItemInfo::class.java) + assertThat(newHotseatItems[1]).isNotInstanceOf(TaskItemInfo::class.java) + val hotseatItem1 = newHotseatItems[0] as TaskItemInfo + assertThat(hotseatItem1.taskId).isEqualTo(1) + } + + @Test + fun updateHotseatItemInfos_inDesktopMode_twoRunningTasksSamePackage_hotseatCoversFirstTask() { + setInDesktopMode(true) + + val newHotseatItems = + prepareHotseatAndRunningAndRecentApps( + hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2), + runningTasks = + listOf( + createTask(id = 1, HOTSEAT_PACKAGE_1), + createTask(id = 2, HOTSEAT_PACKAGE_1) + ), + recentTaskPackages = emptyList() + ) + + // First task is in Hotseat Items + assertThat(newHotseatItems).hasLength(2) + assertThat(newHotseatItems[0]).isInstanceOf(TaskItemInfo::class.java) + assertThat(newHotseatItems[1]).isNotInstanceOf(TaskItemInfo::class.java) + val hotseatItem1 = newHotseatItems[0] as TaskItemInfo + assertThat(hotseatItem1.taskId).isEqualTo(1) + // Second task is in shownTasks + val shownTasks = recentAppsController.shownTasks.map { it.task1 } + assertThat(shownTasks) + .containsExactlyElementsIn(listOf(createTask(id = 2, HOTSEAT_PACKAGE_1))) + } + @Test fun updateHotseatItemInfos_canShowRecent_notInDesktopMode_returnsNonPredictedHotseatItems() { recentAppsController.canShowRecentApps = true @@ -132,7 +185,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { val newHotseatItems = prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = emptyList() ) val expectedPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2) @@ -146,7 +199,11 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { setInDesktopMode(true) prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1), - runningTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2), + runningTasks = + listOf( + createTask(id = 1, RUNNING_APP_PACKAGE_1), + createTask(id = 2, RUNNING_APP_PACKAGE_2) + ), recentTaskPackages = emptyList() ) assertThat(recentAppsController.shownTasks).isEmpty() @@ -158,7 +215,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { setInDesktopMode(false) prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) ) assertThat(recentAppsController.shownTasks).isEmpty() @@ -169,11 +226,15 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { setInDesktopMode(false) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2), + runningTasks = + listOf( + createTask(id = 1, RUNNING_APP_PACKAGE_1), + createTask(id = 2, RUNNING_APP_PACKAGE_2) + ), recentTaskPackages = emptyList() ) assertThat(recentAppsController.shownTasks).isEmpty() - assertThat(recentAppsController.minimizedAppPackages).isEmpty() + assertThat(recentAppsController.minimizedTaskIds).isEmpty() } @Test @@ -181,7 +242,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { setInDesktopMode(true) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) ) assertThat(recentAppsController.shownTasks).isEmpty() @@ -190,120 +251,161 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { @Test fun onRecentTasksChanged_inDesktopMode_shownTasks_returnsRunningTasks() { setInDesktopMode(true) - val runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) + val task1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val task2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = runningTaskPackages, + runningTasks = listOf(task1, task2), recentTaskPackages = emptyList() ) - val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } - assertThat(shownPackages).containsExactlyElementsIn(runningTaskPackages) - } - - @Test - fun onRecentTasksChanged_inDesktopMode_runningAppIsHotseatItem_shownTasks_returnsDistinctItems() { - setInDesktopMode(true) - prepareHotseatAndRunningAndRecentApps( - hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2), - runningTaskPackages = - listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2), - recentTaskPackages = emptyList() - ) - val expectedPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) - val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } - assertThat(shownPackages).containsExactlyElementsIn(expectedPackages) + val shownTasks = recentAppsController.shownTasks.map { it.task1 } + assertThat(shownTasks).containsExactlyElementsIn(listOf(task1, task2)) } @Test fun onRecentTasksChanged_notInDesktopMode_getRunningApps_returnsEmptySet() { setInDesktopMode(false) + val task1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val task2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2), + runningTasks = listOf(task1, task2), recentTaskPackages = emptyList() ) - assertThat(recentAppsController.runningAppPackages).isEmpty() - assertThat(recentAppsController.minimizedAppPackages).isEmpty() + assertThat(recentAppsController.runningTaskIds).isEmpty() + assertThat(recentAppsController.minimizedTaskIds).isEmpty() } @Test fun onRecentTasksChanged_inDesktopMode_getRunningApps_returnsAllDesktopTasks() { setInDesktopMode(true) - val runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) + val task1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val task2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = runningTaskPackages, + runningTasks = listOf(task1, task2), recentTaskPackages = emptyList() ) - assertThat(recentAppsController.runningAppPackages) - .containsExactlyElementsIn(runningTaskPackages) - assertThat(recentAppsController.minimizedAppPackages).isEmpty() + assertThat(recentAppsController.runningTaskIds).containsExactlyElementsIn(listOf(1, 2)) + assertThat(recentAppsController.minimizedTaskIds).isEmpty() } @Test fun onRecentTasksChanged_inDesktopMode_getRunningApps_includesHotseat() { setInDesktopMode(true) - val runningTaskPackages = - listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) + val runningTasks = + listOf( + createTask(id = 1, HOTSEAT_PACKAGE_1), + createTask(id = 2, RUNNING_APP_PACKAGE_1), + createTask(id = 3, RUNNING_APP_PACKAGE_2) + ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2), - runningTaskPackages = runningTaskPackages, + runningTasks = runningTasks, recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) ) - assertThat(recentAppsController.runningAppPackages) - .containsExactlyElementsIn(runningTaskPackages) - assertThat(recentAppsController.minimizedAppPackages).isEmpty() + assertThat(recentAppsController.runningTaskIds).containsExactlyElementsIn(listOf(1, 2, 3)) + assertThat(recentAppsController.minimizedTaskIds).isEmpty() } @Test - fun getMinimizedApps_inDesktopMode_returnsAllAppsRunningAndInvisibleAppsMinimized() { + fun onRecentTasksChanged_inDesktopMode_allAppsRunningAndInvisibleAppsMinimized() { setInDesktopMode(true) - val runningTaskPackages = - listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3) - val minimizedTaskIndices = setOf(2) // RUNNING_APP_PACKAGE_3 + val task1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val task2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) + val task3Minimized = createTask(id = 3, RUNNING_APP_PACKAGE_3, isVisible = false) + val runningTasks = listOf(task1, task2, task3Minimized) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = runningTaskPackages, - minimizedTaskIndices = minimizedTaskIndices, + runningTasks = runningTasks, recentTaskPackages = emptyList() ) - assertThat(recentAppsController.runningAppPackages) - .containsExactlyElementsIn(runningTaskPackages) - assertThat(recentAppsController.minimizedAppPackages).containsExactly(RUNNING_APP_PACKAGE_3) + assertThat(recentAppsController.runningTaskIds).containsExactly(1, 2, 3) + assertThat(recentAppsController.minimizedTaskIds).containsExactly(3) } @Test - fun getMinimizedApps_inDesktopMode_twoTasksSamePackageOneMinimizedReturnsNotMinimized() { + fun onRecentTasksChanged_inDesktopMode_samePackage_differentTasks_severalRunningTasks() { setInDesktopMode(true) - val runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_1) - val minimizedTaskIndices = setOf(1) // The second RUNNING_APP_PACKAGE_1 task. + val task1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val task2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = runningTaskPackages, - minimizedTaskIndices = minimizedTaskIndices, + runningTasks = listOf(task1, task2), recentTaskPackages = emptyList() ) - assertThat(recentAppsController.runningAppPackages) - .containsExactlyElementsIn(runningTaskPackages.toSet()) - assertThat(recentAppsController.minimizedAppPackages).isEmpty() + assertThat(recentAppsController.runningTaskIds).containsExactlyElementsIn(listOf(1, 2)) } @Test fun onRecentTasksChanged_inDesktopMode_shownTasks_maintainsOrder() { setInDesktopMode(true) - val originalOrder = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) + val task1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val task2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = originalOrder, + runningTasks = listOf(task1, task2), recentTaskPackages = emptyList() ) + prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = listOf(RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_1), + runningTasks = listOf(task2, task1), recentTaskPackages = emptyList() ) - val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } - assertThat(shownPackages).isEqualTo(originalOrder) + + val shownTasks = recentAppsController.shownTasks.map { it.task1 } + assertThat(shownTasks).isEqualTo(listOf(task1, task2)) + } + + @Test + fun onRecentTasksChanged_inDesktopMode_multiInstance_shownTasks_maintainsOrder() { + setInDesktopMode(true) + val task1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val task2 = createTask(id = 2, RUNNING_APP_PACKAGE_1) + prepareHotseatAndRunningAndRecentApps( + hotseatPackages = emptyList(), + runningTasks = listOf(task1, task2), + recentTaskPackages = emptyList() + ) + + prepareHotseatAndRunningAndRecentApps( + hotseatPackages = emptyList(), + runningTasks = listOf(task2, task1), + recentTaskPackages = emptyList() + ) + + val shownTasks = recentAppsController.shownTasks.map { it.task1 } + assertThat(shownTasks).isEqualTo(listOf(task1, task2)) + } + + @Test + fun updateHotseatItems_inDesktopMode_multiInstanceHotseatPackage_shownItems_maintainsOrder() { + setInDesktopMode(true) + val task1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val task2 = createTask(id = 2, RUNNING_APP_PACKAGE_1) + prepareHotseatAndRunningAndRecentApps( + hotseatPackages = listOf(RUNNING_APP_PACKAGE_1), + runningTasks = listOf(task1, task2), + recentTaskPackages = emptyList() + ) + updateRecentTasks( // Trigger a recent-tasks change before calling updateHotseatItems() + runningTasks = listOf(task2, task1), + recentTaskPackages = emptyList() + ) + + prepareHotseatAndRunningAndRecentApps( + hotseatPackages = listOf(RUNNING_APP_PACKAGE_1), + runningTasks = listOf(task2, task1), + recentTaskPackages = emptyList() + ) + + val newHotseatItems = recentAppsController.shownHotseatItems + assertThat(newHotseatItems).hasSize(1) + assertThat(newHotseatItems[0]).isInstanceOf(TaskItemInfo::class.java) + assertThat((newHotseatItems[0] as TaskItemInfo).taskId).isEqualTo(1) + val shownTasks = recentAppsController.shownTasks.map { it.task1 } + assertThat(shownTasks).isEqualTo(listOf(task2)) } @Test @@ -311,12 +413,12 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { setInDesktopMode(false) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3) ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3, RECENT_PACKAGE_1) ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } @@ -327,15 +429,17 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { @Test fun onRecentTasksChanged_inDesktopMode_addTask_shownTasks_maintainsOrder() { setInDesktopMode(true) + val task1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val task2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) + val task3 = createTask(id = 3, RUNNING_APP_PACKAGE_3) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2), + runningTasks = listOf(task1, task2), recentTaskPackages = emptyList() ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = - listOf(RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_3), + runningTasks = listOf(task2, task1, task3), recentTaskPackages = emptyList() ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } @@ -349,12 +453,12 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { setInDesktopMode(false) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_PACKAGE_3, RECENT_PACKAGE_2) ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3, RECENT_PACKAGE_1) ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } @@ -365,15 +469,17 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { @Test fun onRecentTasksChanged_inDesktopMode_removeTask_shownTasks_maintainsOrder() { setInDesktopMode(true) + val task1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val task2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) + val task3 = createTask(id = 3, RUNNING_APP_PACKAGE_3) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = - listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3), + runningTasks = listOf(task1, task2, task3), recentTaskPackages = emptyList() ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = listOf(RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_1), + runningTasks = listOf(task2, task1), recentTaskPackages = emptyList() ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } @@ -385,12 +491,12 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { setInDesktopMode(false) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3) ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3) ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } @@ -401,27 +507,31 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { @Test fun onRecentTasksChanged_enterDesktopMode_shownTasks_onlyIncludesRunningTasks() { setInDesktopMode(false) - val runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) + val runningTask1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val runningTask2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) val recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) + prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = runningTaskPackages, + runningTasks = listOf(runningTask1, runningTask2), recentTaskPackages = recentTaskPackages ) + setInDesktopMode(true) recentTasksChangedListener.onRecentTasksChanged() val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } - assertThat(shownPackages).containsExactlyElementsIn(runningTaskPackages) + assertThat(shownPackages).containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) } @Test fun onRecentTasksChanged_exitDesktopMode_shownTasks_onlyIncludesRecentTasks() { setInDesktopMode(true) - val runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) + val runningTask1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val runningTask2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) val recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = runningTaskPackages, + runningTasks = listOf(runningTask1, runningTask2), recentTaskPackages = recentTaskPackages ) setInDesktopMode(false) @@ -437,7 +547,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { setInDesktopMode(false) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3) ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } @@ -449,9 +559,11 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { @Test fun onRecentTasksChanged_notInDesktopMode_hasRecentAndRunningTasks_shownTasks_returnsRecentTaskAndDesktopTile() { setInDesktopMode(false) + val runningTask1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val runningTask2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2), + runningTasks = listOf(runningTask1, runningTask2), recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) ) val shownPackages = recentAppsController.shownTasks.map { it.packageNames } @@ -467,7 +579,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { setInDesktopMode(false) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_SPLIT_PACKAGES_1, RECENT_PACKAGE_1, RECENT_PACKAGE_2) ) val shownPackages = recentAppsController.shownTasks.map { it.packageNames } @@ -483,14 +595,14 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { setInDesktopMode(false) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() // Call onRecentTasksChanged() again with the same tasks, verify it's a no-op. prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = emptyList(), + runningTasks = emptyList(), recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() @@ -499,16 +611,18 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { @Test fun onRecentTasksChanged_inDesktopMode_noActualChangeToRunning_commitRunningAppsToUI_notCalled() { setInDesktopMode(true) + val runningTask1 = createTask(id = 1, RUNNING_APP_PACKAGE_1) + val runningTask2 = createTask(id = 2, RUNNING_APP_PACKAGE_2) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2), + runningTasks = listOf(runningTask1, runningTask2), recentTaskPackages = emptyList() ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() // Call onRecentTasksChanged() again with the same tasks, verify it's a no-op. prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2), + runningTasks = listOf(runningTask1, runningTask2), recentTaskPackages = emptyList() ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() @@ -517,21 +631,23 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { @Test fun onRecentTasksChanged_onlyMinimizedChanges_commitRunningAppsToUI_isCalled() { setInDesktopMode(true) - val runningTasks = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2) + val task1Minimized = createTask(id = 1, RUNNING_APP_PACKAGE_1, isVisible = false) + val task2Visible = createTask(id = 2, RUNNING_APP_PACKAGE_2) + val task2Minimized = createTask(id = 2, RUNNING_APP_PACKAGE_2, isVisible = false) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = runningTasks, - minimizedTaskIndices = setOf(0), + runningTasks = listOf(task1Minimized, task2Visible), recentTaskPackages = emptyList() ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() + // Call onRecentTasksChanged() again with a new minimized app, verify we update UI. prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), - runningTaskPackages = runningTasks, - minimizedTaskIndices = setOf(0, 1), + runningTasks = listOf(task1Minimized, task2Minimized), recentTaskPackages = emptyList() ) + verify(taskbarViewController, times(2)).commitRunningAppsToUI() } @@ -539,36 +655,46 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { fun onRecentTasksChanged_hotseatAppStartsRunning_commitRunningAppsToUI_isCalled() { setInDesktopMode(true) val hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2) + val originalTasks = listOf(createTask(id = 1, RUNNING_APP_PACKAGE_1)) + val newTasks = + listOf(createTask(id = 1, RUNNING_APP_PACKAGE_1), createTask(id = 2, HOTSEAT_PACKAGE_1)) prepareHotseatAndRunningAndRecentApps( hotseatPackages = hotseatPackages, - runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1), + runningTasks = originalTasks, recentTaskPackages = emptyList() ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() + // Call onRecentTasksChanged() again with a new running app, verify we update UI. prepareHotseatAndRunningAndRecentApps( hotseatPackages = hotseatPackages, - runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, HOTSEAT_PACKAGE_1), + runningTasks = newTasks, recentTaskPackages = emptyList() ) + verify(taskbarViewController, times(2)).commitRunningAppsToUI() } private fun prepareHotseatAndRunningAndRecentApps( hotseatPackages: List, - runningTaskPackages: List, - minimizedTaskIndices: Set = emptySet(), + runningTasks: List, recentTaskPackages: List, ): Array { val hotseatItems = createHotseatItemsFromPackageNames(hotseatPackages) - val newHotseatItems = - recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()) - val runningTasks = createDesktopTask(runningTaskPackages, minimizedTaskIndices) + recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()) + updateRecentTasks(runningTasks, recentTaskPackages) + return recentAppsController.shownHotseatItems.toTypedArray() + } + + private fun updateRecentTasks( + runningTasks: List, + recentTaskPackages: List, + ) { val recentTasks = createRecentTasksFromPackageNames(recentTaskPackages) val allTasks = ArrayList().apply { - if (runningTasks != null) { - add(runningTasks) + if (!runningTasks.isEmpty()) { + add(DesktopTask(ArrayList(runningTasks))) } addAll(recentTasks) } @@ -580,20 +706,21 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { .whenever(mockRecentsModel) .getTasks(any>>()) recentTasksChangedListener.onRecentTasksChanged() - return newHotseatItems } private fun createHotseatItemsFromPackageNames(packageNames: List): List { - return packageNames.map { - createTestAppInfo(packageName = it).apply { - container = - if (it.startsWith("predicted")) { - CONTAINER_HOTSEAT_PREDICTION - } else { - CONTAINER_HOTSEAT - } + return packageNames + .map { + createTestAppInfo(packageName = it).apply { + container = + if (it.startsWith("predicted")) { + CONTAINER_HOTSEAT_PREDICTION + } else { + CONTAINER_HOTSEAT + } + } } - } + .map { it.makeWorkspaceItem(taskbarActivityContext) } } private fun createTestAppInfo( @@ -601,39 +728,24 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { className: String = "testClassName" ) = AppInfo(ComponentName(packageName, className), className /* title */, userHandle, Intent()) - private fun createDesktopTask( - packageNames: List, - minimizedTaskIndices: Set - ): DesktopTask? { - if (packageNames.isEmpty()) return null - - return DesktopTask( - ArrayList( - packageNames.mapIndexed { index, packageName -> - createTask(packageName, index !in minimizedTaskIndices) - } - ) - ) - } - private fun createRecentTasksFromPackageNames(packageNames: List): List { - return packageNames.map { - if (it.startsWith("split")) { - val splitPackages = it.split("_") + return packageNames.map { packageName -> + if (packageName.startsWith("split")) { + val splitPackages = packageName.split("_") GroupTask( - createTask(splitPackages[0]), - createTask(splitPackages[1]), + createTask(100, splitPackages[0]), + createTask(101, splitPackages[1]), /* splitBounds = */ null ) } else { - GroupTask(createTask(it)) + // Use the number at the end of the test packageName as the id. + val id = 1000 + packageName[packageName.length - 1].code + GroupTask(createTask(id, packageName)) } } } - private fun createTask(packageName: String, isVisible: Boolean = true): Task { - // Use the number at the end of the test packageName as the id. - val id = packageName[packageName.length - 1].code + private fun createTask(id: Int, packageName: String, isVisible: Boolean = true): Task { return Task( Task.TaskKey( id, diff --git a/src/com/android/launcher3/model/data/TaskItemInfo.kt b/src/com/android/launcher3/model/data/TaskItemInfo.kt new file mode 100644 index 0000000000..fc1cd4d418 --- /dev/null +++ b/src/com/android/launcher3/model/data/TaskItemInfo.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.model.data + +/** + * Temporary class holding a Task ID to allow us to reference a Task when clicking a hotseat item. + * + * TODO(b/315344726): Remove this class when we have proper Taskbar support for multi-instance apps + */ +class TaskItemInfo(val taskId: Int, itemInfo: WorkspaceItemInfo) : WorkspaceItemInfo(itemInfo)