Loading quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java +1 −1 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro @Override protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() != isDragTowardPositive; boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() == isDragTowardPositive; return draggingFromNav ? OVERVIEW : NORMAL; } Loading src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +4 −1 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ public abstract class AbstractStateChangeTouchController protected final Launcher mLauncher; protected final SwipeDetector mDetector; protected final SwipeDetector.Direction mSwipeDirection; private boolean mNoIntercept; protected int mStartContainerType; Loading Loading @@ -105,6 +106,7 @@ public abstract class AbstractStateChangeTouchController public AbstractStateChangeTouchController(Launcher l, SwipeDetector.Direction dir) { mLauncher = l; mDetector = new SwipeDetector(l, this, dir); mSwipeDirection = dir; } protected long getAtomicDuration() { Loading Loading @@ -272,7 +274,8 @@ public abstract class AbstractStateChangeTouchController displacement + "], progress = [" + progress + "]"); } updateProgress(progress); boolean isDragTowardPositive = (displacement - mDisplacementShift) < 0; boolean isDragTowardPositive = mSwipeDirection.isPositive( displacement - mDisplacementShift); if (progress <= 0) { if (reinitCurrentAnimation(false, isDragTowardPositive)) { mDisplacementShift = displacement; Loading src/com/android/launcher3/touch/SwipeDetector.java +56 −15 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; import com.android.launcher3.Utilities; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; Loading Loading @@ -64,20 +66,25 @@ public class SwipeDetector { public static abstract class Direction { abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint); 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); 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 float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) { float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint, boolean isRtl) { return ev.getY(pointerIndex) - refPoint.y; } Loading @@ -87,16 +94,32 @@ public class SwipeDetector { } @Override float getVelocity(VelocityTracker tracker) { float getVelocity(VelocityTracker tracker, boolean isRtl) { return tracker.getYVelocity(); } @Override boolean isPositive(float displacement) { // Up return displacement < 0; } @Override boolean isNegative(float displacement) { // Down return displacement > 0; } }; public static final Direction HORIZONTAL = new Direction() { @Override float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) { return ev.getX(pointerIndex) - refPoint.x; float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint, boolean isRtl) { float displacement = ev.getX(pointerIndex) - refPoint.x; if (isRtl) { displacement = -displacement; } return displacement; } @Override Loading @@ -105,8 +128,24 @@ public class SwipeDetector { } @Override float getVelocity(VelocityTracker tracker) { return tracker.getXVelocity(); float getVelocity(VelocityTracker tracker, boolean isRtl) { float velocity = tracker.getXVelocity(); if (isRtl) { velocity = -velocity; } return velocity; } @Override boolean isPositive(float displacement) { // Right return displacement > 0; } @Override boolean isNegative(float displacement) { // Left return displacement < 0; } }; Loading Loading @@ -159,6 +198,7 @@ public class SwipeDetector { 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; Loading @@ -183,14 +223,15 @@ public class SwipeDetector { } public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) { this(ViewConfiguration.get(context), l, dir); this(ViewConfiguration.get(context), l, dir, Utilities.isRtl(context.getResources())); } @VisibleForTesting protected SwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l, @NonNull Direction dir) { @NonNull Direction dir, boolean isRtl) { mListener = l; mDir = dir; mIsRtl = isRtl; mTouchSlop = config.getScaledTouchSlop(); mMaxVelocity = config.getScaledMaximumFlingVelocity(); } Loading @@ -212,8 +253,8 @@ public class SwipeDetector { } // Check if the client is interested in scroll in current direction. if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDisplacement > 0) || ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDisplacement < 0)) { if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDir.isNegative(mDisplacement)) || ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDir.isPositive(mDisplacement))) { return true; } return false; Loading Loading @@ -259,7 +300,7 @@ public class SwipeDetector { if (pointerIndex == INVALID_POINTER_ID) { break; } mDisplacement = mDir.getDisplacement(ev, pointerIndex, mDownPos); mDisplacement = mDir.getDisplacement(ev, pointerIndex, mDownPos, mIsRtl); // handle state and listener calls. if (mState != ScrollState.DRAGGING && shouldScrollStart(ev, pointerIndex)) { Loading Loading @@ -315,7 +356,7 @@ public class SwipeDetector { * @see #DIRECTION_BOTH */ public boolean wasInitialTouchPositive() { return mSubtractDisplacement < 0; return mDir.isPositive(mSubtractDisplacement); } private boolean reportDragging() { Loading @@ -332,7 +373,7 @@ public class SwipeDetector { private void reportDragEnd() { mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); float velocity = mDir.getVelocity(mVelocityTracker) / 1000; float velocity = mDir.getVelocity(mVelocityTracker, mIsRtl) / 1000; if (DBG) { Log.d(TAG, String.format("onScrollEnd disp=%.1f, velocity=%.1f", mDisplacement, velocity)); Loading tests/src/com/android/launcher3/touch/SwipeDetectorTest.java +59 −13 Original line number Diff line number Diff line Loading @@ -15,9 +15,12 @@ */ package com.android.launcher3.touch; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyFloat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.util.Log; import android.view.ViewConfiguration; Loading @@ -29,11 +32,9 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyFloat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @SmallTest @RunWith(AndroidJUnit4.class) Loading Loading @@ -63,7 +64,7 @@ public class SwipeDetectorTest { doReturn(orgConfig.getScaledMaximumFlingVelocity()).when(mMockConfig) .getScaledMaximumFlingVelocity(); mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL); mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL, false); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false); mTouchSlop = orgConfig.getScaledTouchSlop(); doReturn(mTouchSlop).when(mMockConfig).getScaledTouchSlop(); Loading @@ -72,7 +73,19 @@ public class SwipeDetectorTest { } @Test public void testDragStart_vertical() { public void testDragStart_verticalPositive() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL, false); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100, 100 - mTouchSlop); // TODO: actually calculate the following parameters and do exact value checks. verify(mMockListener).onDragStart(anyBoolean()); } @Test public void testDragStart_verticalNegative() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL, false); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_NEGATIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100, 100 + mTouchSlop); // TODO: actually calculate the following parameters and do exact value checks. Loading @@ -88,9 +101,42 @@ public class SwipeDetectorTest { } @Test public void testDragStart_horizontal() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false); public void testDragStart_horizontalPositive() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, false); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100 + mTouchSlop, 100); // TODO: actually calculate the following parameters and do exact value checks. verify(mMockListener).onDragStart(anyBoolean()); } @Test public void testDragStart_horizontalNegative() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, false); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_NEGATIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100 - mTouchSlop, 100); // TODO: actually calculate the following parameters and do exact value checks. verify(mMockListener).onDragStart(anyBoolean()); } @Test public void testDragStart_horizontalRtlPositive() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, true); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100 - mTouchSlop, 100); // TODO: actually calculate the following parameters and do exact value checks. verify(mMockListener).onDragStart(anyBoolean()); } @Test public void testDragStart_horizontalRtlNegative() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, true); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_NEGATIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100 + mTouchSlop, 100); Loading Loading
quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java +1 −1 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro @Override protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() != isDragTowardPositive; boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() == isDragTowardPositive; return draggingFromNav ? OVERVIEW : NORMAL; } Loading
src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +4 −1 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ public abstract class AbstractStateChangeTouchController protected final Launcher mLauncher; protected final SwipeDetector mDetector; protected final SwipeDetector.Direction mSwipeDirection; private boolean mNoIntercept; protected int mStartContainerType; Loading Loading @@ -105,6 +106,7 @@ public abstract class AbstractStateChangeTouchController public AbstractStateChangeTouchController(Launcher l, SwipeDetector.Direction dir) { mLauncher = l; mDetector = new SwipeDetector(l, this, dir); mSwipeDirection = dir; } protected long getAtomicDuration() { Loading Loading @@ -272,7 +274,8 @@ public abstract class AbstractStateChangeTouchController displacement + "], progress = [" + progress + "]"); } updateProgress(progress); boolean isDragTowardPositive = (displacement - mDisplacementShift) < 0; boolean isDragTowardPositive = mSwipeDirection.isPositive( displacement - mDisplacementShift); if (progress <= 0) { if (reinitCurrentAnimation(false, isDragTowardPositive)) { mDisplacementShift = displacement; Loading
src/com/android/launcher3/touch/SwipeDetector.java +56 −15 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; import com.android.launcher3.Utilities; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; Loading Loading @@ -64,20 +66,25 @@ public class SwipeDetector { public static abstract class Direction { abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint); 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); 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 float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) { float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint, boolean isRtl) { return ev.getY(pointerIndex) - refPoint.y; } Loading @@ -87,16 +94,32 @@ public class SwipeDetector { } @Override float getVelocity(VelocityTracker tracker) { float getVelocity(VelocityTracker tracker, boolean isRtl) { return tracker.getYVelocity(); } @Override boolean isPositive(float displacement) { // Up return displacement < 0; } @Override boolean isNegative(float displacement) { // Down return displacement > 0; } }; public static final Direction HORIZONTAL = new Direction() { @Override float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint) { return ev.getX(pointerIndex) - refPoint.x; float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint, boolean isRtl) { float displacement = ev.getX(pointerIndex) - refPoint.x; if (isRtl) { displacement = -displacement; } return displacement; } @Override Loading @@ -105,8 +128,24 @@ public class SwipeDetector { } @Override float getVelocity(VelocityTracker tracker) { return tracker.getXVelocity(); float getVelocity(VelocityTracker tracker, boolean isRtl) { float velocity = tracker.getXVelocity(); if (isRtl) { velocity = -velocity; } return velocity; } @Override boolean isPositive(float displacement) { // Right return displacement > 0; } @Override boolean isNegative(float displacement) { // Left return displacement < 0; } }; Loading Loading @@ -159,6 +198,7 @@ public class SwipeDetector { 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; Loading @@ -183,14 +223,15 @@ public class SwipeDetector { } public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) { this(ViewConfiguration.get(context), l, dir); this(ViewConfiguration.get(context), l, dir, Utilities.isRtl(context.getResources())); } @VisibleForTesting protected SwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l, @NonNull Direction dir) { @NonNull Direction dir, boolean isRtl) { mListener = l; mDir = dir; mIsRtl = isRtl; mTouchSlop = config.getScaledTouchSlop(); mMaxVelocity = config.getScaledMaximumFlingVelocity(); } Loading @@ -212,8 +253,8 @@ public class SwipeDetector { } // Check if the client is interested in scroll in current direction. if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDisplacement > 0) || ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDisplacement < 0)) { if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDir.isNegative(mDisplacement)) || ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDir.isPositive(mDisplacement))) { return true; } return false; Loading Loading @@ -259,7 +300,7 @@ public class SwipeDetector { if (pointerIndex == INVALID_POINTER_ID) { break; } mDisplacement = mDir.getDisplacement(ev, pointerIndex, mDownPos); mDisplacement = mDir.getDisplacement(ev, pointerIndex, mDownPos, mIsRtl); // handle state and listener calls. if (mState != ScrollState.DRAGGING && shouldScrollStart(ev, pointerIndex)) { Loading Loading @@ -315,7 +356,7 @@ public class SwipeDetector { * @see #DIRECTION_BOTH */ public boolean wasInitialTouchPositive() { return mSubtractDisplacement < 0; return mDir.isPositive(mSubtractDisplacement); } private boolean reportDragging() { Loading @@ -332,7 +373,7 @@ public class SwipeDetector { private void reportDragEnd() { mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); float velocity = mDir.getVelocity(mVelocityTracker) / 1000; float velocity = mDir.getVelocity(mVelocityTracker, mIsRtl) / 1000; if (DBG) { Log.d(TAG, String.format("onScrollEnd disp=%.1f, velocity=%.1f", mDisplacement, velocity)); Loading
tests/src/com/android/launcher3/touch/SwipeDetectorTest.java +59 −13 Original line number Diff line number Diff line Loading @@ -15,9 +15,12 @@ */ package com.android.launcher3.touch; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyFloat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.util.Log; import android.view.ViewConfiguration; Loading @@ -29,11 +32,9 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyFloat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @SmallTest @RunWith(AndroidJUnit4.class) Loading Loading @@ -63,7 +64,7 @@ public class SwipeDetectorTest { doReturn(orgConfig.getScaledMaximumFlingVelocity()).when(mMockConfig) .getScaledMaximumFlingVelocity(); mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL); mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL, false); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false); mTouchSlop = orgConfig.getScaledTouchSlop(); doReturn(mTouchSlop).when(mMockConfig).getScaledTouchSlop(); Loading @@ -72,7 +73,19 @@ public class SwipeDetectorTest { } @Test public void testDragStart_vertical() { public void testDragStart_verticalPositive() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL, false); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100, 100 - mTouchSlop); // TODO: actually calculate the following parameters and do exact value checks. verify(mMockListener).onDragStart(anyBoolean()); } @Test public void testDragStart_verticalNegative() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.VERTICAL, false); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_NEGATIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100, 100 + mTouchSlop); // TODO: actually calculate the following parameters and do exact value checks. Loading @@ -88,9 +101,42 @@ public class SwipeDetectorTest { } @Test public void testDragStart_horizontal() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false); public void testDragStart_horizontalPositive() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, false); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100 + mTouchSlop, 100); // TODO: actually calculate the following parameters and do exact value checks. verify(mMockListener).onDragStart(anyBoolean()); } @Test public void testDragStart_horizontalNegative() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, false); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_NEGATIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100 - mTouchSlop, 100); // TODO: actually calculate the following parameters and do exact value checks. verify(mMockListener).onDragStart(anyBoolean()); } @Test public void testDragStart_horizontalRtlPositive() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, true); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100 - mTouchSlop, 100); // TODO: actually calculate the following parameters and do exact value checks. verify(mMockListener).onDragStart(anyBoolean()); } @Test public void testDragStart_horizontalRtlNegative() { mDetector = new SwipeDetector(mMockConfig, mMockListener, SwipeDetector.HORIZONTAL, true); mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_NEGATIVE, false); mGenerator.put(0, 100, 100); mGenerator.move(0, 100 + mTouchSlop, 100); Loading