summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopTaskToFrontReason.aidl19
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopTaskToFrontReason.kt47
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt128
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt54
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt33
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt89
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt208
10 files changed, 490 insertions, 134 deletions
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopTaskToFrontReason.aidl b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopTaskToFrontReason.aidl
new file mode 100644
index 000000000000..78c4c35727de
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopTaskToFrontReason.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.shared.desktopmode;
+
+parcelable DesktopTaskToFrontReason; \ No newline at end of file
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopTaskToFrontReason.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopTaskToFrontReason.kt
new file mode 100644
index 000000000000..4a24af74b212
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopTaskToFrontReason.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2025 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.wm.shell.shared.desktopmode
+
+import android.os.Parcel
+import android.os.Parcelable
+
+/** Reason for moving a task to front in Desktop Mode. */
+enum class DesktopTaskToFrontReason : Parcelable {
+ UNKNOWN,
+ TASKBAR_TAP,
+ ALT_TAB,
+ TASKBAR_MANAGE_WINDOW;
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(dest: Parcel, flags: Int) {
+ dest.writeString(name)
+ }
+
+ companion object {
+ @JvmField
+ val CREATOR = object : Parcelable.Creator<DesktopTaskToFrontReason> {
+ override fun createFromParcel(parcel: Parcel): DesktopTaskToFrontReason {
+ return parcel.readString()?.let { valueOf(it) } ?: UNKNOWN
+ }
+
+ override fun newArray(size: Int) = arrayOfNulls<DesktopTaskToFrontReason>(size)
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
index 68bdbd1758b3..702c67473db2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
@@ -407,7 +407,7 @@ class DesktopModeEventLogger {
* @property taskX x-coordinate of the top-left corner
* @property taskY y-coordinate of the top-left corner
* @property minimizeReason the reason the task was minimized
- * @property unminimizeEvent the reason the task was unminimized
+ * @property unminimizeReason the reason the task was unminimized
*/
data class TaskUpdate(
val instanceId: Int,
@@ -499,6 +499,14 @@ class DesktopModeEventLogger {
FrameworkStatsLog
.DESKTOP_MODE_SESSION_TASK_UPDATE__UNMINIMIZE_REASON__UNMINIMIZE_TASK_LAUNCH
),
+ APP_HANDLE_MENU_BUTTON(
+ FrameworkStatsLog
+ .DESKTOP_MODE_SESSION_TASK_UPDATE__UNMINIMIZE_REASON__UNMINIMIZE_APP_HANDLE_MENU_BUTTON
+ ),
+ TASKBAR_MANAGE_WINDOW(
+ FrameworkStatsLog
+ .DESKTOP_MODE_SESSION_TASK_UPDATE__UNMINIMIZE_REASON__UNMINIMIZE_TASKBAR_MANAGE_WINDOW
+ ),
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
index 2dd89c790b58..df4b1c4a66ec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
@@ -41,6 +41,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterRe
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON
@@ -297,7 +298,12 @@ class DesktopModeLoggerTransitionObserver(
when {
// new tasks added
previousTaskInfo == null -> {
- desktopModeEventLogger.logTaskAdded(currentTaskUpdate)
+ // The current task is now visible while before it wasn't - this might be the
+ // result of an unminimize action.
+ val unminimizeReason = getUnminimizeReason(transition, taskInfo)
+ desktopModeEventLogger.logTaskAdded(
+ currentTaskUpdate.copy(unminimizeReason = unminimizeReason)
+ )
Trace.setCounter(
Trace.TRACE_TAG_WINDOW_MANAGER,
VISIBLE_TASKS_COUNTER_NAME,
@@ -359,13 +365,24 @@ class DesktopModeLoggerTransitionObserver(
return null
}
+ private fun getUnminimizeReason(transition: IBinder, taskInfo: TaskInfo): UnminimizeReason? {
+ val unminimizingTask = desktopTasksLimiter.getOrNull()?.getUnminimizingTask(transition)
+ if (unminimizingTask?.taskId == taskInfo.taskId) {
+ return unminimizingTask.unminimizeReason
+ }
+ return null
+ }
+
private fun buildTaskUpdateForTask(
taskInfo: TaskInfo,
visibleTasks: Int,
minimizeReason: MinimizeReason? = null,
+ unminimizeReason: UnminimizeReason? = null,
): TaskUpdate {
val screenBounds = taskInfo.configuration.windowConfiguration.bounds
val positionInParent = taskInfo.positionInParent
+ // We can't both minimize and unminimize the same task in one go.
+ assert(minimizeReason == null || unminimizeReason == null)
return TaskUpdate(
instanceId = taskInfo.taskId,
uid = taskInfo.effectiveUid,
@@ -375,6 +392,7 @@ class DesktopModeLoggerTransitionObserver(
taskY = positionInParent.y,
visibleTaskCount = visibleTasks,
minimizeReason = minimizeReason,
+ unminimizeReason = unminimizeReason,
)
}
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 172410d0482c..b25c80c18fda 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
@@ -89,6 +89,7 @@ import com.android.wm.shell.compatui.isTransparentTask
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason
import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.DragStartState
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType
@@ -115,6 +116,7 @@ import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.DESKTOP_DENSITY_OVERRIDE
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.useDesktopOverrideDensity
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
+import com.android.wm.shell.shared.desktopmode.DesktopTaskToFrontReason
import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_UNDEFINED
import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
@@ -753,12 +755,16 @@ class DesktopTasksController(
* Desktop task limit, so [remoteTransition] should also handle any such minimize change.
*/
@JvmOverloads
- fun moveTaskToFront(taskId: Int, remoteTransition: RemoteTransition? = null) {
+ fun moveTaskToFront(
+ taskId: Int,
+ remoteTransition: RemoteTransition? = null,
+ unminimizeReason: UnminimizeReason,
+ ) {
val task = shellTaskOrganizer.getRunningTaskInfo(taskId)
if (task == null) {
- moveBackgroundTaskToFront(taskId, remoteTransition)
+ moveBackgroundTaskToFront(taskId, remoteTransition, unminimizeReason)
} else {
- moveTaskToFront(task, remoteTransition)
+ moveTaskToFront(task, remoteTransition, unminimizeReason)
}
}
@@ -767,7 +773,11 @@ class DesktopTasksController(
* desktop. If outside of desktop and want to launch a background task in desktop, use
* [moveBackgroundTaskToDesktop] instead.
*/
- private fun moveBackgroundTaskToFront(taskId: Int, remoteTransition: RemoteTransition?) {
+ private fun moveBackgroundTaskToFront(
+ taskId: Int,
+ remoteTransition: RemoteTransition?,
+ unminimizeReason: UnminimizeReason,
+ ) {
logV("moveBackgroundTaskToFront taskId=%s", taskId)
val wct = WindowContainerTransaction()
wct.startTask(
@@ -776,7 +786,13 @@ class DesktopTasksController(
.apply { launchWindowingMode = WINDOWING_MODE_FREEFORM }
.toBundle(),
)
- startLaunchTransition(TRANSIT_OPEN, wct, taskId, remoteTransition = remoteTransition)
+ startLaunchTransition(
+ TRANSIT_OPEN,
+ wct,
+ taskId,
+ remoteTransition = remoteTransition,
+ unminimizeReason = unminimizeReason,
+ )
}
/**
@@ -786,7 +802,11 @@ class DesktopTasksController(
* Desktop task limit, so [remoteTransition] should also handle any such minimize change.
*/
@JvmOverloads
- fun moveTaskToFront(taskInfo: RunningTaskInfo, remoteTransition: RemoteTransition? = null) {
+ fun moveTaskToFront(
+ taskInfo: RunningTaskInfo,
+ remoteTransition: RemoteTransition? = null,
+ unminimizeReason: UnminimizeReason = UnminimizeReason.UNKNOWN,
+ ) {
logV("moveTaskToFront taskId=%s", taskInfo.taskId)
// If a task is tiled, another task should be brought to foreground with it so let
// tiling controller handle the request.
@@ -801,6 +821,7 @@ class DesktopTasksController(
launchingTaskId = taskInfo.taskId,
remoteTransition = remoteTransition,
displayId = taskInfo.displayId,
+ unminimizeReason = unminimizeReason,
)
}
@@ -810,6 +831,7 @@ class DesktopTasksController(
launchingTaskId: Int?,
remoteTransition: RemoteTransition? = null,
displayId: Int = DEFAULT_DISPLAY,
+ unminimizeReason: UnminimizeReason = UnminimizeReason.UNKNOWN,
): IBinder {
val taskIdToMinimize =
addAndGetMinimizeChanges(
@@ -825,8 +847,8 @@ class DesktopTasksController(
excludeTaskId = launchingTaskId,
reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
)
- if (remoteTransition == null) {
- val t =
+ val t =
+ if (remoteTransition == null) {
desktopMixedTransitionHandler.startLaunchTransition(
transitionType = transitionType,
wct = wct,
@@ -834,27 +856,29 @@ class DesktopTasksController(
minimizingTaskId = taskIdToMinimize,
exitingImmersiveTask = exitImmersiveResult.asExit()?.exitingTask,
)
- taskIdToMinimize?.let { addPendingMinimizeTransition(t, it, MinimizeReason.TASK_LIMIT) }
- exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t)
- return t
+ } else if (taskIdToMinimize == null) {
+ val remoteTransitionHandler = OneShotRemoteHandler(mainExecutor, remoteTransition)
+ transitions.startTransition(transitionType, wct, remoteTransitionHandler).also {
+ remoteTransitionHandler.setTransition(it)
+ }
+ } else {
+ val remoteTransitionHandler =
+ DesktopWindowLimitRemoteHandler(
+ mainExecutor,
+ rootTaskDisplayAreaOrganizer,
+ remoteTransition,
+ taskIdToMinimize,
+ )
+ transitions.startTransition(transitionType, wct, remoteTransitionHandler).also {
+ remoteTransitionHandler.setTransition(it)
+ }
+ }
+ if (taskIdToMinimize != null) {
+ addPendingMinimizeTransition(t, taskIdToMinimize, MinimizeReason.TASK_LIMIT)
+ }
+ if (launchingTaskId != null && taskRepository.isMinimizedTask(launchingTaskId)) {
+ addPendingUnminimizeTransition(t, displayId, launchingTaskId, unminimizeReason)
}
- if (taskIdToMinimize == null) {
- val remoteTransitionHandler = OneShotRemoteHandler(mainExecutor, remoteTransition)
- val t = transitions.startTransition(transitionType, wct, remoteTransitionHandler)
- remoteTransitionHandler.setTransition(t)
- exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t)
- return t
- }
- val remoteTransitionHandler =
- DesktopWindowLimitRemoteHandler(
- mainExecutor,
- rootTaskDisplayAreaOrganizer,
- remoteTransition,
- taskIdToMinimize,
- )
- val t = transitions.startTransition(transitionType, wct, remoteTransitionHandler)
- remoteTransitionHandler.setTransition(t)
- taskIdToMinimize.let { addPendingMinimizeTransition(t, it, MinimizeReason.TASK_LIMIT) }
exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t)
return t
}
@@ -1731,7 +1755,10 @@ class DesktopTasksController(
val requestedTaskInfo = shellTaskOrganizer.getRunningTaskInfo(requestedTaskId)
if (requestedTaskInfo?.isFreeform == true) {
// If requested task is an already open freeform task, just move it to front.
- moveTaskToFront(requestedTaskId)
+ moveTaskToFront(
+ requestedTaskId,
+ unminimizeReason = UnminimizeReason.APP_HANDLE_MENU_BUTTON,
+ )
} else {
moveBackgroundTaskToDesktop(
requestedTaskId,
@@ -1894,6 +1921,16 @@ class DesktopTasksController(
if (useDesktopOverrideDensity()) {
wct.setDensityDpi(task.token, DESKTOP_DENSITY_OVERRIDE)
}
+ // The task that is launching might have been minimized before - in which case this is an
+ // unminimize action.
+ if (taskRepository.isMinimizedTask(task.taskId)) {
+ addPendingUnminimizeTransition(
+ transition,
+ task.displayId,
+ task.taskId,
+ UnminimizeReason.TASK_LAUNCH,
+ )
+ }
// Desktop Mode is showing and we're launching a new Task:
// 1) Exit immersive if needed.
desktopImmersiveController.exitImmersiveIfApplicable(
@@ -2206,6 +2243,22 @@ class DesktopTasksController(
}
}
+ private fun addPendingUnminimizeTransition(
+ transition: IBinder,
+ displayId: Int,
+ taskIdToUnminimize: Int,
+ unminimizeReason: UnminimizeReason,
+ ) {
+ desktopTasksLimiter.ifPresent {
+ it.addPendingUnminimizeChange(
+ transition,
+ displayId = displayId,
+ taskId = taskIdToUnminimize,
+ unminimizeReason,
+ )
+ }
+ }
+
private fun addPendingAppLaunchTransition(
transition: IBinder,
launchTaskId: Int,
@@ -2883,9 +2936,13 @@ class DesktopTasksController(
}
}
- override fun showDesktopApp(taskId: Int, remoteTransition: RemoteTransition?) {
+ override fun showDesktopApp(
+ taskId: Int,
+ remoteTransition: RemoteTransition?,
+ toFrontReason: DesktopTaskToFrontReason,
+ ) {
executeRemoteCallWithTaskPermission(controller, "showDesktopApp") { c ->
- c.moveTaskToFront(taskId, remoteTransition)
+ c.moveTaskToFront(taskId, remoteTransition, toFrontReason.toUnminimizeReason())
}
}
@@ -2980,6 +3037,15 @@ class DesktopTasksController(
private val APP_HANDLE_DRAG_HOLD_CUJ_TIMEOUT_MS: Long = TimeUnit.SECONDS.toMillis(10L)
private const val TAG = "DesktopTasksController"
+
+ private fun DesktopTaskToFrontReason.toUnminimizeReason(): UnminimizeReason =
+ when (this) {
+ DesktopTaskToFrontReason.UNKNOWN -> UnminimizeReason.UNKNOWN
+ DesktopTaskToFrontReason.TASKBAR_TAP -> UnminimizeReason.TASKBAR_TAP
+ DesktopTaskToFrontReason.ALT_TAB -> UnminimizeReason.ALT_TAB
+ DesktopTaskToFrontReason.TASKBAR_MANAGE_WINDOW ->
+ UnminimizeReason.TASKBAR_MANAGE_WINDOW
+ }
}
/** Defines interface for classes that can listen to changes for task resize. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
index 204b39645248..81b136dd1569 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
@@ -31,6 +31,7 @@ import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.sysui.UserChangeListener
@@ -73,6 +74,7 @@ class DesktopTasksLimiter(
val taskId: Int,
var transitionInfo: TransitionInfo? = null,
val minimizeReason: MinimizeReason? = null,
+ val unminimizeReason: UnminimizeReason? = null,
)
/**
@@ -83,20 +85,39 @@ class DesktopTasksLimiter(
return minimizeTransitionObserver.getMinimizingTask(transition)
}
+ /**
+ * Returns the task being unminimized in the given transition if that transition is a pending or
+ * active unminimize transition.
+ */
+ fun getUnminimizingTask(transition: IBinder): TaskDetails? {
+ return minimizeTransitionObserver.getUnminimizingTask(transition)
+ }
+
// TODO(b/333018485): replace this observer when implementing the minimize-animation
private inner class MinimizeTransitionObserver : TransitionObserver {
private val pendingTransitionTokensAndTasks = mutableMapOf<IBinder, TaskDetails>()
private val activeTransitionTokensAndTasks = mutableMapOf<IBinder, TaskDetails>()
+ private val pendingUnminimizeTransitionTokensAndTasks = mutableMapOf<IBinder, TaskDetails>()
+ private val activeUnminimizeTransitionTokensAndTasks = mutableMapOf<IBinder, TaskDetails>()
fun addPendingTransitionToken(transition: IBinder, taskDetails: TaskDetails) {
pendingTransitionTokensAndTasks[transition] = taskDetails
}
+ fun addPendingUnminimizeTransitionToken(transition: IBinder, taskDetails: TaskDetails) {
+ pendingUnminimizeTransitionTokensAndTasks[transition] = taskDetails
+ }
+
fun getMinimizingTask(transition: IBinder): TaskDetails? {
return pendingTransitionTokensAndTasks[transition]
?: activeTransitionTokensAndTasks[transition]
}
+ fun getUnminimizingTask(transition: IBinder): TaskDetails? {
+ return pendingUnminimizeTransitionTokensAndTasks[transition]
+ ?: activeUnminimizeTransitionTokensAndTasks[transition]
+ }
+
override fun onTransitionReady(
transition: IBinder,
info: TransitionInfo,
@@ -104,10 +125,11 @@ class DesktopTasksLimiter(
finishTransaction: SurfaceControl.Transaction,
) {
val taskRepository = desktopUserRepositories.current
- handleMinimizeTransition(taskRepository, transition, info)
+ handleMinimizeTransitionReady(taskRepository, transition, info)
+ handleUnminimizeTransitionReady(transition)
}
- private fun handleMinimizeTransition(
+ private fun handleMinimizeTransitionReady(
taskRepository: DesktopRepository,
transition: IBinder,
info: TransitionInfo,
@@ -131,6 +153,12 @@ class DesktopTasksLimiter(
this@DesktopTasksLimiter.minimizeTask(taskToMinimize.displayId, taskToMinimize.taskId)
}
+ private fun handleUnminimizeTransitionReady(transition: IBinder) {
+ val taskToUnminimize =
+ pendingUnminimizeTransitionTokensAndTasks.remove(transition) ?: return
+ activeUnminimizeTransitionTokensAndTasks[transition] = taskToUnminimize
+ }
+
/**
* Returns whether the Task [taskDetails] is being reordered to the back in the transition
* [info], or is already invisible.
@@ -173,6 +201,11 @@ class DesktopTasksLimiter(
pendingTransitionTokensAndTasks.remove(merged)?.let { taskToTransfer ->
pendingTransitionTokensAndTasks[playing] = taskToTransfer
}
+
+ activeUnminimizeTransitionTokensAndTasks.remove(merged)
+ pendingUnminimizeTransitionTokensAndTasks.remove(merged)?.let { taskToTransfer ->
+ pendingUnminimizeTransitionTokensAndTasks[playing] = taskToTransfer
+ }
}
override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {
@@ -184,6 +217,8 @@ class DesktopTasksLimiter(
}
}
pendingTransitionTokensAndTasks.remove(transition)
+ activeUnminimizeTransitionTokensAndTasks.remove(transition)
+ pendingUnminimizeTransitionTokensAndTasks.remove(transition)
}
}
@@ -277,6 +312,21 @@ class DesktopTasksLimiter(
}
/**
+ * Add a pending unminimize transition change to allow tracking unminimizing transitions /
+ * tasks.
+ */
+ fun addPendingUnminimizeChange(
+ transition: IBinder,
+ displayId: Int,
+ taskId: Int,
+ unminimizeReason: UnminimizeReason,
+ ) =
+ minimizeTransitionObserver.addPendingUnminimizeTransitionToken(
+ transition,
+ TaskDetails(displayId, taskId, unminimizeReason = unminimizeReason),
+ )
+
+ /**
* Returns the minimized task from the list of visible tasks ordered from front to back with the
* new task placed in front of other tasks.
*/
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 54f031293486..ae4c2773215b 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
@@ -22,6 +22,7 @@ import android.os.Bundle;
import android.window.RemoteTransition;
import com.android.wm.shell.desktopmode.IDesktopTaskListener;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
+import com.android.wm.shell.shared.desktopmode.DesktopTaskToFrontReason;
/**
* Interface that is exposed to remote callers to manipulate desktop mode features.
@@ -38,12 +39,13 @@ interface IDesktopMode {
void hideStashedDesktopApps(int displayId);
/**
- * Bring task with the given id to front, using the given remote transition.
- *
- * <p> Note: beyond moving a task to the front, this method will minimize a task if we reach the
- * Desktop task limit, so {@code remoteTransition} should also handle any such minimize change.
- */
- oneway void showDesktopApp(int taskId, in @nullable RemoteTransition remoteTransition);
+ * Bring task with the given id to front, using the given remote transition.
+ *
+ * <p> Note: beyond moving a task to the front, this method will minimize a task if we reach the
+ * Desktop task limit, so {@code remoteTransition} should also handle any such minimize change.
+ */
+ oneway void showDesktopApp(int taskId, in @nullable RemoteTransition remoteTransition,
+ in DesktopTaskToFrontReason toFrontReason);
/** Get count of visible desktop tasks on the given display */
int getVisibleTaskCount(int displayId);
@@ -66,4 +68,4 @@ interface IDesktopMode {
/** 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/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
index a9ebcef9bd98..2e9d6d95eebb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
@@ -49,6 +49,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterRe
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON
@@ -795,6 +796,38 @@ class DesktopModeLoggerTransitionObserverTest : ShellTestCase() {
)
}
+ @Test
+ fun onTransitionReady_taskIsBeingUnminimized_logsTaskUnminimized() {
+ transitionObserver.isSessionActive = true
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(WINDOWING_MODE_FREEFORM, id = 1))
+ val taskInfo2 = createTaskInfo(WINDOWING_MODE_FREEFORM, id = 2)
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_TO_FRONT, /* flags= */ 0)
+ .addChange(createChange(TRANSIT_TO_FRONT, taskInfo2))
+ .build()
+ `when`(desktopTasksLimiter.getUnminimizingTask(any()))
+ .thenReturn(
+ DesktopTasksLimiter.TaskDetails(
+ taskInfo2.displayId,
+ taskInfo2.taskId,
+ unminimizeReason = UnminimizeReason.TASKBAR_MANAGE_WINDOW,
+ )
+ )
+
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1))
+ .logTaskAdded(
+ eq(
+ DEFAULT_TASK_UPDATE.copy(
+ instanceId = 2,
+ visibleTaskCount = 2,
+ unminimizeReason = UnminimizeReason.TASKBAR_MANAGE_WINDOW,
+ )
+ )
+ )
+ }
+
/** Simulate calling the onTransitionReady() method */
private fun callOnTransitionReady(transitionInfo: TransitionInfo) {
val transition = mock<IBinder>()
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 6c4f043a4f39..471565462340 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
@@ -104,6 +104,7 @@ import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitResult
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason
import com.android.wm.shell.desktopmode.DesktopTasksController.DesktopModeEntryExitTransitionListener
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
import com.android.wm.shell.desktopmode.DesktopTasksController.TaskbarDesktopTaskListener
@@ -1150,6 +1151,16 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun launchIntent_taskInDesktopMode_transitionStarted() {
setUpLandscapeDisplay()
val freeformTask = setUpFreeformTask()
+ whenever(
+ desktopMixedTransitionHandler.startLaunchTransition(
+ eq(TRANSIT_OPEN),
+ any(),
+ anyOrNull(),
+ anyOrNull(),
+ anyOrNull(),
+ )
+ )
+ .thenReturn(Binder())
controller.startLaunchIntentTransition(
freeformTask.baseIntent,
@@ -1672,6 +1683,16 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun moveTaskToFront_postsWctWithReorderOp() {
val task1 = setUpFreeformTask()
setUpFreeformTask()
+ whenever(
+ desktopMixedTransitionHandler.startLaunchTransition(
+ eq(TRANSIT_TO_FRONT),
+ any(),
+ eq(task1.taskId),
+ anyOrNull(),
+ anyOrNull(),
+ )
+ )
+ .thenReturn(Binder())
controller.moveTaskToFront(task1, remoteTransition = null)
@@ -1704,6 +1725,46 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ fun moveTaskToFront_minimizedTask_marksTaskAsUnminimized() {
+ val transition = Binder()
+ val freeformTask = setUpFreeformTask()
+ taskRepository.minimizeTask(DEFAULT_DISPLAY, freeformTask.taskId)
+ whenever(
+ desktopMixedTransitionHandler.startLaunchTransition(
+ eq(TRANSIT_TO_FRONT),
+ any(),
+ eq(freeformTask.taskId),
+ anyOrNull(),
+ anyOrNull(),
+ )
+ )
+ .thenReturn(transition)
+
+ controller.moveTaskToFront(freeformTask, unminimizeReason = UnminimizeReason.ALT_TAB)
+
+ val task = desktopTasksLimiter.getUnminimizingTask(transition)
+ assertThat(task).isNotNull()
+ assertThat(task?.taskId).isEqualTo(freeformTask.taskId)
+ assertThat(task?.unminimizeReason).isEqualTo(UnminimizeReason.ALT_TAB)
+ }
+
+ @Test
+ fun handleRequest_minimizedFreeformTask_marksTaskAsUnminimized() {
+ val transition = Binder()
+ // Create a visible task so we stay in Desktop Mode when minimizing task under test.
+ setUpFreeformTask().also { markTaskVisible(it) }
+ val freeformTask = setUpFreeformTask()
+ taskRepository.minimizeTask(DEFAULT_DISPLAY, freeformTask.taskId)
+
+ controller.handleRequest(transition, createTransition(freeformTask, TRANSIT_OPEN))
+
+ val task = desktopTasksLimiter.getUnminimizingTask(transition)
+ assertThat(task).isNotNull()
+ assertThat(task?.taskId).isEqualTo(freeformTask.taskId)
+ assertThat(task?.unminimizeReason).isEqualTo(UnminimizeReason.TASK_LAUNCH)
+ }
+
+ @Test
fun moveTaskToFront_remoteTransition_usesOneshotHandler() {
setUpHomeTask()
val freeformTasks = List(MAX_TASK_LIMIT) { setUpFreeformTask() }
@@ -1734,8 +1795,18 @@ class DesktopTasksControllerTest : ShellTestCase() {
fun moveTaskToFront_backgroundTask_launchesTask() {
val task = createTaskInfo(1)
whenever(shellTaskOrganizer.getRunningTaskInfo(anyInt())).thenReturn(null)
+ whenever(
+ desktopMixedTransitionHandler.startLaunchTransition(
+ eq(TRANSIT_OPEN),
+ any(),
+ anyOrNull(),
+ anyOrNull(),
+ anyOrNull(),
+ )
+ )
+ .thenReturn(Binder())
- controller.moveTaskToFront(task.taskId, remoteTransition = null)
+ controller.moveTaskToFront(task.taskId, unminimizeReason = UnminimizeReason.UNKNOWN)
val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN)
assertThat(wct.hierarchyOps).hasSize(1)
@@ -1758,7 +1829,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
)
.thenReturn(Binder())
- controller.moveTaskToFront(task.taskId, remoteTransition = null)
+ controller.moveTaskToFront(task.taskId, unminimizeReason = UnminimizeReason.UNKNOWN)
val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_OPEN)
assertThat(wct.hierarchyOps.size).isEqualTo(2) // launch + minimize
@@ -4026,6 +4097,16 @@ class DesktopTasksControllerTest : ShellTestCase() {
setUpLandscapeDisplay()
val task = setUpFreeformTask()
val taskToRequest = setUpFreeformTask()
+ whenever(
+ desktopMixedTransitionHandler.startLaunchTransition(
+ eq(TRANSIT_TO_FRONT),
+ any(),
+ eq(taskToRequest.taskId),
+ anyOrNull(),
+ anyOrNull(),
+ )
+ )
+ .thenReturn(Binder())
runOpenInstance(task, taskToRequest.taskId)
verify(desktopMixedTransitionHandler)
.startLaunchTransition(anyInt(), any(), anyInt(), anyOrNull(), anyOrNull())
@@ -4759,7 +4840,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
)
.thenReturn(transition)
- controller.moveTaskToFront(task.taskId, remoteTransition = null)
+ controller.moveTaskToFront(task.taskId, unminimizeReason = UnminimizeReason.UNKNOWN)
verify(mMockDesktopImmersiveController)
.exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId), any())
@@ -4791,7 +4872,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
)
.thenReturn(transition)
- controller.moveTaskToFront(task.taskId, remoteTransition = null)
+ controller.moveTaskToFront(task.taskId, unminimizeReason = UnminimizeReason.UNKNOWN)
verify(mMockDesktopImmersiveController)
.exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId), any())
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
index acfe1e9fd5a2..e85901bbd9d4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
@@ -45,6 +45,7 @@ import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason
import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
@@ -192,14 +193,10 @@ class DesktopTasksLimiterTest : ShellTestCase() {
val task = setUpFreeformTask()
markTaskHidden(task)
- desktopTasksLimiter
- .getTransitionObserver()
- .onTransitionReady(
- /* transition= */ Binder(),
- TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
- /* startTransaction= */ StubTransaction(),
- /* finishTransaction= */ StubTransaction(),
- )
+ callOnTransitionReady(
+ Binder(),
+ TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
+ )
assertThat(desktopTaskRepo.isMinimizedTask(taskId = task.taskId)).isFalse()
}
@@ -212,14 +209,10 @@ class DesktopTasksLimiterTest : ShellTestCase() {
markTaskHidden(task)
addPendingMinimizeChange(pendingTransition, taskId = task.taskId)
- desktopTasksLimiter
- .getTransitionObserver()
- .onTransitionReady(
- /* transition= */ taskTransition,
- TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
- /* startTransaction= */ StubTransaction(),
- /* finishTransaction= */ StubTransaction(),
- )
+ callOnTransitionReady(
+ taskTransition,
+ TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
+ )
assertThat(desktopTaskRepo.isMinimizedTask(taskId = task.taskId)).isFalse()
}
@@ -231,14 +224,7 @@ class DesktopTasksLimiterTest : ShellTestCase() {
markTaskVisible(task)
addPendingMinimizeChange(transition, taskId = task.taskId)
- desktopTasksLimiter
- .getTransitionObserver()
- .onTransitionReady(
- transition,
- TransitionInfoBuilder(TRANSIT_OPEN).build(),
- /* startTransaction= */ StubTransaction(),
- /* finishTransaction= */ StubTransaction(),
- )
+ callOnTransitionReady(transition, TransitionInfoBuilder(TRANSIT_OPEN).build())
assertThat(desktopTaskRepo.isMinimizedTask(taskId = task.taskId)).isFalse()
}
@@ -250,14 +236,7 @@ class DesktopTasksLimiterTest : ShellTestCase() {
markTaskHidden(task)
addPendingMinimizeChange(transition, taskId = task.taskId)
- desktopTasksLimiter
- .getTransitionObserver()
- .onTransitionReady(
- transition,
- TransitionInfoBuilder(TRANSIT_OPEN).build(),
- /* startTransaction= */ StubTransaction(),
- /* finishTransaction= */ StubTransaction(),
- )
+ callOnTransitionReady(transition, TransitionInfoBuilder(TRANSIT_OPEN).build())
assertThat(desktopTaskRepo.isMinimizedTask(taskId = task.taskId)).isTrue()
}
@@ -268,14 +247,10 @@ class DesktopTasksLimiterTest : ShellTestCase() {
val task = setUpFreeformTask()
addPendingMinimizeChange(transition, taskId = task.taskId)
- desktopTasksLimiter
- .getTransitionObserver()
- .onTransitionReady(
- transition,
- TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
- /* startTransaction= */ StubTransaction(),
- /* finishTransaction= */ StubTransaction(),
- )
+ callOnTransitionReady(
+ transition,
+ TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
+ )
assertThat(desktopTaskRepo.isMinimizedTask(taskId = task.taskId)).isTrue()
}
@@ -293,14 +268,10 @@ class DesktopTasksLimiterTest : ShellTestCase() {
taskInfo = task
setStartAbsBounds(bounds)
}
- desktopTasksLimiter
- .getTransitionObserver()
- .onTransitionReady(
- transition,
- TransitionInfo(TRANSIT_OPEN, TransitionInfo.FLAG_NONE).apply { addChange(change) },
- /* startTransaction= */ StubTransaction(),
- /* finishTransaction= */ StubTransaction(),
- )
+ callOnTransitionReady(
+ transition,
+ TransitionInfo(TRANSIT_OPEN, TransitionInfo.FLAG_NONE).apply { addChange(change) },
+ )
assertThat(desktopTaskRepo.isMinimizedTask(taskId = task.taskId)).isTrue()
assertThat(desktopTaskRepo.removeBoundsBeforeMinimize(taskId = task.taskId))
@@ -316,15 +287,14 @@ class DesktopTasksLimiterTest : ShellTestCase() {
desktopTasksLimiter
.getTransitionObserver()
.onTransitionMerged(mergedTransition, newTransition)
-
desktopTasksLimiter
.getTransitionObserver()
- .onTransitionReady(
- newTransition,
- TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
- /* startTransaction= */ StubTransaction(),
- /* finishTransaction= */ StubTransaction(),
- )
+ .onTransitionMerged(mergedTransition, newTransition)
+
+ callOnTransitionReady(
+ newTransition,
+ TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
+ )
assertThat(desktopTaskRepo.isMinimizedTask(taskId = task.taskId)).isTrue()
}
@@ -521,14 +491,10 @@ class DesktopTasksLimiterTest : ShellTestCase() {
val task = setUpFreeformTask()
addPendingMinimizeChange(transition, taskId = task.taskId)
- desktopTasksLimiter
- .getTransitionObserver()
- .onTransitionReady(
- transition,
- TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
- /* startTransaction= */ StubTransaction(),
- /* finishTransaction= */ StubTransaction(),
- )
+ callOnTransitionReady(
+ transition,
+ TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
+ )
desktopTasksLimiter.getTransitionObserver().onTransitionStarting(transition)
@@ -549,14 +515,10 @@ class DesktopTasksLimiterTest : ShellTestCase() {
val task = setUpFreeformTask()
addPendingMinimizeChange(transition, taskId = task.taskId)
- desktopTasksLimiter
- .getTransitionObserver()
- .onTransitionReady(
- transition,
- TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
- /* startTransaction= */ StubTransaction(),
- /* finishTransaction= */ StubTransaction(),
- )
+ callOnTransitionReady(
+ transition,
+ TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
+ )
desktopTasksLimiter.getTransitionObserver().onTransitionStarting(transition)
@@ -578,14 +540,10 @@ class DesktopTasksLimiterTest : ShellTestCase() {
val task = setUpFreeformTask()
addPendingMinimizeChange(mergedTransition, taskId = task.taskId)
- desktopTasksLimiter
- .getTransitionObserver()
- .onTransitionReady(
- mergedTransition,
- TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
- /* startTransaction= */ StubTransaction(),
- /* finishTransaction= */ StubTransaction(),
- )
+ callOnTransitionReady(
+ mergedTransition,
+ TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build(),
+ )
desktopTasksLimiter.getTransitionObserver().onTransitionStarting(mergedTransition)
@@ -634,14 +592,57 @@ class DesktopTasksLimiterTest : ShellTestCase() {
val transitionInfo =
TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build()
- desktopTasksLimiter
- .getTransitionObserver()
- .onTransitionReady(
- transition,
- transitionInfo,
- /* startTransaction= */ StubTransaction(),
- /* finishTransaction= */ StubTransaction(),
+ callOnTransitionReady(transition, transitionInfo)
+
+ assertThat(desktopTasksLimiter.getMinimizingTask(transition))
+ .isEqualTo(
+ createTaskDetails(
+ taskId = task.taskId,
+ transitionInfo = transitionInfo,
+ minimizeReason = MinimizeReason.TASK_LIMIT,
+ )
+ )
+ }
+
+ @Test
+ fun getUnminimizingTask_noPendingTransition_returnsNull() {
+ val transition = Binder()
+
+ assertThat(desktopTasksLimiter.getMinimizingTask(transition)).isNull()
+ }
+
+ @Test
+ fun getUnminimizingTask_pendingTaskTransition_returnsTask() {
+ val transition = Binder()
+ val task = setUpFreeformTask()
+ addPendingUnminimizeChange(
+ transition,
+ taskId = task.taskId,
+ unminimizeReason = UnminimizeReason.TASKBAR_TAP,
+ )
+
+ assertThat(desktopTasksLimiter.getUnminimizingTask(transition))
+ .isEqualTo(
+ createTaskDetails(
+ taskId = task.taskId,
+ unminimizeReason = UnminimizeReason.TASKBAR_TAP,
+ )
)
+ }
+
+ @Test
+ fun getUnminimizingTask_activeTaskTransition_returnsTask() {
+ val transition = Binder()
+ val task = setUpFreeformTask()
+ addPendingMinimizeChange(
+ transition,
+ taskId = task.taskId,
+ minimizeReason = MinimizeReason.TASK_LIMIT,
+ )
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build()
+
+ callOnTransitionReady(transition, transitionInfo)
assertThat(desktopTasksLimiter.getMinimizingTask(transition))
.isEqualTo(
@@ -665,15 +666,46 @@ class DesktopTasksLimiterTest : ShellTestCase() {
taskId: Int,
transitionInfo: TransitionInfo? = null,
minimizeReason: MinimizeReason? = null,
- ) = DesktopTasksLimiter.TaskDetails(displayId, taskId, transitionInfo, minimizeReason)
+ unminimizeReason: UnminimizeReason? = null,
+ ) =
+ DesktopTasksLimiter.TaskDetails(
+ displayId,
+ taskId,
+ transitionInfo,
+ minimizeReason,
+ unminimizeReason,
+ )
+
+ private fun callOnTransitionReady(
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction = StubTransaction(),
+ finishTransaction: SurfaceControl.Transaction = StubTransaction(),
+ ) =
+ desktopTasksLimiter
+ .getTransitionObserver()
+ .onTransitionReady(transition, info, startTransaction, finishTransaction)
- fun addPendingMinimizeChange(
+ private fun addPendingMinimizeChange(
transition: IBinder,
displayId: Int = DEFAULT_DISPLAY,
taskId: Int,
minimizeReason: MinimizeReason = MinimizeReason.TASK_LIMIT,
) = desktopTasksLimiter.addPendingMinimizeChange(transition, displayId, taskId, minimizeReason)
+ private fun addPendingUnminimizeChange(
+ transition: IBinder,
+ displayId: Int = DEFAULT_DISPLAY,
+ taskId: Int,
+ unminimizeReason: UnminimizeReason,
+ ) =
+ desktopTasksLimiter.addPendingUnminimizeChange(
+ transition,
+ displayId,
+ taskId,
+ unminimizeReason,
+ )
+
private fun markTaskVisible(task: RunningTaskInfo) {
desktopTaskRepo.updateTask(task.displayId, task.taskId, isVisible = true)
}