From d5aef3dbd7cb47de196bab1c2cff8f2bae4816b0 Mon Sep 17 00:00:00 2001 From: Suphon Thanakornpakapong Date: Mon, 16 May 2022 11:04:27 +0700 Subject: [PATCH 1/2] Fix widget resize triggering while scrolling --- .../e/blisslauncher/core/Utilities.java | 11 ++ .../core/customviews/RoundedWidgetView.java | 38 +----- .../widgets/CheckLongPressHelper.java | 128 +++++++++++++++--- 3 files changed, 125 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/foundation/e/blisslauncher/core/Utilities.java b/app/src/main/java/foundation/e/blisslauncher/core/Utilities.java index 51492aa865..537ff2276a 100755 --- a/app/src/main/java/foundation/e/blisslauncher/core/Utilities.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/Utilities.java @@ -209,6 +209,17 @@ public class Utilities { return defaultValue; } + /** + * Utility method to determine whether the given point, in local coordinates, + * is inside the view, where the area of the view is expanded by the slop factor. + * This method is called while processing touch-move events to determine if the event + * is still within the view. + */ + public static boolean pointInView(View v, float localX, float localY, float slop) { + return localX >= -slop && localY >= -slop && localX < (v.getWidth() + slop) && + localY < (v.getHeight() + slop); + } + /** * Ensures that a value is within given bounds. Specifically: * If value is less than lowerBound, return lowerBound; else if value is greater than upperBound, diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java index 9142d970bd..1d470abc33 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java @@ -86,38 +86,14 @@ public class RoundedWidgetView extends AppWidgetHostView { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - Log.d(TAG, "onInterceptTouchEvent() called with: ev = [" + ev.getAction() + "]"); - - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - mLongPressHelper.cancelLongPress(); - } - - // Consume any touch events for ourselves after longpress is triggered - if (mLongPressHelper.hasPerformedLongPress()) { - mLongPressHelper.cancelLongPress(); - return true; - } - - // Watch for longpress events at this level to make sure - // users can always pick up this widget - switch (ev.getAction()) { - case MotionEvent.ACTION_DOWN: { - mLongPressHelper.postCheckForLongPress(); - break; - } - - case MotionEvent.ACTION_UP: - mLongPressHelper.cancelLongPress(); - break; - - case MotionEvent.ACTION_CANCEL: - mLongPressHelper.cancelLongPress(); - break; - } - - // Otherwise continue letting touch events fall through to children - return false; + mLongPressHelper.onTouchEvent(ev); + return mLongPressHelper.hasPerformedLongPress(); + } + @Override + public boolean onTouchEvent(MotionEvent event) { + mLongPressHelper.onTouchEvent(event); + return true; } @Override diff --git a/app/src/main/java/foundation/e/blisslauncher/features/widgets/CheckLongPressHelper.java b/app/src/main/java/foundation/e/blisslauncher/features/widgets/CheckLongPressHelper.java index 9563d20f62..a688201ad8 100644 --- a/app/src/main/java/foundation/e/blisslauncher/features/widgets/CheckLongPressHelper.java +++ b/app/src/main/java/foundation/e/blisslauncher/features/widgets/CheckLongPressHelper.java @@ -16,54 +16,140 @@ package foundation.e.blisslauncher.features.widgets; -import android.util.Log; +import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; -import foundation.e.blisslauncher.BlissLauncher; +import foundation.e.blisslauncher.core.Utilities; +/** + * Utility class to handle tripper long press on a view with custom timeout and stylus event + */ public class CheckLongPressHelper { - private View mView; + + public static final float DEFAULT_LONG_PRESS_TIMEOUT_FACTOR = 0.75f; + + private final View mView; + private final View.OnLongClickListener mListener; + private final float mSlop; + + private float mLongPressTimeoutFactor = DEFAULT_LONG_PRESS_TIMEOUT_FACTOR; + private boolean mHasPerformedLongPress; - private CheckForLongPress mPendingCheckForLongPress; - private static final String TAG = "CheckLongPressHelper"; + private Runnable mPendingCheckForLongPress; + + public CheckLongPressHelper(View v) { + this(v, null); + } - class CheckForLongPress implements Runnable { - public void run() { - if ((mView.getParent() != null) && mView.hasWindowFocus() - && !mHasPerformedLongPress) { - if (mView.performLongClick()) { - mView.setPressed(false); - mHasPerformedLongPress = true; + 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; } } - public CheckLongPressHelper(View v) { - mView = v; + /** + * Overrides the default long press timeout. + */ + public void setLongPressTimeoutFactor(float longPressTimeoutFactor) { + mLongPressTimeoutFactor = longPressTimeoutFactor; } - public void postCheckForLongPress() { - Log.d(TAG, "postCheckForLongPress() called"); + private void postCheckForLongPress() { mHasPerformedLongPress = false; if (mPendingCheckForLongPress == null) { - mPendingCheckForLongPress = new CheckForLongPress(); + mPendingCheckForLongPress = this::triggerLongPress; } - mView.postDelayed(mPendingCheckForLongPress, BlissLauncher.getLongPressTimeout()); + mView.postDelayed(mPendingCheckForLongPress, + (long) (ViewConfiguration.getLongPressTimeout() * mLongPressTimeoutFactor)); } + /** + * Cancels any pending long press + */ public void cancelLongPress() { - Log.d(TAG, "cancelLongPress() called"); 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() + && (!mView.isPressed() || mListener != null) + && !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); } } -- GitLab From a41137ede7bc78f4c8f4a6f2013fd25b7edc8a54 Mon Sep 17 00:00:00 2001 From: Suphon Thanakornpakapong Date: Mon, 16 May 2022 15:28:10 +0700 Subject: [PATCH 2/2] Remove unused import --- .../e/blisslauncher/core/customviews/RoundedWidgetView.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java b/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java index 1d470abc33..69d69f3e58 100644 --- a/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java +++ b/app/src/main/java/foundation/e/blisslauncher/core/customviews/RoundedWidgetView.java @@ -6,7 +6,6 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Path; import android.graphics.Rect; -import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -- GitLab