From 3ae5052e7b879647291930a19164d9bc4712fe71 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Tue, 24 Nov 2020 15:57:57 -0500 Subject: [PATCH] Add HistoryTracker to FalsingManager This institutes a HistoryTracker mechanism that will allow the FalsingManager to take recent activity into account when classifying gestures. The HistoryTracker returns a penalty that is pased to each classifier for them to use when making decisions. As of right now, no classifier actually uses the history penalty when making a classification decision. The HistoryTracker keeps records of the last 3 seconds of falsing results, applying a decaying penalty to the results over time. It also assigns a confidence to its results, based on how consistent they are. Each individual classifier is also able to return a confidence score now, such that, if they are not confident in their decision, they don't throw off the score that gets stored in the HistoryTracker. Confidences currently returned by the classifiers are somewhat arbitrary and should be adjusted in future CLs. Everything is currently open for adjustment: - The length of history - The decay function applied to history - The method by which our confidence in the history is calculated - The confidence returned by each individual classfier - How the history penalty is taken into account by each classifier - ... and probably more. Bug: 172655679 Test: atest SystemUITests Change-Id: Ief2a5144a0cda659c7d78ed6e489231d481b6872 --- .../systemui/plugins/FalsingManager.java | 6 +- .../classifier/BrightLineFalsingManager.java | 34 +++- .../classifier/DiagonalClassifier.java | 11 +- .../classifier/DistanceClassifier.java | 5 +- .../classifier/DoubleTapClassifier.java | 6 +- .../classifier/FalsingClassifier.java | 39 +++- .../systemui/classifier/FalsingCollector.java | 2 +- .../classifier/FalsingCollectorFake.java | 2 +- .../classifier/FalsingCollectorImpl.java | 3 +- .../classifier/FalsingDataProvider.java | 36 ++++ .../classifier/FalsingManagerFake.java | 6 - .../classifier/FalsingManagerProxy.java | 6 - .../systemui/classifier/HistoryTracker.java | 177 ++++++++++++++++++ .../classifier/PointerCountClassifier.java | 6 +- .../classifier/ProximityClassifier.java | 8 +- .../classifier/SingleTapClassifier.java | 4 +- .../systemui/classifier/TypeClassifier.java | 14 +- .../systemui/classifier/ZigZagClassifier.java | 6 +- ...NotificationShadeWindowViewController.java | 2 +- .../classifier/BrightLineClassifierTest.java | 41 +++- .../classifier/DiagonalClassifierTest.java | 62 +++--- .../classifier/DistanceClassifierTest.java | 24 +-- .../classifier/DoubleTapClassifierTest.java | 12 +- .../classifier/HistoryTrackerTest.java | 125 +++++++++++++ .../PointerCountClassifierTest.java | 8 +- .../classifier/ProximityClassifierTest.java | 12 +- .../classifier/SingleTapClassifierTest.java | 18 +- .../classifier/TypeClassifierTest.java | 80 ++++---- .../classifier/ZigZagClassifierTest.java | 94 +++++----- 29 files changed, 622 insertions(+), 227 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java index 6e86f268a7258..4fc197340e928 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java @@ -60,8 +60,8 @@ public interface FalsingManager { * Returns true if the last two gestures do not look like a double tap. * * Only works on data that has already been reported to the FalsingManager. Be sure that - * {@link #onTouchEvent(MotionEvent, int, int)} has already been called for all of the - * taps you want considered. + * {@link com.android.systemui.classifier.FalsingCollector#onTouchEvent(MotionEvent)} + * has already been called for all of the taps you want considered. * * This looks at the last two gestures on the screen, ensuring that they meet the following * criteria: @@ -85,8 +85,6 @@ public interface FalsingManager { boolean isReportingEnabled(); - void onTouchEvent(MotionEvent ev, int width, int height); - /** From com.android.systemui.Dumpable. */ void dump(FileDescriptor fd, PrintWriter pw, String[] args); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java index e24a513437eae..e9b1abcd5999c 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java @@ -23,7 +23,6 @@ import android.net.Uri; import android.os.Build; import android.util.IndentingPrintWriter; import android.util.Log; -import android.view.MotionEvent; import androidx.annotation.NonNull; @@ -33,10 +32,12 @@ import com.android.systemui.dagger.qualifiers.TestHarness; import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.util.sensors.ThresholdSensor; +import com.android.systemui.util.time.SystemClock; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Locale; @@ -63,6 +64,8 @@ public class BrightLineFalsingManager implements FalsingManager { private final DockManager mDockManager; private final SingleTapClassifier mSingleTapClassifier; private final DoubleTapClassifier mDoubleTapClassifier; + private final HistoryTracker mHistoryTracker; + private final SystemClock mSystemClock; private final boolean mTestHarness; private final MetricsLogger mMetricsLogger; private int mIsFalseTouchCalls; @@ -85,6 +88,17 @@ public class BrightLineFalsingManager implements FalsingManager { } }; + private final FalsingDataProvider.GestureCompleteListener mGestureCompleteListener = + new FalsingDataProvider.GestureCompleteListener() { + @Override + public void onGestureComplete() { + mHistoryTracker.addResults( + mClassifiers.stream().map(FalsingClassifier::classifyGesture) + .collect(Collectors.toCollection(ArrayList::new)), + mSystemClock.uptimeMillis()); + } + }; + private boolean mPreviousResult = false; @Inject @@ -92,6 +106,7 @@ public class BrightLineFalsingManager implements FalsingManager { DockManager dockManager, MetricsLogger metricsLogger, @Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set classifiers, SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier, + HistoryTracker historyTracker, SystemClock systemClock, @TestHarness boolean testHarness) { mDataProvider = falsingDataProvider; mDockManager = dockManager; @@ -99,9 +114,12 @@ public class BrightLineFalsingManager implements FalsingManager { mClassifiers = classifiers; mSingleTapClassifier = singleTapClassifier; mDoubleTapClassifier = doubleTapClassifier; + mHistoryTracker = historyTracker; + mSystemClock = systemClock; mTestHarness = testHarness; mDataProvider.addSessionListener(mSessionListener); + mDataProvider.addGestureCompleteListener(mGestureCompleteListener); } @Override @@ -119,7 +137,8 @@ public class BrightLineFalsingManager implements FalsingManager { mPreviousResult = !mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked() && mClassifiers.stream().anyMatch(falsingClassifier -> { - boolean result = falsingClassifier.isFalseTouch(); + boolean result = falsingClassifier.classifyGesture( + mHistoryTracker.falsePenalty(), mHistoryTracker.falseConfidence()); if (result) { logInfo(String.format( (Locale) null, @@ -179,7 +198,7 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public boolean isFalseDoubleTap() { - boolean result = mDoubleTapClassifier.isFalseTouch(); + boolean result = mDoubleTapClassifier.classifyGesture().isFalse(); if (result) { logInfo(String.format( (Locale) null, "{classifier=%s}", mDoubleTapClassifier.getClass().getName())); @@ -191,13 +210,6 @@ public class BrightLineFalsingManager implements FalsingManager { return result; } - @Override - public void onTouchEvent(MotionEvent motionEvent, int width, int height) { - // TODO: some of these classifiers might allow us to abort early, meaning we don't have to - // make these calls. - mClassifiers.forEach((classifier) -> classifier.onTouchEvent(motionEvent)); - } - @Override public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) { // TODO: some of these classifiers might allow us to abort early, meaning we don't have to @@ -271,6 +283,8 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void cleanup() { mDataProvider.removeSessionListener(mSessionListener); + mDataProvider.removeGestureCompleteListener(mGestureCompleteListener); + mClassifiers.forEach(FalsingClassifier::cleanup); } static void logDebug(String msg) { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java index 92dd8b74e9596..3a758ae0bbf55 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java @@ -62,17 +62,16 @@ class DiagonalClassifier extends FalsingClassifier { VERTICAL_ANGLE_RANGE); } - @Override - boolean isFalseTouch() { + Result calculateFalsingResult(double historyPenalty, double historyConfidence) { float angle = getAngle(); if (angle == Float.MAX_VALUE) { // Unknown angle - return false; + return new Result(false, 0); } if (getInteractionType() == LEFT_AFFORDANCE || getInteractionType() == RIGHT_AFFORDANCE) { - return false; + return new Result(false, 0); } float minAngle = DIAGONAL - mHorizontalAngleRange; @@ -82,11 +81,11 @@ class DiagonalClassifier extends FalsingClassifier { maxAngle = DIAGONAL + mVerticalAngleRange; } - return angleBetween(angle, minAngle, maxAngle) + return new Result(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); + maxAngle + ONE_HUNDRED_EIGHTY_DEG), 0.5f); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java index 50d55f6f60283..9661b57b620f1 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java @@ -123,7 +123,6 @@ class DistanceClassifier extends FalsingClassifier { } VelocityTracker velocityTracker = VelocityTracker.obtain(); - for (MotionEvent motionEvent : motionEvents) { velocityTracker.addMovement(motionEvent); } @@ -148,8 +147,8 @@ class DistanceClassifier extends FalsingClassifier { } @Override - public boolean isFalseTouch() { - return !getPassedFlingThreshold(); + Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + return new Result(!getPassedFlingThreshold(), 0.5); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java index 1c8f4208edba9..225e066d1b363 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java @@ -49,7 +49,7 @@ public class DoubleTapClassifier extends FalsingClassifier { } @Override - boolean isFalseTouch() { + Result calculateFalsingResult(double historyPenalty, double historyConfidence) { List secondTapEvents = getRecentMotionEvents(); Queue> historicalEvents = getHistoricalEvents(); List firstTapEvents = historicalEvents.peek(); @@ -58,10 +58,10 @@ public class DoubleTapClassifier extends FalsingClassifier { if (firstTapEvents == null) { mReason.append("Only one gesture recorded"); - return true; + return new Result(true, 1); } - return !isDoubleTap(firstTapEvents, secondTapEvents, mReason); + return new Result(!isDoubleTap(firstTapEvents, secondTapEvents, mReason), 0.5); } /** Returns true if the two supplied lists of {@link MotionEvent}s look like a double-tap. */ diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java index 82575c3e639e0..ce5f21a3a5c42 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java @@ -29,8 +29,11 @@ import java.util.Queue; public abstract class FalsingClassifier { private final FalsingDataProvider mDataProvider; + private final FalsingDataProvider.MotionEventListener mMotionEventListener = this::onTouchEvent; + FalsingClassifier(FalsingDataProvider dataProvider) { mDataProvider = dataProvider; + mDataProvider.addMotionEventListener(mMotionEventListener); } List getRecentMotionEvents() { @@ -89,6 +92,10 @@ public abstract class FalsingClassifier { return mDataProvider.getInteractionType(); } + void cleanup() { + mDataProvider.removeMotionEventListener(mMotionEventListener); + } + /** * Called whenever a MotionEvent occurs. * @@ -115,13 +122,21 @@ public abstract class FalsingClassifier { /** * Returns true if the data captured so far looks like a false touch. */ - abstract boolean isFalseTouch(); + Result classifyGesture() { + return calculateFalsingResult(0, 0); + } + + boolean classifyGesture(double historyPenalty, double historyConfidence) { + return calculateFalsingResult(historyPenalty, historyConfidence).isFalse(); + } + + abstract Result calculateFalsingResult(double historyPenalty, double historyConfidence); /** * Give the classifier a chance to log more details about why it triggered. * - * This should only be called after a call to {@link #isFalseTouch()}, and only if - * {@link #isFalseTouch()} returns true; + * This should only be called after a call to {@link #classifyGesture()}, and only if + * {@link #classifyGesture()} returns true; */ abstract String getReason(); @@ -139,4 +154,22 @@ public abstract class FalsingClassifier { public static void logError(String msg) { BrightLineFalsingManager.logError(msg); } + + static class Result { + private final boolean mFalsed; + private final double mConfidence; + + Result(boolean falsed, double confidence) { + mFalsed = falsed; + mConfidence = confidence; + } + + public boolean isFalse() { + return mFalsed; + } + + public double getConfidence() { + return mConfidence; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java index c05ce93f0c137..fe47162a1d4ec 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java @@ -113,7 +113,7 @@ public interface FalsingCollector { void onBouncerHidden(); /** */ - void onTouchEvent(MotionEvent ev, int width, int height); + void onTouchEvent(MotionEvent ev); /** */ void cleanup(); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java index a5691118261a8..fd059898f7a6b 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java @@ -143,7 +143,7 @@ public class FalsingCollectorFake implements FalsingCollector { } @Override - public void onTouchEvent(MotionEvent ev, int width, int height) { + public void onTouchEvent(MotionEvent ev) { } @Override diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java index 3547392512a7a..4c11ecf669565 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java @@ -244,9 +244,8 @@ class FalsingCollectorImpl implements FalsingCollector { } @Override - public void onTouchEvent(MotionEvent ev, int width, int height) { + public void onTouchEvent(MotionEvent ev) { mFalsingDataProvider.onMotionEvent(ev); - mFalsingManager.onTouchEvent(ev, width, height); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java index 009b311f23636..deb9e6dc442ca 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java @@ -50,6 +50,8 @@ public class FalsingDataProvider { private final float mXdpi; private final float mYdpi; private final List mSessionListeners = new ArrayList<>(); + private final List mMotionEventListeners = new ArrayList<>(); + private final List mGestuerCompleteListeners = new ArrayList<>(); private @Classifier.InteractionType int mInteractionType; private final Deque mExtendedMotionEvents = new LinkedList<>(); @@ -97,6 +99,8 @@ public class FalsingDataProvider { FalsingClassifier.logDebug("Size: " + mRecentMotionEvents.size()); + mMotionEventListeners.forEach(listener -> listener.onMotionEvent(motionEvent)); + mDirty = true; } @@ -321,6 +325,26 @@ public class FalsingDataProvider { mSessionListeners.remove(listener); } + /** Register a {@link MotionEventListener}. */ + public void addMotionEventListener(MotionEventListener listener) { + mMotionEventListeners.add(listener); + } + + /** Unegister a {@link MotionEventListener}. */ + public void removeMotionEventListener(MotionEventListener listener) { + mMotionEventListeners.remove(listener); + } + + /** Register a {@link GestureCompleteListener}. */ + public void addGestureCompleteListener(GestureCompleteListener listener) { + mGestuerCompleteListeners.add(listener); + } + + /** Unregister a {@link GestureCompleteListener}. */ + public void removeGestureCompleteListener(GestureCompleteListener listener) { + mGestuerCompleteListeners.remove(listener); + } + void onSessionStarted() { mSessionListeners.forEach(SessionListener::onSessionStarted); } @@ -353,4 +377,16 @@ public class FalsingDataProvider { /** Called when the lock screen exits and falsing-tracking ends. */ void onSessionEnded(); } + + /** Callback for receiving {@link android.view.MotionEvent}s as they are reported. */ + public interface MotionEventListener { + /** */ + void onMotionEvent(MotionEvent ev); + } + + /** Callback to be alerted when the current gesture ends. */ + public interface GestureCompleteListener { + /** */ + void onGestureComplete(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java index 32d27bcc01a69..d4d8d06b081b5 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java @@ -17,7 +17,6 @@ package com.android.systemui.classifier; import android.net.Uri; -import android.view.MotionEvent; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.plugins.FalsingManager; @@ -116,11 +115,6 @@ public class FalsingManagerFake implements FalsingManager { return mIsReportingEnabled; } - @Override - public void onTouchEvent(MotionEvent ev, int width, int height) { - - } - @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index d4f58c324d39c..cbec0576e449f 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -19,7 +19,6 @@ package com.android.systemui.classifier; import android.content.Context; import android.net.Uri; import android.provider.DeviceConfig; -import android.view.MotionEvent; import androidx.annotation.NonNull; @@ -161,11 +160,6 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { return mInternalFalsingManager.isReportingEnabled(); } - @Override - public void onTouchEvent(MotionEvent ev, int width, int height) { - mInternalFalsingManager.onTouchEvent(ev, width, height); - } - @Override public void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) { mInternalFalsingManager.onProximityEvent(proximityEvent); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java new file mode 100644 index 0000000000000..8bd94a122707c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.classifier; + +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.util.time.SystemClock; + +import java.util.Collection; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; + +/** + * A stateful class for tracking recent {@link FalsingManager} results. + * + * Can return a "penalty" based on recent gestures that may make it harder or easier to + * unlock a phone, as well as a "confidence" relating to how consistent recent falsing results + * have been. + */ +@SysUISingleton +public class HistoryTracker { + private static final double HISTORY_DECAY = 0.8f; + private static final long DECAY_INTERVAL_MS = 100; + // We expire items once their decay factor is below 0.001. + private static final double MINIMUM_SCORE = 0.001; + private static final long TOTAL_DECAY_TIME_MS = + DECAY_INTERVAL_MS * (long) (Math.log(MINIMUM_SCORE) / Math.log(HISTORY_DECAY)); + private final SystemClock mSystemClock; + + DelayQueue mResults = new DelayQueue<>(); + + @Inject + HistoryTracker(SystemClock systemClock) { + mSystemClock = systemClock; + } + + /** + * Returns how much the HistoryClassifier thinks the past events indicate pocket dialing. + * + * A result of 0 means that all prior gestures succeeded or there is no data to + * calculate a score with. Use {@link #falseConfidence()} to differentiate between the + * two cases. + * + * A result of 1 means that all prior gestures were very obviously false. The current gesture + * might be valid, but it should have a high-bar to be classified as such. + * + * See also {@link #falseConfidence()}. + */ + double falsePenalty() { + //noinspection StatementWithEmptyBody + while (mResults.poll() != null) { + // Empty out the expired results. + } + + if (mResults.isEmpty()) { + return 0; + } + + long nowMs = mSystemClock.uptimeMillis(); + return mResults.stream() + .map(result -> result.getDecayedScore(nowMs)) + .reduce(0.0, Double::sum) / mResults.size(); + } + + /** + * Returns how confident the HistoryClassifier is in its own score. + * + * A result of 0.0 means that there are no data to make a calculation with. The HistoryTracker's + * results have nothing to add and should not be considered. + * + * A result of 0.5 means that the data are not consistent with each other, sometimes falsing + * sometimes not. + * + * A result of 1 means that there are ample, fresh data to act upon that is all consistent + * with each other. + * + * See als {@link #falsePenalty()}. + */ + double falseConfidence() { + //noinspection StatementWithEmptyBody + while (mResults.poll() != null) { + // Empty out the expired results. + } + + // Our confidence is 1 - the population stddev. Smaller stddev == higher confidence. + if (mResults.isEmpty()) { + return 0; + } + + double mean = mResults.stream() + .map(CombinedResult::getScore) + .reduce(0.0, Double::sum) / mResults.size(); + + double stddev = Math.sqrt( + mResults.stream() + .map(result -> Math.pow(result.getScore() - mean, 2)) + .reduce(0.0, Double::sum) / mResults.size()); + + return 1 - stddev; + } + + void addResults(Collection results, long uptimeMillis) { + double finalScore = 0; + for (FalsingClassifier.Result result : results) { + // A confidence of 1 adds either 0 for non-falsed or 1 for falsed. + // A confidence of 0 adds 0.5. + finalScore += (result.isFalse() ? .5 : -.5) * result.getConfidence() + 0.5; + } + + finalScore /= results.size(); + + //noinspection StatementWithEmptyBody + while (mResults.poll() != null) { + // Empty out the expired results. + } + + mResults.add(new CombinedResult(uptimeMillis, finalScore)); + } + + /** + * Represents a falsing score combing all the classifiers together. + * + * Can "decay" over time, such that older results contribute less. Once they drop below + * a certain threshold, the {@link #getDelay(TimeUnit)} method will return <= 0, indicating + * that this result can be discarded. + */ + private class CombinedResult implements Delayed { + + private final long mExpiryMs; + private final double mScore; + + CombinedResult(long uptimeMillis, double score) { + mExpiryMs = uptimeMillis + TOTAL_DECAY_TIME_MS; + mScore = score; + } + + double getDecayedScore(long nowMs) { + long remainingTimeMs = mExpiryMs - nowMs; + long decayedTimeMs = TOTAL_DECAY_TIME_MS - remainingTimeMs; + double timeIntervals = (double) decayedTimeMs / DECAY_INTERVAL_MS; + return mScore * Math.pow(HISTORY_DECAY, timeIntervals); + } + + double getScore() { + return mScore; + } + + @Override + public long getDelay(TimeUnit unit) { + return unit.convert(mExpiryMs - mSystemClock.uptimeMillis(), TimeUnit.MILLISECONDS); + } + + @Override + public int compareTo(Delayed o) { + long ourDelay = getDelay(TimeUnit.MILLISECONDS); + long otherDelay = o.getDelay(TimeUnit.MILLISECONDS); + return Long.compare(ourDelay, otherDelay); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java index 0565165e1e8d4..6d8bb42bd01b8 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java @@ -56,12 +56,12 @@ class PointerCountClassifier extends FalsingClassifier { } @Override - public boolean isFalseTouch() { + Result calculateFalsingResult(double historyPenalty, double historyConfidence) { int interactionType = getInteractionType(); if (interactionType == QUICK_SETTINGS || interactionType == NOTIFICATION_DRAG_DOWN) { - return mMaxPointerCount > MAX_ALLOWED_POINTERS_SWIPE_DOWN; + return new Result(mMaxPointerCount > MAX_ALLOWED_POINTERS_SWIPE_DOWN, 1); } - return mMaxPointerCount > MAX_ALLOWED_POINTERS; + return new Result(mMaxPointerCount > MAX_ALLOWED_POINTERS, 1); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java index 6e73fc06de4c9..64601362454e6 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java @@ -112,18 +112,18 @@ class ProximityClassifier extends FalsingClassifier { } @Override - public boolean isFalseTouch() { + Result calculateFalsingResult(double historyPenalty, double historyConfidence) { if (getInteractionType() == QUICK_SETTINGS) { - return false; + return new Result(false, 0); } logInfo("Percent of gesture in proximity: " + mPercentNear); if (mPercentNear > mPercentCoveredThreshold) { - return !mDistanceClassifier.isLongSwipe(); + return new Result(!mDistanceClassifier.isLongSwipe(), 0.5); } - return false; + return new Result(false, 0.5); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java index 6b7a1413bc747..bcca599817401 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java @@ -40,8 +40,8 @@ public class SingleTapClassifier extends FalsingClassifier { } @Override - boolean isFalseTouch() { - return !isTap(getRecentMotionEvents()); + Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + return new Result(!isTap(getRecentMotionEvents()), 0.5); } /** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */ diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java index 711a0fc0f4784..3269d836859e5 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java @@ -38,7 +38,7 @@ public class TypeClassifier extends FalsingClassifier { } @Override - public boolean isFalseTouch() { + Result calculateFalsingResult(double historyPenalty, double historyConfidence) { boolean vertical = isVertical(); boolean up = isUp(); boolean right = isRight(); @@ -47,18 +47,18 @@ public class TypeClassifier extends FalsingClassifier { case QUICK_SETTINGS: case PULSE_EXPAND: case NOTIFICATION_DRAG_DOWN: - return !vertical || up; + return new Result(!vertical || up, 0.5); case NOTIFICATION_DISMISS: - return vertical; + return new Result(vertical, 0.5); case UNLOCK: case BOUNCER_UNLOCK: - return !vertical || !up; + return new Result(!vertical || !up, 0.5); case LEFT_AFFORDANCE: // Swiping from the bottom left corner for camera or similar. - return !right || !up; + return new Result(!right || !up, 0.5); case RIGHT_AFFORDANCE: // Swiping from the bottom right corner for camera or similar. - return right || !up; + return new Result(right || !up, 0.5); default: - return true; + return new Result(true, 1); } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java index 383dda498b490..04634da47ac9c 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java @@ -84,7 +84,7 @@ class ZigZagClassifier extends FalsingClassifier { } @Override - boolean isFalseTouch() { + Result calculateFalsingResult(double historyPenalty, double historyConfidence) { List motionEvents = getRecentMotionEvents(); // Rotate horizontal gestures to be horizontal between their first and last point. // Rotate vertical gestures to be vertical between their first and last point. @@ -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 false; + return new Result(false, 0); } List rotatedPoints; @@ -155,7 +155,7 @@ class ZigZagClassifier extends FalsingClassifier { logDebug("Straightness Deviance: (" + devianceX + "," + devianceY + ") vs " + "(" + maxXDeviance + "," + maxYDeviance + ")"); - return devianceX > maxXDeviance || devianceY > maxYDeviance; + return new Result(devianceX > maxXDeviance || devianceY > maxYDeviance, 0.5); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java index ba4fbb871b979..2ac9f301a89ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java @@ -238,7 +238,7 @@ public class NotificationShadeWindowViewController { if (mTouchCancelled || mExpandAnimationRunning || mExpandAnimationPending) { return false; } - mFalsingCollector.onTouchEvent(ev, mView.getWidth(), mView.getHeight()); + mFalsingCollector.onTouchEvent(ev); mGestureDetector.onTouchEvent(ev); if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == View.VISIBLE) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java index 19f0a15c89369..d9df8282f0865 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java @@ -20,6 +20,8 @@ import static com.android.systemui.util.mockito.KotlinMockitoHelpersKt.any; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyDouble; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -31,15 +33,19 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.systemui.SysuiTestCase; +import com.android.systemui.classifier.FalsingDataProvider.GestureCompleteListener; import com.android.systemui.dock.DockManagerFake; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -62,6 +68,12 @@ public class BrightLineClassifierTest extends SysuiTestCase { @Mock private FalsingClassifier mClassifierB; private final List mMotionEventList = new ArrayList<>(); + @Mock + 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); @Before public void setup() { @@ -71,7 +83,8 @@ public class BrightLineClassifierTest extends SysuiTestCase { when(mFalsingDataProvider.isDirty()).thenReturn(true); when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList); mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager, - mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier, false); + mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier, + mHistoryTracker, mSystemClock, false); } @Test @@ -98,20 +111,20 @@ public class BrightLineClassifierTest extends SysuiTestCase { @Test public void testIsFalseTouch_ClassifierARejects() { - when(mClassifierA.isFalseTouch()).thenReturn(true); + when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(true); assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue(); } @Test public void testIsFalseTouch_ClassifierBRejects() { - when(mClassifierB.isFalseTouch()).thenReturn(true); + when(mClassifierB.classifyGesture(anyDouble(), anyDouble())).thenReturn(true); assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue(); } @Test public void testIsFalseTouch_FaceAuth() { // Even when the classifiers report a false, we should allow. - when(mClassifierA.isFalseTouch()).thenReturn(true); + when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(true); when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true); assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse(); @@ -120,7 +133,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { @Test public void testIsFalseTouch_Docked() { // Even when the classifiers report a false, we should allow. - when(mClassifierA.isFalseTouch()).thenReturn(true); + when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(true); mDockManager.setIsDocked(true); assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse(); @@ -153,12 +166,26 @@ public class BrightLineClassifierTest extends SysuiTestCase { @Test public void testIsFalseDoubleTap() { - when(mDoubleTapClassifier.isFalseTouch()).thenReturn(false); + when(mDoubleTapClassifier.classifyGesture()).thenReturn(mFalseResult); assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isFalse(); - when(mDoubleTapClassifier.isFalseTouch()).thenReturn(true); + when(mDoubleTapClassifier.classifyGesture()).thenReturn(mTrueResult); assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isTrue(); } + + @Test + public void testHistory() { + ArgumentCaptor gestureCompleteListenerCaptor = + ArgumentCaptor.forClass(GestureCompleteListener.class); + + verify(mFalsingDataProvider).addGestureCompleteListener( + gestureCompleteListenerCaptor.capture()); + + GestureCompleteListener gestureCompleteListener = gestureCompleteListenerCaptor.getValue(); + gestureCompleteListener.onGestureComplete(); + + verify(mHistoryTracker).addResults(any(Collection.class), eq(mSystemClock.uptimeMillis())); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java index 7659db8cc9efa..dafc87133d39f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java @@ -69,93 +69,93 @@ public class DiagonalClassifierTest extends ClassifierTest { @Test public void testPass_UnknownAngle() { when(mDataProvider.getAngle()).thenReturn(Float.MAX_VALUE); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test public void testPass_VerticalSwipe() { when(mDataProvider.getAngle()).thenReturn(UP_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn(DOWN_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test public void testPass_MostlyVerticalSwipe() { when(mDataProvider.getAngle()).thenReturn(UP_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn(UP_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn(DOWN_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn(DOWN_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS * 2); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test public void testPass_BarelyVerticalSwipe() { when(mDataProvider.getAngle()).thenReturn( UP_IN_RADIANS - FORTY_FIVE_DEG_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn( UP_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn( DOWN_IN_RADIANS - FORTY_FIVE_DEG_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn( DOWN_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS * 2); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test public void testPass_HorizontalSwipe() { when(mDataProvider.getAngle()).thenReturn(RIGHT_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn(LEFT_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test public void testPass_MostlyHorizontalSwipe() { when(mDataProvider.getAngle()).thenReturn(RIGHT_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn(RIGHT_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn(LEFT_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn(LEFT_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test public void testPass_BarelyHorizontalSwipe() { when(mDataProvider.getAngle()).thenReturn( RIGHT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn( LEFT_IN_RADIANS - FORTY_FIVE_DEG_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn( LEFT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getAngle()).thenReturn( RIGHT_IN_RADIANS - FORTY_FIVE_DEG_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS * 2); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -163,12 +163,12 @@ public class DiagonalClassifierTest extends ClassifierTest { when(mDataProvider.getInteractionType()).thenReturn(LEFT_AFFORDANCE); when(mDataProvider.getAngle()).thenReturn( RIGHT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.getInteractionType()).thenReturn(RIGHT_AFFORDANCE); when(mDataProvider.getAngle()).thenReturn( LEFT_IN_RADIANS - FORTY_FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); // This classifier may return false for other angles, but these are the only // two that actually matter, as affordances generally only travel in these two directions. @@ -182,37 +182,37 @@ public class DiagonalClassifierTest extends ClassifierTest { when(mDataProvider.isVertical()).thenReturn(false); when(mDataProvider.getAngle()).thenReturn( RIGHT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.getAngle()).thenReturn( UP_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS + FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.getAngle()).thenReturn( LEFT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.getAngle()).thenReturn( DOWN_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS + FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); // Vertical Swipes when(mDataProvider.isVertical()).thenReturn(true); when(mDataProvider.getAngle()).thenReturn( RIGHT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS + FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.getAngle()).thenReturn( UP_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.getAngle()).thenReturn( LEFT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS + FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.getAngle()).thenReturn( DOWN_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - FIVE_DEG_IN_RADIANS); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java index 013fa369e876f..f6c14240c8f43 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java @@ -51,32 +51,32 @@ public class DistanceClassifierTest extends ClassifierTest { @Test public void testPass_noPointer() { - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test public void testPass_fling() { mClassifier.onTouchEvent(appendDownEvent(1, 1)); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); mClassifier.onTouchEvent(appendMoveEvent(1, 40)); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); mClassifier.onTouchEvent(appendUpEvent(1, 80)); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test public void testFail_flingShort() { mClassifier.onTouchEvent(appendDownEvent(1, 1)); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); mClassifier.onTouchEvent(appendMoveEvent(1, 2)); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); mClassifier.onTouchEvent(appendUpEvent(1, 10)); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -84,26 +84,26 @@ public class DistanceClassifierTest extends ClassifierTest { // These events, in testing, result in a fling that falls just short of the threshold. mClassifier.onTouchEvent(appendDownEvent(1, 1, 1)); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); mClassifier.onTouchEvent(appendMoveEvent(1, 15, 2)); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); mClassifier.onTouchEvent(appendMoveEvent(1, 16, 3)); mClassifier.onTouchEvent(appendMoveEvent(1, 17, 300)); mClassifier.onTouchEvent(appendMoveEvent(1, 18, 301)); mClassifier.onTouchEvent(appendUpEvent(1, 19, 501)); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test public void testPass_swipe() { mClassifier.onTouchEvent(appendDownEvent(1, 1)); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); mClassifier.onTouchEvent(appendMoveEvent(1, mDataProvider.getYdpi() * 3, 3)); mClassifier.onTouchEvent(appendUpEvent(1, mDataProvider.getYdpi() * 3, 300)); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java index 4c4108a0cb90e..67890a5573673 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java @@ -81,7 +81,7 @@ public class DoubleTapClassifierTest extends ClassifierTest { addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1); addMotionEvent(0, 1, MotionEvent.ACTION_UP, TOUCH_SLOP, 1); - boolean result = mClassifier.isFalseTouch(); + boolean result = mClassifier.classifyGesture().isFalse(); assertThat("Single tap recognized as a valid double tap", result, is(true)); } @@ -97,7 +97,7 @@ 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.isFalseTouch(); + boolean result = mClassifier.classifyGesture().isFalse(); assertThat(mClassifier.getReason(), result, is(false)); } @@ -113,7 +113,7 @@ public class DoubleTapClassifierTest extends ClassifierTest { addMotionEvent(2, 2, MotionEvent.ACTION_DOWN, 1, 1); addMotionEvent(2, 3, MotionEvent.ACTION_UP, 1, 1); - boolean result = mClassifier.isFalseTouch(); + boolean result = mClassifier.classifyGesture().isFalse(); assertThat("Bad first touch allowed", result, is(true)); } @@ -129,7 +129,7 @@ public class DoubleTapClassifierTest extends ClassifierTest { addMotionEvent(2, 2, MotionEvent.ACTION_DOWN, 1, 1); addMotionEvent(2, 3, MotionEvent.ACTION_UP, 1, 1); - boolean result = mClassifier.isFalseTouch(); + boolean result = mClassifier.classifyGesture().isFalse(); assertThat("Bad second touch allowed", result, is(true)); } @@ -145,7 +145,7 @@ public class DoubleTapClassifierTest extends ClassifierTest { addMotionEvent(2, 2, MotionEvent.ACTION_DOWN, TOUCH_SLOP + 1, TOUCH_SLOP); addMotionEvent(2, 3, MotionEvent.ACTION_UP, TOUCH_SLOP, TOUCH_SLOP + 1); - boolean result = mClassifier.isFalseTouch(); + boolean result = mClassifier.classifyGesture().isFalse(); assertThat("Sloppy second touch allowed", result, is(true)); } @@ -163,7 +163,7 @@ public class DoubleTapClassifierTest extends ClassifierTest { addMotionEvent(DOUBLE_TAP_TIMEOUT_MS + 1, DOUBLE_TAP_TIMEOUT_MS + 2, MotionEvent.ACTION_UP, 1, 1); - boolean result = mClassifier.isFalseTouch(); + boolean result = mClassifier.classifyGesture().isFalse(); assertThat("Slow second tap allowed", result, is(true)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java new file mode 100644 index 0000000000000..8e7cc4e1013cb --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.classifier; + +import static com.google.common.truth.Truth.assertThat; + +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.util.time.FakeSystemClock; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +import java.util.Collections; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class HistoryTrackerTest extends SysuiTestCase { + + private FakeSystemClock mSystemClock = new FakeSystemClock(); + + private HistoryTracker mHistoryTracker; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mHistoryTracker = new HistoryTracker(mSystemClock); + } + + @Test + public void testNoDataNoPenalty() { + assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0); + assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0); + } + + @Test + public void testOneResultFullConfidence() { + addResult(true, 1); + assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1); + assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); + } + + @Test + public void testMultipleResultsSameTimestamp() { + addResult(true, 1); + addResult(false, 1); + + assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0.5); + assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0.5); + } + + @Test + public void testMultipleConfidences() { + addResult(true, 1); + addResult(true, 0); + + assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0.75); + assertThat(mHistoryTracker.falseConfidence()).isEqualTo(.75); + } + + @Test + public void testDecay() { + addResult(true, 1); + + assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1); + assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); + + mSystemClock.advanceTime(1000); + + assertThat(mHistoryTracker.falsePenalty()).isWithin(0.01).of(0.1); + assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); + } + + @Test + public void testMultipleResultsDifferentTimestamp() { + addResult(true, 1); + mSystemClock.advanceTime(1000); + addResult(false, .5); + + assertThat(mHistoryTracker.falsePenalty()).isWithin(0.01).of(0.17); + assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0.625); + } + + @Test + public void testCompleteDecay() { + addResult(true, 1); + + assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1); + assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); + + mSystemClock.advanceTime(2999); + + assertThat(mHistoryTracker.falsePenalty()).isGreaterThan(0); + assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); + + mSystemClock.advanceTime(1); + + assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0); + assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0); + } + + private void addResult(boolean falsed, double confidence) { + mHistoryTracker.addResults(Collections.singletonList( + new FalsingClassifier.Result(falsed, confidence)), mSystemClock.uptimeMillis()); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java index ee289b5b922d7..76802f4de14fa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java @@ -50,13 +50,13 @@ public class PointerCountClassifierTest extends ClassifierTest { @Test public void testPass_noPointer() { - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test public void testPass_singlePointer() { mClassifier.onTouchEvent(appendDownEvent(1, 1)); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -72,7 +72,7 @@ public class PointerCountClassifierTest extends ClassifierTest { 0, 0); mClassifier.onTouchEvent(motionEvent); motionEvent.recycle(); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -89,6 +89,6 @@ public class PointerCountClassifierTest extends ClassifierTest { mClassifier.onTouchEvent(motionEvent); motionEvent.recycle(); getDataProvider().setInteractionType(QUICK_SETTINGS); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java index 38b025f675eee..3986bb7ff7eb1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java @@ -69,7 +69,7 @@ public class ProximityClassifierTest extends ClassifierTest { public void testPass_uncovered() { touchDown(); touchUp(10); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -78,7 +78,7 @@ public class ProximityClassifierTest extends ClassifierTest { mClassifier.onProximityEvent(createSensorEvent(true, 1)); mClassifier.onProximityEvent(createSensorEvent(false, 2)); touchUp(20); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -88,7 +88,7 @@ public class ProximityClassifierTest extends ClassifierTest { mClassifier.onProximityEvent(createSensorEvent(true, 1)); mClassifier.onProximityEvent(createSensorEvent(false, 11)); touchUp(10); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -97,7 +97,7 @@ public class ProximityClassifierTest extends ClassifierTest { mClassifier.onProximityEvent(createSensorEvent(true, 1)); mClassifier.onProximityEvent(createSensorEvent(false, 11)); touchUp(10); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -108,7 +108,7 @@ public class ProximityClassifierTest extends ClassifierTest { mClassifier.onProximityEvent(createSensorEvent(true, 96)); mClassifier.onProximityEvent(createSensorEvent(false, 100)); touchUp(100); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -118,7 +118,7 @@ public class ProximityClassifierTest extends ClassifierTest { mClassifier.onProximityEvent(createSensorEvent(false, 11)); touchUp(10); when(mDistanceClassifier.isLongSwipe()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } private void touchDown() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java index 941e12e475f9c..e4470759cb46f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java @@ -70,14 +70,14 @@ public class SingleTapClassifierTest extends ClassifierTest { addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1); addMotionEvent(0, 1, MotionEvent.ACTION_UP, TOUCH_SLOP, 1); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); mMotionEvents.clear(); addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1); addMotionEvent(0, 1, MotionEvent.ACTION_UP, -TOUCH_SLOP + 2, 1); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @@ -86,14 +86,14 @@ public class SingleTapClassifierTest extends ClassifierTest { addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1); addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, TOUCH_SLOP); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); mMotionEvents.clear(); addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1); addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, -TOUCH_SLOP + 2); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @@ -102,14 +102,14 @@ public class SingleTapClassifierTest extends ClassifierTest { addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1); addMotionEvent(0, 1, MotionEvent.ACTION_UP, TOUCH_SLOP + 1, 1); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); mMotionEvents.clear(); addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1); addMotionEvent(0, 1, MotionEvent.ACTION_UP, -TOUCH_SLOP - 1, 1); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @@ -118,14 +118,14 @@ public class SingleTapClassifierTest extends ClassifierTest { addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1); addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, TOUCH_SLOP + 1); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); mMotionEvents.clear(); addMotionEvent(0, 0, MotionEvent.ACTION_DOWN, 1, 1); addMotionEvent(0, 1, MotionEvent.ACTION_UP, 1, -TOUCH_SLOP - 1); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -134,7 +134,7 @@ public class SingleTapClassifierTest extends ClassifierTest { addMotionEvent(0, 1, MotionEvent.ACTION_MOVE, 1, TOUCH_SLOP + 1); addMotionEvent(0, 2, MotionEvent.ACTION_UP, 1, 1); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java index 6b9bb4fedd16c..4a896a8574b9e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java @@ -61,10 +61,10 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isUp()).thenReturn(false); when(mDataProvider.isRight()).thenReturn(false); // right should cause no effect. - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -73,11 +73,11 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isVertical()).thenReturn(false); when(mDataProvider.isUp()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isVertical()).thenReturn(true); when(mDataProvider.isUp()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -87,10 +87,10 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isUp()).thenReturn(false); when(mDataProvider.isRight()).thenReturn(false); // right should cause no effect. - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -99,11 +99,11 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isVertical()).thenReturn(false); when(mDataProvider.isUp()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isVertical()).thenReturn(true); when(mDataProvider.isUp()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -113,10 +113,10 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isUp()).thenReturn(false); when(mDataProvider.isRight()).thenReturn(false); // right should cause no effect. - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -125,11 +125,11 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isVertical()).thenReturn(false); when(mDataProvider.isUp()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isVertical()).thenReturn(true); when(mDataProvider.isUp()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -139,19 +139,19 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isUp()).thenReturn(false); // up and right should cause no effect. when(mDataProvider.isRight()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.isUp()).thenReturn(true); when(mDataProvider.isRight()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.isUp()).thenReturn(false); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.isUp()).thenReturn(true); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -161,19 +161,19 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isUp()).thenReturn(false); // up and right should cause no effect. when(mDataProvider.isRight()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isUp()).thenReturn(true); when(mDataProvider.isRight()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isUp()).thenReturn(false); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isUp()).thenReturn(true); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @@ -185,10 +185,10 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isRight()).thenReturn(false); // right should cause no effect. - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -197,15 +197,15 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isVertical()).thenReturn(false); when(mDataProvider.isUp()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isVertical()).thenReturn(true); when(mDataProvider.isUp()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isVertical()).thenReturn(false); when(mDataProvider.isUp()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -216,10 +216,10 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isRight()).thenReturn(false); // right should cause no effect. - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -228,15 +228,15 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isVertical()).thenReturn(false); when(mDataProvider.isUp()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isVertical()).thenReturn(true); when(mDataProvider.isUp()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isVertical()).thenReturn(false); when(mDataProvider.isUp()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -247,10 +247,10 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isVertical()).thenReturn(false); // vertical should cause no effect. - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.isVertical()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -259,15 +259,15 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isRight()).thenReturn(false); when(mDataProvider.isUp()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isRight()).thenReturn(true); when(mDataProvider.isUp()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isRight()).thenReturn(false); when(mDataProvider.isUp()).thenReturn(false); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -278,10 +278,10 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isVertical()).thenReturn(false); // vertical should cause no effect. - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); when(mDataProvider.isVertical()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -290,14 +290,14 @@ public class TypeClassifierTest extends ClassifierTest { when(mDataProvider.isUp()).thenReturn(true); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isUp()).thenReturn(false); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); when(mDataProvider.isUp()).thenReturn(false); when(mDataProvider.isRight()).thenReturn(true); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java index 339dd9e9e6d23..09bee128c6733 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java @@ -51,11 +51,11 @@ public class ZigZagClassifierTest extends ClassifierTest { @Test public void testPass_fewTouchesVertical() { - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); appendMoveEvent(0, 0); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); appendMoveEvent(0, 100); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -63,16 +63,16 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(0, 100); appendMoveEvent(0, 200); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test public void testPass_fewTouchesHorizontal() { - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); appendMoveEvent(0, 0); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); appendMoveEvent(100, 0); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -80,7 +80,7 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(100, 0); appendMoveEvent(200, 0); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @@ -89,7 +89,7 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(0, 100); appendMoveEvent(0, 1); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -97,7 +97,7 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(100, 0); appendMoveEvent(1, 0); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -105,7 +105,7 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(10, 10); appendMoveEvent(20, 20); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -115,7 +115,7 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(5, 100); appendMoveEvent(-5, 200); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -125,7 +125,7 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(100, 5); appendMoveEvent(200, -5); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); } @Test @@ -135,7 +135,7 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(6, 10); appendMoveEvent(-6, 20); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -145,7 +145,7 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(10, 5); appendMoveEvent(20, -5); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -153,25 +153,25 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(100, 5); appendMoveEvent(200, 10); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(100, 0); appendMoveEvent(200, 10); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(100, -10); appendMoveEvent(200, 10); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(100, -10); appendMoveEvent(200, 50); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -179,25 +179,25 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(10, 50); appendMoveEvent(8, 100); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(1, 800); appendMoveEvent(2, 900); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-10, 600); appendMoveEvent(30, 700); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(40, 100); appendMoveEvent(0, 101); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -205,25 +205,25 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(-10, 50); appendMoveEvent(-24, 100); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-20, 800); appendMoveEvent(-20, 900); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(30, 600); appendMoveEvent(-10, 700); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-80, 100); appendMoveEvent(-10, 101); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -231,25 +231,25 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(-120, 10); appendMoveEvent(-200, 20); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-20, 8); appendMoveEvent(-40, 2); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-500, -2); appendMoveEvent(-600, 70); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-80, 100); appendMoveEvent(-100, 1); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -257,25 +257,25 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(-120, -10); appendMoveEvent(-200, -20); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-20, -8); appendMoveEvent(-40, -2); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-500, 2); appendMoveEvent(-600, -70); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-80, -100); appendMoveEvent(-100, -1); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -283,25 +283,25 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(-12, -20); appendMoveEvent(-20, -40); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-20, -130); appendMoveEvent(-40, -260); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(1, -100); appendMoveEvent(-6, -200); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-80, -100); appendMoveEvent(-10, -110); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -309,25 +309,25 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(12, -20); appendMoveEvent(20, -40); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(20, -130); appendMoveEvent(40, -260); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(-1, -100); appendMoveEvent(6, -200); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(80, -100); appendMoveEvent(10, -110); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test @@ -335,25 +335,25 @@ public class ZigZagClassifierTest extends ClassifierTest { appendMoveEvent(0, 0); appendMoveEvent(120, -20); appendMoveEvent(200, -40); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(200, -13); appendMoveEvent(400, -30); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(100, 10); appendMoveEvent(600, -20); - assertThat(mClassifier.isFalseTouch(), is(false)); + assertThat(mClassifier.classifyGesture().isFalse(), is(false)); resetDataProvider(); appendMoveEvent(0, 0); appendMoveEvent(80, -100); appendMoveEvent(100, -1); - assertThat(mClassifier.isFalseTouch(), is(true)); + assertThat(mClassifier.classifyGesture().isFalse(), is(true)); } @Test