From 769c795edfe77fe2a3f6472a5b60fd1a73618a13 Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Tue, 1 Oct 2019 13:52:22 -0700 Subject: Some cleanup for SwipeDetector. It is now organized as follows: - private constants - public constants - private final fields - private variable fields - constructors - public methods - private methods - public interface/abstract class This is intended to be a functional no-op. Bug: 141939911 Change-Id: Iad5a9b3b73b35641f8a4f1d52ada6adef3825c47 Tested: Built and sanity checked manually. --- .../notification/NotificationItemView.java | 4 +- src/com/android/launcher3/touch/SwipeDetector.java | 275 ++++++++++----------- .../android/launcher3/touch/SwipeDetectorTest.java | 8 +- 3 files changed, 136 insertions(+), 151 deletions(-) diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java index 32410a64b..717a7e93d 100644 --- a/src/com/android/launcher3/notification/NotificationItemView.java +++ b/src/com/android/launcher3/notification/NotificationItemView.java @@ -16,6 +16,8 @@ package com.android.launcher3.notification; +import static com.android.launcher3.touch.SwipeDetector.HORIZONTAL; + import android.app.Notification; import android.content.Context; import android.graphics.Color; @@ -33,8 +35,6 @@ import com.android.launcher3.util.Themes; import java.util.List; -import static com.android.launcher3.touch.SwipeDetector.HORIZONTAL; - /** * Utility class to manage notification UI */ diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java index 3777a41ad..d0edfd87d 100644 --- a/src/com/android/launcher3/touch/SwipeDetector.java +++ b/src/com/android/launcher3/touch/SwipeDetector.java @@ -24,12 +24,11 @@ import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; -import com.android.launcher3.Utilities; -import com.android.launcher3.testing.TestProtocol; - import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import com.android.launcher3.Utilities; + /** * One dimensional scroll/drag/swipe gesture detector. * @@ -41,47 +40,14 @@ public class SwipeDetector { private static final boolean DBG = false; private static final String TAG = "SwipeDetector"; + private static final float ANIMATION_DURATION = 1200; + /** The minimum release velocity in pixels per millisecond that triggers fling.*/ + private static final float RELEASE_VELOCITY_PX_MS = 1.0f; - private int mScrollConditions; public static final int DIRECTION_POSITIVE = 1 << 0; public static final int DIRECTION_NEGATIVE = 1 << 1; public static final int DIRECTION_BOTH = DIRECTION_NEGATIVE | DIRECTION_POSITIVE; - private static final float ANIMATION_DURATION = 1200; - - protected int mActivePointerId = INVALID_POINTER_ID; - - /** - * The minimum release velocity in pixels per millisecond that triggers fling.. - */ - public static final float RELEASE_VELOCITY_PX_MS = 1.0f; - - /* Scroll state, this is set to true during dragging and animation. */ - private ScrollState mState = ScrollState.IDLE; - - enum ScrollState { - IDLE, - DRAGGING, // onDragStart, onDrag - SETTLING // onDragEnd - } - - public static abstract class Direction { - - abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint, - boolean isRtl); - - /** - * Distance in pixels a touch can wander before we think the user is scrolling. - */ - abstract float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos); - - abstract float getVelocity(VelocityTracker tracker, boolean isRtl); - - abstract boolean isPositive(float displacement); - - abstract boolean isNegative(float displacement); - } - public static final Direction VERTICAL = new Direction() { @Override @@ -150,88 +116,28 @@ public class SwipeDetector { } }; - //------------------- ScrollState transition diagram ----------------------------------- - // - // IDLE -> (mDisplacement > mTouchSlop) -> DRAGGING - // DRAGGING -> (MotionEvent#ACTION_UP, MotionEvent#ACTION_CANCEL) -> SETTLING - // SETTLING -> (MotionEvent#ACTION_DOWN) -> DRAGGING - // SETTLING -> (View settled) -> IDLE - - private void setState(ScrollState newState) { - if (DBG) { - Log.d(TAG, "setState:" + mState + "->" + newState); - } - // onDragStart and onDragEnd is reported ONLY on state transition - if (newState == ScrollState.DRAGGING) { - initializeDragging(); - if (mState == ScrollState.IDLE) { - reportDragStart(false /* recatch */); - } else if (mState == ScrollState.SETTLING) { - reportDragStart(true /* recatch */); - } - } - if (newState == ScrollState.SETTLING) { - reportDragEnd(); - } - - mState = newState; - } - - public boolean isDraggingOrSettling() { - return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING; - } - - public int getDownX() { - return (int) mDownPos.x; - } - - public int getDownY() { - return (int) mDownPos.y; - } - /** - * There's no touch and there's no animation. - */ - public boolean isIdleState() { - return mState == ScrollState.IDLE; - } - - public boolean isSettlingState() { - return mState == ScrollState.SETTLING; - } - - public boolean isDraggingState() { - return mState == ScrollState.DRAGGING; - } - private final PointF mDownPos = new PointF(); private final PointF mLastPos = new PointF(); private final Direction mDir; private final boolean mIsRtl; - private final float mTouchSlop; private final float mMaxVelocity; - /* Client of this gesture detector can register a callback. */ private final Listener mListener; + private int mActivePointerId = INVALID_POINTER_ID; private VelocityTracker mVelocityTracker; - private float mLastDisplacement; private float mDisplacement; - private float mSubtractDisplacement; private boolean mIgnoreSlopWhenSettling; + private int mScrollDirections; + private ScrollState mState = ScrollState.IDLE; - public interface Listener { - void onDragStart(boolean start); - - boolean onDrag(float displacement); - - default boolean onDrag(float displacement, MotionEvent event) { - return onDrag(displacement); - } - - void onDragEnd(float velocity, boolean fling); + private enum ScrollState { + IDLE, + DRAGGING, // onDragStart, onDrag + SETTLING // onDragEnd } public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) { @@ -248,28 +154,65 @@ public class SwipeDetector { mMaxVelocity = config.getScaledMaximumFlingVelocity(); } + public static long calculateDuration(float velocity, float progressNeeded) { + // TODO: make these values constants after tuning. + float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity)); + float travelDistance = Math.max(0.2f, progressNeeded); + long duration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance); + if (DBG) { + Log.d(TAG, String.format( + "calculateDuration=%d, v=%f, d=%f", duration, velocity, progressNeeded)); + } + return duration; + } + + public int getDownX() { + return (int) mDownPos.x; + } + + public int getDownY() { + return (int) mDownPos.y; + } + /** + * There's no touch and there's no animation. + */ + public boolean isIdleState() { + return mState == ScrollState.IDLE; + } + + public boolean isSettlingState() { + return mState == ScrollState.SETTLING; + } + + public boolean isDraggingState() { + return mState == ScrollState.DRAGGING; + } + + public boolean isDraggingOrSettling() { + return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING; + } + public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) { - mScrollConditions = scrollDirectionFlags; + mScrollDirections = scrollDirectionFlags; mIgnoreSlopWhenSettling = ignoreSlop; } public int getScrollDirections() { - return mScrollConditions; + return mScrollDirections; } - private boolean shouldScrollStart(MotionEvent ev, int pointerIndex) { - // reject cases where the angle or slop condition is not met. - if (Math.max(mDir.getActiveTouchSlop(ev, pointerIndex, mDownPos), mTouchSlop) - > Math.abs(mDisplacement)) { - return false; - } + public void finishedScrolling() { + setState(ScrollState.IDLE); + } - // Check if the client is interested in scroll in current direction. - if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDir.isNegative(mDisplacement)) || - ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDir.isPositive(mDisplacement))) { - return true; - } - return false; + /** + * Returns if the start drag was towards the positive direction or negative. + * + * @see #setDetectableScrollConditions(int, boolean) + * @see #DIRECTION_BOTH + */ + public boolean wasInitialTouchPositive() { + return mDir.isPositive(mSubtractDisplacement); } public boolean onTouchEvent(MotionEvent ev) { @@ -338,16 +281,50 @@ public class SwipeDetector { return true; } - public void finishedScrolling() { - setState(ScrollState.IDLE); + //------------------- ScrollState transition diagram ----------------------------------- + // + // IDLE -> (mDisplacement > mTouchSlop) -> DRAGGING + // DRAGGING -> (MotionEvent#ACTION_UP, MotionEvent#ACTION_CANCEL) -> SETTLING + // SETTLING -> (MotionEvent#ACTION_DOWN) -> DRAGGING + // SETTLING -> (View settled) -> IDLE + + private void setState(ScrollState newState) { + if (DBG) { + Log.d(TAG, "setState:" + mState + "->" + newState); + } + // onDragStart and onDragEnd is reported ONLY on state transition + if (newState == ScrollState.DRAGGING) { + initializeDragging(); + if (mState == ScrollState.IDLE) { + reportDragStart(false /* recatch */); + } else if (mState == ScrollState.SETTLING) { + reportDragStart(true /* recatch */); + } + } + if (newState == ScrollState.SETTLING) { + reportDragEnd(); + } + + mState = newState; + } + + private boolean shouldScrollStart(MotionEvent ev, int pointerIndex) { + // reject cases where the angle or slop condition is not met. + if (Math.max(mDir.getActiveTouchSlop(ev, pointerIndex, mDownPos), mTouchSlop) + > Math.abs(mDisplacement)) { + return false; + } + + // Check if the client is interested in scroll in current direction. + return ((mScrollDirections & DIRECTION_NEGATIVE) > 0 && mDir.isNegative(mDisplacement)) + || ((mScrollDirections & DIRECTION_POSITIVE) > 0 && mDir.isPositive(mDisplacement)); } - private boolean reportDragStart(boolean recatch) { + private void reportDragStart(boolean recatch) { mListener.onDragStart(!recatch); if (DBG) { Log.d(TAG, "onDragStart recatch:" + recatch); } - return true; } private void initializeDragging() { @@ -361,26 +338,15 @@ public class SwipeDetector { } } - /** - * Returns if the start drag was towards the positive direction or negative. - * - * @see #setDetectableScrollConditions(int, boolean) - * @see #DIRECTION_BOTH - */ - public boolean wasInitialTouchPositive() { - return mDir.isPositive(mSubtractDisplacement); - } - - private boolean reportDragging(MotionEvent event) { + private void reportDragging(MotionEvent event) { if (mDisplacement != mLastDisplacement) { if (DBG) { Log.d(TAG, String.format("onDrag disp=%.1f", mDisplacement)); } mLastDisplacement = mDisplacement; - return mListener.onDrag(mDisplacement - mSubtractDisplacement, event); + mListener.onDrag(mDisplacement - mSubtractDisplacement, event); } - return true; } private void reportDragEnd() { @@ -394,14 +360,33 @@ public class SwipeDetector { mListener.onDragEnd(velocity, Math.abs(velocity) > RELEASE_VELOCITY_PX_MS); } - public static long calculateDuration(float velocity, float progressNeeded) { - // TODO: make these values constants after tuning. - float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity)); - float travelDistance = Math.max(0.2f, progressNeeded); - long duration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance); - if (DBG) { - Log.d(TAG, String.format("calculateDuration=%d, v=%f, d=%f", duration, velocity, progressNeeded)); + /** Listener to receive updates on the swipe. */ + public interface Listener { + void onDragStart(boolean start); + + boolean onDrag(float displacement); + + default boolean onDrag(float displacement, MotionEvent event) { + return onDrag(displacement); } - return duration; + + void onDragEnd(float velocity, boolean fling); + } + + public abstract static class Direction { + + abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint, + boolean isRtl); + + /** + * Distance in pixels a touch can wander before we think the user is scrolling. + */ + abstract float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos); + + abstract float getVelocity(VelocityTracker tracker, boolean isRtl); + + abstract boolean isPositive(float displacement); + + abstract boolean isNegative(float displacement); } } diff --git a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java index e04235708..f209fae97 100644 --- a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java +++ b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java @@ -25,6 +25,10 @@ import static org.mockito.Mockito.verify; import android.util.Log; import android.view.ViewConfiguration; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import com.android.launcher3.testcomponent.TouchEventGenerator; import org.junit.Before; @@ -33,10 +37,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - @SmallTest @RunWith(AndroidJUnit4.class) public class SwipeDetectorTest { -- cgit v1.2.3