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

Commit 4afcdf74 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Modify flag behaviour to apply edge resizing to both stylus & cursor." into main

parents 9bd13ddc e3d29ca3
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;
@@ -392,10 +393,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) {
                        // Save the id of the pointer for this drag interaction; we will use the
@@ -405,7 +405,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,
@@ -493,8 +494,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) {
@@ -536,9 +540,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);
        }