Add method to start transition on intent launch.

This forces the task to correctly start the TRANSIT_OPEN transiiton in
Desktop mode when launching an intent from the taskbar and prevent it
from opening in full screen.

Fixes: 361366053
Flag: EXEMPT bugfix
Test: manual test
Change-Id: I6ce85cdfdf2b027a57cbca8402baf2ed7421f3bb
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 73d1527..5e905c9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -35,6 +35,7 @@
 import android.graphics.Rect
 import android.graphics.Region
 import android.os.Binder
+import android.os.Bundle
 import android.os.Handler
 import android.os.IBinder
 import android.os.SystemProperties
@@ -880,6 +881,36 @@
     }
 
     /**
+     * Start an intent through a launch transition for starting tasks whose transition does not get
+     * handled by [handleRequest]
+     */
+    fun startLaunchIntentTransition(intent: Intent, options: Bundle, displayId: Int) {
+        val wct = WindowContainerTransaction()
+        val displayLayout = displayController.getDisplayLayout(displayId) ?: return
+        val bounds = calculateDefaultDesktopTaskBounds(displayLayout)
+        if (DesktopModeFlags.ENABLE_CASCADING_WINDOWS.isTrue) {
+            cascadeWindow(bounds, displayLayout, displayId)
+        }
+        val pendingIntent =
+            PendingIntent.getActivity(
+                context,
+                /* requestCode= */ 0,
+                intent,
+                PendingIntent.FLAG_IMMUTABLE,
+            )
+        val ops =
+            ActivityOptions.fromBundle(options).apply {
+                launchWindowingMode = WINDOWING_MODE_FREEFORM
+                pendingIntentBackgroundActivityStartMode =
+                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
+                launchBounds = bounds
+            }
+
+        wct.sendPendingIntent(pendingIntent, intent, ops.toBundle())
+        startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null)
+    }
+
+    /**
      * Move [task] to display with [displayId].
      *
      * No-op if task is already on that display per [RunningTaskInfo.displayId].
@@ -2862,6 +2893,12 @@
                 c.moveToNextDisplay(taskId)
             }
         }
+
+        override fun startLaunchIntentTransition(intent: Intent, options: Bundle, displayId: Int) {
+            executeRemoteCallWithTaskPermission(controller, "startLaunchIntentTransition") { c ->
+                c.startLaunchIntentTransition(intent, options, displayId)
+            }
+        }
     }
 
     private fun logV(msg: String, vararg arguments: Any?) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
index fa383cb..54f0312 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
@@ -17,6 +17,8 @@
 package com.android.wm.shell.desktopmode;
 
 import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Intent;
+import android.os.Bundle;
 import android.window.RemoteTransition;
 import com.android.wm.shell.desktopmode.IDesktopTaskListener;
 import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
@@ -61,4 +63,7 @@
 
     /** Move a task with given `taskId` to external display */
     void moveToExternalDisplay(int taskId);
+
+    /** Start a transition when launching an intent in desktop mode */
+    void startLaunchIntentTransition(in Intent intent, in Bundle options, in int displayId);
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 95ed8b4..a85d1fe 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -1118,6 +1118,21 @@
     }
 
     @Test
+    fun launchIntent_taskInDesktopMode_transitionStarted() {
+        setUpLandscapeDisplay()
+        val freeformTask = setUpFreeformTask()
+
+        controller.startLaunchIntentTransition(
+            freeformTask.baseIntent,
+            Bundle.EMPTY,
+            DEFAULT_DISPLAY,
+        )
+
+        val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN)
+        assertThat(wct.hierarchyOps).hasSize(1)
+    }
+
+    @Test
     @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
     fun addMoveToDesktopChanges_landscapeDevice_userFullscreenOverride_defaultPortraitBounds() {
         setUpLandscapeDisplay()
@@ -5110,7 +5125,7 @@
         val arg: ArgumentCaptor<WindowContainerTransaction> =
             ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
         verify(desktopMixedTransitionHandler)
-            .startLaunchTransition(eq(type), capture(arg), anyInt(), anyOrNull(), anyOrNull())
+            .startLaunchTransition(eq(type), capture(arg), anyOrNull(), anyOrNull(), anyOrNull())
         return arg.value
     }