summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-02-13 21:33:43 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-02-13 21:33:43 -0800
commitdc6484132ee0e9314a364d4d07ee9fcf247a7c0e (patch)
tree8a3c6cd2e845d33b7740a063c528ff67ff05b4fe
parent54007d84a58bf89cb1fa209777035672372077e3 (diff)
parentc6e124f46ab9b3a8958c12a0364cac61dc556aed (diff)
Merge changes I25eb4365,I2b51e3ab into main
* changes: [15/N] Desks: Deactivate desk when last window is minimized [14/N] Desks: Deactivate desk when last window is closed
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt140
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt68
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt17
6 files changed, 199 insertions, 41 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 4dc82b66b916..eba1be517147 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -821,7 +821,7 @@ class DesktopRepository(
/** Removes the given task from the given desk. */
fun removeTaskFromDesk(deskId: Int, taskId: Int) {
- logD("removeTaskFromDesk: deskId=%d, taskId=%d", taskId, deskId)
+ logD("removeTaskFromDesk: deskId=%d, taskId=%d", deskId, taskId)
// TODO: b/362720497 - consider not clearing bounds on any removal, such as when moving
// it between desks. It might be better to allow restoring to the previous bounds as long
// as they're valid (probably valid if in the same display).
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 5eb86506d876..0afceac8a861 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
@@ -153,6 +153,16 @@ import java.util.concurrent.TimeUnit
import java.util.function.Consumer
import kotlin.jvm.optionals.getOrNull
+/**
+ * A callback to be invoked when a transition is started via |Transitions.startTransition| with the
+ * transition binder token that it produces.
+ *
+ * Useful when multiple components are appending WCT operations to a single transition that is
+ * started outside of their control, and each of them wants to track the transition lifecycle
+ * independently by cross-referencing the transition token with future ready-transitions.
+ */
+typealias RunOnTransitStart = (IBinder) -> Unit
+
/** Handles moving tasks in and out of desktop */
class DesktopTasksController(
private val context: Context,
@@ -481,7 +491,7 @@ class DesktopTasksController(
): Boolean {
val runningTask = shellTaskOrganizer.getRunningTaskInfo(taskId)
if (runningTask != null) {
- moveRunningTaskToDesk(
+ return moveRunningTaskToDesk(
task = runningTask,
deskId = deskId,
wct = wct,
@@ -563,10 +573,10 @@ class DesktopTasksController(
transitionSource: DesktopModeTransitionSource,
remoteTransition: RemoteTransition? = null,
callback: IMoveToDesktopCallback? = null,
- ) {
+ ): Boolean {
if (desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing(task)) {
logW("Cannot enter desktop for taskId %d, ineligible top activity found", task.taskId)
- return
+ return false
}
val displayId = taskRepository.getDisplayForDesk(deskId)
logV(
@@ -621,6 +631,7 @@ class DesktopTasksController(
} else {
taskRepository.setActiveDesk(displayId = displayId, deskId = deskId)
}
+ return true
}
/**
@@ -789,24 +800,44 @@ class DesktopTasksController(
wct: WindowContainerTransaction,
displayId: Int,
taskInfo: RunningTaskInfo,
- ): ((IBinder) -> Unit)? {
+ ): ((IBinder) -> Unit) {
val taskId = taskInfo.taskId
+ val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId)
snapEventHandler.removeTaskIfTiled(displayId, taskId)
- // TODO: b/394268248 - desk needs to be deactivated when closing the last task and going
- // home.
- performDesktopExitCleanupIfNeeded(taskId, displayId, wct, forceToFullscreen = false)
+ val shouldExitDesktop =
+ willExitDesktop(
+ triggerTaskId = taskInfo.taskId,
+ displayId = displayId,
+ forceToFullscreen = false,
+ )
+ taskRepository.setPipShouldKeepDesktopActive(displayId, keepActive = true)
+ val desktopExitRunnable =
+ performDesktopExitCleanUp(
+ wct = wct,
+ deskId = deskId,
+ displayId = displayId,
+ willExitDesktop = shouldExitDesktop,
+ shouldEndUpAtHome = true,
+ )
+
taskRepository.addClosingTask(displayId, taskId)
taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
doesAnyTaskRequireTaskbarRounding(displayId, taskId)
)
- return desktopImmersiveController
- .exitImmersiveIfApplicable(
- wct = wct,
- taskInfo = taskInfo,
- reason = DesktopImmersiveController.ExitReason.CLOSED,
- )
- .asExit()
- ?.runOnTransitionStart
+
+ val immersiveRunnable =
+ desktopImmersiveController
+ .exitImmersiveIfApplicable(
+ wct = wct,
+ taskInfo = taskInfo,
+ reason = DesktopImmersiveController.ExitReason.CLOSED,
+ )
+ .asExit()
+ ?.runOnTransitionStart
+ return { transitionToken ->
+ immersiveRunnable?.invoke(transitionToken)
+ desktopExitRunnable?.invoke(transitionToken)
+ }
}
fun minimizeTask(taskInfo: RunningTaskInfo, minimizeReason: MinimizeReason) {
@@ -840,12 +871,20 @@ class DesktopTasksController(
private fun minimizeTaskInner(taskInfo: RunningTaskInfo, minimizeReason: MinimizeReason) {
val taskId = taskInfo.taskId
+ val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId)
val displayId = taskInfo.displayId
val wct = WindowContainerTransaction()
+
snapEventHandler.removeTaskIfTiled(displayId, taskId)
- // TODO: b/394268248 - desk needs to be deactivated when minimizing the last task and going
- // home.
- performDesktopExitCleanupIfNeeded(taskId, displayId, wct, forceToFullscreen = false)
+ taskRepository.setPipShouldKeepDesktopActive(displayId, keepActive = true)
+ val willExitDesktop = willExitDesktop(taskId, displayId, forceToFullscreen = false)
+ val desktopExitRunnable =
+ performDesktopExitCleanUp(
+ wct = wct,
+ deskId = deskId,
+ displayId = displayId,
+ willExitDesktop = willExitDesktop,
+ )
// Notify immersive handler as it might need to exit immersive state.
val exitResult =
desktopImmersiveController.exitImmersiveIfApplicable(
@@ -867,6 +906,7 @@ class DesktopTasksController(
)
}
exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
+ desktopExitRunnable?.invoke(transition)
}
/** Move a task with given `taskId` to fullscreen */
@@ -915,7 +955,7 @@ class DesktopTasksController(
logV("moveToFullscreenWithAnimation taskId=%d", task.taskId)
val wct = WindowContainerTransaction()
val willExitDesktop = willExitDesktop(task.taskId, task.displayId, forceToFullscreen = true)
- val deactivatingDeskId = addMoveToFullscreenChanges(wct, task, willExitDesktop)
+ val deactivationRunnable = addMoveToFullscreenChanges(wct, task, willExitDesktop)
// We are moving a freeform task to fullscreen, put the home task under the fullscreen task.
if (!forceEnterDesktop(task.displayId)) {
@@ -930,11 +970,7 @@ class DesktopTasksController(
position,
mOnAnimationFinishedCallback,
)
- if (deactivatingDeskId != null) {
- desksTransitionObserver.addPendingTransition(
- DeskTransition.DeactivateDesk(token = transition, deskId = deactivatingDeskId)
- )
- }
+ deactivationRunnable?.invoke(transition)
// handles case where we are moving to full screen without closing all DW tasks.
if (!taskRepository.isOnlyVisibleNonClosingTask(task.taskId)) {
@@ -1770,19 +1806,30 @@ class DesktopTasksController(
wct: WindowContainerTransaction,
forceToFullscreen: Boolean,
shouldEndUpAtHome: Boolean = true,
- ) {
+ ): RunOnTransitStart? {
taskRepository.setPipShouldKeepDesktopActive(displayId, keepActive = !forceToFullscreen)
if (!willExitDesktop(taskId, displayId, forceToFullscreen)) {
- return
+ return null
}
- performDesktopExitCleanUp(wct, displayId, shouldEndUpAtHome)
+ // TODO: b/394268248 - update remaining callers to pass in a |deskId| and apply the
+ // |RunOnTransitStart| when the transition is started.
+ return performDesktopExitCleanUp(
+ wct = wct,
+ deskId = null,
+ displayId = displayId,
+ willExitDesktop = true,
+ shouldEndUpAtHome = shouldEndUpAtHome,
+ )
}
private fun performDesktopExitCleanUp(
wct: WindowContainerTransaction,
+ deskId: Int?,
displayId: Int,
+ willExitDesktop: Boolean,
shouldEndUpAtHome: Boolean = true,
- ) {
+ ): RunOnTransitStart? {
+ if (!willExitDesktop) return null
desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(
FULLSCREEN_ANIMATION_DURATION
)
@@ -1792,6 +1839,7 @@ class DesktopTasksController(
// intent.
addLaunchHomePendingIntent(wct, displayId)
}
+ return prepareDeskDeactivationIfNeeded(wct, deskId)
}
fun releaseVisualIndicator() {
@@ -2473,7 +2521,7 @@ class DesktopTasksController(
wct: WindowContainerTransaction,
taskInfo: RunningTaskInfo,
willExitDesktop: Boolean,
- ): Int? {
+ ): RunOnTransitStart? {
val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(taskInfo.displayId)!!
val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode
val targetWindowingMode =
@@ -2492,15 +2540,14 @@ class DesktopTasksController(
wct.reparent(taskInfo.token, tdaInfo.token, /* onTop= */ true)
}
taskRepository.setPipShouldKeepDesktopActive(taskInfo.displayId, keepActive = false)
- if (willExitDesktop) {
- performDesktopExitCleanUp(wct, taskInfo.displayId, shouldEndUpAtHome = false)
- val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId)
- if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue && deskId != null) {
- desksOrganizer.deactivateDesk(wct, deskId)
- return deskId
- }
- }
- return null
+ val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId)
+ return performDesktopExitCleanUp(
+ wct = wct,
+ deskId = deskId,
+ displayId = taskInfo.displayId,
+ willExitDesktop = willExitDesktop,
+ shouldEndUpAtHome = false,
+ )
}
private fun cascadeWindow(bounds: Rect, displayLayout: DisplayLayout, displayId: Int) {
@@ -2661,6 +2708,23 @@ class DesktopTasksController(
)
}
+ /**
+ * TODO: b/393978539 - Deactivation should not happen in desktop-first devices when going home.
+ */
+ private fun prepareDeskDeactivationIfNeeded(
+ wct: WindowContainerTransaction,
+ deskId: Int?,
+ ): RunOnTransitStart? {
+ if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return null
+ if (deskId == null) return null
+ desksOrganizer.deactivateDesk(wct, deskId)
+ return { transition ->
+ desksTransitionObserver.addPendingTransition(
+ DeskTransition.DeactivateDesk(token = transition, deskId = deskId)
+ )
+ }
+ }
+
/** Removes the default desk in the given display. */
@Deprecated("Deprecated with multi-desks.", ReplaceWith("removeDesk()"))
fun removeDefaultDeskInDisplay(displayId: Int) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
index d4586abc8ec4..e57b56378fb3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
@@ -92,10 +92,11 @@ class DesksTransitionObserver(
}
}
is DeskTransition.DeactivateDesk -> {
+ var visibleDeactivation = false
for (change in info.changes) {
val isDeskChange = desksOrganizer.isDeskChange(change, deskTransition.deskId)
if (isDeskChange) {
- desktopRepository.setDeskInactive(deskId = deskTransition.deskId)
+ visibleDeactivation = true
continue
}
val taskId = change.taskInfo?.taskId ?: continue
@@ -109,6 +110,14 @@ class DesksTransitionObserver(
)
}
}
+ // Always deactivate even if there's no change that confirms the desk was
+ // deactivated. Some interactions, such as the desk deactivating because it's
+ // occluded by a fullscreen task result in a transition change, but others, such
+ // as transitioning from an empty desk to home may not.
+ if (!visibleDeactivation) {
+ logD("Deactivating desk without transition change")
+ }
+ desktopRepository.setDeskInactive(deskId = deskTransition.deskId)
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index c7134c53aad9..a25289d0ea79 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -984,7 +984,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
mDesktopTasksController.onDesktopWindowClose(
wct, mDisplayId, decoration.mTaskInfo);
final IBinder transition = mTaskOperations.closeTask(mTaskToken, wct);
- if (transition != null && runOnTransitionStart != null) {
+ if (transition != null) {
runOnTransitionStart.invoke(transition);
}
}
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 ed40acfdb705..e2c3dda0d927 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
@@ -2922,6 +2922,32 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onDesktopWindowClose_lastWindow_deactivatesDesk() {
+ val task = setUpFreeformTask()
+ val wct = WindowContainerTransaction()
+
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, task)
+
+ verify(desksOrganizer).deactivateDesk(wct, deskId = 0)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onDesktopWindowClose_lastWindow_addsPendingDeactivateTransition() {
+ val task = setUpFreeformTask()
+ val wct = WindowContainerTransaction()
+
+ val transition = Binder()
+ val runOnTransitStart =
+ controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, task)
+ runOnTransitStart(transition)
+
+ verify(desksTransitionsObserver)
+ .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId = 0))
+ }
+
+ @Test
fun onDesktopWindowMinimize_noActiveTask_doesntRemoveWallpaper() {
val task = setUpFreeformTask(active = false)
val transition = Binder()
@@ -2945,6 +2971,48 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onDesktopWindowMinimize_lastWindow_deactivatesDesk() {
+ val task = setUpFreeformTask()
+ val transition = Binder()
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
+ .thenReturn(transition)
+
+ controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
+
+ val captor = argumentCaptor<WindowContainerTransaction>()
+ verify(freeformTaskTransitionStarter)
+ .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(true))
+ verify(desksOrganizer).deactivateDesk(captor.firstValue, deskId = 0)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onDesktopWindowMinimize_lastWindow_addsPendingDeactivateTransition() {
+ val task = setUpFreeformTask()
+ val transition = Binder()
+ whenever(
+ freeformTaskTransitionStarter.startMinimizedModeTransition(
+ any(),
+ anyInt(),
+ anyBoolean(),
+ )
+ )
+ .thenReturn(transition)
+
+ controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
+
+ verify(desksTransitionsObserver)
+ .addPendingTransition(DeskTransition.DeactivateDesk(token = transition, deskId = 0))
+ }
+
+ @Test
fun onPipTaskMinimize_autoEnterEnabled_startPipTransition() {
val task = setUpPipTask(autoEnterEnabled = true)
val handler = mock(TransitionHandler::class.java)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
index 79310c9ce6c2..4dcf669f4d25 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
@@ -227,4 +227,21 @@ class DesksTransitionObserverTest : ShellTestCase() {
assertThat(repository.isActiveTaskInDesk(deskId = 5, taskId = exitingTask.taskId)).isFalse()
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onTransitionReady_deactivateDeskWithoutVisibleChange_updatesRepository() {
+ val transition = Binder()
+ val deactivateTransition = DeskTransition.DeactivateDesk(transition, deskId = 5)
+ repository.addDesk(DEFAULT_DISPLAY, deskId = 5)
+ repository.setActiveDesk(DEFAULT_DISPLAY, deskId = 5)
+
+ observer.addPendingTransition(deactivateTransition)
+ observer.onTransitionReady(
+ transition = transition,
+ info = TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0),
+ )
+
+ assertThat(repository.getActiveDeskId(DEFAULT_DISPLAY)).isNull()
+ }
}