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

Commit 03c71744 authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Add continuous falsing to keyguard.

With this change, taps outside of the bouncer inputs increase the
FalsingManager's belief that erroneous taps are happening. If the
belief becomes strong enough, the bouncer will be retracted.

Special attention is given to ensure that actual password inputs
are not recorded by the falsing manager. Valid button and pattern
inputs do not have their motion events recorded, but do _decrease_
the FalsingManager's belief in pocket dialing. Thus, a few bad taps
mixed with good taps will not retract the bouncer.

Test: atest SystemUITests && manual
Bug: 172655679
Change-Id: Iac8d2a2f41764f3c1cccb66b9d332c489cabca77
parent 8d0f3a0c
Loading
Loading
Loading
Loading
+2 −57
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ 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;
@@ -35,13 +34,9 @@ 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> {
@@ -49,7 +44,6 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
    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;
@@ -73,61 +67,18 @@ 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, FalsingCollector falsingCollector,
            SingleTapClassifier singleTapClassifier) {
            LatencyTracker latencyTracker, FalsingCollector falsingCollector) {
        super(view, securityMode, keyguardSecurityCallback);
        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
        mLockPatternUtils = lockPatternUtils;
        mLatencyTracker = latencyTracker;
        mFalsingCollector = falsingCollector;
        mSingleTapClassifier = singleTapClassifier;
        KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
        mMessageAreaController = messageAreaControllerFactory.create(kma);
    }
@@ -142,7 +93,6 @@ 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);
@@ -151,12 +101,6 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
        }
    }

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

    @Override
    public void reset() {
        // start fresh
@@ -316,6 +260,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
    }

    protected void onUserInput() {
        mFalsingCollector.updateFalseConfidence(FalsingClassifier.Result.passed(0.6));
        getKeyguardSecurityCallback().userActivity();
        getKeyguardSecurityCallback().onUserInput();
        mMessageAreaController.setMessage("");
+0 −27
Original line number Diff line number Diff line
@@ -26,16 +26,11 @@ import android.widget.LinearLayout;
import androidx.annotation.Nullable;

import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.Gefingerpoken;

import java.util.ArrayList;
import java.util.List;

/**
 * A Base class for all Keyguard password/pattern/pin related inputs.
 */
public abstract class KeyguardInputView extends LinearLayout {
    private final List<Gefingerpoken> mMotionEventListener = new ArrayList<>();

    public KeyguardInputView(Context context) {
        super(context);
@@ -53,7 +48,6 @@ public abstract class KeyguardInputView extends LinearLayout {
    abstract CharSequence getTitle();

    void animateForIme(float interpolatedFraction) {
        return;
    }

    boolean disallowInterceptTouch(MotionEvent event) {
@@ -66,27 +60,6 @@ public abstract class KeyguardInputView extends LinearLayout {
        return false;
    }

    void addMotionEventListener(Gefingerpoken listener) {
        mMotionEventListener.add(listener);
    }

    void removeMotionEventListener(Gefingerpoken listener) {
        mMotionEventListener.remove(listener);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return mMotionEventListener.stream().anyMatch(listener -> listener.onTouchEvent(event))
                || super.onTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return mMotionEventListener.stream().anyMatch(
                listener -> listener.onInterceptTouchEvent(event))
                || super.onInterceptTouchEvent(event);
    }

    protected AnimatorListenerAdapter getAnimationListener(int cuj) {
        return new AnimatorListenerAdapter() {
            private boolean mIsCancel;
+9 −15
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ 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;
@@ -156,10 +155,9 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
        private final InputMethodManager mInputMethodManager;
        private final DelayableExecutor mMainExecutor;
        private final Resources mResources;
        private LiftToActivateListener mLiftToActivateListener;
        private TelephonyManager mTelephonyManager;
        private final LiftToActivateListener mLiftToActivateListener;
        private final TelephonyManager mTelephonyManager;
        private final FalsingCollector mFalsingCollector;
        private final SingleTapClassifier mSingleTapClassifier;
        private final boolean mIsNewLayoutEnabled;

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

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

            throw new RuntimeException("Unable to find controller for " + keyguardInputView);
+2 −5
Original line number Diff line number Diff line
@@ -41,7 +41,6 @@ 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;

@@ -115,11 +114,9 @@ public class KeyguardPasswordViewController
            InputMethodManager inputMethodManager,
            @Main DelayableExecutor mainExecutor,
            @Main Resources resources,
            FalsingCollector falsingCollector,
            SingleTapClassifier singleTapClassifier) {
            FalsingCollector falsingCollector) {
        super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
                messageAreaControllerFactory, latencyTracker, falsingCollector,
                singleTapClassifier);
                messageAreaControllerFactory, latencyTracker, falsingCollector);
        mKeyguardSecurityCallback = keyguardSecurityCallback;
        mInputMethodManager = inputMethodManager;
        mMainExecutor = mainExecutor;
+18 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.res.ColorStateList;
import android.os.AsyncTask;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;

import com.android.internal.util.LatencyTracker;
@@ -35,6 +36,8 @@ import com.android.keyguard.EmergencyButton.EmergencyButtonCallback;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingClassifier;
import com.android.systemui.classifier.FalsingCollector;

import java.util.List;

@@ -50,6 +53,7 @@ public class KeyguardPatternViewController
    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
    private final LockPatternUtils mLockPatternUtils;
    private final LatencyTracker mLatencyTracker;
    private final FalsingCollector mFalsingCollector;
    private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;

    private KeyguardMessageAreaController mMessageAreaController;
@@ -102,6 +106,11 @@ public class KeyguardPatternViewController

            final int userId = KeyguardUpdateMonitor.getCurrentUser();
            if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
                // Treat single-sized patterns as erroneous taps.
                if (pattern.size() == 1) {
                    mFalsingCollector.updateFalseConfidence(FalsingClassifier.Result.falsed(
                            0.7, "empty pattern input"));
                }
                mLockPatternView.enableInput();
                onPatternChecked(userId, false, 0, false /* not valid - too short */);
                return;
@@ -179,11 +188,13 @@ public class KeyguardPatternViewController
            LockPatternUtils lockPatternUtils,
            KeyguardSecurityCallback keyguardSecurityCallback,
            LatencyTracker latencyTracker,
            FalsingCollector falsingCollector,
            KeyguardMessageAreaController.Factory messageAreaControllerFactory) {
        super(view, securityMode, keyguardSecurityCallback);
        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
        mLockPatternUtils = lockPatternUtils;
        mLatencyTracker = latencyTracker;
        mFalsingCollector = falsingCollector;
        mMessageAreaControllerFactory = messageAreaControllerFactory;
        KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
        mMessageAreaController = mMessageAreaControllerFactory.create(kma);
@@ -205,6 +216,12 @@ public class KeyguardPatternViewController
                KeyguardUpdateMonitor.getCurrentUser()));
        // vibrate mode will be the same for the life of this screen
        mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
        mLockPatternView.setOnTouchListener((v, event) -> {
            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                mFalsingCollector.avoidGesture();
            }
            return false;
        });

        EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
        if (button != null) {
@@ -224,6 +241,7 @@ public class KeyguardPatternViewController
    protected void onViewDetached() {
        super.onViewDetached();
        mLockPatternView.setOnPatternListener(null);
        mLockPatternView.setOnTouchListener(null);
        EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
        if (button != null) {
            button.setCallback(null);
Loading