diff options
| author | 2021-01-25 14:34:43 -0500 | |
|---|---|---|
| committer | 2021-03-10 16:42:23 -0500 | |
| commit | 8d0f3a0c3c735d9ad9fb7173ccce847f1dc89e1f (patch) | |
| tree | 66d44833f3ce8052b56f0cfd02178b9b66a463f1 | |
| parent | e673774033be0dea61ceb35c373044dbc6eeebed (diff) | |
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
33 files changed, 262 insertions, 179 deletions
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 4fc197340e92..0d348e263545 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java @@ -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. diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index 5760565aaab1..4af580df09ea 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -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); @@ -98,6 +152,12 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey } @Override + protected void onViewDetached() { + super.onViewDetached(); + mView.removeMotionEventListener(mGlobalTouchListener); + } + + @Override public void reset() { // start fresh mDismissing = false; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index 957882dc9c6b..8cbaae5661ae 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -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); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java index 0f1c3c8a20b7..1367d8442809 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -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; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java index f2479488db0f..7fe427822d6a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java @@ -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) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java index 49099fa18323..dca84a638640 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java @@ -23,6 +23,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; public class KeyguardPinViewController extends KeyguardPinBasedInputViewController<KeyguardPINView> { @@ -34,10 +35,11 @@ public class KeyguardPinViewController KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, - FalsingCollector falsingCollector, boolean isNewLayoutEnabled) { + FalsingCollector falsingCollector, SingleTapClassifier singleTapClassifier, + boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, - falsingCollector); + falsingCollector, singleTapClassifier); mKeyguardUpdateMonitor = keyguardUpdateMonitor; view.setIsNewLayoutEnabled(isNewLayoutEnabled); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java index cdbbfe643812..6b2be98f3d01 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java @@ -39,6 +39,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; public class KeyguardSimPinViewController extends KeyguardPinBasedInputViewController<KeyguardSimPinView> { @@ -78,11 +79,11 @@ public class KeyguardSimPinViewController KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, - TelephonyManager telephonyManager, - FalsingCollector falsingCollector, boolean isNewLayoutEnabled) { + TelephonyManager telephonyManager, FalsingCollector falsingCollector, + SingleTapClassifier singleTapClassifier, boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, - falsingCollector); + falsingCollector, singleTapClassifier); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mTelephonyManager = telephonyManager; mSimImageView = mView.findViewById(R.id.keyguard_sim); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java index 8fff34278216..3895b6829614 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java @@ -40,6 +40,7 @@ import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.classifier.FalsingCollector; +import com.android.systemui.classifier.SingleTapClassifier; public class KeyguardSimPukViewController extends KeyguardPinBasedInputViewController<KeyguardSimPukView> { @@ -85,11 +86,11 @@ public class KeyguardSimPukViewController KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, - TelephonyManager telephonyManager, - FalsingCollector falsingCollector, boolean isNewLayoutEnabled) { + TelephonyManager telephonyManager, FalsingCollector falsingCollector, + SingleTapClassifier singleTapClassifier, boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, - falsingCollector); + falsingCollector, singleTapClassifier); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mTelephonyManager = telephonyManager; mSimImageView = mView.findViewById(R.id.keyguard_sim); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java index 6572ca95b5c3..1eb3dd17ac6a 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java @@ -18,7 +18,6 @@ package com.android.systemui.classifier; import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_SUCCESS; import static com.android.systemui.classifier.FalsingModule.BRIGHT_LINE_GESTURE_CLASSIFERS; -import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_MS; import android.net.Uri; import android.os.Build; @@ -29,11 +28,9 @@ import androidx.annotation.NonNull; import com.android.internal.logging.MetricsLogger; import com.android.systemui.classifier.FalsingDataProvider.SessionListener; -import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.TestHarness; import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.sensors.ThresholdSensor; import java.io.FileDescriptor; @@ -63,14 +60,13 @@ public class BrightLineFalsingManager implements FalsingManager { private static final int RECENT_INFO_LOG_SIZE = 40; private static final int RECENT_SWIPE_LOG_SIZE = 20; + private static final double TAP_CONFIDENCE_THRESHOLD = 0.7; private final FalsingDataProvider mDataProvider; private final DockManager mDockManager; private final SingleTapClassifier mSingleTapClassifier; private final DoubleTapClassifier mDoubleTapClassifier; private final HistoryTracker mHistoryTracker; - private final DelayableExecutor mDelayableExecutor; - private final long mDoubleTapTimeMs; private final boolean mTestHarness; private final MetricsLogger mMetricsLogger; private int mIsFalseTouchCalls; @@ -98,19 +94,7 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void onGestureComplete(long completionTimeMs) { if (mPriorResults != null) { - // Single taps that may become double taps don't get added right away. - if (mClassifyAsSingleTap) { - Collection<FalsingClassifier.Result> singleTapResults = mPriorResults; - mSingleTapHistoryCanceller = mDelayableExecutor.executeDelayed( - () -> { - mSingleTapHistoryCanceller = null; - mHistoryTracker.addResults(singleTapResults, completionTimeMs); - }, - mDoubleTapTimeMs); - mClassifyAsSingleTap = false; // Don't treat things as single taps by default. - } else { - mHistoryTracker.addResults(mPriorResults, completionTimeMs); - } + mHistoryTracker.addResults(mPriorResults, completionTimeMs); mPriorResults = null; } else { // Gestures that were not classified get treated as a false. @@ -123,17 +107,13 @@ public class BrightLineFalsingManager implements FalsingManager { }; private Collection<FalsingClassifier.Result> mPriorResults; - private boolean mClassifyAsSingleTap; - private Runnable mSingleTapHistoryCanceller; @Inject public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider, DockManager dockManager, MetricsLogger metricsLogger, @Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers, SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier, - HistoryTracker historyTracker, @Main DelayableExecutor delayableExecutor, - @Named(DOUBLE_TAP_TIMEOUT_MS) long doubleTapTimeMs, - @TestHarness boolean testHarness) { + HistoryTracker historyTracker, @TestHarness boolean testHarness) { mDataProvider = falsingDataProvider; mDockManager = dockManager; mMetricsLogger = metricsLogger; @@ -141,8 +121,6 @@ public class BrightLineFalsingManager implements FalsingManager { mSingleTapClassifier = singleTapClassifier; mDoubleTapClassifier = doubleTapClassifier; mHistoryTracker = historyTracker; - mDelayableExecutor = delayableExecutor; - mDoubleTapTimeMs = doubleTapTimeMs; mTestHarness = testHarness; mDataProvider.addSessionListener(mSessionListener); @@ -158,7 +136,6 @@ public class BrightLineFalsingManager implements FalsingManager { public boolean isFalseTouch(@Classifier.InteractionType int interactionType) { boolean result; - mClassifyAsSingleTap = false; mDataProvider.setInteractionType(interactionType); if (!mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()) { @@ -166,7 +143,7 @@ public class BrightLineFalsingManager implements FalsingManager { mClassifiers.stream().map(falsingClassifier -> { FalsingClassifier.Result classifierResult = falsingClassifier.classifyGesture( - mHistoryTracker.falsePenalty(), + mHistoryTracker.falseBelief(), mHistoryTracker.falseConfidence()); if (classifierResult.isFalse()) { logInfo(String.format( @@ -217,9 +194,7 @@ public class BrightLineFalsingManager implements FalsingManager { } @Override - public boolean isFalseTap(boolean robustCheck) { - mClassifyAsSingleTap = true; - + public boolean isFalseTap(boolean robustCheck, double falsePenalty) { FalsingClassifier.Result singleTapResult = mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents()); mPriorResults = Collections.singleton(singleTapResult); @@ -233,14 +208,19 @@ public class BrightLineFalsingManager implements FalsingManager { return true; } - // TODO(b/172655679): More heuristics to come. For now, allow touches through if face-authed if (robustCheck) { - boolean result = !mDataProvider.isJustUnlockedWithFace(); - mPriorResults = Collections.singleton( - result ? FalsingClassifier.Result.falsed(0.1, "no face detected") - : FalsingClassifier.Result.passed(1)); - - return result; + if (mDataProvider.isJustUnlockedWithFace()) { + mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1)); + return false; + } else if (mHistoryTracker.falseBelief() > TAP_CONFIDENCE_THRESHOLD) { + mPriorResults = Collections.singleton( + FalsingClassifier.Result.falsed(0.1, "bad history")); + return true; + } else { + mPriorResults = Collections.singleton( + FalsingClassifier.Result.falsed(falsePenalty, "no face detected")); + return false; + } } return false; @@ -248,7 +228,6 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public boolean isFalseDoubleTap() { - mClassifyAsSingleTap = false; FalsingClassifier.Result result = mDoubleTapClassifier.classifyGesture(); mPriorResults = Collections.singleton(result); if (result.isFalse()) { @@ -258,12 +237,6 @@ public class BrightLineFalsingManager implements FalsingManager { if (reason != null) { logInfo(reason); } - } else { - // A valid double tap prevents an invalid single tap from going into history. - if (mSingleTapHistoryCanceller != null) { - mSingleTapHistoryCanceller.run(); - mSingleTapHistoryCanceller = null; - } } return result.isFalse(); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java index bbb937176f59..ffcdb93b11b1 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java @@ -62,7 +62,7 @@ class DiagonalClassifier extends FalsingClassifier { VERTICAL_ANGLE_RANGE); } - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { float angle = getAngle(); if (angle == Float.MAX_VALUE) { // Unknown angle diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java index 4cb5aa2cce37..0f121c1c9ae7 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java @@ -147,7 +147,7 @@ class DistanceClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { return !getPassedFlingThreshold() ? Result.falsed(0.5, getReason()) : Result.passed(0.5); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java index f7fe14a8e841..9bb6b06f40a7 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java @@ -46,7 +46,7 @@ public class DoubleTapClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { List<MotionEvent> secondTapEvents = getRecentMotionEvents(); List<MotionEvent> firstTapEvents = getPriorMotionEvents(); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java index f40045b0f08e..1af5f7c488a5 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java @@ -124,7 +124,7 @@ public abstract class FalsingClassifier { * See also {@link #classifyGesture(double, double)}. */ Result classifyGesture() { - return calculateFalsingResult(0, 0); + return calculateFalsingResult(0.5, 0); } /** @@ -135,16 +135,16 @@ public abstract class FalsingClassifier { * * See also {@link #classifyGesture()}. */ - Result classifyGesture(double historyPenalty, double historyConfidence) { - return calculateFalsingResult(historyPenalty, historyConfidence); + Result classifyGesture(double historyBelief, double historyConfidence) { + return calculateFalsingResult(historyBelief, historyConfidence); } /** * Calculate a result based on available data. * - * When passed a historyConfidence of 0, the history penalty should be wholly ignored. + * When passed a historyConfidence of 0, the history belief should be wholly ignored. */ - abstract Result calculateFalsingResult(double historyPenalty, double historyConfidence); + abstract Result calculateFalsingResult(double historyBelief, double historyConfidence); /** */ public static void logDebug(String msg) { @@ -164,7 +164,7 @@ public abstract class FalsingClassifier { /** * A Falsing result that encapsulates the boolean result along with confidence and a reason. */ - static class Result { + public static class Result { private final boolean mFalsed; private final double mConfidence; private final String mReason; @@ -193,14 +193,14 @@ public abstract class FalsingClassifier { /** * Construct a "falsed" result indicating that a gesture should be treated as accidental. */ - static Result falsed(double confidence, String reason) { + public static Result falsed(double confidence, String reason) { return new Result(true, confidence, reason); } /** * Construct a "passed" result indicating that a gesture should be allowed. */ - static Result passed(double confidence) { + public static Result passed(double confidence) { return new Result(false, confidence, null); } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java index b0bbab366e93..bb037202d985 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java @@ -120,5 +120,8 @@ public interface FalsingCollector { /** */ void cleanup(); + + /** */ + void updateFalseConfidence(FalsingClassifier.Result result); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java index 12a060439106..939b45a2b4a5 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java @@ -153,4 +153,8 @@ public class FalsingCollectorFake implements FalsingCollector { @Override public void cleanup() { } + + @Override + public void updateFalseConfidence(FalsingClassifier.Result result) { + } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java index e08b43b3521f..e090006cca4f 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java @@ -29,6 +29,9 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.sensors.ThresholdSensor; +import com.android.systemui.util.time.SystemClock; + +import java.util.Collections; import javax.inject.Inject; @@ -42,8 +45,10 @@ class FalsingCollectorImpl implements FalsingCollector { private final FalsingDataProvider mFalsingDataProvider; private final FalsingManager mFalsingManager; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final HistoryTracker mHistoryTracker; private final ProximitySensor mProximitySensor; private final StatusBarStateController mStatusBarStateController; + private final SystemClock mSystemClock; private int mState; private boolean mShowingAod; @@ -80,13 +85,16 @@ class FalsingCollectorImpl implements FalsingCollector { @Inject FalsingCollectorImpl(FalsingDataProvider falsingDataProvider, FalsingManager falsingManager, - KeyguardUpdateMonitor keyguardUpdateMonitor, - ProximitySensor proximitySensor, StatusBarStateController statusBarStateController) { + KeyguardUpdateMonitor keyguardUpdateMonitor, HistoryTracker historyTracker, + ProximitySensor proximitySensor, StatusBarStateController statusBarStateController, + SystemClock systemClock) { mFalsingDataProvider = falsingDataProvider; mFalsingManager = falsingManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mHistoryTracker = historyTracker; mProximitySensor = proximitySensor; mStatusBarStateController = statusBarStateController; + mSystemClock = systemClock; mProximitySensor.setTag(PROXIMITY_SENSOR_TAG); @@ -282,6 +290,11 @@ class FalsingCollectorImpl implements FalsingCollector { mStatusBarStateController.removeCallback(mStatusBarStateListener); } + @Override + public void updateFalseConfidence(FalsingClassifier.Result result) { + mHistoryTracker.addResults(Collections.singleton(result), mSystemClock.uptimeMillis()); + } + private void updateInteractionType(@Classifier.InteractionType int type) { logDebug("InteractionType: " + type); mFalsingDataProvider.setInteractionType(type); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java index d4d8d06b081b..aac27cb43376 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java @@ -76,7 +76,7 @@ public class FalsingManagerFake implements FalsingManager { } @Override - public boolean isFalseTap(boolean robustCheck) { + public boolean isFalseTap(boolean robustCheck, double falsePenalty) { return robustCheck ? mIsFalseRobustTap : mIsFalseTap; } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index cbec0576e449..e9bb48c7b1a9 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -131,8 +131,8 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { } @Override - public boolean isFalseTap(boolean robustCheck) { - return mInternalFalsingManager.isFalseTap(robustCheck); + public boolean isFalseTap(boolean robustCheck, double falsePenalty) { + return mInternalFalsingManager.isFalseTap(robustCheck, falsePenalty); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java index 8bd94a122707..be48ec415652 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/HistoryTracker.java @@ -36,12 +36,17 @@ import javax.inject.Inject; */ @SysUISingleton public class HistoryTracker { - private static final double HISTORY_DECAY = 0.8f; + private static final long HISTORY_MAX_AGE_MS = 10000; + // A score is decayed discretely every DECAY_INTERVAL_MS. 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)); + // We expire items once their decay factor is below 0.1. + private static final double MINIMUM_SCORE = 0.1; + // This magic number is the factor a score is reduced by every DECAY_INTERVAL_MS. + // Once a score is HISTORY_MAX_AGE_MS ms old, it will be reduced by being multiplied by + // MINIMUM_SCORE. The math below ensures that. + private static final double HISTORY_DECAY = + Math.pow(10, Math.log10(MINIMUM_SCORE) / HISTORY_MAX_AGE_MS * DECAY_INTERVAL_MS); + private final SystemClock mSystemClock; DelayQueue<CombinedResult> mResults = new DelayQueue<>(); @@ -54,29 +59,36 @@ public class HistoryTracker { /** * 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 close to 0.5 means that prior data is inconclusive (inconsistent, lacking + * confidence, or simply lacking in quantity). + * + * A result close to 0 means that prior gestures indicate a success. * - * 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. + * A result close to 1 means that prior gestures were very obviously false. + * + * The current gesture might be different than what is reported by this method, but there should + * be a high-bar to be classified differently. * * See also {@link #falseConfidence()}. */ - double falsePenalty() { + double falseBelief() { //noinspection StatementWithEmptyBody while (mResults.poll() != null) { // Empty out the expired results. } if (mResults.isEmpty()) { - return 0; + return 0.5; } long nowMs = mSystemClock.uptimeMillis(); + // Get our Bayes on. return mResults.stream() .map(result -> result.getDecayedScore(nowMs)) - .reduce(0.0, Double::sum) / mResults.size(); + .reduce(0.5, + (prior, measurement) -> + (prior * measurement) + / (prior * measurement + (1 - prior) * (1 - measurement))); } /** @@ -91,7 +103,7 @@ public class HistoryTracker { * 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()}. + * See als {@link #falseBelief()}. */ double falseConfidence() { //noinspection StatementWithEmptyBody @@ -126,6 +138,15 @@ public class HistoryTracker { finalScore /= results.size(); + // Never add a 0 or 1, else Bayes breaks down (a 0 and a 1 together results in NaN). In + // other words, you shouldn't need Bayes if you have 100% confidence one way or another. + // Instead, make the number ever so slightly smaller so that our math never breaks. + if (finalScore == 1) { + finalScore = 0.99999; + } else if (finalScore == 0) { + finalScore = 0.00001; + } + //noinspection StatementWithEmptyBody while (mResults.poll() != null) { // Empty out the expired results. @@ -147,15 +168,17 @@ public class HistoryTracker { private final double mScore; CombinedResult(long uptimeMillis, double score) { - mExpiryMs = uptimeMillis + TOTAL_DECAY_TIME_MS; + mExpiryMs = uptimeMillis + HISTORY_MAX_AGE_MS; mScore = score; } double getDecayedScore(long nowMs) { long remainingTimeMs = mExpiryMs - nowMs; - long decayedTimeMs = TOTAL_DECAY_TIME_MS - remainingTimeMs; + long decayedTimeMs = HISTORY_MAX_AGE_MS - remainingTimeMs; double timeIntervals = (double) decayedTimeMs / DECAY_INTERVAL_MS; - return mScore * Math.pow(HISTORY_DECAY, timeIntervals); + + // Score should decay towards 0.5. + return (mScore - 0.5) * Math.pow(HISTORY_DECAY, timeIntervals) + 0.5; } double getScore() { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java index cd399fe15de1..77d2d4267679 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java @@ -56,7 +56,7 @@ class PointerCountClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { int interactionType = getInteractionType(); int allowedPointerCount = (interactionType == QUICK_SETTINGS || interactionType == NOTIFICATION_DRAG_DOWN) diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java index 9ee85986c53c..6e97857f83da 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java @@ -112,7 +112,7 @@ class ProximityClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { if (getInteractionType() == QUICK_SETTINGS) { return Result.passed(0); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java index f2622ec4e6e9..bff709ca83a2 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java @@ -39,12 +39,15 @@ public class SingleTapClassifier extends FalsingClassifier { } @Override - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { return isTap(getRecentMotionEvents()); } /** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */ public Result isTap(List<MotionEvent> motionEvents) { + if (motionEvents.isEmpty()) { + return Result.falsed(0, "no motion events"); + } float downX = motionEvents.get(0).getX(); float downY = motionEvents.get(0).getY(); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java index d470d6297170..4e032ea487c9 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 - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { boolean vertical = isVertical(); boolean up = isUp(); boolean right = isRight(); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java index 2bfb2186191b..205825790461 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 - Result calculateFalsingResult(double historyPenalty, double historyConfidence) { + Result calculateFalsingResult(double historyBelief, double historyConfidence) { List<MotionEvent> 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. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 19b98953325f..8e8353ce39d4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -576,8 +576,8 @@ public class NotificationPanelViewController extends PanelViewController { FeatureFlags featureFlags) { super(view, falsingManager, dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, vibratorHelper, - latencyTracker, flingAnimationUtilsBuilder.get(), statusBarTouchableRegionManager, - ambientState); + statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(), + statusBarTouchableRegionManager, ambientState); mView = view; mMetricsLogger = metricsLogger; mActivityManager = activityManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java index 50c8e2e0d710..66df936dd556 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationTapHelper.java @@ -64,7 +64,7 @@ public class NotificationTapHelper { mTrackTouch = event.getY() <= maxTouchableHeight; break; case MotionEvent.ACTION_MOVE: - if (mTrackTouch && mFalsingManager.isFalseTap(false)) { + if (mTrackTouch && mFalsingManager.isFalseTap(false, 0)) { makeInactive(); mTrackTouch = false; } @@ -78,10 +78,10 @@ public class NotificationTapHelper { // 1) See if we have confidence that we can activate after a single tap. // 2) Else, see if it looks like a tap at all and check for a double-tap. - if (!mFalsingManager.isFalseTap(true)) { + if (!mFalsingManager.isFalseTap(true, 0)) { makeInactive(); return mDoubleTapListener.onDoubleTap(); - } else if (!mFalsingManager.isFalseTap(false)) { + } else if (!mFalsingManager.isFalseTap(false, 0)) { if (mSlideBackListener != null && mSlideBackListener.onSlideBack()) { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index b6ed3e50ed7e..3ac69378d7d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -167,6 +167,7 @@ public abstract class PanelViewController { private boolean mIgnoreXTouchSlop; private boolean mExpandLatencyTracking; private final PanelView mView; + private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; protected final Resources mResources; protected final KeyguardStateController mKeyguardStateController; protected final SysuiStatusBarStateController mStatusBarStateController; @@ -235,12 +236,14 @@ public abstract class PanelViewController { FalsingManager falsingManager, DozeLog dozeLog, KeyguardStateController keyguardStateController, SysuiStatusBarStateController statusBarStateController, VibratorHelper vibratorHelper, + StatusBarKeyguardViewManager statusBarKeyguardViewManager, LatencyTracker latencyTracker, FlingAnimationUtils.Builder flingAnimationUtilsBuilder, StatusBarTouchableRegionManager statusBarTouchableRegionManager, AmbientState ambientState) { mAmbientState = ambientState; mView = view; + mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { @@ -1391,8 +1394,13 @@ public abstract class PanelViewController { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: - addMovement(event); - endMotionEvent(event, x, y, false /* forceCancel */); + if (mStatusBarKeyguardViewManager.isBouncerShowing() + && mFalsingManager.isFalseTap(true, 0.5)) { + endMotionEvent(event, x, y, true /* forceCancel */); + } else { + addMovement(event); + endMotionEvent(event, x, y, false /* forceCancel */); + } InteractionJankMonitor monitor = InteractionJankMonitor.getInstance(); if (event.getActionMasked() == MotionEvent.ACTION_UP) { monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 5083e330f9a0..01ada0f4c86c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -76,7 +76,7 @@ import javax.inject.Inject; * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done, * which is in turn, reported to this class by the current - * {@link com.android.keyguard.KeyguardViewBase}. + * {@link com.android.keyguard.KeyguardViewController}. */ @SysUISingleton public class StatusBarKeyguardViewManager implements RemoteInputController.Callback, diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java index c2ade81a9877..088de1d99d65 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -36,6 +36,9 @@ import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.classifier.FalsingCollector; +import com.android.systemui.classifier.FalsingCollectorFake; +import com.android.systemui.classifier.SingleTapClassifier; import org.junit.Before; import org.junit.Test; @@ -69,6 +72,9 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { private KeyguardMessageAreaController mKeyguardMessageAreaController; @Mock private LatencyTracker mLatencyTracker; + private FalsingCollector mFalsingCollector = new FalsingCollectorFake(); + @Mock + private SingleTapClassifier mSingleTapClassifier; private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController; @@ -84,7 +90,8 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { .thenReturn(mKeyguardMessageArea); mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, - mKeyguardMessageAreaControllerFactory, mLatencyTracker) { + mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector, + mSingleTapClassifier) { @Override void resetState() { } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java index 31cc7bb7c958..a36a2b0414c9 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java @@ -33,6 +33,7 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollectorFake; +import com.android.systemui.classifier.SingleTapClassifier; import org.junit.Before; import org.junit.Test; @@ -69,6 +70,8 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { private LiftToActivateListener mLiftToactivateListener; private FalsingCollector mFalsingCollector = new FalsingCollectorFake(); @Mock + private SingleTapClassifier mSingleTapClassifier; + @Mock private View mDeleteButton; @Mock private View mOkButton; @@ -92,7 +95,7 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { mKeyguardPinViewController = new KeyguardPinBasedInputViewController(mPinBasedInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener, - mFalsingCollector) { + mFalsingCollector, mSingleTapClassifier) { @Override public void onResume(int reason) { super.onResume(reason); 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 5709ce3035a2..a53377e3e08c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java @@ -21,10 +21,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.ArgumentMatchers.anyDouble; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -93,7 +90,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList); mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager, mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier, - mHistoryTracker, mFakeExecutor, DOUBLE_TAP_TIMEOUT_MS, false); + mHistoryTracker, false); ArgumentCaptor<GestureCompleteListener> gestureCompleteListenerCaptor = @@ -161,25 +158,26 @@ public class BrightLineClassifierTest extends SysuiTestCase { public void testIsFalseTap_BasicCheck() { when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mFalsedResult); - assertThat(mBrightLineFalsingManager.isFalseTap(false)).isTrue(); + assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isTrue(); when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult); - assertThat(mBrightLineFalsingManager.isFalseTap(false)).isFalse(); + assertThat(mBrightLineFalsingManager.isFalseTap(false, 0)).isFalse(); } @Test public void testIsFalseTap_RobustCheck_NoFaceAuth() { when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult); + when(mHistoryTracker.falseBelief()).thenReturn(1.0); mFalsingDataProvider.setJustUnlockedWithFace(false); - assertThat(mBrightLineFalsingManager.isFalseTap(true)).isTrue(); + assertThat(mBrightLineFalsingManager.isFalseTap(true, 0)).isTrue(); } @Test public void testIsFalseTap_RobustCheck_FaceAuth() { when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(mPassedResult); when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true); - assertThat(mBrightLineFalsingManager.isFalseTap(true)).isFalse(); + assertThat(mBrightLineFalsingManager.isFalseTap(true, 0)).isFalse(); } @Test @@ -203,43 +201,29 @@ public class BrightLineClassifierTest extends SysuiTestCase { @Test public void testHistory_singleTap() { // When trying to classify single taps, we don't immediately add results to history. - mBrightLineFalsingManager.isFalseTap(false); + mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); - - verify(mHistoryTracker, never()).addResults(any(), anyLong()); - - mFakeExecutor.advanceClockToNext(); - mFakeExecutor.runAllReady(); - verify(mHistoryTracker).addResults(anyCollection(), eq(1000L)); } @Test public void testHistory_multipleSingleTaps() { // When trying to classify single taps, we don't immediately add results to history. - mBrightLineFalsingManager.isFalseTap(false); + mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); - mBrightLineFalsingManager.isFalseTap(false); + mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(2000); - - verify(mHistoryTracker, never()).addResults(any(), anyLong()); - - mFakeExecutor.advanceClockToNext(); - mFakeExecutor.runNextReady(); verify(mHistoryTracker).addResults(anyCollection(), eq(1000L)); - reset(mHistoryTracker); - mFakeExecutor.advanceClockToNext(); - mFakeExecutor.runNextReady(); verify(mHistoryTracker).addResults(anyCollection(), eq(2000L)); } @Test public void testHistory_doubleTap() { // When trying to classify single taps, we don't immediately add results to history. - mBrightLineFalsingManager.isFalseTap(false); + mBrightLineFalsingManager.isFalseTap(false, 0); mGestureCompleteListener.onGestureComplete(1000); // Before checking for double tap, we may check for single-tap on the second gesture. - mBrightLineFalsingManager.isFalseTap(false); + mBrightLineFalsingManager.isFalseTap(false, 0); mBrightLineFalsingManager.isFalseDoubleTap(); mGestureCompleteListener.onGestureComplete(2000); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java index 23ef865750b2..dc79b8881891 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java @@ -36,6 +36,7 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.sensors.ThresholdSensor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -56,6 +57,8 @@ public class FalsingCollectorImplTest extends SysuiTestCase { @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock + private HistoryTracker mHistoryTracker; + @Mock private ProximitySensor mProximitySensor; @Mock private SysuiStatusBarStateController mStatusBarStateController; @@ -67,7 +70,8 @@ public class FalsingCollectorImplTest extends SysuiTestCase { when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); mFalsingCollector = new FalsingCollectorImpl(mFalsingDataProvider, mFalsingManager, - mKeyguardUpdateMonitor, mProximitySensor, mStatusBarStateController); + mKeyguardUpdateMonitor, mHistoryTracker, mProximitySensor, + mStatusBarStateController, new FakeSystemClock()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java index 01cce3579b0c..bb7545f93b4b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/HistoryTrackerTest.java @@ -48,14 +48,14 @@ public class HistoryTrackerTest extends SysuiTestCase { @Test public void testNoDataNoPenalty() { - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0); + assertThat(mHistoryTracker.falseBelief()).isEqualTo(0.5); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0); } @Test public void testOneResultFullConfidence() { addResult(true, 1); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); } @@ -64,8 +64,8 @@ public class HistoryTrackerTest extends SysuiTestCase { addResult(true, 1); addResult(false, 1); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0.5); - assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0.5); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(0.5); + assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(0.5); } @Test @@ -73,20 +73,20 @@ public class HistoryTrackerTest extends SysuiTestCase { addResult(true, 1); addResult(true, 0); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0.75); - assertThat(mHistoryTracker.falseConfidence()).isEqualTo(.75); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1); + assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(.75); } @Test public void testDecay() { addResult(true, 1); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); - mSystemClock.advanceTime(1000); + mSystemClock.advanceTime(9999); - assertThat(mHistoryTracker.falsePenalty()).isWithin(0.01).of(0.1); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.005).of(0.55); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); } @@ -96,25 +96,25 @@ public class HistoryTrackerTest extends SysuiTestCase { mSystemClock.advanceTime(1000); addResult(false, .5); - assertThat(mHistoryTracker.falsePenalty()).isWithin(0.01).of(0.17); - assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0.625); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.01).of(0.74); + assertThat(mHistoryTracker.falseConfidence()).isWithin(0.001).of(0.625); } @Test public void testCompleteDecay() { addResult(true, 1); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(1); + assertThat(mHistoryTracker.falseBelief()).isWithin(0.001).of(1); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); - mSystemClock.advanceTime(2999); + mSystemClock.advanceTime(9999); - assertThat(mHistoryTracker.falsePenalty()).isGreaterThan(0); + assertThat(mHistoryTracker.falseBelief()).isGreaterThan(0); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(1); mSystemClock.advanceTime(1); - assertThat(mHistoryTracker.falsePenalty()).isEqualTo(0); + assertThat(mHistoryTracker.falseBelief()).isEqualTo(0.5); assertThat(mHistoryTracker.falseConfidence()).isEqualTo(0); } |