summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java24
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt92
2 files changed, 111 insertions, 5 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
index a3d364a0068e..0bce3acecb3c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
@@ -40,6 +40,7 @@ class TaskPositioner implements DragPositioningCallback {
private final DisplayController mDisplayController;
private final WindowDecoration mWindowDecoration;
+ private final Rect mTempBounds = new Rect();
private final Rect mTaskBoundsAtDragStart = new Rect();
private final PointF mRepositionStartPoint = new PointF();
private final Rect mRepositionTaskBounds = new Rect();
@@ -117,17 +118,32 @@ class TaskPositioner implements DragPositioningCallback {
final float deltaX = x - mRepositionStartPoint.x;
final float deltaY = y - mRepositionStartPoint.y;
mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
+
+ final Rect stableBounds = mTempBounds;
+ // Make sure the new resizing destination in any direction falls within the stable bounds.
+ // If not, set the bounds back to the old location that was valid to avoid conflicts with
+ // some regions such as the gesture area.
+ mDisplayController.getDisplayLayout(mWindowDecoration.mDisplay.getDisplayId())
+ .getStableBounds(stableBounds);
if ((mCtrlType & CTRL_TYPE_LEFT) != 0) {
- mRepositionTaskBounds.left += deltaX;
+ final int candidateLeft = mRepositionTaskBounds.left + (int) deltaX;
+ mRepositionTaskBounds.left = (candidateLeft > stableBounds.left)
+ ? candidateLeft : oldLeft;
}
if ((mCtrlType & CTRL_TYPE_RIGHT) != 0) {
- mRepositionTaskBounds.right += deltaX;
+ final int candidateRight = mRepositionTaskBounds.right + (int) deltaX;
+ mRepositionTaskBounds.right = (candidateRight < stableBounds.right)
+ ? candidateRight : oldRight;
}
if ((mCtrlType & CTRL_TYPE_TOP) != 0) {
- mRepositionTaskBounds.top += deltaY;
+ final int candidateTop = mRepositionTaskBounds.top + (int) deltaY;
+ mRepositionTaskBounds.top = (candidateTop > stableBounds.top)
+ ? candidateTop : oldTop;
}
if ((mCtrlType & CTRL_TYPE_BOTTOM) != 0) {
- mRepositionTaskBounds.bottom += deltaY;
+ final int candidateBottom = mRepositionTaskBounds.bottom + (int) deltaY;
+ mRepositionTaskBounds.bottom = (candidateBottom < stableBounds.bottom)
+ ? candidateBottom : oldBottom;
}
if (mCtrlType == CTRL_TYPE_UNDEFINED) {
mRepositionTaskBounds.offset((int) deltaX, (int) deltaY);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
index 8f66f4e7e47b..94c064bda763 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
@@ -5,13 +5,16 @@ import android.app.WindowConfiguration
import android.graphics.Rect
import android.os.IBinder
import android.testing.AndroidTestingRunner
+import android.view.Display
import android.window.WindowContainerToken
+import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING
import androidx.test.filters.SmallTest
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_BOTTOM
import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_TOP
import com.android.wm.shell.windowdecor.TaskPositioner.CTRL_TYPE_UNDEFINED
@@ -19,10 +22,11 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
/**
@@ -51,6 +55,8 @@ class TaskPositionerTest : ShellTestCase() {
private lateinit var mockDisplayController: DisplayController
@Mock
private lateinit var mockDisplayLayout: DisplayLayout
+ @Mock
+ private lateinit var mockDisplay: Display
private lateinit var taskPositioner: TaskPositioner
@@ -68,6 +74,9 @@ class TaskPositionerTest : ShellTestCase() {
`when`(taskToken.asBinder()).thenReturn(taskBinder)
`when`(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
`when`(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
+ `when`(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
+ (i.arguments.first() as Rect).set(STABLE_BOUNDS)
+ }
mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
taskId = TASK_ID
@@ -78,6 +87,8 @@ class TaskPositionerTest : ShellTestCase() {
displayId = DISPLAY_ID
configuration.windowConfiguration.bounds = STARTING_BOUNDS
}
+ mockWindowDecoration.mDisplay = mockDisplay
+ `when`(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
}
@Test
@@ -451,6 +462,72 @@ class TaskPositionerTest : ShellTestCase() {
})
}
+ fun testDragResize_toDisallowedBounds_freezesAtLimit() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, // Resize right-bottom corner
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.bottom.toFloat()
+ )
+
+ // Resize the task by 10px to the right and bottom, a valid destination
+ val newBounds = Rect(
+ STARTING_BOUNDS.left,
+ STARTING_BOUNDS.top,
+ STARTING_BOUNDS.right + 10,
+ STARTING_BOUNDS.bottom + 10)
+ taskPositioner.onDragPositioningMove(
+ newBounds.right.toFloat(),
+ newBounds.bottom.toFloat()
+ )
+
+ // Resize the task by another 10px to the right (allowed) and to just in the disallowed
+ // area of the Y coordinate.
+ val newBounds2 = Rect(
+ newBounds.left,
+ newBounds.top,
+ newBounds.right + 10,
+ DISALLOWED_RESIZE_AREA.top
+ )
+ taskPositioner.onDragPositioningMove(
+ newBounds2.right.toFloat(),
+ newBounds2.bottom.toFloat()
+ )
+
+ taskPositioner.onDragPositioningEnd(newBounds2.right.toFloat(), newBounds2.bottom.toFloat())
+
+ // The first resize falls in the allowed area, verify there's a change for it.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(newBounds)
+ }
+ })
+ // The second resize falls in the disallowed area, verify there's no change for it.
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(newBounds2)
+ }
+ })
+ // Instead, there should be a change for its allowed portion (the X movement) with the Y
+ // staying frozen in the last valid resize position.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(
+ Rect(
+ newBounds2.left,
+ newBounds2.top,
+ newBounds2.right,
+ newBounds.bottom // Stayed at the first resize destination.
+ )
+ )
+ }
+ })
+ }
+
+ private fun WindowContainerTransaction.Change.ofBounds(bounds: Rect): Boolean {
+ return ((windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) &&
+ bounds == configuration.windowConfiguration.bounds
+ }
+
companion object {
private const val TASK_ID = 5
private const val MIN_WIDTH = 10
@@ -458,6 +535,19 @@ class TaskPositionerTest : ShellTestCase() {
private const val DENSITY_DPI = 20
private const val DEFAULT_MIN = 40
private const val DISPLAY_ID = 1
+ private const val NAVBAR_HEIGHT = 50
+ private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
+ private val DISALLOWED_RESIZE_AREA = Rect(
+ DISPLAY_BOUNDS.left,
+ DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT,
+ DISPLAY_BOUNDS.right,
+ DISPLAY_BOUNDS.bottom)
+ private val STABLE_BOUNDS = Rect(
+ DISPLAY_BOUNDS.left,
+ DISPLAY_BOUNDS.top,
+ DISPLAY_BOUNDS.right,
+ DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
+ )
}
}