Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java +32 −4 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import android.graphics.Rect; import android.util.DisplayMetrics; import android.view.SurfaceControl; import androidx.annotation.NonNull; import com.android.window.flags.Flags; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayController; Loading Loading @@ -106,13 +108,15 @@ public class DragPositioningCallbackUtility { repositionTaskBounds.bottom = (candidateBottom < stableBounds.bottom) ? candidateBottom : oldBottom; } // If width or height are negative or less than the minimum width or height, revert the // If width or height are negative or exceeding the width or height constraints, revert the // respective bounds to use previous bound dimensions. if (repositionTaskBounds.width() < getMinWidth(displayController, windowDecoration)) { if (isExceedingWidthConstraint(repositionTaskBounds, stableBounds, displayController, windowDecoration)) { repositionTaskBounds.right = oldRight; repositionTaskBounds.left = oldLeft; } if (repositionTaskBounds.height() < getMinHeight(displayController, windowDecoration)) { if (isExceedingHeightConstraint(repositionTaskBounds, stableBounds, displayController, windowDecoration)) { repositionTaskBounds.top = oldTop; repositionTaskBounds.bottom = oldBottom; } Loading Loading @@ -174,6 +178,30 @@ public class DragPositioningCallbackUtility { return result; } private static boolean isExceedingWidthConstraint(@NonNull Rect repositionTaskBounds, Rect maxResizeBounds, DisplayController displayController, WindowDecoration windowDecoration) { // Check if width is less than the minimum width constraint. if (repositionTaskBounds.width() < getMinWidth(displayController, windowDecoration)) { return true; } // Check if width is more than the maximum resize bounds on desktop windowing mode. return isSizeConstraintForDesktopModeEnabled(windowDecoration.mDecorWindowContext) && repositionTaskBounds.width() > maxResizeBounds.width(); } private static boolean isExceedingHeightConstraint(@NonNull Rect repositionTaskBounds, Rect maxResizeBounds, DisplayController displayController, WindowDecoration windowDecoration) { // Check if height is less than the minimum height constraint. if (repositionTaskBounds.height() < getMinHeight(displayController, windowDecoration)) { return true; } // Check if height is more than the maximum resize bounds on desktop windowing mode. return isSizeConstraintForDesktopModeEnabled(windowDecoration.mDecorWindowContext) && repositionTaskBounds.height() > maxResizeBounds.height(); } private static float getMinWidth(DisplayController displayController, WindowDecoration windowDecoration) { return windowDecoration.mTaskInfo.minWidth < 0 ? getDefaultMinWidth(displayController, Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt +58 −0 Original line number Diff line number Diff line Loading @@ -21,7 +21,9 @@ import android.content.res.Resources import android.graphics.PointF import android.graphics.Rect import android.os.IBinder import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display import android.window.WindowContainerToken Loading @@ -36,6 +38,7 @@ import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock Loading @@ -53,21 +56,32 @@ import org.mockito.MockitoAnnotations class DragPositioningCallbackUtilityTest { @Mock private lateinit var mockWindowDecoration: WindowDecoration<*> @Mock private lateinit var taskToken: WindowContainerToken @Mock private lateinit var taskBinder: IBinder @Mock private lateinit var mockDisplayController: DisplayController @Mock private lateinit var mockDisplayLayout: DisplayLayout @Mock private lateinit var mockDisplay: Display @Mock private lateinit var mockContext: Context @Mock private lateinit var mockResources: Resources @JvmField @Rule val setFlagsRule = SetFlagsRule() @Before fun setup() { MockitoAnnotations.initMocks(this) Loading Loading @@ -323,6 +337,49 @@ class DragPositioningCallbackUtilityTest { assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom - 50) } @Test @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS) fun testChangeBounds_windowSizeExceedsStableBounds_shouldBeAllowedToChangeBounds() { val startingPoint = PointF(OFF_CENTER_STARTING_BOUNDS.right.toFloat(), OFF_CENTER_STARTING_BOUNDS.bottom.toFloat()) val repositionTaskBounds = Rect(OFF_CENTER_STARTING_BOUNDS) // Increase height and width by STABLE_BOUNDS. Subtract by 5px so that it doesn't reach // the disallowed drag area. val offset = 5 val newX = STABLE_BOUNDS.right.toFloat() - offset val newY = STABLE_BOUNDS.bottom.toFloat() - offset val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint) DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, repositionTaskBounds, OFF_CENTER_STARTING_BOUNDS, STABLE_BOUNDS, delta, mockDisplayController, mockWindowDecoration) assertThat(repositionTaskBounds.width()).isGreaterThan(STABLE_BOUNDS.right) assertThat(repositionTaskBounds.height()).isGreaterThan(STABLE_BOUNDS.bottom) } @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS) fun testChangeBoundsInDesktopMode_windowSizeExceedsStableBounds_shouldBeLimitedToDisplaySize() { whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true) val startingPoint = PointF(OFF_CENTER_STARTING_BOUNDS.right.toFloat(), OFF_CENTER_STARTING_BOUNDS.bottom.toFloat()) val repositionTaskBounds = Rect(OFF_CENTER_STARTING_BOUNDS) // Increase height and width by STABLE_BOUNDS. Subtract by 5px so that it doesn't reach // the disallowed drag area. val offset = 5 val newX = STABLE_BOUNDS.right.toFloat() - offset val newY = STABLE_BOUNDS.bottom.toFloat() - offset val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint) DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, repositionTaskBounds, OFF_CENTER_STARTING_BOUNDS, STABLE_BOUNDS, delta, mockDisplayController, mockWindowDecoration) assertThat(repositionTaskBounds.width()).isLessThan(STABLE_BOUNDS.right) assertThat(repositionTaskBounds.height()).isLessThan(STABLE_BOUNDS.bottom) } private fun initializeTaskInfo(taskMinWidth: Int = MIN_WIDTH, taskMinHeight: Int = MIN_HEIGHT) { mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply { taskId = TASK_ID Loading @@ -347,6 +404,7 @@ class DragPositioningCallbackUtilityTest { 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 OFF_CENTER_STARTING_BOUNDS = Rect(-100, -100, 10, 10) private val DISALLOWED_RESIZE_AREA = Rect( DISPLAY_BOUNDS.left, DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT, Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt +9 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.wm.shell.windowdecor import android.app.ActivityManager import android.app.WindowConfiguration import android.content.Context import android.content.res.Resources import android.graphics.Point import android.graphics.Rect import android.os.IBinder Loading Loading @@ -98,6 +100,10 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { private lateinit var mockFinishCallback: TransitionFinishCallback @Mock private lateinit var mockTransitions: Transitions @Mock private lateinit var mockContext: Context @Mock private lateinit var mockResources: Resources private lateinit var taskPositioner: VeiledResizeTaskPositioner Loading @@ -105,6 +111,9 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) mockDesktopWindowDecoration.mDisplay = mockDisplay mockDesktopWindowDecoration.mDecorWindowContext = mockContext whenever(mockContext.getResources()).thenReturn(mockResources) whenever(taskToken.asBinder()).thenReturn(taskBinder) whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout) whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI) Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java +32 −4 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import android.graphics.Rect; import android.util.DisplayMetrics; import android.view.SurfaceControl; import androidx.annotation.NonNull; import com.android.window.flags.Flags; import com.android.wm.shell.R; import com.android.wm.shell.common.DisplayController; Loading Loading @@ -106,13 +108,15 @@ public class DragPositioningCallbackUtility { repositionTaskBounds.bottom = (candidateBottom < stableBounds.bottom) ? candidateBottom : oldBottom; } // If width or height are negative or less than the minimum width or height, revert the // If width or height are negative or exceeding the width or height constraints, revert the // respective bounds to use previous bound dimensions. if (repositionTaskBounds.width() < getMinWidth(displayController, windowDecoration)) { if (isExceedingWidthConstraint(repositionTaskBounds, stableBounds, displayController, windowDecoration)) { repositionTaskBounds.right = oldRight; repositionTaskBounds.left = oldLeft; } if (repositionTaskBounds.height() < getMinHeight(displayController, windowDecoration)) { if (isExceedingHeightConstraint(repositionTaskBounds, stableBounds, displayController, windowDecoration)) { repositionTaskBounds.top = oldTop; repositionTaskBounds.bottom = oldBottom; } Loading Loading @@ -174,6 +178,30 @@ public class DragPositioningCallbackUtility { return result; } private static boolean isExceedingWidthConstraint(@NonNull Rect repositionTaskBounds, Rect maxResizeBounds, DisplayController displayController, WindowDecoration windowDecoration) { // Check if width is less than the minimum width constraint. if (repositionTaskBounds.width() < getMinWidth(displayController, windowDecoration)) { return true; } // Check if width is more than the maximum resize bounds on desktop windowing mode. return isSizeConstraintForDesktopModeEnabled(windowDecoration.mDecorWindowContext) && repositionTaskBounds.width() > maxResizeBounds.width(); } private static boolean isExceedingHeightConstraint(@NonNull Rect repositionTaskBounds, Rect maxResizeBounds, DisplayController displayController, WindowDecoration windowDecoration) { // Check if height is less than the minimum height constraint. if (repositionTaskBounds.height() < getMinHeight(displayController, windowDecoration)) { return true; } // Check if height is more than the maximum resize bounds on desktop windowing mode. return isSizeConstraintForDesktopModeEnabled(windowDecoration.mDecorWindowContext) && repositionTaskBounds.height() > maxResizeBounds.height(); } private static float getMinWidth(DisplayController displayController, WindowDecoration windowDecoration) { return windowDecoration.mTaskInfo.minWidth < 0 ? getDefaultMinWidth(displayController, Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt +58 −0 Original line number Diff line number Diff line Loading @@ -21,7 +21,9 @@ import android.content.res.Resources import android.graphics.PointF import android.graphics.Rect import android.os.IBinder import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display import android.window.WindowContainerToken Loading @@ -36,6 +38,7 @@ import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock Loading @@ -53,21 +56,32 @@ import org.mockito.MockitoAnnotations class DragPositioningCallbackUtilityTest { @Mock private lateinit var mockWindowDecoration: WindowDecoration<*> @Mock private lateinit var taskToken: WindowContainerToken @Mock private lateinit var taskBinder: IBinder @Mock private lateinit var mockDisplayController: DisplayController @Mock private lateinit var mockDisplayLayout: DisplayLayout @Mock private lateinit var mockDisplay: Display @Mock private lateinit var mockContext: Context @Mock private lateinit var mockResources: Resources @JvmField @Rule val setFlagsRule = SetFlagsRule() @Before fun setup() { MockitoAnnotations.initMocks(this) Loading Loading @@ -323,6 +337,49 @@ class DragPositioningCallbackUtilityTest { assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom - 50) } @Test @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS) fun testChangeBounds_windowSizeExceedsStableBounds_shouldBeAllowedToChangeBounds() { val startingPoint = PointF(OFF_CENTER_STARTING_BOUNDS.right.toFloat(), OFF_CENTER_STARTING_BOUNDS.bottom.toFloat()) val repositionTaskBounds = Rect(OFF_CENTER_STARTING_BOUNDS) // Increase height and width by STABLE_BOUNDS. Subtract by 5px so that it doesn't reach // the disallowed drag area. val offset = 5 val newX = STABLE_BOUNDS.right.toFloat() - offset val newY = STABLE_BOUNDS.bottom.toFloat() - offset val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint) DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, repositionTaskBounds, OFF_CENTER_STARTING_BOUNDS, STABLE_BOUNDS, delta, mockDisplayController, mockWindowDecoration) assertThat(repositionTaskBounds.width()).isGreaterThan(STABLE_BOUNDS.right) assertThat(repositionTaskBounds.height()).isGreaterThan(STABLE_BOUNDS.bottom) } @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS) fun testChangeBoundsInDesktopMode_windowSizeExceedsStableBounds_shouldBeLimitedToDisplaySize() { whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true) val startingPoint = PointF(OFF_CENTER_STARTING_BOUNDS.right.toFloat(), OFF_CENTER_STARTING_BOUNDS.bottom.toFloat()) val repositionTaskBounds = Rect(OFF_CENTER_STARTING_BOUNDS) // Increase height and width by STABLE_BOUNDS. Subtract by 5px so that it doesn't reach // the disallowed drag area. val offset = 5 val newX = STABLE_BOUNDS.right.toFloat() - offset val newY = STABLE_BOUNDS.bottom.toFloat() - offset val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint) DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, repositionTaskBounds, OFF_CENTER_STARTING_BOUNDS, STABLE_BOUNDS, delta, mockDisplayController, mockWindowDecoration) assertThat(repositionTaskBounds.width()).isLessThan(STABLE_BOUNDS.right) assertThat(repositionTaskBounds.height()).isLessThan(STABLE_BOUNDS.bottom) } private fun initializeTaskInfo(taskMinWidth: Int = MIN_WIDTH, taskMinHeight: Int = MIN_HEIGHT) { mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply { taskId = TASK_ID Loading @@ -347,6 +404,7 @@ class DragPositioningCallbackUtilityTest { 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 OFF_CENTER_STARTING_BOUNDS = Rect(-100, -100, 10, 10) private val DISALLOWED_RESIZE_AREA = Rect( DISPLAY_BOUNDS.left, DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT, Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt +9 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.wm.shell.windowdecor import android.app.ActivityManager import android.app.WindowConfiguration import android.content.Context import android.content.res.Resources import android.graphics.Point import android.graphics.Rect import android.os.IBinder Loading Loading @@ -98,6 +100,10 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { private lateinit var mockFinishCallback: TransitionFinishCallback @Mock private lateinit var mockTransitions: Transitions @Mock private lateinit var mockContext: Context @Mock private lateinit var mockResources: Resources private lateinit var taskPositioner: VeiledResizeTaskPositioner Loading @@ -105,6 +111,9 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) mockDesktopWindowDecoration.mDisplay = mockDisplay mockDesktopWindowDecoration.mDecorWindowContext = mockContext whenever(mockContext.getResources()).thenReturn(mockResources) whenever(taskToken.asBinder()).thenReturn(taskBinder) whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout) whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI) Loading