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

Commit 78b37190 authored by Ats Jenk's avatar Ats Jenk Committed by Android (Google) Code Review
Browse files

Merge "Resize tasks from corners when in touch mode" into tm-qpr-dev

parents fd0c9bfa b30627ad
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.os.Handler;
import android.view.Choreographer;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewConfiguration;
import android.window.WindowContainerTransaction;

import com.android.wm.shell.R;
@@ -55,6 +56,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
    // Height of button (32dp)  + 2 * margin (5dp each)
    private static final int DECOR_CAPTION_HEIGHT_IN_DIP = 42;
    private static final int RESIZE_HANDLE_IN_DIP = 30;
    private static final int RESIZE_CORNER_IN_DIP = 44;

    private static final Rect EMPTY_OUTSET = new Rect();
    private static final Rect RESIZE_HANDLE_OUTSET = new Rect(
@@ -153,8 +155,11 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
                        mDragResizeCallback);
        }

        int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()).getScaledTouchSlop();

        mDragResizeListener.setGeometry(
                mResult.mWidth, mResult.mHeight, (int) (mResult.mDensity * RESIZE_HANDLE_IN_DIP));
                mResult.mWidth, mResult.mHeight, (int) (mResult.mDensity * RESIZE_HANDLE_IN_DIP),
                (int) (mResult.mDensity * RESIZE_CORNER_IN_DIP), touchSlop);
    }

    /**
+150 −15
Original line number Diff line number Diff line
@@ -16,11 +16,13 @@

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.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;

import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.input.InputManager;
@@ -42,8 +44,11 @@ import com.android.internal.view.BaseIWindow;

/**
 * An input event listener registered to InputDispatcher to receive input events on task edges and
 * convert them to drag resize requests.
 * and corners. Converts them to drag resize requests.
 * Task edges are for resizing with a mouse.
 * Task corners are for resizing with touch input.
 */
// TODO(b/251270585): investigate how to pass taps in corners to the tasks
class DragResizeInputListener implements AutoCloseable {
    private static final String TAG = "DragResizeInputListener";

@@ -63,8 +68,15 @@ class DragResizeInputListener implements AutoCloseable {
    private int mWidth;
    private int mHeight;
    private int mResizeHandleThickness;
    private int mCornerSize;

    private Rect mLeftTopCornerBounds;
    private Rect mRightTopCornerBounds;
    private Rect mLeftBottomCornerBounds;
    private Rect mRightBottomCornerBounds;

    private int mDragPointerId = -1;
    private int mTouchSlop;

    DragResizeInputListener(
            Context context,
@@ -118,16 +130,23 @@ class DragResizeInputListener implements AutoCloseable {
     * @param height The height of the drag resize handler in pixels, including resize handle
     *               thickness. That is task height + 2 * resize handle thickness.
     * @param resizeHandleThickness The thickness of the resize handle in pixels.
     * @param cornerSize The size of the resize handle centered in each corner.
     * @param touchSlop The distance in pixels user has to drag with touch for it to register as
     *                  a resize action.
     */
    void setGeometry(int width, int height, int resizeHandleThickness) {
    void setGeometry(int width, int height, int resizeHandleThickness, int cornerSize,
            int touchSlop) {
        if (mWidth == width && mHeight == height
                && mResizeHandleThickness == resizeHandleThickness) {
                && mResizeHandleThickness == resizeHandleThickness
                && mCornerSize == cornerSize) {
            return;
        }

        mWidth = width;
        mHeight = height;
        mResizeHandleThickness = resizeHandleThickness;
        mCornerSize = cornerSize;
        mTouchSlop = touchSlop;

        Region touchRegion = new Region();
        final Rect topInputBounds = new Rect(0, 0, mWidth, mResizeHandleThickness);
@@ -146,6 +165,40 @@ class DragResizeInputListener implements AutoCloseable {
                mWidth, mHeight);
        touchRegion.union(bottomInputBounds);

        // Set up touch areas in each corner.
        int cornerRadius = mCornerSize / 2;
        mLeftTopCornerBounds = new Rect(
                mResizeHandleThickness - cornerRadius,
                mResizeHandleThickness - cornerRadius,
                mResizeHandleThickness + cornerRadius,
                mResizeHandleThickness + cornerRadius
        );
        touchRegion.union(mLeftTopCornerBounds);

        mRightTopCornerBounds = new Rect(
                mWidth - mResizeHandleThickness - cornerRadius,
                mResizeHandleThickness - cornerRadius,
                mWidth - mResizeHandleThickness + cornerRadius,
                mResizeHandleThickness + cornerRadius
        );
        touchRegion.union(mRightTopCornerBounds);

        mLeftBottomCornerBounds = new Rect(
                mResizeHandleThickness - cornerRadius,
                mHeight - mResizeHandleThickness - cornerRadius,
                mResizeHandleThickness + cornerRadius,
                mHeight - mResizeHandleThickness + cornerRadius
        );
        touchRegion.union(mLeftBottomCornerBounds);

        mRightBottomCornerBounds = new Rect(
                mWidth - mResizeHandleThickness - cornerRadius,
                mHeight - mResizeHandleThickness - cornerRadius,
                mWidth - mResizeHandleThickness + cornerRadius,
                mHeight - mResizeHandleThickness + cornerRadius
        );
        touchRegion.union(mRightBottomCornerBounds);

        try {
            mWindowSession.updateInputChannel(
                    mInputChannel.getToken(),
@@ -173,6 +226,9 @@ class DragResizeInputListener implements AutoCloseable {
        private final Choreographer mChoreographer;
        private final Runnable mConsumeBatchEventRunnable;
        private boolean mConsumeBatchEventScheduled;
        private boolean mShouldHandleEvents;
        private boolean mDragging;
        private final PointF mActionDownPoint = new PointF();

        private TaskResizeInputEventReceiver(
                InputChannel inputChannel, Handler handler, Choreographer choreographer) {
@@ -216,41 +272,101 @@ class DragResizeInputListener implements AutoCloseable {
            }

            MotionEvent e = (MotionEvent) inputEvent;
            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 = (e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN;

            switch (e.getActionMasked()) {
                case MotionEvent.ACTION_DOWN: {
                    float x = e.getX(0);
                    float y = e.getY(0);
                    if (isTouch) {
                        mShouldHandleEvents = isInCornerBounds(x, y);
                    } else {
                        mShouldHandleEvents = isInResizeHandleBounds(x, y);
                    }
                    if (mShouldHandleEvents) {
                        mDragPointerId = e.getPointerId(0);
                    mCallback.onDragResizeStart(
                            calculateCtrlType(e.getX(0), e.getY(0)), e.getRawX(0), e.getRawY(0));
                        float rawX = e.getRawX(0);
                        float rawY = e.getRawY(0);
                        mActionDownPoint.set(rawX, rawY);
                        int ctrlType = calculateCtrlType(isTouch, x, y);
                        mCallback.onDragResizeStart(ctrlType, rawX, rawY);
                        result = true;
                    }
                    break;
                }
                case MotionEvent.ACTION_MOVE: {
                    if (!mShouldHandleEvents) {
                        break;
                    }
                    int dragPointerIndex = e.findPointerIndex(mDragPointerId);
                    mCallback.onDragResizeMove(
                            e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex));
                    float rawX = e.getRawX(dragPointerIndex);
                    float rawY = e.getRawY(dragPointerIndex);
                    if (isTouch) {
                        // Check for touch slop for touch events
                        float dx = rawX - mActionDownPoint.x;
                        float dy = rawY - mActionDownPoint.y;
                        if (!mDragging && Math.hypot(dx, dy) > mTouchSlop) {
                            mDragging = true;
                        }
                    } else {
                        // For all other types allow immediate dragging.
                        mDragging = true;
                    }
                    if (mDragging) {
                        mCallback.onDragResizeMove(rawX, rawY);
                        result = true;
                    }
                    break;
                }
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL: {
                    if (mDragging) {
                        int dragPointerIndex = e.findPointerIndex(mDragPointerId);
                        mCallback.onDragResizeEnd(
                                e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex));
                    }
                    mDragging = false;
                    mShouldHandleEvents = false;
                    mActionDownPoint.set(0, 0);
                    mDragPointerId = -1;
                    result = true;
                    break;
                }
                case MotionEvent.ACTION_HOVER_ENTER:
                case MotionEvent.ACTION_HOVER_MOVE: {
                    updateCursorType(e.getXCursorPosition(), e.getYCursorPosition());
                    result = true;
                    break;
                }
                case MotionEvent.ACTION_HOVER_EXIT:
                    mInputManager.setPointerIconType(PointerIcon.TYPE_DEFAULT);
                    result = true;
                    break;
            }
            return true;
            return result;
        }

        private boolean isInCornerBounds(float xf, float yf) {
            return calculateCornersCtrlType(xf, yf) != 0;
        }

        private boolean isInResizeHandleBounds(float x, float y) {
            return calculateResizeHandlesCtrlType(x, y) != 0;
        }

        @TaskPositioner.CtrlType
        private int calculateCtrlType(boolean isTouch, float x, float y) {
            if (isTouch) {
                return calculateCornersCtrlType(x, y);
            }
            return calculateResizeHandlesCtrlType(x, y);
        }

        @TaskPositioner.CtrlType
        private int calculateCtrlType(float x, float y) {
        private int calculateResizeHandlesCtrlType(float x, float y) {
            int ctrlType = 0;
            if (x < mResizeHandleThickness) {
                ctrlType |= TaskPositioner.CTRL_TYPE_LEFT;
@@ -267,8 +383,27 @@ class DragResizeInputListener implements AutoCloseable {
            return ctrlType;
        }

        @TaskPositioner.CtrlType
        private int calculateCornersCtrlType(float x, float y) {
            int xi = (int) x;
            int yi = (int) y;
            if (mLeftTopCornerBounds.contains(xi, yi)) {
                return TaskPositioner.CTRL_TYPE_LEFT | TaskPositioner.CTRL_TYPE_TOP;
            }
            if (mLeftBottomCornerBounds.contains(xi, yi)) {
                return TaskPositioner.CTRL_TYPE_LEFT | TaskPositioner.CTRL_TYPE_BOTTOM;
            }
            if (mRightTopCornerBounds.contains(xi, yi)) {
                return TaskPositioner.CTRL_TYPE_RIGHT | TaskPositioner.CTRL_TYPE_TOP;
            }
            if (mRightBottomCornerBounds.contains(xi, yi)) {
                return TaskPositioner.CTRL_TYPE_RIGHT | TaskPositioner.CTRL_TYPE_BOTTOM;
            }
            return 0;
        }

        private void updateCursorType(float x, float y) {
            @TaskPositioner.CtrlType int ctrlType = calculateCtrlType(x, y);
            @TaskPositioner.CtrlType int ctrlType = calculateResizeHandlesCtrlType(x, y);

            int cursorType = PointerIcon.TYPE_DEFAULT;
            switch (ctrlType) {
+2 −1
Original line number Diff line number Diff line
@@ -25,9 +25,10 @@ import com.android.wm.shell.ShellTaskOrganizer;

class TaskPositioner implements DragResizeCallback {

    @IntDef({CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM})
    @IntDef({CTRL_TYPE_UNDEFINED, CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM})
    @interface CtrlType {}

    static final int CTRL_TYPE_UNDEFINED = 0;
    static final int CTRL_TYPE_LEFT = 1;
    static final int CTRL_TYPE_RIGHT = 2;
    static final int CTRL_TYPE_TOP = 4;