diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java index d42a53cc875e0..e7114a962cfbc 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java @@ -23,10 +23,16 @@ import android.widget.LinearLayout; import androidx.annotation.Nullable; +import com.android.systemui.Gefingerpoken; + +import java.util.ArrayList; +import java.util.List; + /** * A Base class for all Keyguard password/pattern/pin related inputs. */ public abstract class KeyguardInputView extends LinearLayout { + private final List mMotionEventListener = new ArrayList<>(); public KeyguardInputView(Context context) { super(context); @@ -52,4 +58,25 @@ public abstract class KeyguardInputView extends LinearLayout { boolean startDisappearAnimation(Runnable finishRunnable) { return false; } + + void addMotionEventListener(Gefingerpoken listener) { + mMotionEventListener.add(listener); + } + + void removeMotionEventListener(Gefingerpoken listener) { + mMotionEventListener.remove(listener); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return mMotionEventListener.stream().anyMatch(listener -> listener.onTouchEvent(event)) + || super.onTouchEvent(event); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + return mMotionEventListener.stream().anyMatch( + listener -> listener.onInterceptTouchEvent(event)) + || super.onInterceptTouchEvent(event); + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index 6aa5e0df3653b..1c691e7098a11 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -26,6 +26,7 @@ import com.android.internal.util.LatencyTracker; 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.dagger.qualifiers.Main; import com.android.systemui.util.ViewController; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -155,6 +156,7 @@ public abstract class KeyguardInputViewController private final Resources mResources; private LiftToActivateListener mLiftToActivateListener; private TelephonyManager mTelephonyManager; + private final FalsingCollector mFalsingCollector; @Inject public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor, @@ -163,7 +165,7 @@ public abstract class KeyguardInputViewController KeyguardMessageAreaController.Factory messageAreaControllerFactory, InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor, @Main Resources resources, LiftToActivateListener liftToActivateListener, - TelephonyManager telephonyManager) { + TelephonyManager telephonyManager, FalsingCollector falsingCollector) { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; @@ -173,6 +175,7 @@ public abstract class KeyguardInputViewController mResources = resources; mLiftToActivateListener = liftToActivateListener; mTelephonyManager = telephonyManager; + mFalsingCollector = falsingCollector; } /** Create a new {@link KeyguardInputViewController}. */ @@ -191,17 +194,17 @@ public abstract class KeyguardInputViewController return new KeyguardPinViewController((KeyguardPINView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mLiftToActivateListener); + mLiftToActivateListener, mFalsingCollector); } else if (keyguardInputView instanceof KeyguardSimPinView) { return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mLiftToActivateListener, mTelephonyManager); + mLiftToActivateListener, mTelephonyManager, mFalsingCollector); } else if (keyguardInputView instanceof KeyguardSimPukView) { return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mLiftToActivateListener, mTelephonyManager); + mLiftToActivateListener, mTelephonyManager, mFalsingCollector); } throw new RuntimeException("Unable to find controller for " + keyguardInputView); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java index 4d0ebfffbe04f..df8709c12442e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java @@ -25,12 +25,15 @@ 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; public abstract class KeyguardPinBasedInputViewController extends KeyguardAbsKeyInputViewController { private final LiftToActivateListener mLiftToActivateListener; + private final FalsingCollector mFalsingCollector; protected PasswordTextView mPasswordEntry; private final OnKeyListener mOnKeyListener = (v, keyCode, event) -> { @@ -40,13 +43,26 @@ public abstract class KeyguardPinBasedInputViewController { + private final OnTouchListener mActionButtonTouchListener = (v, event) -> { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { mView.doHapticKeyClick(); } 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, @@ -54,10 +70,12 @@ public abstract class KeyguardPinBasedInputViewController { // check for time-based lockouts if (mPasswordEntry.isEnabled()) { @@ -87,7 +107,7 @@ public abstract class KeyguardPinBasedInputViewController { @@ -32,10 +33,11 @@ public class KeyguardPinViewController SecurityMode securityMode, LockPatternUtils lockPatternUtils, KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, - LatencyTracker latencyTracker, - LiftToActivateListener liftToActivateListener) { + LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, + FalsingCollector falsingCollector) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, - messageAreaControllerFactory, latencyTracker, liftToActivateListener); + messageAreaControllerFactory, latencyTracker, liftToActivateListener, + falsingCollector); mKeyguardUpdateMonitor = keyguardUpdateMonitor; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java index 5b4a7ff3e16ed..b218141346074 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java @@ -38,6 +38,7 @@ import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.R; +import com.android.systemui.classifier.FalsingCollector; public class KeyguardSimPinViewController extends KeyguardPinBasedInputViewController { @@ -76,11 +77,11 @@ public class KeyguardSimPinViewController SecurityMode securityMode, LockPatternUtils lockPatternUtils, KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, - LatencyTracker latencyTracker, - LiftToActivateListener liftToActivateListener, - TelephonyManager telephonyManager) { + LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, + TelephonyManager telephonyManager, FalsingCollector falsingCollector) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, - messageAreaControllerFactory, latencyTracker, liftToActivateListener); + messageAreaControllerFactory, latencyTracker, liftToActivateListener, + falsingCollector); 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 eafb33f8195d4..890a17c1cf921 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java @@ -39,6 +39,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.classifier.FalsingCollector; public class KeyguardSimPukViewController extends KeyguardPinBasedInputViewController { @@ -83,11 +84,11 @@ public class KeyguardSimPukViewController SecurityMode securityMode, LockPatternUtils lockPatternUtils, KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, - LatencyTracker latencyTracker, - LiftToActivateListener liftToActivateListener, - TelephonyManager telephonyManager) { + LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, + TelephonyManager telephonyManager, FalsingCollector falsingCollector) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, - messageAreaControllerFactory, latencyTracker, liftToActivateListener); + messageAreaControllerFactory, latencyTracker, liftToActivateListener, + falsingCollector); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mTelephonyManager = telephonyManager; mSimImageView = mView.findViewById(R.id.keyguard_sim); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java index fe47162a1d4ec..b0bbab366e93a 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java @@ -115,6 +115,9 @@ public interface FalsingCollector { /** */ void onTouchEvent(MotionEvent ev); + /** */ + void avoidGesture(); + /** */ void cleanup(); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java index fd059898f7a6b..12a0604391061 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java @@ -146,6 +146,10 @@ public class FalsingCollectorFake implements FalsingCollector { public void onTouchEvent(MotionEvent ev) { } + @Override + public void avoidGesture() { + } + @Override public void cleanup() { } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java index 4c11ecf669565..75fa6f19bce05 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java @@ -49,6 +49,8 @@ class FalsingCollectorImpl implements FalsingCollector { private boolean mShowingAod; private boolean mScreenOn; private boolean mSessionStarted; + private MotionEvent mPendingDownEvent; + private boolean mAvoidGesture; private final ThresholdSensor.Listener mSensorEventListener = this::onProximityEvent; @@ -245,7 +247,32 @@ class FalsingCollectorImpl implements FalsingCollector { @Override public void onTouchEvent(MotionEvent ev) { - mFalsingDataProvider.onMotionEvent(ev); + // We delay processing down events to see if another component wants to process them. + // If #avoidGesture is called after a MotionEvent.ACTION_DOWN, all following motion events + //will be ignored by the collector until another MotionEvent.ACTION_DOWN is passed in. + // avoidGesture must be called immediately following the MotionEvent.ACTION_DOWN, before + // any other events are processed, otherwise the whole gesture will be recorded. + if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { + // Make a copy of ev, since it will be recycled after we exit this method. + mPendingDownEvent = MotionEvent.obtain(ev); + mAvoidGesture = false; + } else if (!mAvoidGesture) { + if (mPendingDownEvent != null) { + mFalsingDataProvider.onMotionEvent(mPendingDownEvent); + mPendingDownEvent.recycle(); + mPendingDownEvent = null; + } + mFalsingDataProvider.onMotionEvent(ev); + } + } + + @Override + public void avoidGesture() { + if (mPendingDownEvent != null) { + mAvoidGesture = true; + mPendingDownEvent.recycle(); + mPendingDownEvent = null; + } } @Override diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java index 4944284698a05..31cc7bb7c958e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java @@ -31,6 +31,8 @@ import com.android.internal.widget.LockPatternUtils; 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 org.junit.Before; import org.junit.Test; @@ -65,6 +67,7 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { private LatencyTracker mLatencyTracker; @Mock private LiftToActivateListener mLiftToactivateListener; + private FalsingCollector mFalsingCollector = new FalsingCollectorFake(); @Mock private View mDeleteButton; @Mock @@ -88,7 +91,8 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { .thenReturn(mOkButton); mKeyguardPinViewController = new KeyguardPinBasedInputViewController(mPinBasedInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, - mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener) { + mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener, + mFalsingCollector) { @Override public void onResume(int reason) { super.onResume(reason); 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 af5e789a0c41e..23ef865750b2e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java @@ -17,12 +17,15 @@ package com.android.systemui.classifier; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; +import android.view.MotionEvent; import androidx.test.filters.SmallTest; @@ -38,6 +41,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -66,7 +70,6 @@ public class FalsingCollectorImplTest extends SysuiTestCase { mKeyguardUpdateMonitor, mProximitySensor, mStatusBarStateController); } - @Test public void testRegisterSensor() { mFalsingCollector.onScreenTurningOn(); @@ -110,7 +113,6 @@ public class FalsingCollectorImplTest extends SysuiTestCase { @Test public void testUnregisterSensor_StateTransition() { - ArgumentCaptor stateListenerArgumentCaptor = ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); verify(mStatusBarStateController).addCallback(stateListenerArgumentCaptor.capture()); @@ -120,4 +122,37 @@ public class FalsingCollectorImplTest extends SysuiTestCase { stateListenerArgumentCaptor.getValue().onStateChanged(StatusBarState.SHADE); verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class)); } + + @Test + public void testPassThroughGesture() { + MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); + MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0); + + // Nothing passed initially + mFalsingCollector.onTouchEvent(down); + verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); + + // Up event flushes the down event. + mFalsingCollector.onTouchEvent(up); + InOrder orderedCalls = inOrder(mFalsingDataProvider); + // We can't simply use "eq" or similar because the collector makes a copy of "down". + orderedCalls.verify(mFalsingDataProvider).onMotionEvent( + argThat(argument -> argument.getActionMasked() == MotionEvent.ACTION_DOWN)); + orderedCalls.verify(mFalsingDataProvider).onMotionEvent(up); + } + + @Test + public void testAvoidGesture() { + MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); + MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); + + // Nothing passed initially + mFalsingCollector.onTouchEvent(down); + verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); + + mFalsingCollector.avoidGesture(); + // Up event would flush, but we were told to avoid. + mFalsingCollector.onTouchEvent(up); + verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); + } }