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

Commit 8d0f3a0c authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Incorporate Bayes into Falsing.

This uses the HistoryTracker on pin-based input to determine if a
tap outside of an intended region is a false touch, retracting the
pin input if we believe pocket dialing is occuring.

To do this, the cl properly integrates the HistoryTracker into
falsing, at least for single taps.

Most importantly, HistoryTracker#falsingBelief now return 0.5 when
it is unsure if a tap is false or not, and tends towards 0 when it
believes it's valid and 1 when it believes it's false.
HistoryTracker#falsingConfidence remains unchanged.

Test: atest SystemUITests && manual
Bug: 172655679
Change-Id: Ie771b1bf8ac564af7ffb68e190772fff5c562e89
parent e6737740
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ public interface FalsingManager {
    /**
     * Returns true if the FalsingManager thinks the last gesure was not a valid tap.
     *
     * Accepts one parameter, robustCheck, that distinctly changes behavior. When set to false,
     * 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
@@ -53,8 +53,11 @@ public interface FalsingManager {
     * 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.
     *
     * The second parameter, falsePenalty, indicates how much this should affect future gesture
     * classifications if this tap looks like a false.
     */
    boolean isFalseTap(boolean robustCheck);
    boolean isFalseTap(boolean robustCheck, double falsePenalty);

    /**
     * Returns true if the last two gestures do not look like a double tap.
+61 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.os.AsyncTask;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.view.KeyEvent;
import android.view.MotionEvent;

import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternChecker;
@@ -34,13 +35,21 @@ import com.android.internal.widget.LockscreenCredential;
import com.android.keyguard.EmergencyButton.EmergencyButtonCallback;
import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingClassifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.SingleTapClassifier;

import java.util.Arrays;

public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKeyInputView>
        extends KeyguardInputViewController<T> {
    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
    private final LockPatternUtils mLockPatternUtils;
    private final LatencyTracker mLatencyTracker;
    private final FalsingCollector mFalsingCollector;
    private final SingleTapClassifier mSingleTapClassifier;
    private CountDownTimer mCountdownTimer;
    protected KeyguardMessageAreaController mMessageAreaController;
    private boolean mDismissing;
@@ -64,17 +73,61 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
        }
    };

    private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
        private MotionEvent mTouchDown;
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            mFalsingCollector.avoidGesture();
            // Do just a bit of our own falsing. People should only be tapping on the input, not
            // swiping.
            if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
                if (mTouchDown != null) {
                    mTouchDown.recycle();
                    mTouchDown = null;
                }
                mTouchDown = MotionEvent.obtain(ev);
            } else if (mTouchDown != null) {
                FalsingClassifier.Result tapResult =
                        mSingleTapClassifier.isTap(Arrays.asList(mTouchDown, ev));
                if (tapResult.isFalse()
                        || ev.getActionMasked() == MotionEvent.ACTION_UP
                        || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
                    // TODO: if we've gotten too false, retract input.
                    if (tapResult.isFalse()) {
                        mFalsingCollector.updateFalseConfidence(tapResult);
                    } else {
                        // The classifier returns 0 confidence when a tap is detected.
                        // We can be more sure that the tap was intentional here.
                        mFalsingCollector.updateFalseConfidence(
                                FalsingClassifier.Result.passed(0.6));
                    }
                    mTouchDown.recycle();
                    mTouchDown = null;
                }
            }
            return false;
        }

        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            return false;
        }
    };

    protected KeyguardAbsKeyInputViewController(T view,
            KeyguardUpdateMonitor keyguardUpdateMonitor,
            SecurityMode securityMode,
            LockPatternUtils lockPatternUtils,
            KeyguardSecurityCallback keyguardSecurityCallback,
            KeyguardMessageAreaController.Factory messageAreaControllerFactory,
            LatencyTracker latencyTracker) {
            LatencyTracker latencyTracker, FalsingCollector falsingCollector,
            SingleTapClassifier singleTapClassifier) {
        super(view, securityMode, keyguardSecurityCallback);
        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
        mLockPatternUtils = lockPatternUtils;
        mLatencyTracker = latencyTracker;
        mFalsingCollector = falsingCollector;
        mSingleTapClassifier = singleTapClassifier;
        KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
        mMessageAreaController = messageAreaControllerFactory.create(kma);
    }
@@ -89,6 +142,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
    @Override
    protected void onViewAttached() {
        super.onViewAttached();
        mView.addMotionEventListener(mGlobalTouchListener);
        mView.setKeyDownListener(mKeyDownListener);
        mView.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
        EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
@@ -97,6 +151,12 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
        }
    }

    @Override
    protected void onViewDetached() {
        super.onViewDetached();
        mView.removeMotionEventListener(mGlobalTouchListener);
    }

    @Override
    public void reset() {
        // start fresh
+12 −6
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.SingleTapClassifier;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.ViewController;
@@ -158,6 +159,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
        private LiftToActivateListener mLiftToActivateListener;
        private TelephonyManager mTelephonyManager;
        private final FalsingCollector mFalsingCollector;
        private final SingleTapClassifier mSingleTapClassifier;
        private final boolean mIsNewLayoutEnabled;

        @Inject
@@ -169,6 +171,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
                @Main Resources resources, LiftToActivateListener liftToActivateListener,
                TelephonyManager telephonyManager,
                FalsingCollector falsingCollector,
                SingleTapClassifier singleTapClassifier,
                FeatureFlags featureFlags) {
            mKeyguardUpdateMonitor = keyguardUpdateMonitor;
            mLockPatternUtils = lockPatternUtils;
@@ -180,6 +183,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
            mLiftToActivateListener = liftToActivateListener;
            mTelephonyManager = telephonyManager;
            mFalsingCollector = falsingCollector;
            mSingleTapClassifier = singleTapClassifier;
            mIsNewLayoutEnabled = featureFlags.isKeyguardLayoutEnabled();
        }

@@ -194,24 +198,26 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
                return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView,
                        mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
                        keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
                        mInputMethodManager, mMainExecutor, mResources);
                        mInputMethodManager, mMainExecutor, mResources, mFalsingCollector,
                        mSingleTapClassifier);
            } else if (keyguardInputView instanceof KeyguardPINView) {
                return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
                        mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
                        keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
                        mLiftToActivateListener, mFalsingCollector, mIsNewLayoutEnabled);
                        mLiftToActivateListener, mFalsingCollector, mSingleTapClassifier,
                        mIsNewLayoutEnabled);
            } else if (keyguardInputView instanceof KeyguardSimPinView) {
                return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
                        mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
                        keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
                        mLiftToActivateListener, mTelephonyManager,
                        mFalsingCollector, mIsNewLayoutEnabled);
                        mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
                        mSingleTapClassifier, mIsNewLayoutEnabled);
            } else if (keyguardInputView instanceof KeyguardSimPukView) {
                return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView,
                        mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
                        keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
                        mLiftToActivateListener, mTelephonyManager,
                        mFalsingCollector, mIsNewLayoutEnabled);
                        mLiftToActivateListener, mTelephonyManager, mFalsingCollector,
                        mSingleTapClassifier, mIsNewLayoutEnabled);
            }

            throw new RuntimeException("Unable to find controller for " + keyguardInputView);
+7 −2
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.SingleTapClassifier;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.concurrency.DelayableExecutor;

@@ -112,9 +114,12 @@ public class KeyguardPasswordViewController
            LatencyTracker latencyTracker,
            InputMethodManager inputMethodManager,
            @Main DelayableExecutor mainExecutor,
            @Main Resources resources) {
            @Main Resources resources,
            FalsingCollector falsingCollector,
            SingleTapClassifier singleTapClassifier) {
        super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
                messageAreaControllerFactory, latencyTracker);
                messageAreaControllerFactory, latencyTracker, falsingCollector,
                singleTapClassifier);
        mKeyguardSecurityCallback = keyguardSecurityCallback;
        mInputMethodManager = inputMethodManager;
        mMainExecutor = mainExecutor;
+5 −25
Original line number Diff line number Diff line
@@ -25,15 +25,14 @@ import android.view.View.OnTouchListener;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.SingleTapClassifier;

public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinBasedInputView>
        extends KeyguardAbsKeyInputViewController<T> {

    private final LiftToActivateListener mLiftToActivateListener;
    private final FalsingCollector mFalsingCollector;
    protected PasswordTextView mPasswordEntry;

    private final OnKeyListener mOnKeyListener = (v, keyCode, event) -> {
@@ -50,19 +49,6 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB
        return false;
    };

    private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            mFalsingCollector.avoidGesture();
            return false;
        }

        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            return false;
        }
    };

    protected KeyguardPinBasedInputViewController(T view,
            KeyguardUpdateMonitor keyguardUpdateMonitor,
            SecurityMode securityMode,
@@ -71,11 +57,12 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB
            KeyguardMessageAreaController.Factory messageAreaControllerFactory,
            LatencyTracker latencyTracker,
            LiftToActivateListener liftToActivateListener,
            FalsingCollector falsingCollector) {
            FalsingCollector falsingCollector,
            SingleTapClassifier singleTapClassifier) {
        super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
                messageAreaControllerFactory, latencyTracker);
                messageAreaControllerFactory, latencyTracker, falsingCollector,
                singleTapClassifier);
        mLiftToActivateListener = liftToActivateListener;
        mFalsingCollector = falsingCollector;
        mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());
    }

@@ -83,8 +70,6 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB
    protected void onViewAttached() {
        super.onViewAttached();

        mView.addMotionEventListener(mGlobalTouchListener);

        mPasswordEntry.setOnKeyListener(mOnKeyListener);
        mPasswordEntry.setUserActivityListener(this::onUserInput);

@@ -120,11 +105,6 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB
        }
    }

    @Override
    protected void onViewDetached() {
        super.onViewDetached();
        mView.removeMotionEventListener(mGlobalTouchListener);
    }

    @Override
    public void onResume(int reason) {
Loading