Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b767920d authored by mattsziklay's avatar mattsziklay
Browse files

Update the stable bounds stored in TaskPositioners on new drag.

Updates the stable bounds on every drag start rather than just the
first. This accounts for display rotation changing the stable bounds.

Bug: 296921896
Test: Manual; drag resize a task, rotate screen, resize again without
old stable bound restrictions.

Change-Id: Ied8e381faeea68eb5078520954ba6c45a09e13bd
parent 1ade2aac
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.wm.shell.windowdecor;

import android.graphics.PointF;
import android.graphics.Rect;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;

@@ -45,6 +46,7 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
    private final int mDisallowedAreaForEndBoundsHeight;
    private boolean mHasDragResized;
    private int mCtrlType;
    @Surface.Rotation private int mRotation;

    FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
            DisplayController displayController, int disallowedAreaForEndBoundsHeight) {
@@ -78,7 +80,10 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
            mTaskOrganizer.applyTransaction(wct);
        }
        mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
        if (mStableBounds.isEmpty()) {
        int rotation = mWindowDecoration
                .mTaskInfo.configuration.windowConfiguration.getDisplayRotation();
        if (mStableBounds.isEmpty() || mRotation != rotation) {
            mRotation = rotation;
            mDisplayController.getDisplayLayout(mWindowDecoration.mDisplay.getDisplayId())
                    .getStableBounds(mStableBounds);
        }
+6 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.view.WindowManager.TRANSIT_CHANGE;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -58,6 +59,7 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
    private final int mDisallowedAreaForEndBoundsHeight;
    private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
    private int mCtrlType;
    @Surface.Rotation private int mRotation;

    public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer,
            DesktopModeWindowDecoration windowDecoration, DisplayController displayController,
@@ -98,7 +100,10 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback,
        }
        mDragStartListener.onDragStart(mDesktopWindowDecoration.mTaskInfo.taskId);
        mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
        if (mStableBounds.isEmpty()) {
        int rotation = mDesktopWindowDecoration
                .mTaskInfo.configuration.windowConfiguration.getDisplayRotation();
        if (mStableBounds.isEmpty() || mRotation != rotation) {
            mRotation = rotation;
            mDisplayController.getDisplayLayout(mDesktopWindowDecoration.mDisplay.getDisplayId())
                    .getStableBounds(mStableBounds);
        }
+95 −4
Original line number Diff line number Diff line
@@ -6,6 +6,9 @@ import android.graphics.Rect
import android.os.IBinder
import android.testing.AndroidTestingRunner
import android.view.Display
import android.view.Surface
import android.view.Surface.ROTATION_270
import android.view.Surface.ROTATION_90
import android.view.SurfaceControl
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
@@ -24,6 +27,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
import org.mockito.Mockito.never
@@ -76,7 +80,15 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
        whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
        whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
        whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
            (i.arguments.first() as Rect).set(STABLE_BOUNDS)
            if (mockWindowDecoration.mTaskInfo.configuration.windowConfiguration
                    .displayRotation == ROTATION_90 ||
                mockWindowDecoration.mTaskInfo.configuration.windowConfiguration
                    .displayRotation == ROTATION_270
            ) {
                (i.arguments.first() as Rect).set(STABLE_BOUNDS_LANDSCAPE)
            } else {
                (i.arguments.first() as Rect).set(STABLE_BOUNDS_PORTRAIT)
            }
        }
        `when`(mockDisplayLayout.stableInsets()).thenReturn(STABLE_INSETS)
        `when`(mockTransactionFactory.get()).thenReturn(mockTransaction)
@@ -89,6 +101,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
            defaultMinSize = DEFAULT_MIN
            displayId = DISPLAY_ID
            configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
            configuration.windowConfiguration.displayRotation = ROTATION_90
        }
        mockWindowDecoration.mDisplay = mockDisplay
        whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
@@ -623,7 +636,7 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
        )

        val newX = STARTING_BOUNDS.left.toFloat()
        val newY = STABLE_BOUNDS.top.toFloat() - 5
        val newY = STABLE_BOUNDS_LANDSCAPE.top.toFloat() - 5
        taskPositioner.onDragPositioningMove(
                newX,
                newY
@@ -641,11 +654,83 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
                token == taskBinder &&
                        (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
                        change.configuration.windowConfiguration.bounds.top ==
                        STABLE_BOUNDS.top
                        STABLE_BOUNDS_LANDSCAPE.top
            }
        })
    }

    @Test
    fun testDragResize_drag_updatesStableBoundsOnRotate() {
        // Test landscape stable bounds
        performDrag(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat(),
            STARTING_BOUNDS.right.toFloat() + 2000, STARTING_BOUNDS.bottom.toFloat() + 2000,
            CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM)
        val rectAfterDrag = Rect(STARTING_BOUNDS)
        rectAfterDrag.right += 2000
        // First drag; we should fetch stable bounds.
        verify(mockDisplayLayout, Mockito.times(1)).getStableBounds(any())
        verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
            return@argThat wct.changes.any { (token, change) ->
                token == taskBinder &&
                        (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
                        change.configuration.windowConfiguration.bounds == rectAfterDrag
            }
        })
        // Drag back to starting bounds.
        performDrag(
            STARTING_BOUNDS.right.toFloat() + 2000, STARTING_BOUNDS.bottom.toFloat(),
            STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat(),
            CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM)

        // Display did not rotate; we should use previous stable bounds
        verify(mockDisplayLayout, Mockito.times(1)).getStableBounds(any())

        // Rotate the screen to portrait
        mockWindowDecoration.mTaskInfo.apply {
            configuration.windowConfiguration.displayRotation = Surface.ROTATION_0
        }
        // Test portrait stable bounds
        performDrag(
            STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat(),
            STARTING_BOUNDS.right.toFloat() + 2000, STARTING_BOUNDS.bottom.toFloat() + 2000,
            CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM)
        rectAfterDrag.right -= 2000
        rectAfterDrag.bottom += 2000

        verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
            return@argThat wct.changes.any { (token, change) ->
                token == taskBinder &&
                        (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
                        change.configuration.windowConfiguration.bounds == rectAfterDrag
            }
        })
        // Display has rotated; we expect a new stable bounds.
        verify(mockDisplayLayout, Mockito.times(2)).getStableBounds(any())
    }

    private fun performDrag(
        startX: Float,
        startY: Float,
        endX: Float,
        endY: Float,
        ctrlType: Int
    ) {
        taskPositioner.onDragPositioningStart(
            ctrlType,
            startX,
            startY
        )
        taskPositioner.onDragPositioningMove(
            endX,
            endY
        )

        taskPositioner.onDragPositioningEnd(
            endX,
            endY
        )
    }

    companion object {
        private const val TASK_ID = 5
        private const val MIN_WIDTH = 10
@@ -664,11 +749,17 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
                DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT,
                DISPLAY_BOUNDS.right,
                DISPLAY_BOUNDS.bottom)
        private val STABLE_BOUNDS = Rect(
        private val STABLE_BOUNDS_LANDSCAPE = Rect(
                DISPLAY_BOUNDS.left,
                DISPLAY_BOUNDS.top + CAPTION_HEIGHT,
                DISPLAY_BOUNDS.right,
                DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
        )
        private val STABLE_BOUNDS_PORTRAIT = Rect(
            DISPLAY_BOUNDS.top,
            DISPLAY_BOUNDS.left + CAPTION_HEIGHT,
            DISPLAY_BOUNDS.bottom,
            DISPLAY_BOUNDS.right - NAVBAR_HEIGHT
        )
    }
}
+91 −5
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ import android.graphics.Rect
import android.os.IBinder
import android.testing.AndroidTestingRunner
import android.view.Display
import android.view.Surface.ROTATION_0
import android.view.Surface.ROTATION_270
import android.view.Surface.ROTATION_90
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
import android.window.WindowContainerToken
@@ -30,6 +33,7 @@ import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
@@ -93,10 +97,17 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
        whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
        whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
        whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
            (i.arguments.first() as Rect).set(STABLE_BOUNDS)
            if (mockDesktopWindowDecoration.mTaskInfo.configuration.windowConfiguration
                .displayRotation == ROTATION_90 ||
                mockDesktopWindowDecoration.mTaskInfo.configuration.windowConfiguration
                    .displayRotation == ROTATION_270
            ) {
                (i.arguments.first() as Rect).set(STABLE_BOUNDS_LANDSCAPE)
            } else {
                (i.arguments.first() as Rect).set(STABLE_BOUNDS_PORTRAIT)
            }
        }
        `when`(mockTransactionFactory.get()).thenReturn(mockTransaction)

        mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
            taskId = TASK_ID
            token = taskToken
@@ -105,6 +116,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
            defaultMinSize = DEFAULT_MIN
            displayId = DISPLAY_ID
            configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
            configuration.windowConfiguration.displayRotation = ROTATION_90
        }
        mockDesktopWindowDecoration.mDisplay = mockDisplay
        whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
@@ -343,7 +355,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
        )

        val newX = STARTING_BOUNDS.left.toFloat()
        val newY = STABLE_BOUNDS.top.toFloat() - 5
        val newY = STABLE_BOUNDS_LANDSCAPE.top.toFloat() - 5
        taskPositioner.onDragPositioningMove(
                newX,
                newY
@@ -361,11 +373,79 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
                token == taskBinder &&
                        (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
                        change.configuration.windowConfiguration.bounds.top ==
                        STABLE_BOUNDS.top
                        STABLE_BOUNDS_LANDSCAPE.top
            }
        })
    }

    @Test
    fun testDragResize_drag_updatesStableBoundsOnRotate() {
        // Test landscape stable bounds
        performDrag(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat(),
            STARTING_BOUNDS.right.toFloat() + 2000, STARTING_BOUNDS.bottom.toFloat() + 2000,
            CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM)
        val rectAfterDrag = Rect(STARTING_BOUNDS)
        rectAfterDrag.right += 2000
        // First drag; we should fetch stable bounds.
        verify(mockDisplayLayout, times(1)).getStableBounds(any())
        verify(mockTransitions).startTransition(eq(TRANSIT_CHANGE), argThat { wct ->
            return@argThat wct.changes.any { (token, change) ->
                token == taskBinder &&
                        (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
                        change.configuration.windowConfiguration.bounds == rectAfterDrag}},
            eq(taskPositioner))
        // Drag back to starting bounds.
        performDrag(STARTING_BOUNDS.right.toFloat() + 2000, STARTING_BOUNDS.bottom.toFloat(),
            STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat(),
            CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM)

        // Display did not rotate; we should use previous stable bounds
        verify(mockDisplayLayout, times(1)).getStableBounds(any())

        // Rotate the screen to portrait
        mockDesktopWindowDecoration.mTaskInfo.apply {
            configuration.windowConfiguration.displayRotation = ROTATION_0
        }
        // Test portrait stable bounds
        performDrag(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat(),
            STARTING_BOUNDS.right.toFloat() + 2000, STARTING_BOUNDS.bottom.toFloat() + 2000,
            CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM)
        rectAfterDrag.right -= 2000
        rectAfterDrag.bottom += 2000

        verify(mockTransitions).startTransition(eq(TRANSIT_CHANGE), argThat { wct ->
            return@argThat wct.changes.any { (token, change) ->
                token == taskBinder &&
                        (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
                        change.configuration.windowConfiguration.bounds == rectAfterDrag}},
            eq(taskPositioner))
        // Display has rotated; we expect a new stable bounds.
        verify(mockDisplayLayout, times(2)).getStableBounds(any())
    }

    private fun performDrag(
        startX: Float,
        startY: Float,
        endX: Float,
        endY: Float,
        ctrlType: Int
    ) {
        taskPositioner.onDragPositioningStart(
            ctrlType,
            startX,
            startY
        )
        taskPositioner.onDragPositioningMove(
            endX,
            endY
        )

        taskPositioner.onDragPositioningEnd(
            endX,
            endY
        )
    }

    companion object {
        private const val TASK_ID = 5
        private const val MIN_WIDTH = 10
@@ -378,11 +458,17 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
        private const val DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT = 10
        private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
        private val STARTING_BOUNDS = Rect(100, 100, 200, 200)
        private val STABLE_BOUNDS = Rect(
        private val STABLE_BOUNDS_LANDSCAPE = Rect(
            DISPLAY_BOUNDS.left,
            DISPLAY_BOUNDS.top + CAPTION_HEIGHT,
            DISPLAY_BOUNDS.right,
            DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
        )
        private val STABLE_BOUNDS_PORTRAIT = Rect(
            DISPLAY_BOUNDS.top,
            DISPLAY_BOUNDS.left + CAPTION_HEIGHT,
            DISPLAY_BOUNDS.bottom,
            DISPLAY_BOUNDS.right - NAVBAR_HEIGHT
        )
    }
}