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

Commit 7ea23aa2 authored by Garfield Tan's avatar Garfield Tan
Browse files

Refactor DragDetector and fix a few resizing bugs

There are a few things this CL does:

1. It refactors DragDetector to filter out moves in the slop instead of
   returning a boolean value to let the caller to decide what to do with
   it.
2. It fixes the bug that window decors respond to window moves in the
   slop.
3. It skips the unnecessary transaction at the end of drag resizing
   gesture in TaskPositioner if nothing has changed.
4. It fixes the bug that TaskPositioner uses if the new task bounds is
   empty to decide if there is no change in the task bounds.

Bug: 266448890
Test: Drag resize windows with mice and fingers.
Test: atest WMShellUnitTests

Change-Id: I8e9e1204e841bfd8f730d4091e37955f1f376018
parent f7347b49
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -175,16 +175,18 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
                new CaptionTouchEventListener(taskInfo, taskPositioner);
        windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
        windowDecoration.setDragResizeCallback(taskPositioner);
        windowDecoration.setDragDetector(touchEventListener.mDragDetector);
        windowDecoration.relayout(taskInfo, startT, finishT);
        setupCaptionColor(taskInfo, windowDecoration);
    }

    private class CaptionTouchEventListener implements
            View.OnClickListener, View.OnTouchListener {
            View.OnClickListener, View.OnTouchListener, DragDetector.MotionEventHandler {

        private final int mTaskId;
        private final WindowContainerToken mTaskToken;
        private final DragResizeCallback mDragResizeCallback;
        private final DragDetector mDragDetector;

        private int mDragPointerId = -1;

@@ -194,6 +196,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
            mTaskId = taskInfo.taskId;
            mTaskToken = taskInfo.token;
            mDragResizeCallback = dragResizeCallback;
            mDragDetector = new DragDetector(this);
        }

        @Override
@@ -216,7 +219,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
            if (v.getId() != R.id.caption) {
                return false;
            }
            handleEventForMove(e);
            mDragDetector.onMotionEvent(e);

            if (e.getAction() != MotionEvent.ACTION_DOWN) {
                return false;
@@ -235,10 +238,11 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
         * @param e {@link MotionEvent} to process
         * @return {@code true} if a drag is happening; or {@code false} if it is not
         */
        private void handleEventForMove(MotionEvent e) {
        @Override
        public boolean handleMotionEvent(MotionEvent e) {
            final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
            if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
                return;
                return false;
            }
            switch (e.getActionMasked()) {
                case MotionEvent.ACTION_DOWN: {
@@ -261,6 +265,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
                    break;
                }
            }
            return true;
        }
    }
}
 No newline at end of file
+6 −2
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
    private View.OnTouchListener mOnCaptionTouchListener;
    private DragResizeCallback mDragResizeCallback;
    private DragResizeInputListener mDragResizeListener;
    private final DragDetector mDragDetector;
    private DragDetector mDragDetector;

    private RelayoutParams mRelayoutParams = new RelayoutParams();
    private final RelayoutResult<WindowDecorLinearLayout> mResult =
@@ -69,7 +69,6 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
        mHandler = handler;
        mChoreographer = choreographer;
        mSyncQueue = syncQueue;
        mDragDetector = new DragDetector(ViewConfiguration.get(context).getScaledTouchSlop());
    }

    void setCaptionListeners(
@@ -83,6 +82,11 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
        mDragResizeCallback = dragResizeCallback;
    }

    void setDragDetector(DragDetector dragDetector) {
        mDragDetector = dragDetector;
        mDragDetector.setTouchSlop(ViewConfiguration.get(mContext).getScaledTouchSlop());
    }

    @Override
    void relayout(RunningTaskInfo taskInfo) {
        final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+13 −14
Original line number Diff line number Diff line
@@ -205,7 +205,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
    }

    private class DesktopModeTouchEventListener implements
            View.OnClickListener, View.OnTouchListener {
            View.OnClickListener, View.OnTouchListener, DragDetector.MotionEventHandler {

        private final int mTaskId;
        private final WindowContainerToken mTaskToken;
@@ -216,12 +216,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {

        private DesktopModeTouchEventListener(
                RunningTaskInfo taskInfo,
                DragResizeCallback dragResizeCallback,
                DragDetector dragDetector) {
                DragResizeCallback dragResizeCallback) {
            mTaskId = taskInfo.taskId;
            mTaskToken = taskInfo.token;
            mDragResizeCallback = dragResizeCallback;
            mDragDetector = dragDetector;
            mDragDetector = new DragDetector(this);
        }

        @Override
@@ -254,8 +253,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                return false;
            }
            if (id == R.id.caption_handle) {
                isDrag = mDragDetector.detectDragEvent(e);
                handleEventForMove(e);
                isDrag = mDragDetector.onMotionEvent(e);
            }
            if (e.getAction() != MotionEvent.ACTION_DOWN) {
                return isDrag;
@@ -272,19 +270,19 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {

        /**
         * @param e {@link MotionEvent} to process
         * @return {@code true} if a drag is happening; or {@code false} if it is not
         * @return {@code true} if the motion event is handled.
         */
        private void handleEventForMove(MotionEvent e) {
        @Override
        public boolean handleMotionEvent(MotionEvent e) {
            final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
            if (DesktopModeStatus.isProto2Enabled()
                    && taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
                return;
                return false;
            }
            if (DesktopModeStatus.isProto1Enabled() && mDesktopModeController.isPresent()
                    && mDesktopModeController.get().getDisplayAreaWindowingMode(
                    taskInfo.displayId)
                    && mDesktopModeController.get().getDisplayAreaWindowingMode(taskInfo.displayId)
                    == WINDOWING_MODE_FULLSCREEN) {
                return;
                return false;
            }
            switch (e.getActionMasked()) {
                case MotionEvent.ACTION_DOWN: {
@@ -324,6 +322,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                    break;
                }
            }
            return true;
        }
    }

@@ -560,10 +559,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        final TaskPositioner taskPositioner =
                new TaskPositioner(mTaskOrganizer, windowDecoration, mDragStartListener);
        final DesktopModeTouchEventListener touchEventListener =
                new DesktopModeTouchEventListener(
                        taskInfo, taskPositioner, windowDecoration.getDragDetector());
                new DesktopModeTouchEventListener(taskInfo, taskPositioner);
        windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
        windowDecoration.setDragResizeCallback(taskPositioner);
        windowDecoration.setDragDetector(touchEventListener.mDragDetector);
        windowDecoration.relayout(taskInfo, startT, finishT);
        incrementEventReceiverTasks(taskInfo.displayId);
    }
+4 −4
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private View.OnTouchListener mOnCaptionTouchListener;
    private DragResizeCallback mDragResizeCallback;
    private DragResizeInputListener mDragResizeListener;
    private final DragDetector mDragDetector;
    private DragDetector mDragDetector;

    private RelayoutParams mRelayoutParams = new RelayoutParams();
    private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult =
@@ -81,7 +81,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        mChoreographer = choreographer;
        mSyncQueue = syncQueue;
        mDesktopActive = DesktopModeStatus.isActive(mContext);
        mDragDetector = new DragDetector(ViewConfiguration.get(context).getScaledTouchSlop());
    }

    void setCaptionListeners(
@@ -95,8 +94,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        mDragResizeCallback = dragResizeCallback;
    }

    DragDetector getDragDetector() {
        return mDragDetector;
    void setDragDetector(DragDetector dragDetector) {
        mDragDetector = dragDetector;
        mDragDetector.setTouchSlop(ViewConfiguration.get(mContext).getScaledTouchSlop());
    }

    @Override
+51 −31
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.wm.shell.windowdecor;

import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
@@ -25,63 +26,82 @@ import android.graphics.PointF;
import android.view.MotionEvent;

/**
 * A detector for touch inputs that differentiates between drag and click inputs.
 * A detector for touch inputs that differentiates between drag and click inputs. It receives a flow
 * of {@link MotionEvent} and generates a new flow of motion events with slop in consideration to
 * the event handler. In particular, it always passes down, up and cancel events. It'll pass move
 * events only when there is at least one move event that's beyond the slop threshold. For the
 * purpose of convenience it also passes all events of other actions.
 *
 * All touch events must be passed through this class to track a drag event.
 */
public class DragDetector {
class DragDetector {
    private final MotionEventHandler mEventHandler;

    private final PointF mInputDownPoint = new PointF();
    private int mTouchSlop;
    private PointF mInputDownPoint;
    private boolean mIsDragEvent;
    private int mDragPointerId;
    public DragDetector(int touchSlop) {
        mTouchSlop = touchSlop;
        mInputDownPoint = new PointF();
        mIsDragEvent = false;
        mDragPointerId = -1;

    private boolean mResultOfDownAction;

    DragDetector(MotionEventHandler eventHandler) {
        resetState();
        mEventHandler = eventHandler;
    }

    /**
     * Determine if {@link MotionEvent} is part of a drag event.
     * @return {@code true} if this is a drag event, {@code false} if not
     * The receiver of the {@link MotionEvent} flow.
     *
     * @return the result returned by {@link #mEventHandler}, or the result when
     * {@link #mEventHandler} handles the previous down event if the event shouldn't be passed
    */
    public boolean detectDragEvent(MotionEvent ev) {
        switch (ev.getAction()) {
    boolean onMotionEvent(MotionEvent ev) {
        switch (ev.getActionMasked()) {
            case ACTION_DOWN: {
                // Only touch screens generate noisy moves.
                mIsDragEvent = (ev.getSource() & SOURCE_TOUCHSCREEN) != SOURCE_TOUCHSCREEN;
                mDragPointerId = ev.getPointerId(0);
                float rawX = ev.getRawX(0);
                float rawY = ev.getRawY(0);
                mInputDownPoint.set(rawX, rawY);
                return false;
                mResultOfDownAction = mEventHandler.handleMotionEvent(ev);
                return mResultOfDownAction;
            }
            case ACTION_MOVE: {
                if (!mIsDragEvent) {
                    int dragPointerIndex = ev.findPointerIndex(mDragPointerId);
                    float dx = ev.getRawX(dragPointerIndex) - mInputDownPoint.x;
                    float dy = ev.getRawY(dragPointerIndex) - mInputDownPoint.y;
                    if (Math.hypot(dx, dy) > mTouchSlop) {
                        mIsDragEvent = true;
                    }
                    mIsDragEvent = Math.hypot(dx, dy) > mTouchSlop;
                }
                return mIsDragEvent;
                if (mIsDragEvent) {
                    return mEventHandler.handleMotionEvent(ev);
                } else {
                    return mResultOfDownAction;
                }
            case ACTION_UP: {
                boolean result = mIsDragEvent;
                mIsDragEvent = false;
                mInputDownPoint.set(0, 0);
                mDragPointerId = -1;
                return result;
            }
            case ACTION_UP:
            case ACTION_CANCEL: {
                mIsDragEvent = false;
                mInputDownPoint.set(0, 0);
                mDragPointerId = -1;
                return false;
                resetState();
                return mEventHandler.handleMotionEvent(ev);
            }
            default:
                return mEventHandler.handleMotionEvent(ev);
        }
        return mIsDragEvent;
    }

    public void setTouchSlop(int touchSlop) {
    void setTouchSlop(int touchSlop) {
        mTouchSlop = touchSlop;
    }

    private void resetState() {
        mIsDragEvent = false;
        mInputDownPoint.set(0, 0);
        mDragPointerId = -1;
        mResultOfDownAction = false;
    }

    interface MotionEventHandler {
        boolean handleMotionEvent(MotionEvent ev);
    }
}
Loading