Add ability to ignore gestures in FalsingManager

This gives other parts of the system the ability to temporarily
override the falsing manager, telling it to ignore a given gesture.

The intent is to give other parts of the system a chance to include
their own falsing information (such as whether a button was tapped or
not), giving the FalsingManager more context about what is going on.

As of right now, their is no way to feedback this context-aware
falsing information back to the FalsingManager. An API for this is
still being explored.

Bug: 172655679
Test: atest SystemUITests && manual
Change-Id: I87ee94a2386622ebff7580346325ae07e3bb5f5d
This commit is contained in:
Dave Mankoff
2020-12-09 11:44:47 -05:00
parent 246e924066
commit 8848abd1b5
11 changed files with 150 additions and 23 deletions

View File

@@ -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<Gefingerpoken> 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);
}
}

View File

@@ -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<T extends KeyguardInputView>
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<T extends KeyguardInputView>
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<T extends KeyguardInputView>
mResources = resources;
mLiftToActivateListener = liftToActivateListener;
mTelephonyManager = telephonyManager;
mFalsingCollector = falsingCollector;
}
/** Create a new {@link KeyguardInputViewController}. */
@@ -191,17 +194,17 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
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);

View File

@@ -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<T extends KeyguardPinBasedInputView>
extends KeyguardAbsKeyInputViewController<T> {
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<T extends KeyguardPinB
return false;
};
private final OnTouchListener mOnTouchListener = (v, event) -> {
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<T extends KeyguardPinB
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
LatencyTracker latencyTracker,
LiftToActivateListener liftToActivateListener) {
LiftToActivateListener liftToActivateListener,
FalsingCollector falsingCollector) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker);
mLiftToActivateListener = liftToActivateListener;
mFalsingCollector = falsingCollector;
mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());
}
@@ -65,11 +83,13 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB
protected void onViewAttached() {
super.onViewAttached();
mView.addMotionEventListener(mGlobalTouchListener);
mPasswordEntry.setOnKeyListener(mOnKeyListener);
mPasswordEntry.setUserActivityListener(this::onUserInput);
View deleteButton = mView.findViewById(R.id.delete_button);
deleteButton.setOnTouchListener(mOnTouchListener);
deleteButton.setOnTouchListener(mActionButtonTouchListener);
deleteButton.setOnClickListener(v -> {
// check for time-based lockouts
if (mPasswordEntry.isEnabled()) {
@@ -87,7 +107,7 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB
View okButton = mView.findViewById(R.id.key_enter);
if (okButton != null) {
okButton.setOnTouchListener(mOnTouchListener);
okButton.setOnTouchListener(mActionButtonTouchListener);
okButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

View File

@@ -22,6 +22,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 KeyguardPinViewController
extends KeyguardPinBasedInputViewController<KeyguardPINView> {
@@ -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;
}

View File

@@ -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<KeyguardSimPinView> {
@@ -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);

View File

@@ -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<KeyguardSimPukView> {
@@ -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);

View File

@@ -115,6 +115,9 @@ public interface FalsingCollector {
/** */
void onTouchEvent(MotionEvent ev);
/** */
void avoidGesture();
/** */
void cleanup();
}

View File

@@ -146,6 +146,10 @@ public class FalsingCollectorFake implements FalsingCollector {
public void onTouchEvent(MotionEvent ev) {
}
@Override
public void avoidGesture() {
}
@Override
public void cleanup() {
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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<StatusBarStateController.StateListener> 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));
}
}