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

Commit 58718c7f authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Separate out FalsingManager#isFalseTap

Method no longer takes `robustCheck` parameter. Instead,
FalsingManager#isSimpleTap is added for basic checking, and
FalsingManager#isTap does robust checking by default.

FalsingManager#isTap takes an enum value for penalty instead of
a double, making the value more understandable.

Bug: 172655679
Test: atest SystemUITests && manual
Change-Id: Ib4a99f87bcd6acee67a98420f460c98d44fa6360
parent 0d4e5104
Loading
Loading
Loading
Loading
+18 −19
Original line number Diff line number Diff line
@@ -70,17 +70,17 @@ target. Match the methods with the gesture you expect the device owner to use.

### Single Tap

`FalsingManager#isFalseTap(boolean robustCheck, double falsePenalty)`. This
method tells the `FalsingManager` that you want to validate a single tap. It
`FalsingManager#isSimpleTape()`. This method
performs a only very basic checking, checking that observed `MotionEvent`s are
all within some small x & y region ("touch slop"). Useful for only the most simple of scenarios,
you probably want `FalsingManager#isFalseTap` method for most cases.

`FalsingManager#isFalseTap(@Penalty int penalty)`. This
method tells the `FalsingManager` that you want to thoroughly validate a single tap. It
returns true if it thinks the tap should be rejected (i.e. the tap looks more
like a swipe) and false otherwise.

`robustCheck` determines what heuristics are used. If set to false, the method
performs a only very basic checking, checking that observed `MotionEvent`s are
all within some small x & y region ("touch slop").

When `robustCheck` is set to true, several more advanced rules are additionally
applied:
It runs through the following heuristics to validate a tap:

1.  If the device recognizes a face (i.e. face-auth) the tap is **accepted**.
2.  If the tap is the _second_ tap in recent history and looks like a valid Double Tap
@@ -90,19 +90,18 @@ applied:
4.  Otherwise the tap is **accepted**.

All the above rules are applied only after first confirming the gesture does
in fact look like a basic tap.
in fact look like a simple tap.

`falsePenalty` is a measure of how much the `HistoryTracker`'s belief should be
`penalty` is a measure of how much the `HistoryTracker`'s belief should be
penalized in the event that the tap is rejected. This value is only used if
`robustCheck` is set to true.

A value of `0` means no change in belief. A value of `1` means a _very_ strong
confidence in a false tap. In general, as a single tap on the screen is not
verifiable, a small value should be supplied - on the order of `0.1`. Pass `0`
if you don't want to penalize belief at all. Pass a higher value
the earlier in the UX flow your interaction occurs. Once an owner is farther
along in a UX flow (multiple taps or swipes), its safer to assume that a single
accidental tap should cause less of a penalty.
the gesture fails to validate as a simple tap.

The `@FalsingManager.Penalty` values are fairly straightforward, but note that you
should generally be choosing `LOW_PENALTY`. It is inherently difficult to know if a
tap is truly false or not, so a single mis-tap should apply only a small penalty.
If the owner is further along in a UX flow, and is still mis-tapping, it may make more
sense to increase the penalty as mis-taps should be less likely to occur after
several successful gestures.

### Double Tap

+36 −11
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.plugins;

import android.annotation.IntDef;
import android.net.Uri;
import android.view.MotionEvent;

@@ -24,6 +25,8 @@ import com.android.systemui.util.sensors.ThresholdSensor;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Interface that decides whether a touch on the phone was accidental. i.e. Pocket Dialing.
@@ -34,6 +37,20 @@ import java.io.PrintWriter;
public interface FalsingManager {
    int VERSION = 6;

    int NO_PENALTY = 0;
    int LOW_PENALTY = 1;
    int MODERATE_PENALTY = 2;
    int HIGH_PENALTY = 3;

    @IntDef({
            NO_PENALTY,
            LOW_PENALTY,
            MODERATE_PENALTY,
            HIGH_PENALTY
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Penalty {}

    void onSuccessfulUnlock();

    boolean isUnlockingDisabled();
@@ -41,23 +58,31 @@ public interface FalsingManager {
    /** Returns true if the gesture should be rejected. */
    boolean isFalseTouch(int interactionType);


    /**
     * Does basic checking to see if gesture looks like a tap.
     *
     * Only does the most basic of checks. No penalty is applied if this method returns false.
     *
     * For more robust analysis, use {@link #isFalseTap(int)}.
     */
    boolean isSimpleTap();

    /**
     * Returns true if the FalsingManager thinks the last gesure was not a valid tap.
     * Returns true if the FalsingManager thinks the last gesture was not a valid tap.
     *
     * The first parameter, robustCheck, distinctly changes behavior. When set to false,
     * this method simply looks at the last gesture and returns whether it is a tap or not, (as
     * opposed to a swipe or other non-tap gesture). When set to true, a more thorough analysis
     * is performed that can include historical interactions and other contextual cues to see
     * This method runs a more thorough analysis than the similar {@link #isSimpleTap()},
     * that can include historical interactions and other contextual cues to see
     * if the tap looks accidental.
     *
     * Set robustCheck to true if you want to validate a tap for launching an action, like opening
     * a notification. Set to false if you simply want to know if the last gesture looked like a
     * tap.
     * Use this method to validate a tap for launching an action, like opening
     * a notification.
     *
     * The second parameter, falsePenalty, indicates how much this should affect future gesture
     * classifications if this tap looks like a false.
     * The only parameter, penalty, indicates how much this should affect future gesture
     * classifications if this tap looks like a false. As single taps are hard to confirm as false
     * or otherwise, a low penalty value is encouraged unless context indicates otherwise.
     */
    boolean isFalseTap(boolean robustCheck, double falsePenalty);
    boolean isFalseTap(@Penalty int penalty);

    /**
     * Returns true if the last two gestures do not look like a double tap.
+28 −3
Original line number Diff line number Diff line
@@ -218,18 +218,43 @@ public class BrightLineFalsingManager implements FalsingManager {
    }

    @Override
    public boolean isFalseTap(boolean robustCheck, double falsePenalty) {
    public boolean isSimpleTap() {
        FalsingClassifier.Result result = mSingleTapClassifier.isTap(
                mDataProvider.getRecentMotionEvents(), 0);
        mPriorResults = Collections.singleton(result);

        return !result.isFalse();
    }

    @Override
    public boolean isFalseTap(@Penalty int penalty) {
        if (skipFalsing()) {
            return false;
        }

        double falsePenalty = 0;
        switch(penalty) {
            case NO_PENALTY:
                falsePenalty = 0;
                break;
            case LOW_PENALTY:
                falsePenalty = 0.1;
                break;
            case MODERATE_PENALTY:
                falsePenalty = 0.3;
                break;
            case HIGH_PENALTY:
                falsePenalty = 0.6;
                break;
        }

        FalsingClassifier.Result singleTapResult =
                mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents().isEmpty()
                        ? mDataProvider.getPriorMotionEvents()
                        : mDataProvider.getRecentMotionEvents());
                        : mDataProvider.getRecentMotionEvents(), falsePenalty);
        mPriorResults = Collections.singleton(singleTapResult);

        if (!singleTapResult.isFalse() && robustCheck) {
        if (!singleTapResult.isFalse()) {
            if (mDataProvider.isJustUnlockedWithFace()) {
                // Immediately pass if a face is detected.
                mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1));
+2 −2
Original line number Diff line number Diff line
@@ -66,13 +66,13 @@ public class DoubleTapClassifier extends FalsingClassifier {
    public boolean isDoubleTap(List<MotionEvent> firstEvents, List<MotionEvent> secondEvents,
            StringBuilder reason) {

        Result firstTap = mSingleTapClassifier.isTap(firstEvents);
        Result firstTap = mSingleTapClassifier.isTap(firstEvents, 0.5);
        if (firstTap.isFalse()) {
            reason.append("First gesture is not a tap. ").append(firstTap.getReason());
            return false;
        }

        Result secondTap = mSingleTapClassifier.isTap(secondEvents);
        Result secondTap = mSingleTapClassifier.isTap(secondEvents, 0.5);
        if (secondTap.isFalse()) {
            reason.append("Second gesture is not a tap. ").append(secondTap.getReason());
            return false;
+11 −6
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ import java.util.List;
 */
public class FalsingManagerFake implements FalsingManager {
    private boolean mIsFalseTouch;
    private boolean mIsFalseTap;
    private boolean mIsSimpleTap;
    private boolean mIsFalseDoubleTap;
    private boolean mIsUnlockingDisabled;
    private boolean mIsClassiferEnabled;
@@ -67,12 +67,12 @@ public class FalsingManagerFake implements FalsingManager {
        return mIsFalseTouch;
    }

    public void setFalseRobustTap(boolean falseRobustTap) {
    public void setFalseTap(boolean falseRobustTap) {
        mIsFalseRobustTap = falseRobustTap;
    }

    public void setFalseTap(boolean falseTap) {
        mIsFalseTap = falseTap;
    public void setSimpleTap(boolean isSimpleTape) {
        mIsSimpleTap = isSimpleTape;
    }

    public void setFalseDoubleTap(boolean falseDoubleTap) {
@@ -80,8 +80,13 @@ public class FalsingManagerFake implements FalsingManager {
    }

    @Override
    public boolean isFalseTap(boolean robustCheck, double falsePenalty) {
        return robustCheck ? mIsFalseRobustTap : mIsFalseTap;
    public boolean isSimpleTap() {
        return mIsSimpleTap;
    }

    @Override
    public boolean isFalseTap(@Penalty int penalty) {
        return mIsFalseRobustTap;
    }

    @Override
Loading