Merge "Ignore the closing MotionEvent of swipe gestures for falsing" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
09262ed09d
@@ -38,6 +38,7 @@ import javax.inject.Inject;
|
|||||||
public class FalsingDataProvider {
|
public class FalsingDataProvider {
|
||||||
|
|
||||||
private static final long MOTION_EVENT_AGE_MS = 1000;
|
private static final long MOTION_EVENT_AGE_MS = 1000;
|
||||||
|
private static final long DROP_EVENT_THRESHOLD_MS = 50;
|
||||||
private static final float THREE_HUNDRED_SIXTY_DEG = (float) (2 * Math.PI);
|
private static final float THREE_HUNDRED_SIXTY_DEG = (float) (2 * Math.PI);
|
||||||
|
|
||||||
private final int mWidthPixels;
|
private final int mWidthPixels;
|
||||||
@@ -60,6 +61,7 @@ public class FalsingDataProvider {
|
|||||||
private float mAngle = 0;
|
private float mAngle = 0;
|
||||||
private MotionEvent mFirstRecentMotionEvent;
|
private MotionEvent mFirstRecentMotionEvent;
|
||||||
private MotionEvent mLastMotionEvent;
|
private MotionEvent mLastMotionEvent;
|
||||||
|
private boolean mDropLastEvent;
|
||||||
private boolean mJustUnlockedWithFace;
|
private boolean mJustUnlockedWithFace;
|
||||||
private boolean mA11YAction;
|
private boolean mA11YAction;
|
||||||
|
|
||||||
@@ -95,6 +97,12 @@ public class FalsingDataProvider {
|
|||||||
// Ensure prior gesture was completed. May be a no-op.
|
// Ensure prior gesture was completed. May be a no-op.
|
||||||
completePriorGesture();
|
completePriorGesture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drop the gesture closing event if it is close in time to a previous ACTION_MOVE event.
|
||||||
|
// The reason is that the closing ACTION_UP event of a swipe can be a bit offseted from the
|
||||||
|
// previous ACTION_MOVE event and when it happens, it makes some classifiers fail.
|
||||||
|
mDropLastEvent = shouldDropEvent(motionEvent);
|
||||||
|
|
||||||
mRecentMotionEvents.addAll(motionEvents);
|
mRecentMotionEvents.addAll(motionEvents);
|
||||||
|
|
||||||
FalsingClassifier.logVerbose("Size: " + mRecentMotionEvents.size());
|
FalsingClassifier.logVerbose("Size: " + mRecentMotionEvents.size());
|
||||||
@@ -129,6 +137,7 @@ public class FalsingDataProvider {
|
|||||||
mPriorMotionEvents = mRecentMotionEvents;
|
mPriorMotionEvents = mRecentMotionEvents;
|
||||||
mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS);
|
mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS);
|
||||||
}
|
}
|
||||||
|
mDropLastEvent = false;
|
||||||
mA11YAction = false;
|
mA11YAction = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +159,18 @@ public class FalsingDataProvider {
|
|||||||
return mYdpi;
|
return mYdpi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link MotionEvent}s of the most recent gesture.
|
||||||
|
*
|
||||||
|
* Note that this list may not include the last recorded event.
|
||||||
|
* @see #mDropLastEvent
|
||||||
|
*/
|
||||||
public List<MotionEvent> getRecentMotionEvents() {
|
public List<MotionEvent> getRecentMotionEvents() {
|
||||||
|
if (!mDropLastEvent || mRecentMotionEvents.isEmpty()) {
|
||||||
return mRecentMotionEvents;
|
return mRecentMotionEvents;
|
||||||
|
} else {
|
||||||
|
return mRecentMotionEvents.subList(0, mRecentMotionEvents.size() - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MotionEvent> getPriorMotionEvents() {
|
public List<MotionEvent> getPriorMotionEvents() {
|
||||||
@@ -169,7 +188,12 @@ public class FalsingDataProvider {
|
|||||||
return mFirstRecentMotionEvent;
|
return mFirstRecentMotionEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the last recorded {@link MotionEvent}. */
|
/**
|
||||||
|
* Get the last {@link MotionEvent} of the most recent gesture.
|
||||||
|
*
|
||||||
|
* Note that this may be the event prior to the last recorded event.
|
||||||
|
* @see #mDropLastEvent
|
||||||
|
*/
|
||||||
public MotionEvent getLastMotionEvent() {
|
public MotionEvent getLastMotionEvent() {
|
||||||
recalculateData();
|
recalculateData();
|
||||||
return mLastMotionEvent;
|
return mLastMotionEvent;
|
||||||
@@ -236,12 +260,13 @@ public class FalsingDataProvider {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mRecentMotionEvents.isEmpty()) {
|
List<MotionEvent> recentMotionEvents = getRecentMotionEvents();
|
||||||
|
if (recentMotionEvents.isEmpty()) {
|
||||||
mFirstRecentMotionEvent = null;
|
mFirstRecentMotionEvent = null;
|
||||||
mLastMotionEvent = null;
|
mLastMotionEvent = null;
|
||||||
} else {
|
} else {
|
||||||
mFirstRecentMotionEvent = mRecentMotionEvents.get(0);
|
mFirstRecentMotionEvent = recentMotionEvents.get(0);
|
||||||
mLastMotionEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1);
|
mLastMotionEvent = recentMotionEvents.get(recentMotionEvents.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateAngleInternal();
|
calculateAngleInternal();
|
||||||
@@ -249,6 +274,17 @@ public class FalsingDataProvider {
|
|||||||
mDirty = false;
|
mDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean shouldDropEvent(MotionEvent event) {
|
||||||
|
if (mRecentMotionEvents.size() < 3) return false;
|
||||||
|
|
||||||
|
MotionEvent lastEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1);
|
||||||
|
boolean isCompletingGesture = event.getActionMasked() == MotionEvent.ACTION_UP
|
||||||
|
&& lastEvent.getActionMasked() == MotionEvent.ACTION_MOVE;
|
||||||
|
boolean isRecentEvent =
|
||||||
|
event.getEventTime() - lastEvent.getEventTime() < DROP_EVENT_THRESHOLD_MS;
|
||||||
|
return isCompletingGesture && isRecentEvent;
|
||||||
|
}
|
||||||
|
|
||||||
private void calculateAngleInternal() {
|
private void calculateAngleInternal() {
|
||||||
if (mRecentMotionEvents.size() < 2) {
|
if (mRecentMotionEvents.size() < 2) {
|
||||||
mAngle = Float.MAX_VALUE;
|
mAngle = Float.MAX_VALUE;
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ public class TimeLimitedMotionEventBuffer implements List<MotionEvent> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<MotionEvent> subList(int fromIndex, int toIndex) {
|
public List<MotionEvent> subList(int fromIndex, int toIndex) {
|
||||||
throw new UnsupportedOperationException();
|
return mMotionEvents.subList(fromIndex, toIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Iter implements ListIterator<MotionEvent> {
|
class Iter implements ListIterator<MotionEvent> {
|
||||||
|
|||||||
@@ -94,7 +94,9 @@ public class DistanceClassifierTest extends ClassifierTest {
|
|||||||
mClassifier.onTouchEvent(appendMoveEvent(1, 16, 3));
|
mClassifier.onTouchEvent(appendMoveEvent(1, 16, 3));
|
||||||
mClassifier.onTouchEvent(appendMoveEvent(1, 17, 300));
|
mClassifier.onTouchEvent(appendMoveEvent(1, 17, 300));
|
||||||
mClassifier.onTouchEvent(appendMoveEvent(1, 18, 301));
|
mClassifier.onTouchEvent(appendMoveEvent(1, 18, 301));
|
||||||
mClassifier.onTouchEvent(appendUpEvent(1, 19, 501));
|
mClassifier.onTouchEvent(appendMoveEvent(1, 19, 501));
|
||||||
|
mClassifier.onTouchEvent(appendUpEvent(1, 19, 501)); //event will be dropped
|
||||||
|
|
||||||
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
|
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,16 +75,17 @@ public class FalsingDataProviderTest extends ClassifierTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_trackMotionEvents() {
|
public void test_trackMotionEvents_dropUpEvent() {
|
||||||
mDataProvider.onMotionEvent(appendDownEvent(2, 9));
|
mDataProvider.onMotionEvent(appendDownEvent(2, 9));
|
||||||
mDataProvider.onMotionEvent(appendMoveEvent(4, 7));
|
mDataProvider.onMotionEvent(appendMoveEvent(4, 7));
|
||||||
mDataProvider.onMotionEvent(appendUpEvent(6, 5));
|
mDataProvider.onMotionEvent(appendMoveEvent(6, 5));
|
||||||
|
mDataProvider.onMotionEvent(appendUpEvent(0, 0)); // event will be dropped
|
||||||
List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents();
|
List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents();
|
||||||
|
|
||||||
assertThat(motionEventList.size()).isEqualTo(3);
|
assertThat(motionEventList.size()).isEqualTo(3);
|
||||||
assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN);
|
assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN);
|
||||||
assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
|
assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
|
||||||
assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP);
|
assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
|
||||||
assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L);
|
assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L);
|
||||||
assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L);
|
assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L);
|
||||||
assertThat(motionEventList.get(2).getEventTime()).isEqualTo(3L);
|
assertThat(motionEventList.get(2).getEventTime()).isEqualTo(3L);
|
||||||
@@ -96,6 +97,28 @@ public class FalsingDataProviderTest extends ClassifierTest {
|
|||||||
assertThat(motionEventList.get(2).getY()).isEqualTo(5f);
|
assertThat(motionEventList.get(2).getY()).isEqualTo(5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_trackMotionEvents_keepUpEvent() {
|
||||||
|
mDataProvider.onMotionEvent(appendDownEvent(2, 9));
|
||||||
|
mDataProvider.onMotionEvent(appendMoveEvent(4, 7));
|
||||||
|
mDataProvider.onMotionEvent(appendUpEvent(0, 0, 100));
|
||||||
|
List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents();
|
||||||
|
|
||||||
|
assertThat(motionEventList.size()).isEqualTo(3);
|
||||||
|
assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN);
|
||||||
|
assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE);
|
||||||
|
assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP);
|
||||||
|
assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L);
|
||||||
|
assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L);
|
||||||
|
assertThat(motionEventList.get(2).getEventTime()).isEqualTo(100);
|
||||||
|
assertThat(motionEventList.get(0).getX()).isEqualTo(2f);
|
||||||
|
assertThat(motionEventList.get(1).getX()).isEqualTo(4f);
|
||||||
|
assertThat(motionEventList.get(2).getX()).isEqualTo(0f);
|
||||||
|
assertThat(motionEventList.get(0).getY()).isEqualTo(9f);
|
||||||
|
assertThat(motionEventList.get(1).getY()).isEqualTo(7f);
|
||||||
|
assertThat(motionEventList.get(2).getY()).isEqualTo(0f);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_trackRecentMotionEvents() {
|
public void test_trackRecentMotionEvents() {
|
||||||
mDataProvider.onMotionEvent(appendDownEvent(2, 9, 1));
|
mDataProvider.onMotionEvent(appendDownEvent(2, 9, 1));
|
||||||
|
|||||||
@@ -67,6 +67,15 @@ public class ZigZagClassifierTest extends ClassifierTest {
|
|||||||
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
|
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPass_dropClosingUpEvent() {
|
||||||
|
appendMoveEvent(0, 0);
|
||||||
|
appendMoveEvent(0, 100);
|
||||||
|
appendMoveEvent(0, 200);
|
||||||
|
appendUpEvent(0, 180); // this event would push us over the maxDevianceY
|
||||||
|
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPass_fewTouchesHorizontal() {
|
public void testPass_fewTouchesHorizontal() {
|
||||||
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
|
assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse();
|
||||||
|
|||||||
Reference in New Issue
Block a user