AllApps tray icon tap: use showDesktopApp() for existing Desktop tasks

When tapping an icon in the AllApps tray, before this CL, we would use
the WM Shell API startLaunchIntentTransition() to launch a task for that
app icon. However, this would break the window limit logic since in WM
Shell (startLaunchIntentTransition()) we think we're launching a new
task, when in fact we're just moving an existing one to the front.
With this CL we instead reuse the showDesktopApp() API whenever the app
we're trying to launch has an already visible / minimized Desktop task.

Bug: 391365151
Test: launch visible Desktop app from AllApps - doesn't overtrigger
window limit
Flag: com.android.window.flags.enable_desktop_app_launch_transitions_bugfix

Change-Id: Ia3638012226fe28c853ec6cfd0523a8fb23b8961
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index e28e488..8f7cb76 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -59,7 +59,6 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
-import android.os.Bundle;
 import android.os.IRemoteCallback;
 import android.os.Process;
 import android.os.Trace;
@@ -85,6 +84,7 @@
 import com.android.internal.jank.Cuj;
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.BubbleTextView.RunningAppState;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherPrefs;
@@ -891,36 +891,10 @@
         return makeDefaultActivityOptions(SPLASH_SCREEN_STYLE_UNDEFINED);
     }
 
-    private ActivityOptionsWrapper getActivityLaunchDesktopOptions(ItemInfo info) {
-        if (!DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS.isTrue()
-                && !DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX.isTrue()) {
-            return null;
-        }
-        if (!areDesktopTasksVisible()) {
-            return null;
-        }
-        BubbleTextView.RunningAppState appState =
-                mControllers.taskbarRecentAppsController.getDesktopItemState(info);
-        AppLaunchType launchType = null;
-        switch (appState) {
-            case RUNNING:
-                return null;
-            case MINIMIZED:
-                launchType = AppLaunchType.UNMINIMIZE;
-                break;
-            case NOT_RUNNING:
-                launchType = AppLaunchType.LAUNCH;
-                break;
-        }
+    private ActivityOptionsWrapper getActivityLaunchDesktopOptions() {
         ActivityOptions options = ActivityOptions.makeRemoteTransition(
-                new RemoteTransition(
-                        new DesktopAppLaunchTransition(
-                                /* context= */ this,
-                                getMainExecutor(),
-                                launchType,
-                                Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON
-                        ),
-                        "TaskbarDesktopLaunch"));
+                createDesktopAppLaunchRemoteTransition(
+                        AppLaunchType.LAUNCH, Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON));
         return new ActivityOptionsWrapper(options, new RunnableList());
     }
 
@@ -1322,8 +1296,9 @@
         if (tag instanceof GroupTask groupTask) {
             RemoteTransition remoteTransition =
                     (areDesktopTasksVisible() && canUnminimizeDesktopTask(groupTask.task1.key.id))
-                            ? createUnminimizeRemoteTransition(
-                                    Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON) : null;
+                            ? createDesktopAppLaunchRemoteTransition(AppLaunchType.UNMINIMIZE,
+                                    Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON)
+                            : null;
             if (areDesktopTasksVisible() && mControllers.uiController.isInOverviewUi()) {
                 RunnableList runnableList = recents.launchRunningDesktopTaskView();
                 // Wrapping it in runnable so we post after DW is ready for the app
@@ -1356,7 +1331,8 @@
             }
         } else if (tag instanceof TaskItemInfo info && !Flags.enableMultiInstanceMenuTaskbar()) {
             RemoteTransition remoteTransition = canUnminimizeDesktopTask(info.getTaskId())
-                    ? createUnminimizeRemoteTransition(Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON)
+                    ? createDesktopAppLaunchRemoteTransition(
+                            AppLaunchType.UNMINIMIZE, Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON)
                     : null;
 
             TaskView taskView = null;
@@ -1535,21 +1511,22 @@
     public boolean canUnminimizeDesktopTask(int taskId) {
         BubbleTextView.RunningAppState runningAppState =
                 mControllers.taskbarRecentAppsController.getRunningAppState(taskId);
-        return runningAppState == BubbleTextView.RunningAppState.MINIMIZED
+        return runningAppState == RunningAppState.MINIMIZED
                 && (DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_ALTTAB_TRANSITIONS.isTrue()
                     || DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_ALTTAB_TRANSITIONS_BUGFIX.isTrue()
                     );
     }
 
-    private RemoteTransition createUnminimizeRemoteTransition(@Cuj.CujType int cujType) {
+    private RemoteTransition createDesktopAppLaunchRemoteTransition(
+            AppLaunchType appLaunchType, @Cuj.CujType int cujType) {
         return new RemoteTransition(
                 new DesktopAppLaunchTransition(
                         this,
                         getMainExecutor(),
-                        AppLaunchType.UNMINIMIZE,
+                        appLaunchType,
                         cujType
                 ),
-                "TaskbarDesktopUnminimize");
+                "TaskbarDesktopAppLaunch");
     }
 
     /**
@@ -1680,10 +1657,9 @@
                     return;
                 }
             }
-            if (areDesktopTasksVisible()) {
-                ActivityOptionsWrapper opts = getActivityLaunchDesktopOptions(info);
-                Bundle optionsBundle = opts == null ? Bundle.EMPTY : opts.options.toBundle();
-                mSysUiProxy.startLaunchIntentTransition(intent, optionsBundle, displayId);
+            if (areDesktopTasksVisible()
+                    && DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX.isTrue()) {
+                launchDesktopApp(intent, info, displayId);
             } else {
                 startActivity(intent, null);
             }
@@ -1694,6 +1670,27 @@
         }
     }
 
+    private void launchDesktopApp(Intent intent, ItemInfo info, int displayId) {
+        TaskbarRecentAppsController.TaskState taskState =
+                mControllers.taskbarRecentAppsController.getDesktopItemState(info);
+        RunningAppState appState = taskState.getRunningAppState();
+        if (appState == RunningAppState.RUNNING || appState == RunningAppState.MINIMIZED) {
+            // We only need a custom animation (a RemoteTransition) if the task is minimized - if
+            // it's already visible it will just be brought forward.
+            RemoteTransition remoteTransition = (appState == RunningAppState.MINIMIZED)
+                    ? createDesktopAppLaunchRemoteTransition(
+                            AppLaunchType.UNMINIMIZE, Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON)
+                    : null;
+            UI_HELPER_EXECUTOR.execute(() ->
+                    SystemUiProxy.INSTANCE.get(this).showDesktopApp(taskState.getTaskId(),
+                            remoteTransition, DesktopTaskToFrontReason.TASKBAR_TAP));
+            return;
+        }
+        // There is no task associated with this launch - launch a new task through an intent
+        ActivityOptionsWrapper opts = getActivityLaunchDesktopOptions();
+        mSysUiProxy.startLaunchIntentTransition(intent, opts.options.toBundle(), displayId);
+    }
+
     /** Expands a folder icon when it is clicked */
     private void expandFolder(FolderIcon folderIcon) {
         Folder folder = folderIcon.getFolder();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
index e654fe8..94030d7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -75,30 +75,43 @@
         private set
 
     /**
+     * The task-state of an app, i.e. whether the app has a task and what state
+     * that task is in.
+     *
+     * @property taskId The ID of the task if one exists (i.e. if the state is
+     * RUNNING or MINIMIZED), null otherwise (NOT_RUNNING).
+     */
+    data class TaskState(val runningAppState: RunningAppState, val taskId: Int? = null)
+
+    /**
      * Returns the state of the most active Desktop task represented by the given [ItemInfo].
      *
      * If there are several tasks represented by the same [ItemInfo] we return the most active one,
      * i.e. we return [DesktopAppState.RUNNING] over [DesktopAppState.MINIMIZED], and
      * [DesktopAppState.MINIMIZED] over [DesktopAppState.NOT_RUNNING].
      */
-    fun getDesktopItemState(itemInfo: ItemInfo?): RunningAppState {
-        val packageName = itemInfo?.getTargetPackage() ?: return RunningAppState.NOT_RUNNING
-        return getDesktopAppState(packageName, itemInfo.user.identifier)
+    fun getDesktopItemState(itemInfo: ItemInfo?): TaskState {
+        val packageName =
+            itemInfo?.getTargetPackage() ?: return TaskState(RunningAppState.NOT_RUNNING)
+        return getDesktopTaskState(packageName, itemInfo.user.identifier)
     }
 
-    private fun getDesktopAppState(packageName: String, userId: Int): RunningAppState {
-        val tasks = desktopTask?.tasks ?: return RunningAppState.NOT_RUNNING
+    private fun getDesktopTaskState(packageName: String, userId: Int): TaskState {
+        val tasks = desktopTask?.tasks ?: return TaskState(RunningAppState.NOT_RUNNING)
         val appTasks =
             tasks.filter { task ->
                 packageName == task.key.packageName && task.key.userId == userId
             }
-        if (appTasks.find { getRunningAppState(it.key.id) == RunningAppState.RUNNING } != null) {
-            return RunningAppState.RUNNING
+        val runningTask = appTasks.find { getRunningAppState(it.key.id) == RunningAppState.RUNNING }
+        if (runningTask != null) {
+            return TaskState(RunningAppState.RUNNING, runningTask.key.id)
         }
-        if (appTasks.find { getRunningAppState(it.key.id) == RunningAppState.MINIMIZED } != null) {
-            return RunningAppState.MINIMIZED
+        val minimizedTask =
+            appTasks.find { getRunningAppState(it.key.id) == RunningAppState.MINIMIZED }
+        if (minimizedTask != null) {
+            return TaskState(RunningAppState.MINIMIZED, taskId = minimizedTask.key.id)
         }
-        return RunningAppState.NOT_RUNNING
+        return TaskState(RunningAppState.NOT_RUNNING)
     }
 
     /** Get the [RunningAppState] for the given task. */
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
index 0bae42c..13be86b 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
@@ -34,6 +34,7 @@
 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.taskbar.TaskbarRecentAppsController.TaskState
 import com.android.launcher3.util.LauncherMultivalentJUnit
 import com.android.quickstep.RecentsModel
 import com.android.quickstep.RecentsModel.RecentTasksChangedListener
@@ -159,23 +160,22 @@
     @Test
     fun getDesktopItemState_nullItemInfo_returnsNotRunning() {
         setInDesktopMode(true)
-        assertThat(recentAppsController.getDesktopItemState(/* itemInfo= */ null))
-            .isEqualTo(RunningAppState.NOT_RUNNING)
+        val taskState = recentAppsController.getDesktopItemState(/* itemInfo= */ null)
+        assertThat(taskState).isEqualTo(TaskState(RunningAppState.NOT_RUNNING))
     }
 
     @Test
     fun getDesktopItemState_noItemPackage_returnsNotRunning() {
         setInDesktopMode(true)
-        assertThat(recentAppsController.getDesktopItemState(ItemInfo()))
-            .isEqualTo(RunningAppState.NOT_RUNNING)
+        val taskState = recentAppsController.getDesktopItemState(ItemInfo())
+        assertThat(taskState).isEqualTo(TaskState(RunningAppState.NOT_RUNNING))
     }
 
     @Test
     fun getDesktopItemState_noMatchingTasks_returnsNotRunning() {
         setInDesktopMode(true)
-        val itemInfo = createItemInfo("package")
-        assertThat(recentAppsController.getDesktopItemState(itemInfo))
-            .isEqualTo(RunningAppState.NOT_RUNNING)
+        val taskState = recentAppsController.getDesktopItemState(createItemInfo("package"))
+        assertThat(taskState).isEqualTo(TaskState(RunningAppState.NOT_RUNNING))
     }
 
     @Test
@@ -183,10 +183,10 @@
         setInDesktopMode(true)
         val visibleTask = createTask(id = 1, "visiblePackage", isVisible = true)
         updateRecentTasks(runningTasks = listOf(visibleTask), recentTaskPackages = emptyList())
-        val itemInfo = createItemInfo("visiblePackage")
 
-        assertThat(recentAppsController.getDesktopItemState(itemInfo))
-            .isEqualTo(RunningAppState.RUNNING)
+        val taskState = recentAppsController.getDesktopItemState(createItemInfo("visiblePackage"))
+
+        assertThat(taskState).isEqualTo(TaskState(RunningAppState.RUNNING, taskId = 1))
     }
 
     @Test
@@ -194,10 +194,10 @@
         setInDesktopMode(true)
         val minimizedTask = createTask(id = 1, "minimizedPackage", isVisible = false)
         updateRecentTasks(runningTasks = listOf(minimizedTask), recentTaskPackages = emptyList())
-        val itemInfo = createItemInfo("minimizedPackage")
 
-        assertThat(recentAppsController.getDesktopItemState(itemInfo))
-            .isEqualTo(RunningAppState.MINIMIZED)
+        val taskState = recentAppsController.getDesktopItemState(createItemInfo("minimizedPackage"))
+
+        assertThat(taskState).isEqualTo(TaskState(RunningAppState.MINIMIZED, taskId = 1))
     }
 
     @Test
@@ -211,10 +211,10 @@
                 ),
             recentTaskPackages = emptyList(),
         )
-        val itemInfo = createItemInfo("package")
 
-        assertThat(recentAppsController.getDesktopItemState(itemInfo))
-            .isEqualTo(RunningAppState.RUNNING)
+        val taskState = recentAppsController.getDesktopItemState(createItemInfo("package"))
+
+        assertThat(taskState).isEqualTo(TaskState(RunningAppState.RUNNING, taskId = 2))
     }
 
     @Test
@@ -228,10 +228,11 @@
                 ),
             recentTaskPackages = emptyList(),
         )
-        val itemInfo = createItemInfo("package", USER_HANDLE_2)
 
-        assertThat(recentAppsController.getDesktopItemState(itemInfo))
-            .isEqualTo(RunningAppState.NOT_RUNNING)
+        val taskState =
+            recentAppsController.getDesktopItemState(createItemInfo("package", USER_HANDLE_2))
+
+        assertThat(taskState).isEqualTo(TaskState(RunningAppState.NOT_RUNNING))
     }
 
     @Test