From 9f90efb39efaa7c96b6f672f7fb04f5fb9e52d83 Mon Sep 17 00:00:00 2001 From: Fengjiang Li Date: Thu, 1 Dec 2022 16:53:17 -0800 Subject: [PATCH] Support right click to bring up app menu and actions Test: https://b.corp.google.com/action/issues/250092449/attachments/40159735?download=true Change-Id: I159005cc982478896d442bb2675ccb1bb7f0322e --- .../launcher3/CheckLongPressHelper.java | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/com/android/launcher3/CheckLongPressHelper.java b/src/com/android/launcher3/CheckLongPressHelper.java index c707df04c0..ec29b297a9 100644 --- a/src/com/android/launcher3/CheckLongPressHelper.java +++ b/src/com/android/launcher3/CheckLongPressHelper.java @@ -16,12 +16,15 @@ package com.android.launcher3; +import android.os.Handler; +import android.view.InputDevice; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; /** - * Utility class to handle tripper long press on a view with custom timeout and stylus event + * Utility class to handle tripper long press or right click on a view with custom timeout and + * stylus event */ public class CheckLongPressHelper { @@ -34,6 +37,7 @@ public class CheckLongPressHelper { private float mLongPressTimeoutFactor = DEFAULT_LONG_PRESS_TIMEOUT_FACTOR; private boolean mHasPerformedLongPress; + private boolean mIsInMouseRightClick; private Runnable mPendingCheckForLongPress; @@ -59,6 +63,26 @@ public class CheckLongPressHelper { // start fresh on touch down. cancelLongPress(); + // Mouse right click should immediately trigger a long press + if (isMouseRightClickDownOrMove(ev)) { + mIsInMouseRightClick = true; + triggerLongPress(); + final Handler handler = mView.getHandler(); + if (handler != null) { + // Send an ACTION_UP to end this click gesture to avoid user dragging with + // mouse's right button. Note that we need to call + // {@link Handler#postAtFrontOfQueue()} instead of {@link View#post()} to + // make sure ACTION_UP is sent before any ACTION_MOVE if user is dragging. + final MotionEvent actionUpEvent = MotionEvent.obtain(ev); + actionUpEvent.setAction(MotionEvent.ACTION_UP); + handler.postAtFrontOfQueue(() -> { + mView.getRootView().dispatchTouchEvent(actionUpEvent); + actionUpEvent.recycle(); + }); + } + break; + } + postCheckForLongPress(); if (isStylusButtonPressed(ev)) { triggerLongPress(); @@ -70,7 +94,8 @@ public class CheckLongPressHelper { cancelLongPress(); break; case MotionEvent.ACTION_MOVE: - if (!Utilities.pointInView(mView, ev.getX(), ev.getY(), mSlop)) { + if (mIsInMouseRightClick + || !Utilities.pointInView(mView, ev.getX(), ev.getY(), mSlop)) { cancelLongPress(); } else if (mPendingCheckForLongPress != null && isStylusButtonPressed(ev)) { // Only trigger long press if it has not been cancelled before @@ -98,9 +123,10 @@ public class CheckLongPressHelper { } /** - * Cancels any pending long press + * Cancels any pending long press and right click */ public void cancelLongPress() { + mIsInMouseRightClick = false; mHasPerformedLongPress = false; clearCallbacks(); } @@ -150,4 +176,14 @@ public class CheckLongPressHelper { return event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS && event.isButtonPressed(MotionEvent.BUTTON_SECONDARY); } + + /** + * Detect ACTION_DOWN or ACTION_MOVE from mouse right button. Note that we cannot detect + * ACTION_UP from mouse's right button because, in that case, + * {@link MotionEvent#getButtonState()} returns 0 for any mouse button (right, middle, right). + */ + private static boolean isMouseRightClickDownOrMove(MotionEvent event) { + return event.isFromSource(InputDevice.SOURCE_MOUSE) + && ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0); + } }