summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt47
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt117
3 files changed, 180 insertions, 5 deletions
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index 0150bcdbd412..6bc995f14d44 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -102,6 +102,15 @@ public class DesktopModeStatus {
"persist.wm.debug.enter_desktop_by_default_on_freeform_display";
/**
+ * Sysprop declaring whether to enable drag-to-maximize for desktop windows.
+ *
+ * <p>If it is not defined, then {@code R.integer.config_dragToMaximizeInDesktopMode}
+ * is used.
+ */
+ public static final String ENABLE_DRAG_TO_MAXIMIZE_SYS_PROP =
+ "persist.wm.debug.enable_drag_to_maximize";
+
+ /**
* Sysprop declaring the maximum number of Tasks to show in Desktop Mode at any one time.
*
* <p>If it is not defined, then {@code R.integer.config_maxDesktopWindowingActiveTasks} is
@@ -230,6 +239,18 @@ public class DesktopModeStatus {
R.bool.config_enterDesktopByDefaultOnFreeformDisplay));
}
+ /**
+ * Return {@code true} if a window should be maximized when it's dragged to the top edge of the
+ * screen.
+ */
+ public static boolean shouldMaximizeWhenDragToTopEdge(@NonNull Context context) {
+ if (!Flags.enableDragToMaximize()) {
+ return false;
+ }
+ return SystemProperties.getBoolean(ENABLE_DRAG_TO_MAXIMIZE_SYS_PROP,
+ context.getResources().getBoolean(R.bool.config_dragToMaximizeInDesktopMode));
+ }
+
/** Dumps DesktopModeStatus flags and configs. */
public static void dump(PrintWriter pw, String prefix, Context context) {
String innerPrefix = prefix + " ";
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 3d3c072727be..577c18cfa5e4 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
@@ -857,6 +857,39 @@ class DesktopTasksController(
toggleResizeDesktopTaskTransitionHandler.startTransition(wct)
}
+ private fun dragToMaximizeDesktopTask(
+ taskInfo: RunningTaskInfo,
+ taskSurface: SurfaceControl,
+ currentDragBounds: Rect,
+ motionEvent: MotionEvent
+ ) {
+ val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
+ val stableBounds = Rect()
+ displayLayout.getStableBounds(stableBounds)
+ if (isTaskMaximized(taskInfo, stableBounds)) {
+ // Handle the case where we attempt to drag-to-maximize when already maximized: the task
+ // position won't need to change but we want to animate the surface going back to the
+ // maximized position.
+ val containerBounds = taskInfo.configuration.windowConfiguration.bounds
+ if (containerBounds != currentDragBounds) {
+ returnToDragStartAnimator.start(
+ taskInfo.taskId,
+ taskSurface,
+ startBounds = currentDragBounds,
+ endBounds = containerBounds,
+ isResizable = taskInfo.isResizeable
+ )
+ }
+ return
+ }
+
+ // TODO(b/375356605): Introduce a new ResizeTrigger for drag-to-top.
+ desktopModeEventLogger.logTaskResizingStarted(
+ ResizeTrigger.UNKNOWN_RESIZE_TRIGGER, motionEvent, taskInfo, displayController
+ )
+ toggleDesktopTaskSize(taskInfo, ResizeTrigger.UNKNOWN_RESIZE_TRIGGER, motionEvent)
+ }
+
private fun getMaximizeBounds(taskInfo: RunningTaskInfo, stableBounds: Rect): Rect {
if (taskInfo.isResizeable) {
// if resizable then expand to entire stable bounds (full display minus insets)
@@ -1918,11 +1951,15 @@ class DesktopTasksController(
)
when (indicatorType) {
IndicatorType.TO_FULLSCREEN_INDICATOR -> {
- moveToFullscreenWithAnimation(
- taskInfo,
- position,
- DesktopModeTransitionSource.TASK_DRAG
- )
+ if (DesktopModeStatus.shouldMaximizeWhenDragToTopEdge(context)) {
+ dragToMaximizeDesktopTask(taskInfo, taskSurface, currentDragBounds, motionEvent)
+ } else {
+ moveToFullscreenWithAnimation(
+ taskInfo,
+ position,
+ DesktopModeTransitionSource.TASK_DRAG
+ )
+ }
}
IndicatorType.TO_SPLIT_LEFT_INDICATOR -> {
handleSnapResizingTask(
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 62d2c987ac5d..051079c9d519 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
@@ -2914,6 +2914,123 @@ class DesktopTasksControllerTest : ShellTestCase() {
}
@Test
+ fun onDesktopDragEnd_fullscreenIndicator_dragToExitDesktop() {
+ val task = setUpFreeformTask(bounds = Rect(0, 0, 100, 100))
+ val spyController = spy(controller)
+ val mockSurface = mock(SurfaceControl::class.java)
+ val mockDisplayLayout = mock(DisplayLayout::class.java)
+ val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
+ tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
+ whenever(displayController.getDisplayLayout(task.displayId)).thenReturn(mockDisplayLayout)
+ whenever(mockDisplayLayout.stableInsets()).thenReturn(Rect(0, 100, 2000, 2000))
+ whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ (i.arguments.first() as Rect).set(STABLE_BOUNDS)
+ }
+ whenever(DesktopModeStatus.shouldMaximizeWhenDragToTopEdge(context)).thenReturn(false)
+ whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
+ .thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR)
+
+ // Drag move the task to the top edge
+ spyController.onDragPositioningMove(task, mockSurface, 200f, Rect(100, 200, 500, 1000))
+ spyController.onDragPositioningEnd(
+ task,
+ mockSurface,
+ Point(100, 50), /* position */
+ PointF(200f, 300f), /* inputCoordinate */
+ Rect(100, 50, 500, 1000), /* currentDragBounds */
+ Rect(0, 50, 2000, 2000) /* validDragArea */,
+ Rect() /* dragStartBounds */,
+ motionEvent,
+ desktopWindowDecoration)
+
+ // Assert the task exits desktop mode
+ val wct = getLatestExitDesktopWct()
+ assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_UNDEFINED)
+ }
+
+ @Test
+ fun onDesktopDragEnd_fullscreenIndicator_dragToMaximize() {
+ val task = setUpFreeformTask(bounds = Rect(0, 0, 100, 100))
+ val spyController = spy(controller)
+ val mockSurface = mock(SurfaceControl::class.java)
+ val mockDisplayLayout = mock(DisplayLayout::class.java)
+ val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
+ tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
+ whenever(displayController.getDisplayLayout(task.displayId)).thenReturn(mockDisplayLayout)
+ whenever(mockDisplayLayout.stableInsets()).thenReturn(Rect(0, 100, 2000, 2000))
+ whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ (i.arguments.first() as Rect).set(STABLE_BOUNDS)
+ }
+ whenever(DesktopModeStatus.shouldMaximizeWhenDragToTopEdge(context)).thenReturn(true)
+ whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
+ .thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR)
+
+ // Drag move the task to the top edge
+ spyController.onDragPositioningMove(task, mockSurface, 200f, Rect(100, 200, 500, 1000))
+ spyController.onDragPositioningEnd(
+ task,
+ mockSurface,
+ Point(100, 50), /* position */
+ PointF(200f, 300f), /* inputCoordinate */
+ Rect(100, 50, 500, 1000), /* currentDragBounds */
+ Rect(0, 50, 2000, 2000) /* validDragArea */,
+ Rect() /* dragStartBounds */,
+ motionEvent,
+ desktopWindowDecoration)
+
+ // Assert bounds set to stable bounds
+ val wct = getLatestToggleResizeDesktopTaskWct()
+ assertThat(findBoundsChange(wct, task)).isEqualTo(STABLE_BOUNDS)
+ }
+
+ @Test
+ fun onDesktopDragEnd_fullscreenIndicator_dragToMaximize_noBoundsChange() {
+ val task = setUpFreeformTask(bounds = STABLE_BOUNDS)
+ val spyController = spy(controller)
+ val mockSurface = mock(SurfaceControl::class.java)
+ val mockDisplayLayout = mock(DisplayLayout::class.java)
+ val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
+ tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
+ whenever(displayController.getDisplayLayout(task.displayId)).thenReturn(mockDisplayLayout)
+ whenever(mockDisplayLayout.stableInsets()).thenReturn(Rect(0, 100, 2000, 2000))
+ whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ (i.arguments.first() as Rect).set(STABLE_BOUNDS)
+ }
+ whenever(DesktopModeStatus.shouldMaximizeWhenDragToTopEdge(context)).thenReturn(true)
+ whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
+ whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
+ .thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR)
+
+ // Drag move the task to the top edge
+ val currentDragBounds = Rect(100, 50, 500, 1000)
+ spyController.onDragPositioningMove(task, mockSurface, 200f, Rect(100, 200, 500, 1000))
+ spyController.onDragPositioningEnd(
+ task,
+ mockSurface,
+ Point(100, 50), /* position */
+ PointF(200f, 300f), /* inputCoordinate */
+ currentDragBounds, /* currentDragBounds */
+ Rect(0, 50, 2000, 2000) /* validDragArea */,
+ Rect() /* dragStartBounds */,
+ motionEvent,
+ desktopWindowDecoration)
+
+ // Assert that task is NOT updated via WCT
+ verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any())
+ // Assert that task leash is updated via Surface Animations
+ verify(mReturnToDragStartAnimator).start(
+ eq(task.taskId),
+ eq(mockSurface),
+ eq(currentDragBounds),
+ eq(STABLE_BOUNDS),
+ eq(true)
+ )
+ }
+
+ @Test
fun enterSplit_freeformTaskIsMovedToSplit() {
val task1 = setUpFreeformTask()
val task2 = setUpFreeformTask()