From f3108c59edf192b5c6d644aaeafc23aeff1c2c70 Mon Sep 17 00:00:00 2001 From: Gustav Sennton Date: Fri, 5 Jul 2024 10:57:14 +0000 Subject: [PATCH] Taskbar running apps: show one icon per task + tap opens that task Before this CL we would show only one Taskbar icon per app, making it impossible (through the taskbar) to switch between several windows of the same app. With this CL we add one icon per task instead, making it possible to bring each task to the front individually. Flag: com.android.window.flags.enable_desktop_windowing_taskbar_running_apps Bug: 351118893 Bug: 349790805 Bug: 351156858 Test: Started several Chrome windows -> taskbar has one icon per window Change-Id: Ia692977effceb9ce339906bf6ca24d73e19d8769 --- .../taskbar/TaskbarActivityContext.java | 6 + .../taskbar/TaskbarModelCallbacks.java | 14 +- .../taskbar/TaskbarRecentAppsController.kt | 114 ++++-- .../taskbar/TaskbarViewController.java | 26 +- .../TaskbarRecentAppsControllerTest.kt | 382 +++++++++++------- .../launcher3/model/data/TaskItemInfo.kt | 24 ++ 6 files changed, 383 insertions(+), 183 deletions(-) create mode 100644 src/com/android/launcher3/model/data/TaskItemInfo.kt 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)