diff options
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); } |