Merging stylus click logic in longpress helper for better state-management
Bug: 150825081
Change-Id: I7c507c41e67c09bff5a4ad3abc7a7a62fecf910e
diff --git a/src/com/android/launcher3/CheckLongPressHelper.java b/src/com/android/launcher3/CheckLongPressHelper.java
index 639c173..ef353f9 100644
--- a/src/com/android/launcher3/CheckLongPressHelper.java
+++ b/src/com/android/launcher3/CheckLongPressHelper.java
@@ -16,46 +16,68 @@
package com.android.launcher3;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
-import com.android.launcher3.util.Thunk;
-
+/**
+ * Utility class to handle tripper long press on a view with custom timeout and stylus event
+ */
public class CheckLongPressHelper {
public static final float DEFAULT_LONG_PRESS_TIMEOUT_FACTOR = 0.75f;
- @Thunk View mView;
- @Thunk View.OnLongClickListener mListener;
- @Thunk boolean mHasPerformedLongPress;
- private float mLongPressTimeoutFactor = DEFAULT_LONG_PRESS_TIMEOUT_FACTOR;
- private CheckForLongPress mPendingCheckForLongPress;
+ private final View mView;
+ private final View.OnLongClickListener mListener;
+ private final float mSlop;
- class CheckForLongPress implements Runnable {
- public void run() {
- if ((mView.getParent() != null) && mView.hasWindowFocus()
- && !mHasPerformedLongPress) {
- boolean handled;
- if (mListener != null) {
- handled = mListener.onLongClick(mView);
- } else {
- handled = mView.performLongClick();
- }
- if (handled) {
- mView.setPressed(false);
- mHasPerformedLongPress = true;
- }
- }
- }
- }
+ private float mLongPressTimeoutFactor = DEFAULT_LONG_PRESS_TIMEOUT_FACTOR;
+
+ private boolean mHasPerformedLongPress;
+
+ private Runnable mPendingCheckForLongPress;
public CheckLongPressHelper(View v) {
- mView = v;
+ this(v, null);
}
public CheckLongPressHelper(View v, View.OnLongClickListener listener) {
mView = v;
mListener = listener;
+ mSlop = ViewConfiguration.get(mView.getContext()).getScaledTouchSlop();
+ }
+
+ /**
+ * Handles the touch event on a view
+ *
+ * @see View#onTouchEvent(MotionEvent)
+ */
+ public void onTouchEvent(MotionEvent ev) {
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN: {
+ // Just in case the previous long press hasn't been cleared, we make sure to
+ // start fresh on touch down.
+ cancelLongPress();
+
+ postCheckForLongPress();
+ if (isStylusButtonPressed(ev)) {
+ triggerLongPress();
+ }
+ break;
+ }
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ cancelLongPress();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (!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
+ triggerLongPress();
+ }
+ break;
+ }
}
/**
@@ -65,25 +87,64 @@
mLongPressTimeoutFactor = longPressTimeoutFactor;
}
- public void postCheckForLongPress() {
+ private void postCheckForLongPress() {
mHasPerformedLongPress = false;
if (mPendingCheckForLongPress == null) {
- mPendingCheckForLongPress = new CheckForLongPress();
+ mPendingCheckForLongPress = this::triggerLongPress;
}
mView.postDelayed(mPendingCheckForLongPress,
(long) (ViewConfiguration.getLongPressTimeout() * mLongPressTimeoutFactor));
}
+ /**
+ * Cancels any pending long press
+ */
public void cancelLongPress() {
mHasPerformedLongPress = false;
+ clearCallbacks();
+ }
+
+ /**
+ * Returns true if long press has been performed in the current touch gesture
+ */
+ public boolean hasPerformedLongPress() {
+ return mHasPerformedLongPress;
+ }
+
+ private void triggerLongPress() {
+ if ((mView.getParent() != null) && mView.hasWindowFocus() && !mHasPerformedLongPress) {
+ boolean handled;
+ if (mListener != null) {
+ handled = mListener.onLongClick(mView);
+ } else {
+ handled = mView.performLongClick();
+ }
+ if (handled) {
+ mView.setPressed(false);
+ mHasPerformedLongPress = true;
+ }
+ clearCallbacks();
+ }
+ }
+
+ private void clearCallbacks() {
if (mPendingCheckForLongPress != null) {
mView.removeCallbacks(mPendingCheckForLongPress);
mPendingCheckForLongPress = null;
}
}
- public boolean hasPerformedLongPress() {
- return mHasPerformedLongPress;
+
+ /**
+ * Identifies if the provided {@link MotionEvent} is a stylus with the primary stylus button
+ * pressed.
+ *
+ * @param event The event to check.
+ * @return Whether a stylus button press occurred.
+ */
+ private static boolean isStylusButtonPressed(MotionEvent event) {
+ return event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
+ && event.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
}
}