Make FalsingClassifiers less stateful.
Clasifiers now return a Result object on all their classification methods. The Result object now contains the "reason" for falsing instead of asking the Classifier for the reason after the fact. Bug: 172655679 Test: atest SystemUITests Change-Id: I0865f18cbae9367c203936fbbc3923de55c81007
This commit is contained in:
@@ -137,22 +137,22 @@ public class BrightLineFalsingManager implements FalsingManager {
|
||||
mPreviousResult = !mTestHarness
|
||||
&& !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()
|
||||
&& mClassifiers.stream().anyMatch(falsingClassifier -> {
|
||||
boolean result = falsingClassifier.classifyGesture(
|
||||
FalsingClassifier.Result result = falsingClassifier.classifyGesture(
|
||||
mHistoryTracker.falsePenalty(), mHistoryTracker.falseConfidence());
|
||||
if (result) {
|
||||
if (result.isFalse()) {
|
||||
logInfo(String.format(
|
||||
(Locale) null,
|
||||
"{classifier=%s, interactionType=%d}",
|
||||
falsingClassifier.getClass().getName(),
|
||||
mDataProvider.getInteractionType()));
|
||||
String reason = falsingClassifier.getReason();
|
||||
String reason = result.getReason();
|
||||
if (reason != null) {
|
||||
logInfo(reason);
|
||||
}
|
||||
} else {
|
||||
logDebug(falsingClassifier.getClass().getName() + ": false");
|
||||
}
|
||||
return result;
|
||||
return result.isFalse();
|
||||
});
|
||||
|
||||
logDebug("Is false touch? " + mPreviousResult);
|
||||
@@ -178,10 +178,12 @@ public class BrightLineFalsingManager implements FalsingManager {
|
||||
|
||||
@Override
|
||||
public boolean isFalseTap(boolean robustCheck) {
|
||||
if (!mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents())) {
|
||||
FalsingClassifier.Result singleTapResult =
|
||||
mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents());
|
||||
if (singleTapResult.isFalse()) {
|
||||
logInfo(String.format(
|
||||
(Locale) null, "{classifier=%s}", mSingleTapClassifier.getClass().getName()));
|
||||
String reason = mSingleTapClassifier.getReason();
|
||||
String reason = singleTapResult.getReason();
|
||||
if (reason != null) {
|
||||
logInfo(reason);
|
||||
}
|
||||
@@ -198,16 +200,16 @@ public class BrightLineFalsingManager implements FalsingManager {
|
||||
|
||||
@Override
|
||||
public boolean isFalseDoubleTap() {
|
||||
boolean result = mDoubleTapClassifier.classifyGesture().isFalse();
|
||||
if (result) {
|
||||
FalsingClassifier.Result result = mDoubleTapClassifier.classifyGesture();
|
||||
if (result.isFalse()) {
|
||||
logInfo(String.format(
|
||||
(Locale) null, "{classifier=%s}", mDoubleTapClassifier.getClass().getName()));
|
||||
String reason = mDoubleTapClassifier.getReason();
|
||||
String reason = result.getReason();
|
||||
if (reason != null) {
|
||||
logInfo(reason);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return result.isFalse();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -66,12 +66,12 @@ class DiagonalClassifier extends FalsingClassifier {
|
||||
float angle = getAngle();
|
||||
|
||||
if (angle == Float.MAX_VALUE) { // Unknown angle
|
||||
return new Result(false, 0);
|
||||
return Result.passed(0);
|
||||
}
|
||||
|
||||
if (getInteractionType() == LEFT_AFFORDANCE
|
||||
|| getInteractionType() == RIGHT_AFFORDANCE) {
|
||||
return new Result(false, 0);
|
||||
return Result.passed(0);
|
||||
}
|
||||
|
||||
float minAngle = DIAGONAL - mHorizontalAngleRange;
|
||||
@@ -81,15 +81,15 @@ class DiagonalClassifier extends FalsingClassifier {
|
||||
maxAngle = DIAGONAL + mVerticalAngleRange;
|
||||
}
|
||||
|
||||
return new Result(angleBetween(angle, minAngle, maxAngle)
|
||||
boolean falsed = angleBetween(angle, minAngle, maxAngle)
|
||||
|| angleBetween(angle, minAngle + NINETY_DEG, maxAngle + NINETY_DEG)
|
||||
|| angleBetween(angle, minAngle - NINETY_DEG, maxAngle - NINETY_DEG)
|
||||
|| angleBetween(angle, minAngle + ONE_HUNDRED_EIGHTY_DEG,
|
||||
maxAngle + ONE_HUNDRED_EIGHTY_DEG), 0.5f);
|
||||
maxAngle + ONE_HUNDRED_EIGHTY_DEG);
|
||||
return falsed ? Result.falsed(0.5f, getReason()) : Result.passed(0.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getReason() {
|
||||
private String getReason() {
|
||||
return String.format(
|
||||
(Locale) null,
|
||||
"{angle=%f, vertical=%s}",
|
||||
|
||||
@@ -148,10 +148,10 @@ class DistanceClassifier extends FalsingClassifier {
|
||||
|
||||
@Override
|
||||
Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
|
||||
return new Result(!getPassedFlingThreshold(), 0.5);
|
||||
return !getPassedFlingThreshold()
|
||||
? Result.falsed(0.5, getReason()) : Result.passed(0.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getReason() {
|
||||
DistanceVectors distanceVectors = getDistances();
|
||||
|
||||
@@ -169,10 +169,10 @@ class DistanceClassifier extends FalsingClassifier {
|
||||
mVerticalSwipeThresholdPx);
|
||||
}
|
||||
|
||||
boolean isLongSwipe() {
|
||||
Result isLongSwipe() {
|
||||
boolean longSwipe = getPassedDistanceThreshold();
|
||||
logDebug("Is longSwipe? " + longSwipe);
|
||||
return longSwipe;
|
||||
return longSwipe ? Result.passed(0.5) : Result.falsed(0.5, getReason());
|
||||
}
|
||||
|
||||
private boolean getPassedDistanceThreshold() {
|
||||
|
||||
@@ -36,8 +36,6 @@ public class DoubleTapClassifier extends FalsingClassifier {
|
||||
private final float mDoubleTapSlop;
|
||||
private final long mDoubleTapTimeMs;
|
||||
|
||||
private StringBuilder mReason = new StringBuilder();
|
||||
|
||||
@Inject
|
||||
DoubleTapClassifier(FalsingDataProvider dataProvider, SingleTapClassifier singleTapClassifier,
|
||||
@Named(DOUBLE_TAP_TOUCH_SLOP) float doubleTapSlop,
|
||||
@@ -54,27 +52,29 @@ public class DoubleTapClassifier extends FalsingClassifier {
|
||||
Queue<? extends List<MotionEvent>> historicalEvents = getHistoricalEvents();
|
||||
List<MotionEvent> firstTapEvents = historicalEvents.peek();
|
||||
|
||||
mReason = new StringBuilder();
|
||||
StringBuilder reason = new StringBuilder();
|
||||
|
||||
if (firstTapEvents == null) {
|
||||
mReason.append("Only one gesture recorded");
|
||||
return new Result(true, 1);
|
||||
return Result.falsed(1, "Only one gesture recorded");
|
||||
}
|
||||
|
||||
return new Result(!isDoubleTap(firstTapEvents, secondTapEvents, mReason), 0.5);
|
||||
return !isDoubleTap(firstTapEvents, secondTapEvents, reason)
|
||||
? Result.falsed(0.5, reason.toString()) : Result.passed(0.5);
|
||||
}
|
||||
|
||||
/** Returns true if the two supplied lists of {@link MotionEvent}s look like a double-tap. */
|
||||
public boolean isDoubleTap(List<MotionEvent> firstEvents, List<MotionEvent> secondEvents,
|
||||
StringBuilder reason) {
|
||||
|
||||
if (!mSingleTapClassifier.isTap(firstEvents)) {
|
||||
reason.append("First gesture is not a tap. ").append(mSingleTapClassifier.getReason());
|
||||
Result firstTap = mSingleTapClassifier.isTap(firstEvents);
|
||||
if (firstTap.isFalse()) {
|
||||
reason.append("First gesture is not a tap. ").append(firstTap.getReason());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mSingleTapClassifier.isTap(secondEvents)) {
|
||||
reason.append("Second gesture is not a tap. ").append(mSingleTapClassifier.getReason());
|
||||
Result secondTap = mSingleTapClassifier.isTap(secondEvents);
|
||||
if (secondTap.isFalse()) {
|
||||
reason.append("Second gesture is not a tap. ").append(secondTap.getReason());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -106,9 +106,4 @@ public class DoubleTapClassifier extends FalsingClassifier {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getReason() {
|
||||
return mReason.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,25 +120,32 @@ public abstract class FalsingClassifier {
|
||||
void onSessionEnded() {};
|
||||
|
||||
/**
|
||||
* Returns true if the data captured so far looks like a false touch.
|
||||
* Returns whether a gesture looks like a false touch.
|
||||
*
|
||||
* See also {@link #classifyGesture(double, double)}.
|
||||
*/
|
||||
Result classifyGesture() {
|
||||
return calculateFalsingResult(0, 0);
|
||||
}
|
||||
|
||||
boolean classifyGesture(double historyPenalty, double historyConfidence) {
|
||||
return calculateFalsingResult(historyPenalty, historyConfidence).isFalse();
|
||||
/**
|
||||
* Returns whether a gesture looks like a false touch, with the option to consider history.
|
||||
*
|
||||
* Unlike the parameter-less version of this method, this method allows the classifier to take
|
||||
* history into account, penalizing or boosting confidence in a gesture based on recent results.
|
||||
*
|
||||
* See also {@link #classifyGesture()}.
|
||||
*/
|
||||
Result classifyGesture(double historyPenalty, double historyConfidence) {
|
||||
return calculateFalsingResult(historyPenalty, historyConfidence);
|
||||
}
|
||||
|
||||
abstract Result calculateFalsingResult(double historyPenalty, double historyConfidence);
|
||||
|
||||
/**
|
||||
* Give the classifier a chance to log more details about why it triggered.
|
||||
* Calculate a result based on available data.
|
||||
*
|
||||
* This should only be called after a call to {@link #classifyGesture()}, and only if
|
||||
* {@link #classifyGesture()} returns true;
|
||||
* When passed a historyConfidence of 0, the history penalty should be wholly ignored.
|
||||
*/
|
||||
abstract String getReason();
|
||||
abstract Result calculateFalsingResult(double historyPenalty, double historyConfidence);
|
||||
|
||||
/** */
|
||||
public static void logDebug(String msg) {
|
||||
@@ -155,13 +162,21 @@ public abstract class FalsingClassifier {
|
||||
BrightLineFalsingManager.logError(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* A Falsing result that encapsulates the boolean result along with confidence and a reason.
|
||||
*/
|
||||
static class Result {
|
||||
private final boolean mFalsed;
|
||||
private final double mConfidence;
|
||||
private final String mReason;
|
||||
|
||||
Result(boolean falsed, double confidence) {
|
||||
/**
|
||||
* See {@link #falsed(double, String)} abd {@link #passed(double)}.
|
||||
*/
|
||||
private Result(boolean falsed, double confidence, String reason) {
|
||||
mFalsed = falsed;
|
||||
mConfidence = confidence;
|
||||
mReason = reason;
|
||||
}
|
||||
|
||||
public boolean isFalse() {
|
||||
@@ -171,5 +186,23 @@ public abstract class FalsingClassifier {
|
||||
public double getConfidence() {
|
||||
return mConfidence;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return mReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a "falsed" result indicating that a gesture should be treated as accidental.
|
||||
*/
|
||||
static Result falsed(double confidence, String reason) {
|
||||
return new Result(true, confidence, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a "passed" result indicating that a gesture should be allowed.
|
||||
*/
|
||||
static Result passed(double confidence) {
|
||||
return new Result(false, confidence, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,18 +58,19 @@ class PointerCountClassifier extends FalsingClassifier {
|
||||
@Override
|
||||
Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
|
||||
int interactionType = getInteractionType();
|
||||
if (interactionType == QUICK_SETTINGS || interactionType == NOTIFICATION_DRAG_DOWN) {
|
||||
return new Result(mMaxPointerCount > MAX_ALLOWED_POINTERS_SWIPE_DOWN, 1);
|
||||
}
|
||||
return new Result(mMaxPointerCount > MAX_ALLOWED_POINTERS, 1);
|
||||
int allowedPointerCount =
|
||||
(interactionType == QUICK_SETTINGS || interactionType == NOTIFICATION_DRAG_DOWN)
|
||||
? MAX_ALLOWED_POINTERS_SWIPE_DOWN : MAX_ALLOWED_POINTERS;
|
||||
|
||||
return mMaxPointerCount > allowedPointerCount
|
||||
? Result.falsed(1, getReason(allowedPointerCount)) : Result.passed(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getReason() {
|
||||
private String getReason(int allowedPointerCount) {
|
||||
return String.format(
|
||||
(Locale) null,
|
||||
"{pointersObserved=%d, threshold=%d}",
|
||||
mMaxPointerCount,
|
||||
MAX_ALLOWED_POINTERS);
|
||||
allowedPointerCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import javax.inject.Inject;
|
||||
/**
|
||||
* False touch if proximity sensor is covered for more than a certain percentage of the gesture.
|
||||
*
|
||||
* This classifer is essentially a no-op for QUICK_SETTINGS, as we assume the sensor may be
|
||||
* This classifier is essentially a no-op for QUICK_SETTINGS, as we assume the sensor may be
|
||||
* covered when swiping from the top.
|
||||
*/
|
||||
class ProximityClassifier extends FalsingClassifier {
|
||||
@@ -114,26 +114,27 @@ class ProximityClassifier extends FalsingClassifier {
|
||||
@Override
|
||||
Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
|
||||
if (getInteractionType() == QUICK_SETTINGS) {
|
||||
return new Result(false, 0);
|
||||
return Result.passed(0);
|
||||
}
|
||||
|
||||
logInfo("Percent of gesture in proximity: " + mPercentNear);
|
||||
|
||||
if (mPercentNear > mPercentCoveredThreshold) {
|
||||
return new Result(!mDistanceClassifier.isLongSwipe(), 0.5);
|
||||
Result longSwipeResult = mDistanceClassifier.isLongSwipe();
|
||||
return longSwipeResult.isFalse()
|
||||
? Result.falsed(0.5, getReason(longSwipeResult)) : Result.passed(0.5);
|
||||
}
|
||||
|
||||
return new Result(false, 0.5);
|
||||
return Result.passed(0.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getReason() {
|
||||
private String getReason(Result longSwipeResult) {
|
||||
return String.format(
|
||||
(Locale) null,
|
||||
"{percentInProximity=%f, threshold=%f, distanceClassifier=%s}",
|
||||
mPercentNear,
|
||||
mPercentCoveredThreshold,
|
||||
mDistanceClassifier.getReason());
|
||||
longSwipeResult.getReason());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,6 @@ import javax.inject.Named;
|
||||
*/
|
||||
public class SingleTapClassifier extends FalsingClassifier {
|
||||
private final float mTouchSlop;
|
||||
private String mReason;
|
||||
|
||||
@Inject
|
||||
SingleTapClassifier(FalsingDataProvider dataProvider,
|
||||
@@ -41,35 +40,30 @@ public class SingleTapClassifier extends FalsingClassifier {
|
||||
|
||||
@Override
|
||||
Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
|
||||
return new Result(!isTap(getRecentMotionEvents()), 0.5);
|
||||
return isTap(getRecentMotionEvents());
|
||||
}
|
||||
|
||||
/** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */
|
||||
public boolean isTap(List<MotionEvent> motionEvents) {
|
||||
public Result isTap(List<MotionEvent> motionEvents) {
|
||||
float downX = motionEvents.get(0).getX();
|
||||
float downY = motionEvents.get(0).getY();
|
||||
|
||||
for (MotionEvent event : motionEvents) {
|
||||
String reason;
|
||||
if (Math.abs(event.getX() - downX) >= mTouchSlop) {
|
||||
mReason = "dX too big for a tap: "
|
||||
reason = "dX too big for a tap: "
|
||||
+ Math.abs(event.getX() - downX)
|
||||
+ "vs "
|
||||
+ mTouchSlop;
|
||||
return false;
|
||||
return Result.falsed(0.5, reason);
|
||||
} else if (Math.abs(event.getY() - downY) >= mTouchSlop) {
|
||||
mReason = "dY too big for a tap: "
|
||||
reason = "dY too big for a tap: "
|
||||
+ Math.abs(event.getY() - downY)
|
||||
+ "vs "
|
||||
+ mTouchSlop;
|
||||
return false;
|
||||
return Result.falsed(0.5, reason);
|
||||
}
|
||||
}
|
||||
mReason = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getReason() {
|
||||
return mReason;
|
||||
return Result.passed(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,27 +43,35 @@ public class TypeClassifier extends FalsingClassifier {
|
||||
boolean up = isUp();
|
||||
boolean right = isRight();
|
||||
|
||||
boolean wrongDirection = true;
|
||||
switch (getInteractionType()) {
|
||||
case QUICK_SETTINGS:
|
||||
case PULSE_EXPAND:
|
||||
case NOTIFICATION_DRAG_DOWN:
|
||||
return new Result(!vertical || up, 0.5);
|
||||
wrongDirection = !vertical || up;
|
||||
break;
|
||||
case NOTIFICATION_DISMISS:
|
||||
return new Result(vertical, 0.5);
|
||||
wrongDirection = vertical;
|
||||
break;
|
||||
case UNLOCK:
|
||||
case BOUNCER_UNLOCK:
|
||||
return new Result(!vertical || !up, 0.5);
|
||||
wrongDirection = !vertical || !up;
|
||||
break;
|
||||
case LEFT_AFFORDANCE: // Swiping from the bottom left corner for camera or similar.
|
||||
return new Result(!right || !up, 0.5);
|
||||
wrongDirection = !right || !up;
|
||||
break;
|
||||
case RIGHT_AFFORDANCE: // Swiping from the bottom right corner for camera or similar.
|
||||
return new Result(right || !up, 0.5);
|
||||
wrongDirection = right || !up;
|
||||
break;
|
||||
default:
|
||||
return new Result(true, 1);
|
||||
wrongDirection = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return wrongDirection ? Result.falsed(1, getReason()) : Result.passed(0.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getReason() {
|
||||
private String getReason() {
|
||||
return String.format("{vertical=%s, up=%s, right=%s}", isVertical(), isUp(), isRight());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ class ZigZagClassifier extends FalsingClassifier {
|
||||
// For vertical lines, the difference in the y direction should be small.
|
||||
|
||||
if (motionEvents.size() < 3) {
|
||||
return new Result(false, 0);
|
||||
return Result.passed(0);
|
||||
}
|
||||
|
||||
List<Point> rotatedPoints;
|
||||
@@ -155,11 +155,11 @@ class ZigZagClassifier extends FalsingClassifier {
|
||||
|
||||
logDebug("Straightness Deviance: (" + devianceX + "," + devianceY + ") vs "
|
||||
+ "(" + maxXDeviance + "," + maxYDeviance + ")");
|
||||
return new Result(devianceX > maxXDeviance || devianceY > maxYDeviance, 0.5);
|
||||
return devianceX > maxXDeviance || devianceY > maxYDeviance
|
||||
? Result.falsed(0.5, getReason()) : Result.passed(0.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getReason() {
|
||||
private String getReason() {
|
||||
return String.format(
|
||||
(Locale) null,
|
||||
"{devianceX=%f, maxDevianceX=%s, devianceY=%s, maxDevianceY=%s}",
|
||||
|
||||
@@ -72,12 +72,14 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
||||
private HistoryTracker mHistoryTracker;
|
||||
private FakeSystemClock mSystemClock = new FakeSystemClock();
|
||||
|
||||
private FalsingClassifier.Result mTrueResult = new FalsingClassifier.Result(true, 1);
|
||||
private FalsingClassifier.Result mFalseResult = new FalsingClassifier.Result(false, 1);
|
||||
private final FalsingClassifier.Result mFalsedResult = FalsingClassifier.Result.falsed(1, "");
|
||||
private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1);
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(mPassedResult);
|
||||
when(mClassifierB.classifyGesture(anyDouble(), anyDouble())).thenReturn(mPassedResult);
|
||||
mClassifiers.add(mClassifierA);
|
||||
mClassifiers.add(mClassifierB);
|
||||
when(mFalsingDataProvider.isDirty()).thenReturn(true);
|
||||
@@ -111,20 +113,20 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testIsFalseTouch_ClassifierARejects() {
|
||||
when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(true);
|
||||
when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(mFalsedResult);
|
||||
assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsFalseTouch_ClassifierBRejects() {
|
||||
when(mClassifierB.classifyGesture(anyDouble(), anyDouble())).thenReturn(true);
|
||||
when(mClassifierB.classifyGesture(anyDouble(), anyDouble())).thenReturn(mFalsedResult);
|
||||
assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsFalseTouch_FaceAuth() {
|
||||
// Even when the classifiers report a false, we should allow.
|
||||
when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(true);
|
||||
when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(mPassedResult);
|
||||
when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
|
||||
|
||||
assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
|
||||
@@ -133,7 +135,7 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testIsFalseTouch_Docked() {
|
||||
// Even when the classifiers report a false, we should allow.
|
||||
when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(true);
|
||||
when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(mPassedResult);
|
||||
mDockManager.setIsDocked(true);
|
||||
|
||||
assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
|
||||
@@ -141,36 +143,36 @@ public class BrightLineClassifierTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testIsFalseTap_BasicCheck() {
|
||||
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(false);
|
||||
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mFalsedResult);
|
||||
|
||||
assertThat(mBrightLineFalsingManager.isFalseTap(false)).isTrue();
|
||||
|
||||
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true);
|
||||
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
|
||||
|
||||
assertThat(mBrightLineFalsingManager.isFalseTap(false)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsFalseTap_RobustCheck_NoFaceAuth() {
|
||||
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true);
|
||||
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
|
||||
mFalsingDataProvider.setJustUnlockedWithFace(false);
|
||||
assertThat(mBrightLineFalsingManager.isFalseTap(true)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsFalseTap_RobustCheck_FaceAuth() {
|
||||
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true);
|
||||
when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult);
|
||||
when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
|
||||
assertThat(mBrightLineFalsingManager.isFalseTap(true)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsFalseDoubleTap() {
|
||||
when(mDoubleTapClassifier.classifyGesture()).thenReturn(mFalseResult);
|
||||
when(mDoubleTapClassifier.classifyGesture()).thenReturn(mPassedResult);
|
||||
|
||||
assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isFalse();
|
||||
|
||||
when(mDoubleTapClassifier.classifyGesture()).thenReturn(mTrueResult);
|
||||
when(mDoubleTapClassifier.classifyGesture()).thenReturn(mFalsedResult);
|
||||
|
||||
assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isTrue();
|
||||
}
|
||||
|
||||
@@ -55,6 +55,9 @@ public class DoubleTapClassifierTest extends ClassifierTest {
|
||||
private SingleTapClassifier mSingleTapClassifier;
|
||||
private DoubleTapClassifier mClassifier;
|
||||
|
||||
private final FalsingClassifier.Result mFalsedResult = FalsingClassifier.Result.falsed(1, "");
|
||||
private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1);
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
super.setup();
|
||||
@@ -77,7 +80,7 @@ public class DoubleTapClassifierTest extends ClassifierTest {
|
||||
|
||||
@Test
|
||||
public void testSingleTap() {
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(true);
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(mFalsedResult);
|
||||
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
|
||||
addMotionEvent(0, 1, MotionEvent.ACTION_UP, TOUCH_SLOP, 1);
|
||||
|
||||
@@ -87,7 +90,7 @@ public class DoubleTapClassifierTest extends ClassifierTest {
|
||||
|
||||
@Test
|
||||
public void testDoubleTap() {
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(true);
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(mPassedResult);
|
||||
|
||||
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
|
||||
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
|
||||
@@ -97,13 +100,13 @@ public class DoubleTapClassifierTest extends ClassifierTest {
|
||||
addMotionEvent(2, 2, MotionEvent.ACTION_DOWN, TOUCH_SLOP, TOUCH_SLOP);
|
||||
addMotionEvent(2, 3, MotionEvent.ACTION_UP, TOUCH_SLOP, TOUCH_SLOP);
|
||||
|
||||
boolean result = mClassifier.classifyGesture().isFalse();
|
||||
assertThat(mClassifier.getReason(), result, is(false));
|
||||
FalsingClassifier.Result result = mClassifier.classifyGesture();
|
||||
assertThat(result.getReason(), result.isFalse(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadFirstTap() {
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(false, true);
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(mPassedResult, mFalsedResult);
|
||||
|
||||
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
|
||||
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
|
||||
@@ -119,7 +122,7 @@ public class DoubleTapClassifierTest extends ClassifierTest {
|
||||
|
||||
@Test
|
||||
public void testBadSecondTap() {
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(true, false);
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(mFalsedResult, mPassedResult);
|
||||
|
||||
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
|
||||
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
|
||||
@@ -135,7 +138,7 @@ public class DoubleTapClassifierTest extends ClassifierTest {
|
||||
|
||||
@Test
|
||||
public void testBadTouchSlop() {
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(true);
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(mFalsedResult);
|
||||
|
||||
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
|
||||
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
|
||||
@@ -151,7 +154,7 @@ public class DoubleTapClassifierTest extends ClassifierTest {
|
||||
|
||||
@Test
|
||||
public void testBadTouchSlow() {
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(true);
|
||||
when(mSingleTapClassifier.isTap(anyList())).thenReturn(mFalsedResult);
|
||||
|
||||
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
|
||||
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
|
||||
|
||||
@@ -120,6 +120,9 @@ public class HistoryTrackerTest extends SysuiTestCase {
|
||||
|
||||
private void addResult(boolean falsed, double confidence) {
|
||||
mHistoryTracker.addResults(Collections.singletonList(
|
||||
new FalsingClassifier.Result(falsed, confidence)), mSystemClock.uptimeMillis());
|
||||
falsed
|
||||
? FalsingClassifier.Result.falsed(confidence, "test")
|
||||
: FalsingClassifier.Result.passed(confidence)),
|
||||
mSystemClock.uptimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,12 +50,16 @@ public class ProximityClassifierTest extends ClassifierTest {
|
||||
private DistanceClassifier mDistanceClassifier;
|
||||
private FalsingClassifier mClassifier;
|
||||
|
||||
private final FalsingClassifier.Result mFalsedResult =
|
||||
FalsingClassifier.Result.falsed(1, "test");
|
||||
private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1);
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
super.setup();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mDataProvider.getInteractionType()).thenReturn(GENERIC);
|
||||
when(mDistanceClassifier.isLongSwipe()).thenReturn(false);
|
||||
when(mDistanceClassifier.isLongSwipe()).thenReturn(mFalsedResult);
|
||||
mClassifier = new ProximityClassifier(
|
||||
mDistanceClassifier, mDataProvider, new DeviceConfigProxyFake());
|
||||
}
|
||||
@@ -117,7 +121,7 @@ public class ProximityClassifierTest extends ClassifierTest {
|
||||
mClassifier.onProximityEvent(createSensorEvent(true, 1));
|
||||
mClassifier.onProximityEvent(createSensorEvent(false, 11));
|
||||
touchUp(10);
|
||||
when(mDistanceClassifier.isLongSwipe()).thenReturn(true);
|
||||
when(mDistanceClassifier.isLongSwipe()).thenReturn(mPassedResult);
|
||||
assertThat(mClassifier.classifyGesture().isFalse(), is(false));
|
||||
}
|
||||
|
||||
|
||||
@@ -142,12 +142,12 @@ public class SingleTapClassifierTest extends ClassifierTest {
|
||||
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
|
||||
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, 1);
|
||||
|
||||
assertThat(mClassifier.isTap(mMotionEvents), is(true));
|
||||
assertThat(mClassifier.isTap(mMotionEvents).isFalse(), is(false));
|
||||
|
||||
addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1);
|
||||
addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, TOUCH_SLOP + 1);
|
||||
|
||||
assertThat(mClassifier.isTap(mMotionEvents), is(false));
|
||||
assertThat(mClassifier.isTap(mMotionEvents).isFalse(), is(true));
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user