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

Commit e3d29ca3 authored by Naomi Musgrave's avatar Naomi Musgrave
Browse files

Modify flag behaviour to apply edge resizing to both stylus & cursor.

Finger touch events are limited to corner resizing. Also, corner resize
regions are large for touchscreen input (finger & stylus) and smaller
for non-touchscreen input (cursor).

Flag: com.android.window.flags.enable_windowing_edge_drag_resize
Bug: 342320574
Test: atest WMShellUnitTests:DragResizeWindowGeometryTests
Change-Id: I7567e5d134bfd7c2b7bcc2b491efa9dfd9aa88b1
parent 106560ec
Loading
Loading
Loading
Loading
+9 −9
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.wm.shell.windowdecor;

import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_SPY;
@@ -29,6 +28,8 @@ import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT;
import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.isEdgeResizePermitted;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.isEventFromTouchscreen;

import android.annotation.NonNull;
import android.content.Context;
@@ -389,10 +390,9 @@ class DragResizeInputListener implements AutoCloseable {
            boolean result = false;
            // Check if this is a touch event vs mouse event.
            // Touch events are tracked in four corners. Other events are tracked in resize edges.
            boolean isTouch = isTouchEvent(e);
            switch (e.getActionMasked()) {
                case MotionEvent.ACTION_DOWN: {
                    mShouldHandleEvents = mDragResizeWindowGeometry.shouldHandleEvent(e, isTouch,
                    mShouldHandleEvents = mDragResizeWindowGeometry.shouldHandleEvent(e,
                            new Point() /* offset */);
                    if (mShouldHandleEvents) {
                        mDragPointerId = e.getPointerId(0);
@@ -400,7 +400,8 @@ class DragResizeInputListener implements AutoCloseable {
                        float y = e.getY(0);
                        float rawX = e.getRawX(0);
                        float rawY = e.getRawY(0);
                        int ctrlType = mDragResizeWindowGeometry.calculateCtrlType(isTouch, x, y);
                        final int ctrlType = mDragResizeWindowGeometry.calculateCtrlType(
                                isEventFromTouchscreen(e), isEdgeResizePermitted(e), x, y);
                        ProtoLog.d(WM_SHELL_DESKTOP_MODE,
                                "%s: Handling action down, update ctrlType to %d", TAG, ctrlType);
                        mDragStartTaskBounds = mCallback.onDragPositioningStart(ctrlType,
@@ -474,8 +475,11 @@ class DragResizeInputListener implements AutoCloseable {

        private void updateCursorType(int displayId, int deviceId, int pointerId, float x,
                float y) {
            // Since we are handling cursor, we know that this is not a touchscreen event, and
            // that edge resizing should always be allowed.
            @DragPositioningCallback.CtrlType int ctrlType =
                    mDragResizeWindowGeometry.calculateCtrlType(/* isTouch= */ false, x, y);
                    mDragResizeWindowGeometry.calculateCtrlType(/* isTouchscreen= */
                            false, /* isEdgeResizePermitted= */ true, x, y);

            int cursorType = PointerIcon.TYPE_DEFAULT;
            switch (ctrlType) {
@@ -517,9 +521,5 @@ class DragResizeInputListener implements AutoCloseable {
        private boolean shouldHandleEvent(MotionEvent e, Point offset) {
            return mDragResizeWindowGeometry.shouldHandleEvent(e, offset);
        }

        private boolean isTouchEvent(MotionEvent e) {
            return (e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN;
        }
    }
}
+24 −17
Original line number Diff line number Diff line
@@ -142,40 +142,42 @@ final class DragResizeWindowGeometry {
     * Returns if this MotionEvent should be handled, based on its source and position.
     */
    boolean shouldHandleEvent(@NonNull MotionEvent e, @NonNull Point offset) {
        return shouldHandleEvent(e, isTouchEvent(e), offset);
    }

    /**
     * Returns if this MotionEvent should be handled, based on its source and position.
     */
    boolean shouldHandleEvent(@NonNull MotionEvent e, boolean isTouch, @NonNull Point offset) {
        final float x = e.getX(0) + offset.x;
        final float y = e.getY(0) + offset.y;

        if (enableWindowingEdgeDragResize()) {
            // First check if touch falls within a corner.
            // Large corner bounds are used for course input like touch, otherwise fine bounds.
            boolean result = isTouch
            boolean result = isEventFromTouchscreen(e)
                    ? isInCornerBounds(mLargeTaskCorners, x, y)
                    : isInCornerBounds(mFineTaskCorners, x, y);
            // Check if touch falls within the edge resize handle, since edge resizing can apply
            // for any input source.
            if (!result) {
            // Check if touch falls within the edge resize handle. Limit edge resizing to stylus and
            // mouse input.
            if (!result && isEdgeResizePermitted(e)) {
                result = isInEdgeResizeBounds(x, y);
            }
            return result;
        } else {
            // Legacy uses only fine corners for touch, and edges only for non-touch input.
            return isTouch
            return isEventFromTouchscreen(e)
                    ? isInCornerBounds(mFineTaskCorners, x, y)
                    : isInEdgeResizeBounds(x, y);
        }
    }

    private boolean isTouchEvent(@NonNull MotionEvent e) {
    static boolean isEventFromTouchscreen(@NonNull MotionEvent e) {
        return (e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN;
    }

    static boolean isEdgeResizePermitted(@NonNull MotionEvent e) {
        if (enableWindowingEdgeDragResize()) {
            return e.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
                    || e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE;
        } else {
            return e.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE;
        }
    }

    private boolean isInCornerBounds(TaskCorners corners, float xf, float yf) {
        return corners.calculateCornersCtrlType(xf, yf) != 0;
    }
@@ -187,24 +189,29 @@ final class DragResizeWindowGeometry {
    /**
     * Returns the control type for the drag-resize, based on the touch regions and this
     * MotionEvent's coordinates.
     * @param isTouchscreen Controls the size of the corner resize regions; touchscreen events
     *                      (finger & stylus) are eligible for a larger area than cursor events
     * @param isEdgeResizePermitted Indicates if the event is eligible for falling into an edge
     *                              resize region.
     */
    @DragPositioningCallback.CtrlType
    int calculateCtrlType(boolean isTouch, float x, float y) {
    int calculateCtrlType(boolean isTouchscreen, boolean isEdgeResizePermitted, float x, float y) {
        if (enableWindowingEdgeDragResize()) {
            // First check if touch falls within a corner.
            // Large corner bounds are used for course input like touch, otherwise fine bounds.
            int ctrlType = isTouch
            int ctrlType = isTouchscreen
                    ? mLargeTaskCorners.calculateCornersCtrlType(x, y)
                    : mFineTaskCorners.calculateCornersCtrlType(x, y);

            // Check if touch falls within the edge resize handle, since edge resizing can apply
            // for any input source.
            if (ctrlType == CTRL_TYPE_UNDEFINED) {
            if (ctrlType == CTRL_TYPE_UNDEFINED && isEdgeResizePermitted) {
                ctrlType = calculateEdgeResizeCtrlType(x, y);
            }
            return ctrlType;
        } else {
            // Legacy uses only fine corners for touch, and edges only for non-touch input.
            return isTouch
            return isTouchscreen
                    ? mFineTaskCorners.calculateCornersCtrlType(x, y)
                    : calculateEdgeResizeCtrlType(x, y);
        }
+108 −66
Original line number Diff line number Diff line
@@ -27,10 +27,9 @@ import static com.google.common.truth.Truth.assertThat;
import android.annotation.NonNull;
import android.graphics.Point;
import android.graphics.Region;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
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.util.Size;

@@ -74,7 +73,7 @@ public class DragResizeWindowGeometryTests {
            TASK_SIZE.getHeight() + EDGE_RESIZE_THICKNESS / 2);

    @Rule
    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    /**
     * Check that both groups of objects satisfy equals/hashcode within each group, and that each
@@ -144,10 +143,11 @@ public class DragResizeWindowGeometryTests {

    /**
     * Validate that with the flag enabled, the corner resize regions are the largest size, to
     * capture all eligible input regardless of source (touch or cursor).
     * capture all eligible input regardless of source (touchscreen or cursor).
     * <p>Note that capturing input does not necessarily mean that the event will be handled.
     */
    @Test
    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    public void testRegionUnion_edgeDragResizeEnabled_containsLargeCorners() {
        Region region = new Region();
        GEOMETRY.union(region);
@@ -164,7 +164,7 @@ public class DragResizeWindowGeometryTests {
     * size.
     */
    @Test
    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    @DisableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    public void testRegionUnion_edgeDragResizeDisabled_containsFineCorners() {
        Region region = new Region();
        GEOMETRY.union(region);
@@ -176,74 +176,114 @@ public class DragResizeWindowGeometryTests {
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    public void testCalculateControlType_edgeDragResizeEnabled_edges() {
        // The input source (touch or cursor) shouldn't impact the edge resize size.
        validateCtrlTypeForEdges(/* isTouch= */ false);
        validateCtrlTypeForEdges(/* isTouch= */ true);
        // The input source (touchscreen or cursor) shouldn't impact the edge resize size.
        validateCtrlTypeForEdges(/* isTouchscreen= */ false, /* isEdgeResizePermitted= */ false);
        validateCtrlTypeForEdges(/* isTouchscreen= */ true, /* isEdgeResizePermitted= */ false);
        validateCtrlTypeForEdges(/* isTouchscreen= */ false, /* isEdgeResizePermitted= */ true);
        validateCtrlTypeForEdges(/* isTouchscreen= */ true, /* isEdgeResizePermitted= */ true);
    }

    @Test
    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    @DisableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    public void testCalculateControlType_edgeDragResizeDisabled_edges() {
        // Edge resizing is not supported when the flag is disabled.
        validateCtrlTypeForEdges(/* isTouch= */ false);
        validateCtrlTypeForEdges(/* isTouch= */ false);
        // Edge resizing is not supported for touchscreen input when the flag is disabled.
        validateCtrlTypeForEdges(/* isTouchscreen= */ false, /* isEdgeResizePermitted= */ true);
        validateCtrlTypeForEdges(/* isTouchscreen= */ true, /* isEdgeResizePermitted= */ false);
    }

    private void validateCtrlTypeForEdges(boolean isTouch) {
        assertThat(GEOMETRY.calculateCtrlType(isTouch, LEFT_EDGE_POINT.x,
                LEFT_EDGE_POINT.y)).isEqualTo(CTRL_TYPE_LEFT);
        assertThat(GEOMETRY.calculateCtrlType(isTouch, TOP_EDGE_POINT.x,
                TOP_EDGE_POINT.y)).isEqualTo(CTRL_TYPE_TOP);
        assertThat(GEOMETRY.calculateCtrlType(isTouch, RIGHT_EDGE_POINT.x,
                RIGHT_EDGE_POINT.y)).isEqualTo(CTRL_TYPE_RIGHT);
        assertThat(GEOMETRY.calculateCtrlType(isTouch, BOTTOM_EDGE_POINT.x,
                BOTTOM_EDGE_POINT.y)).isEqualTo(CTRL_TYPE_BOTTOM);
    private void validateCtrlTypeForEdges(boolean isTouchscreen, boolean isEdgeResizePermitted) {
        assertThat(GEOMETRY.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                LEFT_EDGE_POINT.x, LEFT_EDGE_POINT.y)).isEqualTo(
                        isEdgeResizePermitted ? CTRL_TYPE_LEFT : CTRL_TYPE_UNDEFINED);
        assertThat(GEOMETRY.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                TOP_EDGE_POINT.x, TOP_EDGE_POINT.y)).isEqualTo(
                        isEdgeResizePermitted ? CTRL_TYPE_TOP : CTRL_TYPE_UNDEFINED);
        assertThat(GEOMETRY.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                RIGHT_EDGE_POINT.x, RIGHT_EDGE_POINT.y)).isEqualTo(
                        isEdgeResizePermitted ? CTRL_TYPE_RIGHT : CTRL_TYPE_UNDEFINED);
        assertThat(GEOMETRY.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                BOTTOM_EDGE_POINT.x, BOTTOM_EDGE_POINT.y)).isEqualTo(
                        isEdgeResizePermitted ? CTRL_TYPE_BOTTOM : CTRL_TYPE_UNDEFINED);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    public void testCalculateControlType_edgeDragResizeEnabled_corners() {
        final TestPoints fineTestPoints = new TestPoints(TASK_SIZE, FINE_CORNER_SIZE / 2);
        final TestPoints largeCornerTestPoints = new TestPoints(TASK_SIZE, LARGE_CORNER_SIZE / 2);

        // When the flag is enabled, points within fine corners should pass regardless of touch or
        // not. Points outside fine corners should not pass when using a course input (non-touch).
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouch= */ true, true);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouch= */ true, true);
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouch= */ false, true);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouch= */ false, false);
        // Edge resizing permitted (events from stylus/cursor) should have no impact on corners.
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ true, true);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ true, true);
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ false, true);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ false, true);
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ true, true);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ true, false);
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ false, true);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ false, false);

        // When the flag is enabled, points near the large corners should only pass when the point
        // is within the corner for large touch inputs.
        largeCornerTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouch= */ true, true);
        largeCornerTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouch= */ true,
                false);
        largeCornerTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouch= */ false, false);
        largeCornerTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouch= */ false,
                false);
        largeCornerTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ true, true);
        largeCornerTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ true, false);
        largeCornerTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ true, false);
        largeCornerTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ true, false);
    }

    @Test
    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    @DisableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
    public void testCalculateControlType_edgeDragResizeDisabled_corners() {
        final TestPoints fineTestPoints = new TestPoints(TASK_SIZE, FINE_CORNER_SIZE / 2);
        final TestPoints largeCornerTestPoints = new TestPoints(TASK_SIZE, LARGE_CORNER_SIZE / 2);

        // When the flag is disabled, points within fine corners should pass only when touch.
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouch= */ true, true);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouch= */ true, false);
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouch= */ false, false);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouch= */ false, false);
        // When the flag is disabled, points within fine corners should pass only from touchscreen.
        // Edge resize permitted (indicating the event is from a cursor/stylus) should have no
        // impact.
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ true, true);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ true, false);
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ false, true);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ false, false);

        // Points within fine corners should never pass when not from touchscreen; expect edge
        // resizing only.
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ true, false);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ true, false);
        fineTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ false, false);
        fineTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ false, false);

        // When the flag is disabled, points near the large corners should never pass.
        largeCornerTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouch= */ true, false);
        largeCornerTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouch= */ true,
                false);
        largeCornerTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouch= */ false, false);
        largeCornerTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouch= */ false,
                false);
        largeCornerTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ true, false);
        largeCornerTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                true, /* isEdgeResizePermitted= */ true, false);
        largeCornerTestPoints.validateCtrlTypeForInnerPoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ true, false);
        largeCornerTestPoints.validateCtrlTypeForOutsidePoints(GEOMETRY, /* isTouchscreen= */
                false, /* isEdgeResizePermitted= */ true, false);
    }

    /**
@@ -306,19 +346,20 @@ public class DragResizeWindowGeometryTests {
         * {@code @DragPositioningCallback.CtrlType}.
         */
        public void validateCtrlTypeForInnerPoints(@NonNull DragResizeWindowGeometry geometry,
                boolean isTouch, boolean expectedWithinGeometry) {
            assertThat(geometry.calculateCtrlType(isTouch, mTopLeftPoint.x,
                    mTopLeftPoint.y)).isEqualTo(
                boolean isTouchscreen, boolean isEdgeResizePermitted,
                boolean expectedWithinGeometry) {
            assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                    mTopLeftPoint.x, mTopLeftPoint.y)).isEqualTo(
                    expectedWithinGeometry ? CTRL_TYPE_LEFT | CTRL_TYPE_TOP : CTRL_TYPE_UNDEFINED);
            assertThat(geometry.calculateCtrlType(isTouch, mTopRightPoint.x,
                    mTopRightPoint.y)).isEqualTo(
            assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                    mTopRightPoint.x, mTopRightPoint.y)).isEqualTo(
                    expectedWithinGeometry ? CTRL_TYPE_RIGHT | CTRL_TYPE_TOP : CTRL_TYPE_UNDEFINED);
            assertThat(geometry.calculateCtrlType(isTouch, mBottomLeftPoint.x,
                    mBottomLeftPoint.y)).isEqualTo(
            assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                    mBottomLeftPoint.x, mBottomLeftPoint.y)).isEqualTo(
                    expectedWithinGeometry ? CTRL_TYPE_LEFT | CTRL_TYPE_BOTTOM
                            : CTRL_TYPE_UNDEFINED);
            assertThat(geometry.calculateCtrlType(isTouch, mBottomRightPoint.x,
                    mBottomRightPoint.y)).isEqualTo(
            assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                    mBottomRightPoint.x, mBottomRightPoint.y)).isEqualTo(
                    expectedWithinGeometry ? CTRL_TYPE_RIGHT | CTRL_TYPE_BOTTOM
                            : CTRL_TYPE_UNDEFINED);
        }
@@ -328,19 +369,20 @@ public class DragResizeWindowGeometryTests {
         * {@code @DragPositioningCallback.CtrlType}.
         */
        public void validateCtrlTypeForOutsidePoints(@NonNull DragResizeWindowGeometry geometry,
                boolean isTouch, boolean expectedWithinGeometry) {
            assertThat(geometry.calculateCtrlType(isTouch, mTopLeftPointOutside.x,
                    mTopLeftPointOutside.y)).isEqualTo(
                boolean isTouchscreen, boolean isEdgeResizePermitted,
                boolean expectedWithinGeometry) {
            assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                    mTopLeftPointOutside.x, mTopLeftPointOutside.y)).isEqualTo(
                    expectedWithinGeometry ? CTRL_TYPE_LEFT | CTRL_TYPE_TOP : CTRL_TYPE_UNDEFINED);
            assertThat(geometry.calculateCtrlType(isTouch, mTopRightPointOutside.x,
                    mTopRightPointOutside.y)).isEqualTo(
            assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                    mTopRightPointOutside.x, mTopRightPointOutside.y)).isEqualTo(
                    expectedWithinGeometry ? CTRL_TYPE_RIGHT | CTRL_TYPE_TOP : CTRL_TYPE_UNDEFINED);
            assertThat(geometry.calculateCtrlType(isTouch, mBottomLeftPointOutside.x,
                    mBottomLeftPointOutside.y)).isEqualTo(
            assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                    mBottomLeftPointOutside.x, mBottomLeftPointOutside.y)).isEqualTo(
                    expectedWithinGeometry ? CTRL_TYPE_LEFT | CTRL_TYPE_BOTTOM
                            : CTRL_TYPE_UNDEFINED);
            assertThat(geometry.calculateCtrlType(isTouch, mBottomRightPointOutside.x,
                    mBottomRightPointOutside.y)).isEqualTo(
            assertThat(geometry.calculateCtrlType(isTouchscreen, isEdgeResizePermitted,
                    mBottomRightPointOutside.x, mBottomRightPointOutside.y)).isEqualTo(
                    expectedWithinGeometry ? CTRL_TYPE_RIGHT | CTRL_TYPE_BOTTOM
                            : CTRL_TYPE_UNDEFINED);
        }