diff options
Diffstat (limited to 'libs')
8 files changed, 273 insertions, 33 deletions
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 c9b3ec0d3a11..1f7edb413908 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 @@ -71,9 +71,31 @@ class DesktopMixedTransitionHandler( wct: WindowContainerTransaction?, ) = freeformTaskTransitionHandler.startWindowingModeTransition(targetWindowingMode, wct) - /** Delegates starting minimized mode transition to [FreeformTaskTransitionHandler]. */ - override fun startMinimizedModeTransition(wct: WindowContainerTransaction?): IBinder = - freeformTaskTransitionHandler.startMinimizedModeTransition(wct) + /** + * Starts a minimize transition for [taskId], with [isLastTask] which is true if the task going + * to be minimized is the last visible task. + */ + override fun startMinimizedModeTransition( + wct: WindowContainerTransaction?, + taskId: Int, + isLastTask: Boolean, + ): IBinder { + if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX.isTrue) { + return freeformTaskTransitionHandler.startMinimizedModeTransition( + wct, + taskId, + isLastTask, + ) + } + requireNotNull(wct) + return transitions + .startTransition(Transitions.TRANSIT_MINIMIZE, wct, /* handler= */ this) + .also { transition -> + pendingMixedTransitions.add( + PendingMixedTransition.Minimize(transition, taskId, isLastTask) + ) + } + } /** Delegates starting PiP transition to [FreeformTaskTransitionHandler]. */ override fun startPipTransition(wct: WindowContainerTransaction?): IBinder = @@ -298,7 +320,15 @@ class DesktopMixedTransitionHandler( finishTransaction: SurfaceControl.Transaction, finishCallback: TransitionFinishCallback, ): Boolean { - if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue) return false + val shouldAnimate = + if (info.type == Transitions.TRANSIT_MINIMIZE) { + DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX.isTrue + } else { + DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue + } + if (!shouldAnimate) { + return false + } val minimizeChange = findTaskChange(info, pending.minimizingTask) if (minimizeChange == null) { 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 f17b680f6fae..bbf00104711f 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 @@ -844,7 +844,9 @@ class DesktopTasksController( ) wct.reorder(taskInfo.token, false) - val transition = freeformTaskTransitionStarter.startMinimizedModeTransition(wct) + val isLastTask = taskRepository.isOnlyVisibleNonClosingTask(taskId, displayId) + val transition: IBinder = + freeformTaskTransitionStarter.startMinimizedModeTransition(wct, taskId, isLastTask) desktopTasksLimiter.ifPresent { it.addPendingMinimizeChange( transition = transition, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java index 31715f0444a9..b60fb5e7bfdd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java @@ -93,7 +93,8 @@ public class FreeformTaskTransitionHandler } @Override - public IBinder startMinimizedModeTransition(WindowContainerTransaction wct) { + public IBinder startMinimizedModeTransition( + WindowContainerTransaction wct, int taskId, boolean isLastTask) { final int type = Transitions.TRANSIT_MINIMIZE; final IBinder token = mTransitions.startTransition(type, wct, this); mPendingTransitionTokens.add(token); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java index a874a5be426d..822934c1e646 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java @@ -38,10 +38,13 @@ public interface FreeformTaskTransitionStarter { * Starts window minimization transition * * @param wct the {@link WindowContainerTransaction} that changes the windowing mode + * @param taskId the task id of the task being minimized + * @param isLastTask true if the task being minimized is the last visible task * * @return the started transition */ - IBinder startMinimizedModeTransition(WindowContainerTransaction wct); + IBinder startMinimizedModeTransition( + WindowContainerTransaction wct, int taskId, boolean isLastTask); /** * Starts close window transition @@ -60,4 +63,4 @@ public interface FreeformTaskTransitionStarter { * @return the started transition */ IBinder startPipTransition(WindowContainerTransaction wct); -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index 7aa00370ff58..dd5439a8aa10 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -389,7 +389,9 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT } else if (id == R.id.back_button) { mTaskOperations.injectBackKey(mDisplayId); } else if (id == R.id.minimize_window) { - mTaskOperations.minimizeTask(mTaskToken); + // This minimize button uses the same effect for any minimization. The last argument + // doesn't matter. + mTaskOperations.minimizeTask(mTaskToken, mTaskId, /* isLastTask= */ false); } else if (id == R.id.maximize_window) { RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); final DisplayAreaInfo rootDisplayAreaInfo = diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java index bc85d2b40748..45ba4413814c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java @@ -86,14 +86,18 @@ class TaskOperations { return null; } - IBinder minimizeTask(WindowContainerToken taskToken) { - return minimizeTask(taskToken, new WindowContainerTransaction()); + IBinder minimizeTask(WindowContainerToken taskToken, int taskId, boolean isLastTask) { + return minimizeTask(taskToken, taskId, isLastTask, new WindowContainerTransaction()); } - IBinder minimizeTask(WindowContainerToken taskToken, WindowContainerTransaction wct) { + IBinder minimizeTask( + WindowContainerToken taskToken, + int taskId, + boolean isLastTask, + WindowContainerTransaction wct) { wct.reorder(taskToken, false); if (Transitions.ENABLE_SHELL_TRANSITIONS) { - return mTransitionStarter.startMinimizedModeTransition(wct); + return mTransitionStarter.startMinimizedModeTransition(wct, taskId, isLastTask); } else { mSyncQueue.queue(wct); return null; 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 0b41952a89d7..77cd1e56853d 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 @@ -58,6 +58,7 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito @@ -128,12 +129,21 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { @Test fun startMinimizedModeTransition_callsFreeformTaskTransitionHandler() { val wct = WindowContainerTransaction() - whenever(freeformTaskTransitionHandler.startMinimizedModeTransition(any())) + val taskId = 1 + val isLastTask = false + whenever( + freeformTaskTransitionHandler.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(mock()) - mixedHandler.startMinimizedModeTransition(wct) + mixedHandler.startMinimizedModeTransition(wct, taskId, isLastTask) - verify(freeformTaskTransitionHandler).startMinimizedModeTransition(wct) + verify(freeformTaskTransitionHandler) + .startMinimizedModeTransition(eq(wct), eq(taskId), eq(isLastTask)) } @Test @@ -531,6 +541,131 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX) + fun startMinimizedModeTransition_exitByMinimizeTransitionFlagsDisabled_doesNotUseMixedHandler() { + val wct = WindowContainerTransaction() + val task = createTask(WINDOWING_MODE_FREEFORM) + whenever( + freeformTaskTransitionHandler.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) + .thenReturn(mock()) + + mixedHandler.startMinimizedModeTransition( + wct = wct, + taskId = task.taskId, + isLastTask = true, + ) + + verify(freeformTaskTransitionHandler) + .startMinimizedModeTransition(eq(wct), eq(task.taskId), eq(true)) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX) + fun startMinimizedModeTransition_exitByMinimizeTransitionFlagsEnabled_notLastTask_callsMinimizationHandler() { + val wct = WindowContainerTransaction() + val minimizingTask = createTask(WINDOWING_MODE_FREEFORM) + val minimizingTaskChange = createChange(minimizingTask) + val transition = Binder() + whenever( + transitions.startTransition(eq(Transitions.TRANSIT_MINIMIZE), eq(wct), anyOrNull()) + ) + .thenReturn(transition) + whenever( + desktopMinimizationTransitionHandler.startAnimation( + any(), + any(), + any(), + any(), + any(), + ) + ) + .thenReturn(true) + + mixedHandler.startMinimizedModeTransition( + wct = wct, + taskId = minimizingTask.taskId, + isLastTask = false, + ) + val started = + mixedHandler.startAnimation( + transition = transition, + info = + createCloseTransitionInfo( + Transitions.TRANSIT_MINIMIZE, + listOf(minimizingTaskChange), + ), + startTransaction = mock(), + finishTransaction = mock(), + finishCallback = {}, + ) + + assertTrue("Should delegate animation to minimization transition handler", started) + verify(desktopMinimizationTransitionHandler) + .startAnimation( + eq(transition), + argThat { info -> info.changes.contains(minimizingTaskChange) }, + any(), + any(), + any(), + ) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX) + fun startMinimizedModeTransition_exitByMinimizeTransitionFlagsEnabled_withMinimizingLastTask_dispatchesTransition() { + val wct = WindowContainerTransaction() + val minimizingTask = createTask(WINDOWING_MODE_FREEFORM) + val minimizingTaskChange = createChange(minimizingTask) + val transition = Binder() + whenever( + transitions.startTransition(eq(Transitions.TRANSIT_MINIMIZE), eq(wct), anyOrNull()) + ) + .thenReturn(transition) + whenever( + desktopMinimizationTransitionHandler.startAnimation( + any(), + any(), + any(), + any(), + any(), + ) + ) + .thenReturn(true) + + mixedHandler.startMinimizedModeTransition( + wct = wct, + taskId = minimizingTask.taskId, + isLastTask = true, + ) + mixedHandler.startAnimation( + transition = transition, + info = + createCloseTransitionInfo( + Transitions.TRANSIT_MINIMIZE, + listOf(minimizingTaskChange), + ), + startTransaction = mock(), + finishTransaction = mock(), + finishCallback = {}, + ) + + verify(transitions) + .dispatchTransition( + eq(transition), + argThat { info -> info.changes.contains(minimizingTaskChange) }, + any(), + any(), + any(), + eq(mixedHandler), + ) + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX) fun addPendingAndAnimateLaunchTransition_noMinimizeChange_doesNotReparentMinimizeChange() { val wct = WindowContainerTransaction() 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 3ee9501dd8dd..eb4ec1189b0b 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 @@ -179,6 +179,7 @@ import org.mockito.ArgumentMatchers.isA import org.mockito.ArgumentMatchers.isNull import org.mockito.Mock import org.mockito.Mockito +import org.mockito.Mockito.anyBoolean import org.mockito.Mockito.anyInt import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.mock @@ -2763,13 +2764,20 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() fun onDesktopWindowMinimize_noActiveTask_doesntRemoveWallpaper() { val task = setUpFreeformTask(active = false) val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(false)) captor.firstValue.hierarchyOps.none { hop -> hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder() } @@ -2785,18 +2793,26 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) verify(freeformTaskTransitionStarter).startPipTransition(any()) - verify(freeformTaskTransitionStarter, never()).startMinimizedModeTransition(any()) + verify(freeformTaskTransitionStarter, never()) + .startMinimizedModeTransition(any(), anyInt(), anyBoolean()) } @Test fun onPipTaskMinimize_autoEnterDisabled_startMinimizeTransition() { val task = setUpPipTask(autoEnterEnabled = false) - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(Binder()) controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(any()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(any(), eq(task.taskId), anyBoolean()) verify(freeformTaskTransitionStarter, never()).startPipTransition(any()) } @@ -2820,13 +2836,20 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() fun onDesktopWindowMinimize_singleActiveTask_noWallpaperActivityToken_doesntRemoveWallpaper() { val task = setUpFreeformTask(active = true) val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(true)) captor.firstValue.hierarchyOps.none { hop -> hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK } } @@ -2835,14 +2858,21 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() fun onTaskMinimize_singleActiveTask_hasWallpaperActivityToken_removesWallpaper() { val task = setUpFreeformTask() val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) // The only active task is being minimized. controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(true)) // Adds remove wallpaper operation captor.firstValue.assertReorderAt(index = 0, wallpaperToken, toTop = false) } @@ -2851,7 +2881,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() fun onDesktopWindowMinimize_singleActiveTask_alreadyMinimized_doesntRemoveWallpaper() { val task = setUpFreeformTask() val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) taskRepository.minimizeTask(DEFAULT_DISPLAY, task.taskId) @@ -2859,7 +2895,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task.taskId), eq(false)) captor.firstValue.hierarchyOps.none { hop -> hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder() } @@ -2870,13 +2907,20 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task1 = setUpFreeformTask(active = true) setUpFreeformTask(active = true) val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) controller.minimizeTask(task1, MinimizeReason.MINIMIZE_BUTTON) val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task1.taskId), eq(false)) captor.firstValue.hierarchyOps.none { hop -> hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder() } @@ -2888,7 +2932,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task1 = setUpFreeformTask(active = true) val task2 = setUpFreeformTask(active = true) val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) taskRepository.minimizeTask(DEFAULT_DISPLAY, task2.taskId) @@ -2896,7 +2946,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() controller.minimizeTask(task1, MinimizeReason.MINIMIZE_BUTTON) // Adds remove wallpaper operation val captor = argumentCaptor<WindowContainerTransaction>() - verify(freeformTaskTransitionStarter).startMinimizedModeTransition(captor.capture()) + verify(freeformTaskTransitionStarter) + .startMinimizedModeTransition(captor.capture(), eq(task1.taskId), eq(true)) // Adds remove wallpaper operation captor.firstValue.assertReorderAt(index = 0, wallpaperToken, toTop = false) } @@ -2905,7 +2956,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() fun onDesktopWindowMinimize_triesToExitImmersive() { val task = setUpFreeformTask() val transition = Binder() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) @@ -2918,7 +2975,13 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val task = setUpFreeformTask() val transition = Binder() val runOnTransit = RunOnStartTransitionCallback() - whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) .thenReturn(transition) whenever(mMockDesktopImmersiveController.exitImmersiveIfApplicable(any(), eq(task), any())) .thenReturn( |