Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +11 −0 Original line number Original line Diff line number Diff line Loading @@ -759,6 +759,17 @@ sealed class DragToDesktopTransitionHandler( startT.apply() startT.apply() finishCallback.onTransitionFinished(/* wct= */ null) finishCallback.onTransitionFinished(/* wct= */ null) startTransitionFinishCb.onTransitionFinished(/* wct= */ null) startTransitionFinishCb.onTransitionFinished(/* wct= */ null) // For splitscreen, dragging upward to "cancel" actually is a signal from the user // that we want to go to fullscreen. We will cancel the desktop transition, let // splitscreen go back to where it was, and then expand to fullscreen. // TODO (b/396438812): Let this be a single transition that actually goes straight // to fullscreen if (state is TransitionState.FromSplit) { splitScreenController.moveTaskToFullscreen( state.draggedTaskId, SplitScreenController.EXIT_REASON_DRAG_TO_FULLSCREEN, ) } clearState() clearState() return return } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +5 −1 Original line number Original line Diff line number Diff line Loading @@ -153,6 +153,7 @@ public class SplitScreenController implements SplitDragPolicy.Starter, public static final int EXIT_REASON_DESKTOP_MODE = 12; public static final int EXIT_REASON_DESKTOP_MODE = 12; public static final int EXIT_REASON_FULLSCREEN_REQUEST = 13; public static final int EXIT_REASON_FULLSCREEN_REQUEST = 13; public static final int EXIT_REASON_CHILD_TASK_ENTER_BUBBLE = 14; public static final int EXIT_REASON_CHILD_TASK_ENTER_BUBBLE = 14; public static final int EXIT_REASON_DRAG_TO_FULLSCREEN = 15; @IntDef(value = { @IntDef(value = { EXIT_REASON_UNKNOWN, EXIT_REASON_UNKNOWN, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW, Loading @@ -168,7 +169,8 @@ public class SplitScreenController implements SplitDragPolicy.Starter, EXIT_REASON_FULLSCREEN_SHORTCUT, EXIT_REASON_FULLSCREEN_SHORTCUT, EXIT_REASON_DESKTOP_MODE, EXIT_REASON_DESKTOP_MODE, EXIT_REASON_FULLSCREEN_REQUEST, EXIT_REASON_FULLSCREEN_REQUEST, EXIT_REASON_CHILD_TASK_ENTER_BUBBLE EXIT_REASON_CHILD_TASK_ENTER_BUBBLE, EXIT_REASON_DRAG_TO_FULLSCREEN }) }) @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) @interface ExitReason{} @interface ExitReason{} Loading Loading @@ -1081,6 +1083,8 @@ public class SplitScreenController implements SplitDragPolicy.Starter, return "DESKTOP_MODE"; return "DESKTOP_MODE"; case EXIT_REASON_FULLSCREEN_REQUEST: case EXIT_REASON_FULLSCREEN_REQUEST: return "FULLSCREEN_REQUEST"; return "FULLSCREEN_REQUEST"; case EXIT_REASON_DRAG_TO_FULLSCREEN: return "EXIT_REASON_DRAG_TO_FULLSCREEN"; default: default: return "unknown reason, reason int = " + exitReason; return "unknown reason, reason int = " + exitReason; } } Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt +53 −1 Original line number Original line Diff line number Diff line Loading @@ -378,6 +378,40 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { assertFalse("Drag should not be in progress after cancelling", defaultHandler.inProgress) assertFalse("Drag should not be in progress after cancelling", defaultHandler.inProgress) } } @Test fun cancelSplitDragToDesktop_startWasReady_cancel_merged_and_starts_splitscreen_transition() { val draggedTask = createTask(windowingMode = WINDOWING_MODE_MULTI_WINDOW) val otherTask = createTask(windowingMode = WINDOWING_MODE_MULTI_WINDOW) whenever(splitScreenController.getTaskInfo(anyInt())).thenReturn(otherTask) val startToken = startDrag(defaultHandler, task = draggedTask) // Then user cancelled after it had already started. val cancelToken = cancelDragToDesktopTransition( defaultHandler, DragToDesktopTransitionHandler.CancelState.STANDARD_CANCEL, ) defaultHandler.mergeAnimation( cancelToken, TransitionInfo(TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP, 0), mock<SurfaceControl.Transaction>(), mock<SurfaceControl.Transaction>(), startToken, mock<Transitions.TransitionFinishCallback>(), ) // Cancel animation should run since it had already started. verify(dragAnimator).cancelAnimator() assertFalse("Drag should not be in progress after cancelling", defaultHandler.inProgress) // Splitscreen should expand to fullscreen after the regular cancel transition finishes. verify(splitScreenController) .moveTaskToFullscreen( draggedTask.taskId, SplitScreenController.EXIT_REASON_DRAG_TO_FULLSCREEN, ) } @Test @Test fun cancelDragToDesktop_startWasReady_cancel_aborted() { fun cancelDragToDesktop_startWasReady_cancel_aborted() { val startToken = startDrag(defaultHandler) val startToken = startDrag(defaultHandler) Loading Loading @@ -1149,6 +1183,15 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { finishCallback: Transitions.TransitionFinishCallback = mock(), finishCallback: Transitions.TransitionFinishCallback = mock(), ): IBinder { ): IBinder { whenever(dragAnimator.position).thenReturn(PointF()) whenever(dragAnimator.position).thenReturn(PointF()) val splitStageChange: TransitionInfo.Change? = if (task.windowingMode == WINDOWING_MODE_MULTI_WINDOW) { createSplitStageChange().let { change -> task.parentTaskId = checkNotNull(change.taskInfo).taskId change } } else { null } // Simulate transition is started and is ready to animate. // Simulate transition is started and is ready to animate. val transition = startDragToDesktopTransition(handler, task, dragAnimator) val transition = startDragToDesktopTransition(handler, task, dragAnimator) handler.startAnimation( handler.startAnimation( Loading @@ -1158,6 +1201,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { type = TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP, type = TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP, draggedTask = task, draggedTask = task, homeChange = homeChange, homeChange = homeChange, splitStageChange = splitStageChange, rootLeash = transitionRootLeash, rootLeash = transitionRootLeash, ), ), startTransaction = startTransaction, startTransaction = startTransaction, Loading Loading @@ -1255,16 +1299,18 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { homeChange: TransitionInfo.Change? = createHomeChange(), homeChange: TransitionInfo.Change? = createHomeChange(), rootLeash: SurfaceControl = mock(), rootLeash: SurfaceControl = mock(), deskChange: TransitionInfo.Change? = null, deskChange: TransitionInfo.Change? = null, splitStageChange: TransitionInfo.Change? = null, ) = ) = TransitionInfo(type, /* flags= */ 0).apply { TransitionInfo(type, /* flags= */ 0).apply { homeChange?.let { addChange(it) } homeChange?.let { addChange(it) } addChange( // Dragged Task. addChange( // Dragged Task. TransitionInfo.Change(mock(), draggedTaskLeash).apply { TransitionInfo.Change(mock(), draggedTaskLeash).apply { parent = null parent = splitStageChange?.taskInfo?.token taskInfo = draggedTask taskInfo = draggedTask } } ) ) deskChange?.let { addChange(it) } deskChange?.let { addChange(it) } splitStageChange?.let { addChange(it) } addChange( // Wallpaper. addChange( // Wallpaper. TransitionInfo.Change(mock(), wallpaperLeash).apply { TransitionInfo.Change(mock(), wallpaperLeash).apply { parent = null parent = null Loading @@ -1288,6 +1334,12 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { taskInfo = TestRunningTaskInfoBuilder().build() taskInfo = TestRunningTaskInfoBuilder().build() } } private fun createSplitStageChange() = TransitionInfo.Change(mock(), mock()).apply { parent = null taskInfo = TestRunningTaskInfoBuilder().build() } private fun systemPropertiesKey(name: String) = private fun systemPropertiesKey(name: String) = "${SpringDragToDesktopTransitionHandler.SYSTEM_PROPERTIES_GROUP}.$name" "${SpringDragToDesktopTransitionHandler.SYSTEM_PROPERTIES_GROUP}.$name" Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +11 −0 Original line number Original line Diff line number Diff line Loading @@ -759,6 +759,17 @@ sealed class DragToDesktopTransitionHandler( startT.apply() startT.apply() finishCallback.onTransitionFinished(/* wct= */ null) finishCallback.onTransitionFinished(/* wct= */ null) startTransitionFinishCb.onTransitionFinished(/* wct= */ null) startTransitionFinishCb.onTransitionFinished(/* wct= */ null) // For splitscreen, dragging upward to "cancel" actually is a signal from the user // that we want to go to fullscreen. We will cancel the desktop transition, let // splitscreen go back to where it was, and then expand to fullscreen. // TODO (b/396438812): Let this be a single transition that actually goes straight // to fullscreen if (state is TransitionState.FromSplit) { splitScreenController.moveTaskToFullscreen( state.draggedTaskId, SplitScreenController.EXIT_REASON_DRAG_TO_FULLSCREEN, ) } clearState() clearState() return return } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +5 −1 Original line number Original line Diff line number Diff line Loading @@ -153,6 +153,7 @@ public class SplitScreenController implements SplitDragPolicy.Starter, public static final int EXIT_REASON_DESKTOP_MODE = 12; public static final int EXIT_REASON_DESKTOP_MODE = 12; public static final int EXIT_REASON_FULLSCREEN_REQUEST = 13; public static final int EXIT_REASON_FULLSCREEN_REQUEST = 13; public static final int EXIT_REASON_CHILD_TASK_ENTER_BUBBLE = 14; public static final int EXIT_REASON_CHILD_TASK_ENTER_BUBBLE = 14; public static final int EXIT_REASON_DRAG_TO_FULLSCREEN = 15; @IntDef(value = { @IntDef(value = { EXIT_REASON_UNKNOWN, EXIT_REASON_UNKNOWN, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW, Loading @@ -168,7 +169,8 @@ public class SplitScreenController implements SplitDragPolicy.Starter, EXIT_REASON_FULLSCREEN_SHORTCUT, EXIT_REASON_FULLSCREEN_SHORTCUT, EXIT_REASON_DESKTOP_MODE, EXIT_REASON_DESKTOP_MODE, EXIT_REASON_FULLSCREEN_REQUEST, EXIT_REASON_FULLSCREEN_REQUEST, EXIT_REASON_CHILD_TASK_ENTER_BUBBLE EXIT_REASON_CHILD_TASK_ENTER_BUBBLE, EXIT_REASON_DRAG_TO_FULLSCREEN }) }) @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) @interface ExitReason{} @interface ExitReason{} Loading Loading @@ -1081,6 +1083,8 @@ public class SplitScreenController implements SplitDragPolicy.Starter, return "DESKTOP_MODE"; return "DESKTOP_MODE"; case EXIT_REASON_FULLSCREEN_REQUEST: case EXIT_REASON_FULLSCREEN_REQUEST: return "FULLSCREEN_REQUEST"; return "FULLSCREEN_REQUEST"; case EXIT_REASON_DRAG_TO_FULLSCREEN: return "EXIT_REASON_DRAG_TO_FULLSCREEN"; default: default: return "unknown reason, reason int = " + exitReason; return "unknown reason, reason int = " + exitReason; } } Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt +53 −1 Original line number Original line Diff line number Diff line Loading @@ -378,6 +378,40 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { assertFalse("Drag should not be in progress after cancelling", defaultHandler.inProgress) assertFalse("Drag should not be in progress after cancelling", defaultHandler.inProgress) } } @Test fun cancelSplitDragToDesktop_startWasReady_cancel_merged_and_starts_splitscreen_transition() { val draggedTask = createTask(windowingMode = WINDOWING_MODE_MULTI_WINDOW) val otherTask = createTask(windowingMode = WINDOWING_MODE_MULTI_WINDOW) whenever(splitScreenController.getTaskInfo(anyInt())).thenReturn(otherTask) val startToken = startDrag(defaultHandler, task = draggedTask) // Then user cancelled after it had already started. val cancelToken = cancelDragToDesktopTransition( defaultHandler, DragToDesktopTransitionHandler.CancelState.STANDARD_CANCEL, ) defaultHandler.mergeAnimation( cancelToken, TransitionInfo(TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP, 0), mock<SurfaceControl.Transaction>(), mock<SurfaceControl.Transaction>(), startToken, mock<Transitions.TransitionFinishCallback>(), ) // Cancel animation should run since it had already started. verify(dragAnimator).cancelAnimator() assertFalse("Drag should not be in progress after cancelling", defaultHandler.inProgress) // Splitscreen should expand to fullscreen after the regular cancel transition finishes. verify(splitScreenController) .moveTaskToFullscreen( draggedTask.taskId, SplitScreenController.EXIT_REASON_DRAG_TO_FULLSCREEN, ) } @Test @Test fun cancelDragToDesktop_startWasReady_cancel_aborted() { fun cancelDragToDesktop_startWasReady_cancel_aborted() { val startToken = startDrag(defaultHandler) val startToken = startDrag(defaultHandler) Loading Loading @@ -1149,6 +1183,15 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { finishCallback: Transitions.TransitionFinishCallback = mock(), finishCallback: Transitions.TransitionFinishCallback = mock(), ): IBinder { ): IBinder { whenever(dragAnimator.position).thenReturn(PointF()) whenever(dragAnimator.position).thenReturn(PointF()) val splitStageChange: TransitionInfo.Change? = if (task.windowingMode == WINDOWING_MODE_MULTI_WINDOW) { createSplitStageChange().let { change -> task.parentTaskId = checkNotNull(change.taskInfo).taskId change } } else { null } // Simulate transition is started and is ready to animate. // Simulate transition is started and is ready to animate. val transition = startDragToDesktopTransition(handler, task, dragAnimator) val transition = startDragToDesktopTransition(handler, task, dragAnimator) handler.startAnimation( handler.startAnimation( Loading @@ -1158,6 +1201,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { type = TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP, type = TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP, draggedTask = task, draggedTask = task, homeChange = homeChange, homeChange = homeChange, splitStageChange = splitStageChange, rootLeash = transitionRootLeash, rootLeash = transitionRootLeash, ), ), startTransaction = startTransaction, startTransaction = startTransaction, Loading Loading @@ -1255,16 +1299,18 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { homeChange: TransitionInfo.Change? = createHomeChange(), homeChange: TransitionInfo.Change? = createHomeChange(), rootLeash: SurfaceControl = mock(), rootLeash: SurfaceControl = mock(), deskChange: TransitionInfo.Change? = null, deskChange: TransitionInfo.Change? = null, splitStageChange: TransitionInfo.Change? = null, ) = ) = TransitionInfo(type, /* flags= */ 0).apply { TransitionInfo(type, /* flags= */ 0).apply { homeChange?.let { addChange(it) } homeChange?.let { addChange(it) } addChange( // Dragged Task. addChange( // Dragged Task. TransitionInfo.Change(mock(), draggedTaskLeash).apply { TransitionInfo.Change(mock(), draggedTaskLeash).apply { parent = null parent = splitStageChange?.taskInfo?.token taskInfo = draggedTask taskInfo = draggedTask } } ) ) deskChange?.let { addChange(it) } deskChange?.let { addChange(it) } splitStageChange?.let { addChange(it) } addChange( // Wallpaper. addChange( // Wallpaper. TransitionInfo.Change(mock(), wallpaperLeash).apply { TransitionInfo.Change(mock(), wallpaperLeash).apply { parent = null parent = null Loading @@ -1288,6 +1334,12 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() { taskInfo = TestRunningTaskInfoBuilder().build() taskInfo = TestRunningTaskInfoBuilder().build() } } private fun createSplitStageChange() = TransitionInfo.Change(mock(), mock()).apply { parent = null taskInfo = TestRunningTaskInfoBuilder().build() } private fun systemPropertiesKey(name: String) = private fun systemPropertiesKey(name: String) = "${SpringDragToDesktopTransitionHandler.SYSTEM_PROPERTIES_GROUP}.$name" "${SpringDragToDesktopTransitionHandler.SYSTEM_PROPERTIES_GROUP}.$name" Loading