summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt59
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt206
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt76
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt37
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt201
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt74
7 files changed, 582 insertions, 75 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 8d25a9a7fe2d..c6cd3204451b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -703,6 +703,7 @@ public abstract class WMShellModule {
Transitions transitions,
KeyguardManager keyguardManager,
ReturnToDragStartAnimator returnToDragStartAnimator,
+ Optional<DesktopMixedTransitionHandler> desktopMixedTransitionHandler,
EnterDesktopTaskTransitionHandler enterDesktopTransitionHandler,
ExitDesktopTaskTransitionHandler exitDesktopTransitionHandler,
DesktopModeDragAndDropTransitionHandler desktopModeDragAndDropTransitionHandler,
@@ -736,6 +737,7 @@ public abstract class WMShellModule {
transitions,
keyguardManager,
returnToDragStartAnimator,
+ desktopMixedTransitionHandler.get(),
enterDesktopTransitionHandler,
exitDesktopTransitionHandler,
desktopModeDragAndDropTransitionHandler,
@@ -960,6 +962,7 @@ public abstract class WMShellModule {
@DynamicOverride DesktopRepository desktopRepository,
FreeformTaskTransitionHandler freeformTaskTransitionHandler,
CloseDesktopTaskTransitionHandler closeDesktopTaskTransitionHandler,
+ Optional<DesktopImmersiveController> desktopImmersiveController,
InteractionJankMonitor interactionJankMonitor,
@ShellMainThread Handler handler) {
if (!DesktopModeStatus.canEnterDesktopMode(context)) {
@@ -972,6 +975,7 @@ public abstract class WMShellModule {
desktopRepository,
freeformTaskTransitionHandler,
closeDesktopTaskTransitionHandler,
+ desktopImmersiveController.get(),
interactionJankMonitor,
handler));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt
index d0bc5f0955f7..e741892bf6fc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt
@@ -130,7 +130,8 @@ class DesktopImmersiveController(
displayId: Int
) {
if (!Flags.enableFullyImmersiveInDesktop()) return
- exitImmersiveIfApplicable(wct, displayId)?.invoke(transition)
+ val result = exitImmersiveIfApplicable(wct, displayId)
+ result.asExit()?.runOnTransitionStart?.invoke(transition)
}
/**
@@ -145,16 +146,23 @@ class DesktopImmersiveController(
wct: WindowContainerTransaction,
displayId: Int,
excludeTaskId: Int? = null,
- ): ((IBinder) -> Unit)? {
- if (!Flags.enableFullyImmersiveInDesktop()) return null
- val immersiveTask = desktopRepository.getTaskInFullImmersiveState(displayId) ?: return null
+ ): ExitResult {
+ if (!Flags.enableFullyImmersiveInDesktop()) return ExitResult.NoExit
+ val immersiveTask = desktopRepository.getTaskInFullImmersiveState(displayId)
+ ?: return ExitResult.NoExit
if (immersiveTask == excludeTaskId) {
- return null
+ return ExitResult.NoExit
}
- val taskInfo = shellTaskOrganizer.getRunningTaskInfo(immersiveTask) ?: return null
+ val taskInfo = shellTaskOrganizer.getRunningTaskInfo(immersiveTask)
+ ?: return ExitResult.NoExit
logV("Appending immersive exit for task: $immersiveTask in display: $displayId")
wct.setBounds(taskInfo.token, getExitDestinationBounds(taskInfo))
- return { transition -> addPendingImmersiveExit(immersiveTask, displayId, transition) }
+ return ExitResult.Exit(
+ exitingTask = immersiveTask,
+ runOnTransitionStart = { transition ->
+ addPendingImmersiveExit(immersiveTask, displayId, transition)
+ }
+ )
}
/**
@@ -167,22 +175,25 @@ class DesktopImmersiveController(
fun exitImmersiveIfApplicable(
wct: WindowContainerTransaction,
taskInfo: RunningTaskInfo
- ): ((IBinder) -> Unit)? {
- if (!Flags.enableFullyImmersiveInDesktop()) return null
+ ): ExitResult {
+ if (!Flags.enableFullyImmersiveInDesktop()) return ExitResult.NoExit
if (desktopRepository.isTaskInFullImmersiveState(taskInfo.taskId)) {
// A full immersive task is being minimized, make sure the immersive state is broken
// (i.e. resize back to max bounds).
wct.setBounds(taskInfo.token, getExitDestinationBounds(taskInfo))
logV("Appending immersive exit for task: ${taskInfo.taskId}")
- return { transition ->
- addPendingImmersiveExit(
- taskId = taskInfo.taskId,
- displayId = taskInfo.displayId,
- transition = transition
- )
- }
+ return ExitResult.Exit(
+ exitingTask = taskInfo.taskId,
+ runOnTransitionStart = { transition ->
+ addPendingImmersiveExit(
+ taskId = taskInfo.taskId,
+ displayId = taskInfo.displayId,
+ transition = transition
+ )
+ }
+ )
}
- return null
+ return ExitResult.NoExit
}
@@ -461,6 +472,20 @@ class DesktopImmersiveController(
var transition: IBinder,
)
+ /** The result of an external exit request. */
+ sealed class ExitResult {
+ /** An immersive task exit (meaning, resize) was appended to the request. */
+ data class Exit(
+ val exitingTask: Int,
+ val runOnTransitionStart: ((IBinder) -> Unit)
+ ) : ExitResult()
+ /** There was no exit appended to the request. */
+ data object NoExit : ExitResult()
+
+ /** Returns the result as an [Exit] or null if it isn't of that type. */
+ fun asExit(): Exit? = if (this is Exit) this else null
+ }
+
private enum class Direction {
ENTER, EXIT
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
index 54a07f20fd84..0bc571f4782c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt
@@ -27,15 +27,18 @@ import android.window.DesktopModeFlags
import android.window.TransitionInfo
import android.window.TransitionRequestInfo
import android.window.WindowContainerTransaction
+import androidx.annotation.VisibleForTesting
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.protolog.ProtoLog
+import com.android.window.flags.Flags
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.transition.MixedTransitionHandler
import com.android.wm.shell.transition.Transitions
+import com.android.wm.shell.transition.Transitions.TransitionFinishCallback
/** The [Transitions.TransitionHandler] coordinates transition handlers in desktop windowing. */
class DesktopMixedTransitionHandler(
@@ -44,10 +47,14 @@ class DesktopMixedTransitionHandler(
private val desktopRepository: DesktopRepository,
private val freeformTaskTransitionHandler: FreeformTaskTransitionHandler,
private val closeDesktopTaskTransitionHandler: CloseDesktopTaskTransitionHandler,
+ private val desktopImmersiveController: DesktopImmersiveController,
private val interactionJankMonitor: InteractionJankMonitor,
@ShellMainThread private val handler: Handler,
) : MixedTransitionHandler, FreeformTaskTransitionStarter {
+ @VisibleForTesting
+ val pendingMixedTransitions = mutableListOf<PendingMixedTransition>()
+
/** Delegates starting transition to [FreeformTaskTransitionHandler]. */
override fun startWindowingModeTransition(
targetWindowingMode: Int,
@@ -65,6 +72,40 @@ class DesktopMixedTransitionHandler(
}
requireNotNull(wct)
return transitions.startTransition(WindowManager.TRANSIT_CLOSE, wct, /* handler= */ this)
+ .also { transition ->
+ pendingMixedTransitions.add(PendingMixedTransition.Close(transition))
+ }
+ }
+
+ /**
+ * Starts a launch transition for [taskId], with an optional [exitingImmersiveTask] if it was
+ * included in the [wct] and is expected to be animated by this handler.
+ */
+ fun startLaunchTransition(
+ @WindowManager.TransitionType transitionType: Int,
+ wct: WindowContainerTransaction,
+ taskId: Int,
+ exitingImmersiveTask: Int? = null,
+ ): IBinder {
+ if (!Flags.enableFullyImmersiveInDesktop()) {
+ return transitions.startTransition(transitionType, wct, /* handler= */ null)
+ }
+ if (exitingImmersiveTask == null) {
+ logV("Starting mixed launch transition for task#%d", taskId)
+ } else {
+ logV(
+ "Starting mixed launch transition for task#%d with immersive exit of task#%d",
+ taskId, exitingImmersiveTask
+ )
+ }
+ return transitions.startTransition(transitionType, wct, /* handler= */ this)
+ .also { transition ->
+ pendingMixedTransitions.add(PendingMixedTransition.Launch(
+ transition = transition,
+ launchingTask = taskId,
+ exitingImmersiveTask = exitingImmersiveTask
+ ))
+ }
}
/** Returns null, as it only handles transitions started from Shell. */
@@ -78,11 +119,43 @@ class DesktopMixedTransitionHandler(
info: TransitionInfo,
startTransaction: SurfaceControl.Transaction,
finishTransaction: SurfaceControl.Transaction,
- finishCallback: Transitions.TransitionFinishCallback,
+ finishCallback: TransitionFinishCallback,
+ ): Boolean {
+ val pending = pendingMixedTransitions.find { pending -> pending.transition == transition }
+ ?: return false.also {
+ logW("Should have pending desktop transition")
+ }
+ pendingMixedTransitions.remove(pending)
+ logV("Animating pending mixed transition: %s", pending)
+ return when (pending) {
+ is PendingMixedTransition.Close -> animateCloseTransition(
+ transition,
+ info,
+ startTransaction,
+ finishTransaction,
+ finishCallback
+ )
+ is PendingMixedTransition.Launch -> animateLaunchTransition(
+ pending,
+ transition,
+ info,
+ startTransaction,
+ finishTransaction,
+ finishCallback
+ )
+ }
+ }
+
+ private fun animateCloseTransition(
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction,
+ finishCallback: TransitionFinishCallback,
): Boolean {
val closeChange = findCloseDesktopTaskChange(info)
if (closeChange == null) {
- ProtoLog.w(WM_SHELL_DESKTOP_MODE, "%s: Should have closing desktop task", TAG)
+ logW("Should have closing desktop task")
return false
}
if (isLastDesktopTask(closeChange)) {
@@ -106,6 +179,74 @@ class DesktopMixedTransitionHandler(
)
}
+ private fun animateLaunchTransition(
+ pending: PendingMixedTransition.Launch,
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction,
+ finishCallback: TransitionFinishCallback,
+ ): Boolean {
+ // Check if there's also an immersive change during this launch.
+ val immersiveExitChange = pending.exitingImmersiveTask?.let { exitingTask ->
+ findDesktopTaskChange(info, exitingTask)
+ }
+ val launchChange = findDesktopTaskChange(info, pending.launchingTask)
+ ?: error("Should have pending launching task change")
+
+ var subAnimationCount = -1
+ var combinedWct: WindowContainerTransaction? = null
+ val finishCb = TransitionFinishCallback { wct ->
+ --subAnimationCount
+ combinedWct = combinedWct.merge(wct)
+ if (subAnimationCount > 0) return@TransitionFinishCallback
+ finishCallback.onTransitionFinished(combinedWct)
+ }
+
+ logV(
+ "Animating pending mixed launch transition task#%d immersiveExitTask#%s",
+ launchChange.taskInfo!!.taskId, immersiveExitChange?.taskInfo?.taskId
+ )
+ if (immersiveExitChange != null) {
+ subAnimationCount = 2
+ // Animate the immersive exit change separately.
+ info.changes.remove(immersiveExitChange)
+ desktopImmersiveController.animateResizeChange(
+ immersiveExitChange,
+ startTransaction,
+ finishTransaction,
+ finishCb
+ )
+ // Let the leftover/default handler animate the remaining changes.
+ return dispatchToLeftoverHandler(
+ transition,
+ info,
+ startTransaction,
+ finishTransaction,
+ finishCb
+ )
+ }
+ // There's nothing to animate separately, so let the left over handler animate
+ // the entire transition.
+ subAnimationCount = 1
+ return dispatchToLeftoverHandler(
+ transition,
+ info,
+ startTransaction,
+ finishTransaction,
+ finishCb
+ )
+ }
+
+ override fun onTransitionConsumed(
+ transition: IBinder,
+ aborted: Boolean,
+ finishTransaction: SurfaceControl.Transaction?
+ ) {
+ pendingMixedTransitions.removeAll { pending -> pending.transition == transition }
+ super.onTransitionConsumed(transition, aborted, finishTransaction)
+ }
+
/**
* Dispatch close desktop task animation to the default transition handlers. Allows delegating
* it to Launcher to animate in sync with show Home transition.
@@ -126,14 +267,34 @@ class DesktopMixedTransitionHandler(
CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE,
)
// Dispatch the last desktop task closing animation.
+ return dispatchToLeftoverHandler(
+ transition = transition,
+ info = info,
+ startTransaction = startTransaction,
+ finishTransaction = finishTransaction,
+ finishCallback = finishCallback,
+ doOnFinishCallback = {
+ // Finish the jank trace when closing the last window in desktop mode.
+ interactionJankMonitor.end(CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE)
+ }
+ )
+ }
+
+ private fun dispatchToLeftoverHandler(
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction,
+ finishCallback: TransitionFinishCallback,
+ doOnFinishCallback: (() -> Unit)? = null,
+ ): Boolean {
return transitions.dispatchTransition(
transition,
info,
startTransaction,
finishTransaction,
{ wct ->
- // Finish the jank trace when closing the last window in desktop mode.
- interactionJankMonitor.end(CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE)
+ doOnFinishCallback?.invoke()
finishCallback.onTransitionFinished(wct)
},
/* skip= */ this
@@ -155,6 +316,43 @@ class DesktopMixedTransitionHandler(
}
}
+ private fun findDesktopTaskChange(info: TransitionInfo, taskId: Int): TransitionInfo.Change? {
+ return info.changes.firstOrNull { change -> change.taskInfo?.taskId == taskId }
+ }
+
+ private fun WindowContainerTransaction?.merge(
+ wct: WindowContainerTransaction?
+ ): WindowContainerTransaction? {
+ if (wct == null) return this
+ if (this == null) return wct
+ return this.merge(wct)
+ }
+
+ /** A scheduled transition that will potentially be animated by more than one handler */
+ sealed class PendingMixedTransition {
+ abstract val transition: IBinder
+
+ /** A task is closing. */
+ data class Close(
+ override val transition: IBinder,
+ ) : PendingMixedTransition()
+
+ /** A task is opening or moving to front. */
+ data class Launch(
+ override val transition: IBinder,
+ val launchingTask: Int,
+ val exitingImmersiveTask: Int?,
+ ) : PendingMixedTransition()
+ }
+
+ private fun logV(msg: String, vararg arguments: Any?) {
+ ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+ }
+
+ private fun logW(msg: String, vararg arguments: Any?) {
+ ProtoLog.w(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
+ }
+
companion object {
private const val TAG = "DesktopMixedTransitionHandler"
}
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 38a4c71b046f..3d3c072727be 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
@@ -87,6 +87,7 @@ import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.common.SingleInstanceRemoteListener
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing
+import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitResult
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.DragStartState
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType
import com.android.wm.shell.desktopmode.DesktopRepository.VisibleTasksListener
@@ -146,6 +147,7 @@ class DesktopTasksController(
private val transitions: Transitions,
private val keyguardManager: KeyguardManager,
private val returnToDragStartAnimator: ReturnToDragStartAnimator,
+ private val desktopMixedTransitionHandler: DesktopMixedTransitionHandler,
private val enterDesktopTaskTransitionHandler: EnterDesktopTaskTransitionHandler,
private val exitDesktopTaskTransitionHandler: ExitDesktopTaskTransitionHandler,
private val desktopModeDragAndDropTransitionHandler: DesktopModeDragAndDropTransitionHandler,
@@ -379,7 +381,7 @@ class DesktopTasksController(
// TODO(342378842): Instead of using default display, support multiple displays
val taskIdToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(
DEFAULT_DISPLAY, wct, taskId)
- val runOnTransit = desktopImmersiveController.exitImmersiveIfApplicable(
+ val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
wct = wct,
displayId = DEFAULT_DISPLAY,
excludeTaskId = taskId,
@@ -393,7 +395,7 @@ class DesktopTasksController(
// TODO(343149901): Add DPI changes for task launch
val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
- runOnTransit?.invoke(transition)
+ exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
return true
}
@@ -410,7 +412,7 @@ class DesktopTasksController(
}
logV("moveRunningTaskToDesktop taskId=%d", task.taskId)
exitSplitIfApplicable(wct, task)
- val runOnTransit = desktopImmersiveController.exitImmersiveIfApplicable(
+ val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
wct = wct,
displayId = task.displayId,
excludeTaskId = task.taskId,
@@ -422,7 +424,7 @@ class DesktopTasksController(
val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
- runOnTransit?.invoke(transition)
+ exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
}
/**
@@ -459,12 +461,12 @@ class DesktopTasksController(
val taskIdToMinimize =
bringDesktopAppsToFrontBeforeShowingNewTask(taskInfo.displayId, wct, taskInfo.taskId)
addMoveToDesktopChanges(wct, taskInfo)
- val runOnTransit = desktopImmersiveController.exitImmersiveIfApplicable(
+ val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
wct, taskInfo.displayId)
val transition = dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct)
transition?.let {
taskIdToMinimize?.let { taskId -> addPendingMinimizeTransition(it, taskId) }
- runOnTransit?.invoke(transition)
+ exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
}
}
@@ -507,7 +509,8 @@ class DesktopTasksController(
taskId
)
)
- return desktopImmersiveController.exitImmersiveIfApplicable(wct, taskInfo)
+ return desktopImmersiveController.exitImmersiveIfApplicable(wct, taskInfo).asExit()
+ ?.runOnTransitionStart
}
fun minimizeTask(taskInfo: RunningTaskInfo) {
@@ -520,7 +523,7 @@ class DesktopTasksController(
removeWallpaperActivity(wct)
}
// Notify immersive handler as it might need to exit immersive state.
- val runOnTransit = desktopImmersiveController.exitImmersiveIfApplicable(wct, taskInfo)
+ val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(wct, taskInfo)
wct.reorder(taskInfo.token, false)
val transition = freeformTaskTransitionStarter.startMinimizedModeTransition(wct)
@@ -531,7 +534,7 @@ class DesktopTasksController(
taskId = taskId
)
}
- runOnTransit?.invoke(transition)
+ exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
}
/** Move a task with given `taskId` to fullscreen */
@@ -627,7 +630,7 @@ class DesktopTasksController(
logV("moveBackgroundTaskToFront taskId=%s", taskId)
val wct = WindowContainerTransaction()
// TODO: b/342378842 - Instead of using default display, support multiple displays
- val runOnTransit = desktopImmersiveController.exitImmersiveIfApplicable(
+ val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
wct = wct,
displayId = DEFAULT_DISPLAY,
excludeTaskId = taskId,
@@ -638,8 +641,13 @@ class DesktopTasksController(
launchWindowingMode = WINDOWING_MODE_FREEFORM
}.toBundle(),
)
- val transition = startLaunchTransition(TRANSIT_OPEN, wct, taskId, remoteTransition)
- runOnTransit?.invoke(transition)
+ val transition = startLaunchTransition(
+ TRANSIT_OPEN,
+ wct,
+ taskId,
+ remoteTransition = remoteTransition
+ )
+ exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
}
/**
@@ -658,32 +666,39 @@ class DesktopTasksController(
}
val wct = WindowContainerTransaction()
wct.reorder(taskInfo.token, true /* onTop */, true /* includingParents */)
- val runOnTransit = desktopImmersiveController.exitImmersiveIfApplicable(
+ val result = desktopImmersiveController.exitImmersiveIfApplicable(
wct = wct,
displayId = taskInfo.displayId,
excludeTaskId = taskInfo.taskId,
)
- val transition =
- startLaunchTransition(
- TRANSIT_TO_FRONT,
- wct,
- taskInfo.taskId,
- remoteTransition,
- taskInfo.displayId
- )
- runOnTransit?.invoke(transition)
+ val exitResult = if (result is ExitResult.Exit) { result } else { null }
+ val transition = startLaunchTransition(
+ transitionType = TRANSIT_TO_FRONT,
+ wct = wct,
+ taskId = taskInfo.taskId,
+ exitingImmersiveTask = exitResult?.exitingTask,
+ remoteTransition = remoteTransition,
+ displayId = taskInfo.displayId,
+ )
+ exitResult?.runOnTransitionStart?.invoke(transition)
}
private fun startLaunchTransition(
transitionType: Int,
wct: WindowContainerTransaction,
taskId: Int,
- remoteTransition: RemoteTransition?,
+ exitingImmersiveTask: Int? = null,
+ remoteTransition: RemoteTransition? = null,
displayId: Int = DEFAULT_DISPLAY,
): IBinder {
val taskIdToMinimize = addAndGetMinimizeChanges(displayId, wct, taskId)
if (remoteTransition == null) {
- val t = transitions.startTransition(transitionType, wct, null /* handler */)
+ val t = desktopMixedTransitionHandler.startLaunchTransition(
+ transitionType = transitionType,
+ wct = wct,
+ taskId = taskId,
+ exitingImmersiveTask = exitingImmersiveTask,
+ )
taskIdToMinimize?.let { addPendingMinimizeTransition(t, it) }
return t
}
@@ -1373,14 +1388,15 @@ class DesktopTasksController(
wct.startTask(requestedTaskId, options.toBundle())
val taskIdToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(
callingTask.displayId, wct, requestedTaskId)
- val runOnTransit = desktopImmersiveController.exitImmersiveIfApplicable(
- wct = wct,
- displayId = callingTask.displayId,
- excludeTaskId = requestedTaskId,
- )
+ val exitResult = desktopImmersiveController
+ .exitImmersiveIfApplicable(
+ wct = wct,
+ displayId = callingTask.displayId,
+ excludeTaskId = requestedTaskId,
+ )
val transition = transitions.startTransition(TRANSIT_OPEN, wct, null)
taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
- runOnTransit?.invoke(transition)
+ exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
} else {
val splitPosition = splitScreenController.determineNewInstancePosition(callingTask)
splitScreenController.startTask(requestedTaskId, splitPosition,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt
index e83f5c7a79a1..1c4b9bfe2fd7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt
@@ -347,7 +347,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
wct = wct,
displayId = DEFAULT_DISPLAY,
excludeTaskId = task.taskId
- )?.invoke(transition)
+ ).asExit()?.runOnTransitionStart?.invoke(transition)
assertThat(controller.pendingExternalExitTransitions.any { exit ->
exit.transition == transition && exit.displayId == DEFAULT_DISPLAY
@@ -402,7 +402,8 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
immersive = true
)
- controller.exitImmersiveIfApplicable(wct, task)?.invoke(transition)
+ controller.exitImmersiveIfApplicable(wct, task)
+ .asExit()?.runOnTransitionStart?.invoke(transition)
assertThat(controller.pendingExternalExitTransitions.any { exit ->
exit.transition == transition && exit.displayId == DEFAULT_DISPLAY
@@ -412,23 +413,36 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
@Test
@EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
- fun exitImmersiveIfApplicable_byTask_notInImmersive_doesNotAddPendingExitOnRun() {
+ fun exitImmersiveIfApplicable_byTask_notInImmersive_doesNotExit() {
val task = createFreeformTask()
whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
val wct = WindowContainerTransaction()
- val transition = Binder()
desktopRepository.setTaskInFullImmersiveState(
- displayId = DEFAULT_DISPLAY,
+ displayId = task.displayId,
taskId = task.taskId,
immersive = false
)
- controller.exitImmersiveIfApplicable(wct, task)?.invoke(transition)
+ val result = controller.exitImmersiveIfApplicable(wct, task)
- assertThat(controller.pendingExternalExitTransitions.any { exit ->
- exit.transition == transition && exit.displayId == DEFAULT_DISPLAY
- && exit.taskId == task.taskId
- }).isFalse()
+ assertThat(result).isEqualTo(DesktopImmersiveController.ExitResult.NoExit)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+ fun exitImmersiveIfApplicable_byDisplay_notInImmersive_doesNotExit() {
+ val task = createFreeformTask()
+ whenever(mockShellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
+ val wct = WindowContainerTransaction()
+ desktopRepository.setTaskInFullImmersiveState(
+ displayId = task.displayId,
+ taskId = task.taskId,
+ immersive = false
+ )
+
+ val result = controller.exitImmersiveIfApplicable(wct, task.displayId)
+
+ assertThat(result).isEqualTo(DesktopImmersiveController.ExitResult.NoExit)
}
@Test
@@ -631,7 +645,8 @@ class DesktopImmersiveControllerTest : ShellTestCase() {
taskId = task.taskId,
immersive = true
)
- controller.exitImmersiveIfApplicable(wct, task)?.invoke(Binder())
+ controller.exitImmersiveIfApplicable(wct, task)
+ .asExit()?.runOnTransitionStart?.invoke(Binder())
controller.moveTaskToNonImmersive(task)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
index be0663cbd70d..868883d12ac0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt
@@ -31,6 +31,8 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.SurfaceControl
import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_OPEN
+import android.view.WindowManager.TransitionType
import android.window.TransitionInfo
import android.window.WindowContainerTransaction
import androidx.test.filters.SmallTest
@@ -41,6 +43,7 @@ import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestRunningTaskInfoBuilder
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler
import com.android.wm.shell.transition.Transitions
+import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
@@ -51,6 +54,8 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.kotlin.any
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.argThat
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@@ -71,6 +76,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
@Mock lateinit var desktopRepository: DesktopRepository
@Mock lateinit var freeformTaskTransitionHandler: FreeformTaskTransitionHandler
@Mock lateinit var closeDesktopTaskTransitionHandler: CloseDesktopTaskTransitionHandler
+ @Mock lateinit var desktopImmersiveController: DesktopImmersiveController
@Mock lateinit var interactionJankMonitor: InteractionJankMonitor
@Mock lateinit var mockHandler: Handler
@Mock lateinit var closingTaskLeash: SurfaceControl
@@ -86,6 +92,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
desktopRepository,
freeformTaskTransitionHandler,
closeDesktopTaskTransitionHandler,
+ desktopImmersiveController,
interactionJankMonitor,
mockHandler
)
@@ -146,7 +153,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
val transition = mock<IBinder>()
val transitionInfo =
createTransitionInfo(
- changeMode = WindowManager.TRANSIT_OPEN,
+ changeMode = TRANSIT_OPEN,
task = createTask(WINDOWING_MODE_FREEFORM)
)
whenever(freeformTaskTransitionHandler.startAnimation(any(), any(), any(), any(), any()))
@@ -164,7 +171,9 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS)
fun startAnimation_withClosingDesktopTask_callsCloseTaskHandler() {
+ val wct = WindowContainerTransaction()
val transition = mock<IBinder>()
val transitionInfo = createTransitionInfo(task = createTask(WINDOWING_MODE_FREEFORM))
whenever(desktopRepository.getExpandedTaskCount(any())).thenReturn(2)
@@ -172,6 +181,9 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
closeDesktopTaskTransitionHandler.startAnimation(any(), any(), any(), any(), any())
)
.thenReturn(true)
+ whenever(transitions.startTransition(WindowManager.TRANSIT_CLOSE, wct, mixedHandler))
+ .thenReturn(transition)
+ mixedHandler.startRemoveTransition(wct)
val started = mixedHandler.startAnimation(
transition = transition,
@@ -187,12 +199,17 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS)
fun startAnimation_withClosingLastDesktopTask_dispatchesTransition() {
+ val wct = WindowContainerTransaction()
val transition = mock<IBinder>()
val transitionInfo = createTransitionInfo(task = createTask(WINDOWING_MODE_FREEFORM))
whenever(desktopRepository.getExpandedTaskCount(any())).thenReturn(1)
whenever(transitions.dispatchTransition(any(), any(), any(), any(), any(), any()))
.thenReturn(mock())
+ whenever(transitions.startTransition(WindowManager.TRANSIT_CLOSE, wct, mixedHandler))
+ .thenReturn(transition)
+ mixedHandler.startRemoveTransition(wct)
mixedHandler.startAnimation(
transition = transition,
@@ -220,6 +237,176 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
)
}
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+ fun startLaunchTransition_immersiveMixDisabled_doesNotUseMixedHandler() {
+ val wct = WindowContainerTransaction()
+ val task = createTask(WINDOWING_MODE_FREEFORM)
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(Binder())
+
+ mixedHandler.startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ taskId = task.taskId,
+ exitingImmersiveTask = null
+ )
+
+ verify(transitions).startTransition(TRANSIT_OPEN, wct, /* handler= */ null)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+ fun startLaunchTransition_immersiveMixEnabled_usesMixedHandler() {
+ val wct = WindowContainerTransaction()
+ val task = createTask(WINDOWING_MODE_FREEFORM)
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(Binder())
+
+ mixedHandler.startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ taskId = task.taskId,
+ exitingImmersiveTask = null
+ )
+
+ verify(transitions).startTransition(TRANSIT_OPEN, wct, mixedHandler)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+ fun startAndAnimateLaunchTransition_withoutImmersiveChange_dispatchesAllChangesToLeftOver() {
+ val wct = WindowContainerTransaction()
+ val launchingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val transition = Binder()
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(transition)
+
+ mixedHandler.startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ taskId = launchingTask.taskId,
+ exitingImmersiveTask = null,
+ )
+ val launchTaskChange = createChange(launchingTask)
+ val otherChange = createChange(createTask(WINDOWING_MODE_FREEFORM))
+ mixedHandler.startAnimation(
+ transition,
+ createTransitionInfo(
+ TRANSIT_OPEN,
+ listOf(launchTaskChange, otherChange)
+ ),
+ SurfaceControl.Transaction(),
+ SurfaceControl.Transaction(),
+ ) { }
+
+ verify(transitions).dispatchTransition(
+ eq(transition),
+ argThat { info ->
+ info.changes.contains(launchTaskChange) && info.changes.contains(otherChange)
+ },
+ any(),
+ any(),
+ any(),
+ eq(mixedHandler),
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+ fun startAndAnimateLaunchTransition_withImmersiveChange_mixesAnimations() {
+ val wct = WindowContainerTransaction()
+ val launchingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val immersiveTask = createTask(WINDOWING_MODE_FREEFORM)
+ val transition = Binder()
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(transition)
+
+ mixedHandler.startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ taskId = launchingTask.taskId,
+ exitingImmersiveTask = immersiveTask.taskId,
+ )
+ val launchTaskChange = createChange(launchingTask)
+ val immersiveChange = createChange(immersiveTask)
+ mixedHandler.startAnimation(
+ transition,
+ createTransitionInfo(
+ TRANSIT_OPEN,
+ listOf(launchTaskChange, immersiveChange)
+ ),
+ SurfaceControl.Transaction(),
+ SurfaceControl.Transaction(),
+ ) { }
+
+ verify(desktopImmersiveController)
+ .animateResizeChange(eq(immersiveChange), any(), any(), any())
+ verify(transitions).dispatchTransition(
+ eq(transition),
+ argThat { info ->
+ info.changes.contains(launchTaskChange) && !info.changes.contains(immersiveChange)
+ },
+ any(),
+ any(),
+ any(),
+ eq(mixedHandler),
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+ fun startAndAnimateLaunchTransition_removesPendingMixedTransition() {
+ val wct = WindowContainerTransaction()
+ val launchingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val transition = Binder()
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(transition)
+
+ mixedHandler.startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ taskId = launchingTask.taskId,
+ exitingImmersiveTask = null,
+ )
+ val launchTaskChange = createChange(launchingTask)
+ mixedHandler.startAnimation(
+ transition,
+ createTransitionInfo(
+ TRANSIT_OPEN,
+ listOf(launchTaskChange)
+ ),
+ SurfaceControl.Transaction(),
+ SurfaceControl.Transaction(),
+ ) { }
+
+ assertThat(mixedHandler.pendingMixedTransitions).isEmpty()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
+ fun startAndAnimateLaunchTransition_aborted_removesPendingMixedTransition() {
+ val wct = WindowContainerTransaction()
+ val launchingTask = createTask(WINDOWING_MODE_FREEFORM)
+ val transition = Binder()
+ whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull()))
+ .thenReturn(transition)
+
+ mixedHandler.startLaunchTransition(
+ transitionType = TRANSIT_OPEN,
+ wct = wct,
+ taskId = launchingTask.taskId,
+ exitingImmersiveTask = null,
+ )
+ mixedHandler.onTransitionConsumed(
+ transition = transition,
+ aborted = true,
+ finishTransaction = SurfaceControl.Transaction()
+ )
+
+ assertThat(mixedHandler.pendingMixedTransitions).isEmpty()
+ }
+
private fun createTransitionInfo(
type: Int = WindowManager.TRANSIT_CLOSE,
changeMode: Int = WindowManager.TRANSIT_CLOSE,
@@ -235,6 +422,18 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() {
)
}
+ private fun createTransitionInfo(
+ @TransitionType type: Int,
+ changes: List<TransitionInfo.Change> = emptyList()
+ ): TransitionInfo = TransitionInfo(type, /* flags= */ 0).apply {
+ changes.forEach { change -> addChange(change) }
+ }
+
+ private fun createChange(task: RunningTaskInfo): TransitionInfo.Change =
+ TransitionInfo.Change(task.token, SurfaceControl()).apply {
+ taskInfo = task
+ }
+
private fun createTask(@WindowingMode windowingMode: Int): RunningTaskInfo =
TestRunningTaskInfoBuilder()
.setActivityType(ACTIVITY_TYPE_STANDARD)
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 b358686224a0..62d2c987ac5d 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
@@ -196,6 +196,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
@Mock lateinit var transitions: Transitions
@Mock lateinit var keyguardManager: KeyguardManager
@Mock lateinit var mReturnToDragStartAnimator: ReturnToDragStartAnimator
+ @Mock lateinit var desktopMixedTransitionHandler: DesktopMixedTransitionHandler
@Mock lateinit var exitDesktopTransitionHandler: ExitDesktopTaskTransitionHandler
@Mock lateinit var enterDesktopTransitionHandler: EnterDesktopTaskTransitionHandler
@Mock lateinit var dragAndDropTransitionHandler: DesktopModeDragAndDropTransitionHandler
@@ -288,6 +289,12 @@ class DesktopTasksControllerTest : ShellTestCase() {
val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(tda)
+ whenever(mMockDesktopImmersiveController
+ .exitImmersiveIfApplicable(any(), any<RunningTaskInfo>()))
+ .thenReturn(DesktopImmersiveController.ExitResult.NoExit)
+ whenever(mMockDesktopImmersiveController
+ .exitImmersiveIfApplicable(any(), anyInt(), anyOrNull()))
+ .thenReturn(DesktopImmersiveController.ExitResult.NoExit)
controller = createController()
controller.setSplitScreenController(splitScreenController)
@@ -323,6 +330,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
transitions,
keyguardManager,
mReturnToDragStartAnimator,
+ desktopMixedTransitionHandler,
enterDesktopTransitionHandler,
exitDesktopTransitionHandler,
dragAndDropTransitionHandler,
@@ -1389,7 +1397,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveTaskToFront(task1, remoteTransition = null)
- val wct = getLatestWct(type = TRANSIT_TO_FRONT)
+ val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_TO_FRONT)
assertThat(wct.hierarchyOps).hasSize(1)
wct.assertReorderAt(index = 0, task1)
}
@@ -1398,10 +1406,16 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun moveTaskToFront_bringsTasksOverLimit_minimizesBackTask() {
setUpHomeTask()
val freeformTasks = (1..MAX_TASK_LIMIT + 1).map { _ -> setUpFreeformTask() }
+ whenever(desktopMixedTransitionHandler.startLaunchTransition(
+ eq(TRANSIT_TO_FRONT),
+ any(),
+ eq(freeformTasks[0].taskId),
+ anyOrNull()
+ )).thenReturn(Binder())
controller.moveTaskToFront(freeformTasks[0], remoteTransition = null)
- val wct = getLatestWct(type = TRANSIT_TO_FRONT)
+ val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_TO_FRONT)
assertThat(wct.hierarchyOps.size).isEqualTo(2) // move-to-front + minimize
wct.assertReorderAt(0, freeformTasks[0], toTop = true)
wct.assertReorderAt(1, freeformTasks[1], toTop = false)
@@ -1443,7 +1457,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
controller.moveTaskToFront(task.taskId, remoteTransition = null)
- val wct = getLatestWct(type = TRANSIT_OPEN)
+ val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN)
assertThat(wct.hierarchyOps).hasSize(1)
wct.assertLaunchTaskAt(0, task.taskId, WINDOWING_MODE_FREEFORM)
}
@@ -1453,10 +1467,13 @@ class DesktopTasksControllerTest : ShellTestCase() {
val freeformTasks = (1..MAX_TASK_LIMIT).map { _ -> setUpFreeformTask() }
val task = createTaskInfo(1001)
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(null)
+ whenever(desktopMixedTransitionHandler
+ .startLaunchTransition(eq(TRANSIT_OPEN), any(), eq(task.taskId), anyOrNull()))
+ .thenReturn(Binder())
controller.moveTaskToFront(task.taskId, remoteTransition = null)
- val wct = getLatestWct(type = TRANSIT_OPEN)
+ val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN)
assertThat(wct.hierarchyOps.size).isEqualTo(2) // launch + minimize
wct.assertLaunchTaskAt(0, task.taskId, WINDOWING_MODE_FREEFORM)
wct.assertReorderAt(1, freeformTasks[0], toTop = false)
@@ -1791,7 +1808,10 @@ class DesktopTasksControllerTest : ShellTestCase() {
whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any()))
.thenReturn(transition)
whenever(mMockDesktopImmersiveController.exitImmersiveIfApplicable(any(), eq(task)))
- .thenReturn(runOnTransit)
+ .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ exitingTask = task.taskId,
+ runOnTransitionStart = runOnTransit,
+ ))
controller.minimizeTask(task)
@@ -3101,7 +3121,10 @@ class DesktopTasksControllerTest : ShellTestCase() {
.thenReturn(transition)
whenever(mMockDesktopImmersiveController
.exitImmersiveIfApplicable(any(), eq(immersiveTask.displayId), eq(freeformTask.taskId)))
- .thenReturn(runOnStartTransit)
+ .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ exitingTask = immersiveTask.taskId,
+ runOnTransitionStart = runOnStartTransit,
+ ))
runOpenInstance(immersiveTask, freeformTask.taskId)
@@ -3502,7 +3525,11 @@ class DesktopTasksControllerTest : ShellTestCase() {
val runOnStartTransit = RunOnStartTransitionCallback()
val transition = Binder()
whenever(mMockDesktopImmersiveController
- .exitImmersiveIfApplicable(wct, task.displayId, task.taskId)).thenReturn(runOnStartTransit)
+ .exitImmersiveIfApplicable(wct, task.displayId, task.taskId))
+ .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ exitingTask = 5,
+ runOnTransitionStart = runOnStartTransit,
+ ))
whenever(enterDesktopTransitionHandler.moveToDesktop(wct, UNKNOWN)).thenReturn(transition)
controller.moveTaskToDesktop(taskId = task.taskId, wct = wct, transitionSource = UNKNOWN)
@@ -3519,7 +3546,11 @@ class DesktopTasksControllerTest : ShellTestCase() {
val runOnStartTransit = RunOnStartTransitionCallback()
val transition = Binder()
whenever(mMockDesktopImmersiveController
- .exitImmersiveIfApplicable(wct, task.displayId, task.taskId)).thenReturn(runOnStartTransit)
+ .exitImmersiveIfApplicable(wct, task.displayId, task.taskId))
+ .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ exitingTask = 5,
+ runOnTransitionStart = runOnStartTransit,
+ ))
whenever(enterDesktopTransitionHandler.moveToDesktop(wct, UNKNOWN)).thenReturn(transition)
controller.moveTaskToDesktop(taskId = task.taskId, wct = wct, transitionSource = UNKNOWN)
@@ -3536,8 +3567,12 @@ class DesktopTasksControllerTest : ShellTestCase() {
val transition = Binder()
whenever(mMockDesktopImmersiveController
.exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId)))
- .thenReturn(runOnStartTransit)
- whenever(transitions.startTransition(any(), any(), anyOrNull())).thenReturn(transition)
+ .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ exitingTask = 5,
+ runOnTransitionStart = runOnStartTransit,
+ ))
+ whenever(desktopMixedTransitionHandler
+ .startLaunchTransition(any(), any(), anyInt(), anyOrNull())).thenReturn(transition)
controller.moveTaskToFront(task.taskId, remoteTransition = null)
@@ -3553,8 +3588,13 @@ class DesktopTasksControllerTest : ShellTestCase() {
val transition = Binder()
whenever(mMockDesktopImmersiveController
.exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId)))
- .thenReturn(runOnStartTransit)
- whenever(transitions.startTransition(any(), any(), anyOrNull())).thenReturn(transition)
+ .thenReturn(DesktopImmersiveController.ExitResult.Exit(
+ exitingTask = 5,
+ runOnTransitionStart = runOnStartTransit,
+ ))
+ whenever(desktopMixedTransitionHandler
+ .startLaunchTransition(any(), any(), eq(task.taskId), anyOrNull()))
+ .thenReturn(transition)
controller.moveTaskToFront(task.taskId, remoteTransition = null)
@@ -3936,6 +3976,16 @@ class DesktopTasksControllerTest : ShellTestCase() {
return arg.value
}
+ private fun getLatestDesktopMixedTaskWct(
+ @WindowManager.TransitionType type: Int = TRANSIT_OPEN,
+ ): WindowContainerTransaction {
+ val arg: ArgumentCaptor<WindowContainerTransaction> =
+ ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+ verify(desktopMixedTransitionHandler)
+ .startLaunchTransition(eq(type), capture(arg), anyInt(), anyOrNull())
+ return arg.value
+ }
+
private fun getLatestEnterDesktopWct(): WindowContainerTransaction {
val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
verify(enterDesktopTransitionHandler).moveToDesktop(arg.capture(), any())