diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt index 94b5fb2861b1179fb054d1161c78c71b0c15a823..21451dc0ffdf5106a2693ac6e3b35507228e5821 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt @@ -58,6 +58,7 @@ abstract class UdfpsAnimationViewController<T : UdfpsAnimationView>( // Notification shade can be expanded but not visible (fraction: 0.0), for example // when a heads-up notification (HUN) is showing. notificationShadeVisible = event.expanded && event.fraction > 0f + notificationShadeTracking = event.tracking view.onExpansionChanged(event.fraction) updatePauseAuth() } @@ -65,6 +66,9 @@ abstract class UdfpsAnimationViewController<T : UdfpsAnimationView>( /** If the notification shade is visible. */ var notificationShadeVisible: Boolean = false + /** If the notification shade is currently being dragged */ + var notificationShadeTracking: Boolean = false + /** * The amount of translation needed if the view currently requires the user to touch * somewhere other than the exact center of the sensor. For example, this can happen diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt index 802eea300bd4b146407587be57024968d49ad850..96354c2a99ff48eff998a8d52c8ae15cd7a581fe 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt @@ -15,6 +15,7 @@ */ package com.android.systemui.biometrics +import com.android.internal.annotations.VisibleForTesting import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.shade.ShadeExpansionStateManager @@ -39,6 +40,12 @@ class UdfpsBpViewController( override val tag = "UdfpsBpViewController" override fun shouldPauseAuth(): Boolean { - return false + // Do not auth while notification shade is being dragged + return notificationShadeTracking + } + + @VisibleForTesting + public override fun onViewAttached() { + super.onViewAttached() } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index a36870346b9ad4e1a069a0d8999968ab748a9b59..c29f884c848dc5286cb55c26b20ce24bcd855e10 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -549,8 +549,12 @@ public class UdfpsController implements DozeReceiver, Dumpable { Log.e(TAG, "ignoring the touch injected from outside of UdfpsView"); return false; } - if (mOverlay == null) { - Log.w(TAG, "ignoring onTouch with null overlay"); + if (mOverlay == null || mOverlay.getAnimationViewController() == null) { + Log.w(TAG, "ignoring onTouch with null overlay or animation view controller"); + return false; + } + if (mOverlay.getAnimationViewController().shouldPauseAuth()) { + Log.w(TAG, "ignoring onTouch with shouldPauseAuth = true"); return false; } if (!mOverlay.matchesRequestId(requestId)) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt index 7de78a60b73e5f62226be204b2f968e4922b4b98..9be3d820105375e9e0771a0a6dff10478e498d24 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsBpViewControllerTest.kt @@ -23,14 +23,19 @@ import com.android.systemui.RoboPilotTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.shade.ShadeExpansionChangeEvent import com.android.systemui.shade.ShadeExpansionStateManager import com.android.systemui.statusbar.phone.SystemUIDialogManager +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.mockito.withArgCaptor import org.junit.Assert.assertFalse import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit @SmallTest @@ -51,6 +56,8 @@ class UdfpsBpViewControllerTest : SysuiTestCase() { @Before fun setup() { + whenever(shadeExpansionStateManager.addExpansionListener(any())) + .thenReturn(ShadeExpansionChangeEvent(0f, false, false, 0f)) udfpsBpViewController = UdfpsBpViewController( udfpsBpView, @@ -62,7 +69,32 @@ class UdfpsBpViewControllerTest : SysuiTestCase() { } @Test - fun testShouldNeverPauseAuth() { + fun testPauseAuthWhenNotificationShadeDragging() { + udfpsBpViewController.onViewAttached() + val shadeExpansionListener = withArgCaptor { + verify(shadeExpansionStateManager).addExpansionListener(capture()) + } + + // When shade is tracking, should pause auth + shadeExpansionListener.onPanelExpansionChanged( + ShadeExpansionChangeEvent( + fraction = 0f, + expanded = false, + tracking = true, + dragDownPxAmount = 10f + ) + ) + assert(udfpsBpViewController.shouldPauseAuth()) + + // When shade is not tracking, don't pause auth even if expanded + shadeExpansionListener.onPanelExpansionChanged( + ShadeExpansionChangeEvent( + fraction = 0f, + expanded = true, + tracking = false, + dragDownPxAmount = 10f + ) + ) assertFalse(udfpsBpViewController.shouldPauseAuth()) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index e56b5c7406b60324964e05f41e32d6af825d91d7..7dd88b437f1767c8726f9e1b9cd2546502268e6f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -207,6 +207,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private final UdfpsAnimationViewController mUdfpsKeyguardViewController = mock(UdfpsKeyguardViewControllerLegacy.class); @Mock + private UdfpsAnimationViewController mUdfpsAnimationViewController; + @Mock private SystemUIDialogManager mSystemUIDialogManager; @Mock private ActivityLaunchAnimator mActivityLaunchAnimator; @@ -267,6 +269,7 @@ public class UdfpsControllerTest extends SysuiTestCase { when(mSessionTracker.getSessionId(anyInt())).thenReturn( (new InstanceIdSequence(1 << 20)).newInstanceId()); when(mUdfpsView.getViewRootImpl()).thenReturn(mViewRootImpl); + when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsAnimationViewController); final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */, @@ -1379,6 +1382,50 @@ public class UdfpsControllerTest extends SysuiTestCase { downEvent.recycle(); } + @Test + public void onTouch_withNewTouchDetection_ignoreIfAuthPaused() throws RemoteException { + final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L, + 0L); + final TouchProcessorResult processorResultDown = + new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN, + 1 /* pointerId */, touchData); + + // Enable new touch detection. + when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true); + + // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider. + initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */); + + // Configure UdfpsView to not accept the ACTION_DOWN event + when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true); + + // GIVEN that auth is paused + when(mUdfpsAnimationViewController.shouldPauseAuth()).thenReturn(true); + + // GIVEN that the overlay is showing and a11y touch exploration NOT enabled + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false); + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, + BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); + + verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); + + // WHEN ACTION_DOWN is received and touch is within sensor + when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn( + processorResultDown); + MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent); + mBiometricExecutor.runAllReady(); + downEvent.recycle(); + + // THEN the touch is ignored + verify(mInputManager, never()).pilferPointers(any()); + verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(), + anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), + anyBoolean()); + } + @Test public void onTouch_withNewTouchDetection_pilferPointer() throws RemoteException { final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,