Commit d5aef3db authored by Suphon Thanakornpakapong's avatar Suphon Thanakornpakapong
Browse files

Fix widget resize triggering while scrolling

parent 15dc8a71
Pipeline #185943 failed with stage
in 2 minutes and 14 seconds
......@@ -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,
......
......@@ -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
......
......@@ -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);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment