Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ae5052e authored by Dave Mankoff's avatar Dave Mankoff
Browse files

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
parent 7898548e
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -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);

+24 −10
Original line number Diff line number Diff line
@@ -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<FalsingClassifier> 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) {
+5 −6
Original line number Diff line number Diff line
@@ -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
+2 −3
Original line number Diff line number Diff line
@@ -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
+3 −3
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ public class DoubleTapClassifier extends FalsingClassifier {
    }

    @Override
    boolean isFalseTouch() {
    Result calculateFalsingResult(double historyPenalty, double historyConfidence) {
        List<MotionEvent> secondTapEvents = getRecentMotionEvents();
        Queue<? extends List<MotionEvent>> historicalEvents = getHistoricalEvents();
        List<MotionEvent> 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. */
Loading