Merge "Fix BaseSwipeDetector#setState() called inside another setState()" into ub-launcher3-master
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index f470edb..d193bef 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -508,7 +508,7 @@
mAtomicComponentsController.getAnimationPlayer().end();
mAtomicComponentsController = null;
}
- cancelAnimationControllers();
+ clearState();
boolean shouldGoToTargetState = true;
if (mPendingAnimation != null) {
boolean reachedTarget = mToState == targetState;
@@ -546,13 +546,13 @@
mAtomicAnim = null;
}
mScheduleResumeAtomicComponent = false;
+ mDetector.finishedScrolling();
+ mDetector.setDetectableScrollConditions(0, false);
}
private void cancelAnimationControllers() {
mCurrentAnimation = null;
cancelAtomicComponentsController();
- mDetector.finishedScrolling();
- mDetector.setDetectableScrollConditions(0, false);
}
private void cancelAtomicComponentsController() {
diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java
index 12ca5ee..30283da 100644
--- a/src/com/android/launcher3/touch/BaseSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java
@@ -24,6 +24,10 @@
import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
+import java.util.LinkedList;
+import java.util.Queue;
/**
* Scroll/drag/swipe gesture detector.
@@ -49,13 +53,15 @@
protected final boolean mIsRtl;
protected final float mTouchSlop;
protected final float mMaxVelocity;
+ private final Queue<Runnable> mSetStateQueue = new LinkedList<>();
private int mActivePointerId = INVALID_POINTER_ID;
private VelocityTracker mVelocityTracker;
private PointF mLastDisplacement = new PointF();
private PointF mDisplacement = new PointF();
protected PointF mSubtractDisplacement = new PointF();
- private ScrollState mState = ScrollState.IDLE;
+ @VisibleForTesting ScrollState mState = ScrollState.IDLE;
+ private boolean mIsSettingState;
protected boolean mIgnoreSlopWhenSettling;
@@ -195,6 +201,12 @@
// SETTLING -> (View settled) -> IDLE
private void setState(ScrollState newState) {
+ if (mIsSettingState) {
+ mSetStateQueue.add(() -> setState(newState));
+ return;
+ }
+ mIsSettingState = true;
+
if (DBG) {
Log.d(TAG, "setState:" + mState + "->" + newState);
}
@@ -212,6 +224,10 @@
}
mState = newState;
+ mIsSettingState = false;
+ if (!mSetStateQueue.isEmpty()) {
+ mSetStateQueue.remove().run();
+ }
}
private void initializeDragging() {
diff --git a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
index 5174e4d..6d463b5 100644
--- a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
+++ b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
@@ -21,9 +21,11 @@
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyFloat;
import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -168,4 +170,21 @@
// TODO: actually calculate the following parameters and do exact value checks.
verify(mMockListener).onDragEnd(anyFloat());
}
+
+ @Test
+ public void testInterleavedSetState() {
+ doAnswer(invocationOnMock -> {
+ // Sets state to IDLE. (Normally onDragEnd() will have state SETTLING.)
+ mDetector.finishedScrolling();
+ return null;
+ }).when(mMockListener).onDragEnd(anyFloat());
+
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100, 100 + mTouchSlop);
+ mGenerator.move(0, 100, 100 + mTouchSlop * 2);
+ mGenerator.lift(0);
+ verify(mMockListener).onDragEnd(anyFloat());
+ assertTrue("SwipeDetector should be IDLE but was " + mDetector.mState,
+ mDetector.isIdleState());
+ }
}