Merge "Resizing to invalid bounds causes task to jump to fullscreen" into tm-qpr-dev

This commit is contained in:
Maryam Dehaini
2023-02-23 21:58:41 +00:00
committed by Android (Google) Code Review
4 changed files with 287 additions and 5 deletions

View File

@@ -174,7 +174,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
final TaskPositioner taskPositioner =
new TaskPositioner(mTaskOrganizer, windowDecoration);
new TaskPositioner(mTaskOrganizer, windowDecoration, mDisplayController);
final CaptionTouchEventListener touchEventListener =
new CaptionTouchEventListener(taskInfo, taskPositioner);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);

View File

@@ -558,7 +558,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
final TaskPositioner taskPositioner =
new TaskPositioner(mTaskOrganizer, windowDecoration, mDragStartListener);
new TaskPositioner(mTaskOrganizer, windowDecoration, mDisplayController,
mDragStartListener);
final DesktopModeTouchEventListener touchEventListener =
new DesktopModeTouchEventListener(taskInfo, taskPositioner);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);

View File

@@ -19,9 +19,11 @@ package com.android.wm.shell.windowdecor;
import android.annotation.IntDef;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
class TaskPositioner implements DragPositioningCallback {
@@ -35,6 +37,7 @@ class TaskPositioner implements DragPositioningCallback {
static final int CTRL_TYPE_BOTTOM = 8;
private final ShellTaskOrganizer mTaskOrganizer;
private final DisplayController mDisplayController;
private final WindowDecoration mWindowDecoration;
private final Rect mTaskBoundsAtDragStart = new Rect();
@@ -45,14 +48,16 @@ class TaskPositioner implements DragPositioningCallback {
private int mCtrlType;
private DragStartListener mDragStartListener;
TaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration) {
this(taskOrganizer, windowDecoration, dragStartListener -> {});
TaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
DisplayController displayController) {
this(taskOrganizer, windowDecoration, displayController, dragStartListener -> {});
}
TaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
DragStartListener dragStartListener) {
DisplayController displayController, DragStartListener dragStartListener) {
mTaskOrganizer = taskOrganizer;
mWindowDecoration = windowDecoration;
mDisplayController = displayController;
mDragStartListener = dragStartListener;
}
@@ -128,15 +133,44 @@ class TaskPositioner implements DragPositioningCallback {
mRepositionTaskBounds.offset((int) deltaX, (int) deltaY);
}
// If width or height are negative or less than the minimum width or height, revert the
// respective bounds to use previous bound dimensions.
if (mRepositionTaskBounds.width() < getMinWidth()) {
mRepositionTaskBounds.right = oldRight;
mRepositionTaskBounds.left = oldLeft;
}
if (mRepositionTaskBounds.height() < getMinHeight()) {
mRepositionTaskBounds.top = oldTop;
mRepositionTaskBounds.bottom = oldBottom;
}
// If there are no changes to the bounds after checking new bounds against minimum width
// and height, do not set bounds and return false
if (oldLeft == mRepositionTaskBounds.left && oldTop == mRepositionTaskBounds.top
&& oldRight == mRepositionTaskBounds.right
&& oldBottom == mRepositionTaskBounds.bottom) {
return false;
}
wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds);
return true;
}
private float getMinWidth() {
return mWindowDecoration.mTaskInfo.minWidth < 0 ? getDefaultMinSize()
: mWindowDecoration.mTaskInfo.minWidth;
}
private float getMinHeight() {
return mWindowDecoration.mTaskInfo.minHeight < 0 ? getDefaultMinSize()
: mWindowDecoration.mTaskInfo.minHeight;
}
private float getDefaultMinSize() {
float density = mDisplayController.getDisplayLayout(mWindowDecoration.mTaskInfo.displayId)
.densityDpi() * DisplayMetrics.DENSITY_DEFAULT_SCALE;
return mWindowDecoration.mTaskInfo.defaultMinSize * density;
}
interface DragStartListener {
/**
* Inform the implementing class that a drag resize has started

View File

@@ -8,6 +8,8 @@ import android.testing.AndroidTestingRunner
import android.window.WindowContainerToken
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_RIGHT
@@ -45,6 +47,11 @@ class TaskPositionerTest : ShellTestCase() {
@Mock
private lateinit var taskBinder: IBinder
@Mock
private lateinit var mockDisplayController: DisplayController
@Mock
private lateinit var mockDisplayLayout: DisplayLayout
private lateinit var taskPositioner: TaskPositioner
@Before
@@ -54,12 +61,21 @@ class TaskPositionerTest : ShellTestCase() {
taskPositioner = TaskPositioner(
mockShellTaskOrganizer,
mockWindowDecoration,
mockDisplayController,
mockDragStartListener
)
`when`(taskToken.asBinder()).thenReturn(taskBinder)
`when`(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
`when`(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
taskId = TASK_ID
token = taskToken
minWidth = MIN_WIDTH
minHeight = MIN_HEIGHT
defaultMinSize = DEFAULT_MIN
displayId = DISPLAY_ID
configuration.windowConfiguration.bounds = STARTING_BOUNDS
}
}
@@ -209,8 +225,239 @@ class TaskPositionerTest : ShellTestCase() {
})
}
@Test
fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenLessThanMin() {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
STARTING_BOUNDS.right.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
// Resize to width of 95px and height of 5px with min width of 10px
val newX = STARTING_BOUNDS.right.toFloat() - 5
val newY = STARTING_BOUNDS.top.toFloat() + 95
taskPositioner.onDragPositioningMove(
newX,
newY
)
taskPositioner.onDragPositioningEnd(newX, newY)
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.top ==
STARTING_BOUNDS.top &&
change.configuration.windowConfiguration.bounds.bottom ==
STARTING_BOUNDS.bottom
}
})
}
@Test
fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenLessThanMin() {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
STARTING_BOUNDS.right.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
// Resize to height of 95px and width of 5px with min width of 10px
val newX = STARTING_BOUNDS.right.toFloat() - 95
val newY = STARTING_BOUNDS.top.toFloat() + 5
taskPositioner.onDragPositioningMove(
newX,
newY
)
taskPositioner.onDragPositioningEnd(newX, newY)
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.right ==
STARTING_BOUNDS.right &&
change.configuration.windowConfiguration.bounds.left ==
STARTING_BOUNDS.left
}
})
}
@Test
fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenNegative() {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
STARTING_BOUNDS.right.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
// Resize to height of -5px and width of 95px
val newX = STARTING_BOUNDS.right.toFloat() - 5
val newY = STARTING_BOUNDS.top.toFloat() + 105
taskPositioner.onDragPositioningMove(
newX,
newY
)
taskPositioner.onDragPositioningEnd(newX, newY)
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.top ==
STARTING_BOUNDS.top &&
change.configuration.windowConfiguration.bounds.bottom ==
STARTING_BOUNDS.bottom
}
})
}
@Test
fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenNegative() {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
STARTING_BOUNDS.right.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
// Resize to width of -5px and height of 95px
val newX = STARTING_BOUNDS.right.toFloat() - 105
val newY = STARTING_BOUNDS.top.toFloat() + 5
taskPositioner.onDragPositioningMove(
newX,
newY
)
taskPositioner.onDragPositioningEnd(newX, newY)
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.right ==
STARTING_BOUNDS.right &&
change.configuration.windowConfiguration.bounds.left ==
STARTING_BOUNDS.left
}
})
}
@Test
fun testDragResize_resize_setBoundsRunsWhenResizeBoundsValid() {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
STARTING_BOUNDS.right.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
// Shrink to height 20px and width 20px with both min height/width equal to 10px
val newX = STARTING_BOUNDS.right.toFloat() - 80
val newY = STARTING_BOUNDS.top.toFloat() + 80
taskPositioner.onDragPositioningMove(
newX,
newY
)
taskPositioner.onDragPositioningEnd(newX, newY)
verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
return@argThat wct.changes.any { (token, change) ->
token == taskBinder &&
((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
}
})
}
@Test
fun testDragResize_resize_setBoundsDoesNotRunWithNegativeHeightAndWidth() {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
STARTING_BOUNDS.right.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
// Shrink to height 5px and width 5px with both min height/width equal to 10px
val newX = STARTING_BOUNDS.right.toFloat() - 95
val newY = STARTING_BOUNDS.top.toFloat() + 95
taskPositioner.onDragPositioningMove(
newX,
newY
)
taskPositioner.onDragPositioningEnd(newX, newY)
verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
return@argThat wct.changes.any { (token, change) ->
token == taskBinder &&
((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
}
})
}
@Test
fun testDragResize_resize_useDefaultMinWhenMinWidthInvalid() {
mockWindowDecoration.mTaskInfo.minWidth = -1
taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
STARTING_BOUNDS.right.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
// Shrink to width and height of 3px with invalid minWidth = -1 and defaultMinSize = 5px
val newX = STARTING_BOUNDS.right.toFloat() - 97
val newY = STARTING_BOUNDS.top.toFloat() + 97
taskPositioner.onDragPositioningMove(
newX,
newY
)
taskPositioner.onDragPositioningEnd(newX, newY)
verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
return@argThat wct.changes.any { (token, change) ->
token == taskBinder &&
((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
}
})
}
@Test
fun testDragResize_resize_useMinWidthWhenValid() {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
STARTING_BOUNDS.right.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
// Shrink to width and height of 7px with valid minWidth = 10px and defaultMinSize = 5px
val newX = STARTING_BOUNDS.right.toFloat() - 93
val newY = STARTING_BOUNDS.top.toFloat() + 93
taskPositioner.onDragPositioningMove(
newX,
newY
)
taskPositioner.onDragPositioningEnd(newX, newY)
verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
return@argThat wct.changes.any { (token, change) ->
token == taskBinder &&
((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
}
})
}
companion object {
private const val TASK_ID = 5
private const val MIN_WIDTH = 10
private const val MIN_HEIGHT = 10
private const val DENSITY_DPI = 20
private const val DEFAULT_MIN = 40
private const val DISPLAY_ID = 1
private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
}
}