From 9ff8b2afe8edf71e362ecdbb54ccf88f59ca8450 Mon Sep 17 00:00:00 2001 From: mattsziklay Date: Wed, 2 Nov 2022 16:55:26 -0700 Subject: [PATCH] Prevent handle menu from opening on drag. Adds logic to suppress the onClick event if caption handle is dragged rather than clicked. Bug: 257125967 Test: Drag handle at various speeds and confirm menu does not open on ACTION_UP Change-Id: Iae0262b96f3bd28144be00885a2fe70664afb513 --- .../CaptionWindowDecorViewModel.java | 28 +++--- .../windowdecor/CaptionWindowDecoration.java | 9 ++ .../wm/shell/windowdecor/DragDetector.java | 87 +++++++++++++++++++ .../windowdecor/DragResizeInputListener.java | 23 ++--- 4 files changed, 122 insertions(+), 25 deletions(-) create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index ca15f0002faca..ebe5c5e716d72 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -124,7 +124,8 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { TaskPositioner taskPositioner = new TaskPositioner(mTaskOrganizer, windowDecoration, mDragStartListener); CaptionTouchEventListener touchEventListener = - new CaptionTouchEventListener(taskInfo, taskPositioner); + new CaptionTouchEventListener(taskInfo, taskPositioner, + windowDecoration.getDragDetector()); windowDecoration.setCaptionListeners(touchEventListener, touchEventListener); windowDecoration.setDragResizeCallback(taskPositioner); setupWindowDecorationForTransition(taskInfo, startT, finishT); @@ -173,16 +174,18 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { private final int mTaskId; private final WindowContainerToken mTaskToken; private final DragResizeCallback mDragResizeCallback; + private final DragDetector mDragDetector; private int mDragPointerId = -1; - private boolean mDragActive = false; private CaptionTouchEventListener( RunningTaskInfo taskInfo, - DragResizeCallback dragResizeCallback) { + DragResizeCallback dragResizeCallback, + DragDetector dragDetector) { mTaskId = taskInfo.taskId; mTaskToken = taskInfo.token; mDragResizeCallback = dragResizeCallback; + mDragDetector = dragDetector; } @Override @@ -231,19 +234,21 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { @Override public boolean onTouch(View v, MotionEvent e) { + boolean isDrag = false; int id = v.getId(); if (id != R.id.caption_handle && id != R.id.caption) { return false; } - if (id == R.id.caption_handle || mDragActive) { + if (id == R.id.caption_handle) { + isDrag = mDragDetector.detectDragEvent(e); handleEventForMove(e); } if (e.getAction() != MotionEvent.ACTION_DOWN) { - return false; + return isDrag; } RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); if (taskInfo.isFocused) { - return false; + return isDrag; } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.reorder(mTaskToken, true /* onTop */); @@ -251,6 +256,10 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { return true; } + /** + * @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) { RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); int windowingMode = mDesktopModeController @@ -259,12 +268,12 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { return; } switch (e.getActionMasked()) { - case MotionEvent.ACTION_DOWN: - mDragActive = true; - mDragPointerId = e.getPointerId(0); + case MotionEvent.ACTION_DOWN: { + mDragPointerId = e.getPointerId(0); mDragResizeCallback.onDragResizeStart( 0 /* ctrlType */, e.getRawX(0), e.getRawY(0)); break; + } case MotionEvent.ACTION_MOVE: { int dragPointerIdx = e.findPointerIndex(mDragPointerId); mDragResizeCallback.onDragResizeMove( @@ -273,7 +282,6 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { - mDragActive = false; int dragPointerIdx = e.findPointerIndex(mDragPointerId); int statusBarHeight = mDisplayController.getDisplayLayout(taskInfo.displayId) .stableInsets().top; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java index 03cad043ed67a..affde30094567 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java @@ -62,6 +62,8 @@ public class CaptionWindowDecoration extends WindowDecoration mTouchSlop) { + mIsDragEvent = true; + } + } + return mIsDragEvent; + } + case ACTION_UP: { + boolean result = mIsDragEvent; + mIsDragEvent = false; + mInputDownPoint.set(0, 0); + mDragPointerId = -1; + return result; + } + case ACTION_CANCEL: { + mIsDragEvent = false; + mInputDownPoint.set(0, 0); + mDragPointerId = -1; + return false; + } + } + return mIsDragEvent; + } + + public void setTouchSlop(int touchSlop) { + mTouchSlop = touchSlop; + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java index b9f16b63de48c..48c0cea150cc3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java @@ -22,7 +22,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERL 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; @@ -38,6 +37,7 @@ import android.view.InputEventReceiver; import android.view.MotionEvent; import android.view.PointerIcon; import android.view.SurfaceControl; +import android.view.ViewConfiguration; import android.view.WindowManagerGlobal; import com.android.internal.view.BaseIWindow; @@ -76,7 +76,7 @@ class DragResizeInputListener implements AutoCloseable { private Rect mRightBottomCornerBounds; private int mDragPointerId = -1; - private int mTouchSlop; + private DragDetector mDragDetector; DragResizeInputListener( Context context, @@ -115,6 +115,7 @@ class DragResizeInputListener implements AutoCloseable { mInputEventReceiver = new TaskResizeInputEventReceiver( mInputChannel, mHandler, mChoreographer); mCallback = callback; + mDragDetector = new DragDetector(ViewConfiguration.get(context).getScaledTouchSlop()); } /** @@ -146,7 +147,7 @@ class DragResizeInputListener implements AutoCloseable { mHeight = height; mResizeHandleThickness = resizeHandleThickness; mCornerSize = cornerSize; - mTouchSlop = touchSlop; + mDragDetector.setTouchSlop(touchSlop); Region touchRegion = new Region(); final Rect topInputBounds = new Rect(0, 0, mWidth, mResizeHandleThickness); @@ -228,7 +229,6 @@ class DragResizeInputListener implements AutoCloseable { private boolean mConsumeBatchEventScheduled; private boolean mShouldHandleEvents; private boolean mDragging; - private final PointF mActionDownPoint = new PointF(); private TaskResizeInputEventReceiver( InputChannel inputChannel, Handler handler, Choreographer choreographer) { @@ -276,7 +276,9 @@ class DragResizeInputListener implements AutoCloseable { // 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; - + if (isTouch) { + mDragging = mDragDetector.detectDragEvent(e); + } switch (e.getActionMasked()) { case MotionEvent.ACTION_DOWN: { float x = e.getX(0); @@ -290,7 +292,6 @@ class DragResizeInputListener implements AutoCloseable { mDragPointerId = e.getPointerId(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; @@ -304,14 +305,7 @@ class DragResizeInputListener implements AutoCloseable { int dragPointerIndex = e.findPointerIndex(mDragPointerId); 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 { + if (!isTouch) { // For all other types allow immediate dragging. mDragging = true; } @@ -330,7 +324,6 @@ class DragResizeInputListener implements AutoCloseable { } mDragging = false; mShouldHandleEvents = false; - mActionDownPoint.set(0, 0); mDragPointerId = -1; result = true; break;