diff options
| author | 2024-07-03 19:58:26 +0000 | |
|---|---|---|
| committer | 2024-07-03 19:58:26 +0000 | |
| commit | aa5859f25c7d25b1bea98efd5cf998ce686f0ade (patch) | |
| tree | b61a7eb5a25e4483c93612bcd311a829cdf9cfd5 | |
| parent | 4c72af61ef94099e69c421f9006979dc99a6f237 (diff) | |
| parent | 6193bde056d6e4a1474d31fed61dfd936811fa0c (diff) | |
Merge "Add setIgnoreDisplayTouches to FingerprintManager" into main
20 files changed, 312 insertions, 211 deletions
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 2ded615580fd..903e91646332 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -699,6 +699,25 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } /** + * Set whether the HAL should ignore display touches. + * Only applies to sensors where the HAL is reponsible for handling touches. + * @hide + */ + @RequiresPermission(USE_BIOMETRIC_INTERNAL) + public void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouch) { + if (mService == null) { + Slog.w(TAG, "setIgnoreDisplayTouches: no fingerprint service"); + return; + } + + try { + mService.setIgnoreDisplayTouches(requestId, sensorId, ignoreTouch); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Request fingerprint enrollment. This call warms up the fingerprint hardware * and starts scanning for fingerprints. Progress will be indicated by callbacks to the * {@link EnrollmentCallback} object. It terminates when diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java index f701ec3ec367..d84d29292ed5 100644 --- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java +++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java @@ -120,6 +120,14 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna } /** + * Returns if sensor type is ultrasonic Udfps + * @return true if sensor is ultrasonic Udfps, false otherwise + */ + public boolean isUltrasonicUdfps() { + return sensorType == TYPE_UDFPS_ULTRASONIC; + } + + /** * Returns if sensor type is side-FPS * @return true if sensor is side-fps, false otherwise */ diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 742fa570bad7..370f097b6850 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -195,6 +195,9 @@ interface IFingerprintService { @EnforcePermission("USE_BIOMETRIC_INTERNAL") void onUdfpsUiEvent(int event, long requestId, int sensorId); + @EnforcePermission("USE_BIOMETRIC_INTERNAL") + void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches); + // Sets the controller for managing the UDFPS overlay. @EnforcePermission("USE_BIOMETRIC_INTERNAL") void setUdfpsOverlayController(in IUdfpsOverlayController controller); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index d6d40f28d288..b466f31cc509 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -995,6 +995,16 @@ public class AuthController implements } /** + * @return true if ultrasonic udfps HW is supported on this device. Can return true even if + * the user has not enrolled udfps. This may be false if called before + * onAllAuthenticatorsRegistered. + */ + public boolean isUltrasonicUdfpsSupported() { + return getUdfpsProps() != null && !getUdfpsProps().isEmpty() && getUdfpsProps() + .get(0).isUltrasonicUdfps(); + } + + /** * @return true if sfps HW is supported on this device. Can return true even if the user has * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered. */ diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 9d3c6a49a616..3dd375846499 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -270,6 +270,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { @Override public void showUdfpsOverlay(long requestId, int sensorId, int reason, @NonNull IUdfpsOverlayControllerCallback callback) { + mUdfpsOverlayInteractor.setRequestId(requestId); mFgExecutor.execute(() -> UdfpsController.this.showUdfpsOverlay( new UdfpsControllerOverlay( mContext, @@ -404,6 +405,15 @@ public class UdfpsController implements DozeReceiver, Dumpable { handler::post, authenticationCallback); } + + /** + * Debug to run setIgnoreDisplayTouches + */ + public void debugSetIgnoreDisplayTouches(boolean ignoreTouch) { + final long requestId = (mOverlay != null) ? mOverlay.getRequestId() : 0L; + UdfpsController.this.mFingerprintManager.setIgnoreDisplayTouches( + requestId, mSensorProps.sensorId, ignoreTouch); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt index f5e3d29cb878..97ece11b8fbb 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt @@ -75,6 +75,8 @@ class UdfpsShell @Inject constructor(commandRegistry: CommandRegistry) : Command simFingerUp() } else if (args.size == 1 && args[0] == "biometricPrompt") { launchBiometricPrompt() + } else if (args.size == 2 && args[0] == "setIgnoreDisplayTouches") { + setIgnoreDisplayTouches(args[1].toBoolean()) } else { invalidCommand(pw) } @@ -186,6 +188,11 @@ class UdfpsShell @Inject constructor(commandRegistry: CommandRegistry) : Command upEvent?.recycle() } + @VisibleForTesting + fun setIgnoreDisplayTouches(ignoreTouches: Boolean) { + udfpsOverlayController?.debugSetIgnoreDisplayTouches(ignoreTouches) + } + private fun obtainMotionEvent( action: Int, x: Float, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt index a77cc1fea6a6..bb450c0b6d90 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt @@ -17,6 +17,7 @@ package com.android.systemui.biometrics.domain.interactor import android.content.Context +import android.hardware.fingerprint.FingerprintManager import android.util.Log import android.view.MotionEvent import com.android.systemui.biometrics.AuthController @@ -46,6 +47,7 @@ constructor( @Application private val context: Context, private val authController: AuthController, private val selectedUserInteractor: SelectedUserInteractor, + private val fingerprintManager: FingerprintManager?, @Application scope: CoroutineScope ) { private fun calculateIconSize(): Int { @@ -70,8 +72,25 @@ constructor( return isUdfpsEnrolled && isWithinOverlayBounds } + private var _requestId = MutableStateFlow(0L) + + /** RequestId of current AcquisitionClient */ + val requestId: StateFlow<Long> = _requestId.asStateFlow() + + fun setRequestId(requestId: Long) { + _requestId.value = requestId + } + /** Sets whether Udfps overlay should handle touches */ fun setHandleTouches(shouldHandle: Boolean = true) { + if (authController.isUltrasonicUdfpsSupported + && shouldHandle != _shouldHandleTouches.value) { + fingerprintManager?.setIgnoreDisplayTouches( + requestId.value, + authController.udfpsProps!!.get(0).sensorId, + !shouldHandle + ) + } _shouldHandleTouches.value = shouldHandle } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt index 9a99ed7bb512..1e3ee280204b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt @@ -27,6 +27,7 @@ import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton import android.hardware.biometrics.PromptInfo import android.hardware.biometrics.PromptVerticalListContentView import android.hardware.face.FaceSensorPropertiesInternal +import android.hardware.fingerprint.FingerprintManager import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.os.Handler import android.os.IBinder @@ -88,9 +89,8 @@ import org.mockito.Mockito.eq import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify -import org.mockito.junit.MockitoJUnit import org.mockito.Mockito.`when` as whenever - +import org.mockito.junit.MockitoJUnit private const val OP_PACKAGE_NAME = "biometric.testapp" @@ -99,33 +99,21 @@ private const val OP_PACKAGE_NAME = "biometric.testapp" @SmallTest open class AuthContainerViewTest : SysuiTestCase() { - @JvmField @Rule - var mockitoRule = MockitoJUnit.rule() - - @Mock - lateinit var callback: AuthDialogCallback - @Mock - lateinit var userManager: UserManager - @Mock - lateinit var lockPatternUtils: LockPatternUtils - @Mock - lateinit var wakefulnessLifecycle: WakefulnessLifecycle - @Mock - lateinit var panelInteractionDetector: AuthDialogPanelInteractionDetector - @Mock - lateinit var windowToken: IBinder - @Mock - lateinit var interactionJankMonitor: InteractionJankMonitor - @Mock - lateinit var vibrator: VibratorHelper - @Mock - lateinit var udfpsUtils: UdfpsUtils - @Mock - lateinit var authController: AuthController - @Mock - lateinit var selectedUserInteractor: SelectedUserInteractor - @Mock - private lateinit var packageManager: PackageManager + @JvmField @Rule var mockitoRule = MockitoJUnit.rule() + + @Mock lateinit var callback: AuthDialogCallback + @Mock lateinit var userManager: UserManager + @Mock lateinit var fingerprintManager: FingerprintManager + @Mock lateinit var lockPatternUtils: LockPatternUtils + @Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle + @Mock lateinit var panelInteractionDetector: AuthDialogPanelInteractionDetector + @Mock lateinit var windowToken: IBinder + @Mock lateinit var interactionJankMonitor: InteractionJankMonitor + @Mock lateinit var vibrator: VibratorHelper + @Mock lateinit var udfpsUtils: UdfpsUtils + @Mock lateinit var authController: AuthController + @Mock lateinit var selectedUserInteractor: SelectedUserInteractor + @Mock private lateinit var packageManager: PackageManager @Mock private lateinit var activityTaskManager: ActivityTaskManager private lateinit var displayRepository: FakeDisplayRepository @@ -141,11 +129,12 @@ open class AuthContainerViewTest : SysuiTestCase() { private val fingerprintRepository = FakeFingerprintPropertyRepository() private val displayStateRepository = FakeDisplayStateRepository() private val credentialInteractor = FakeCredentialInteractor() - private val bpCredentialInteractor = PromptCredentialInteractor( - Dispatchers.Main.immediate, - biometricPromptRepository, - credentialInteractor, - ) + private val bpCredentialInteractor = + PromptCredentialInteractor( + Dispatchers.Main.immediate, + biometricPromptRepository, + credentialInteractor, + ) private val promptSelectorInteractor by lazy { PromptSelectorInteractorImpl( fingerprintRepository, @@ -166,22 +155,26 @@ open class AuthContainerViewTest : SysuiTestCase() { displayStateInteractor = DisplayStateInteractorImpl( - testScope.backgroundScope, - mContext, - fakeExecutor, - displayStateRepository, - displayRepository, + testScope.backgroundScope, + mContext, + fakeExecutor, + displayStateRepository, + displayRepository, ) udfpsOverlayInteractor = - UdfpsOverlayInteractor( - context, - authController, - selectedUserInteractor, - testScope.backgroundScope, - ) + UdfpsOverlayInteractor( + context, + authController, + selectedUserInteractor, + fingerprintManager, + testScope.backgroundScope, + ) biometricStatusInteractor = - BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository, - fingerprintRepository) + BiometricStatusInteractorImpl( + activityTaskManager, + biometricStatusRepository, + fingerprintRepository + ) iconProvider = IconProvider(context) // Set up default logo icon whenever(packageManager.getApplicationIcon(OP_PACKAGE_NAME)).thenReturn(defaultLogoIcon) @@ -198,10 +191,8 @@ open class AuthContainerViewTest : SysuiTestCase() { @Test fun testNotifiesAnimatedIn() { initializeFingerprintContainer() - verify(callback).onDialogAnimatedIn( - authContainer?.requestId ?: 0L, - true /* startFingerprintNow */ - ) + verify(callback) + .onDialogAnimatedIn(authContainer?.requestId ?: 0L, true /* startFingerprintNow */) } @Test @@ -246,10 +237,8 @@ open class AuthContainerViewTest : SysuiTestCase() { waitForIdleSync() // attaching the view resets the state and allows this to happen again - verify(callback).onDialogAnimatedIn( - authContainer?.requestId ?: 0L, - true /* startFingerprintNow */ - ) + verify(callback) + .onDialogAnimatedIn(authContainer?.requestId ?: 0L, true /* startFingerprintNow */) } @Test @@ -274,10 +263,8 @@ open class AuthContainerViewTest : SysuiTestCase() { // the first time is triggered by initializeFingerprintContainer() // the second time was triggered by dismissWithoutCallback() - verify(callback, times(2)).onDialogAnimatedIn( - authContainer?.requestId ?: 0L, - true /* startFingerprintNow */ - ) + verify(callback, times(2)) + .onDialogAnimatedIn(authContainer?.requestId ?: 0L, true /* startFingerprintNow */) } @Test @@ -288,18 +275,18 @@ open class AuthContainerViewTest : SysuiTestCase() { verify(panelInteractionDetector).disable() } - @Test fun testActionAuthenticated_sendsDismissedAuthenticated() { val container = initializeFingerprintContainer() container.mBiometricCallback.onAuthenticated() waitForIdleSync() - verify(callback).onDismissed( + verify(callback) + .onDismissed( eq(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED), eq<ByteArray?>(null), /* credentialAttestation */ eq(authContainer?.requestId ?: 0L) - ) + ) assertThat(container.parent).isNull() } @@ -309,15 +296,17 @@ open class AuthContainerViewTest : SysuiTestCase() { container.mBiometricCallback.onUserCanceled() waitForIdleSync() - verify(callback).onSystemEvent( + verify(callback) + .onSystemEvent( eq(BiometricConstants.BIOMETRIC_SYSTEM_EVENT_EARLY_USER_CANCEL), eq(authContainer?.requestId ?: 0L) - ) - verify(callback).onDismissed( + ) + verify(callback) + .onDismissed( eq(AuthDialogCallback.DISMISSED_USER_CANCELED), eq<ByteArray?>(null), /* credentialAttestation */ eq(authContainer?.requestId ?: 0L) - ) + ) assertThat(container.parent).isNull() } @@ -327,19 +316,21 @@ open class AuthContainerViewTest : SysuiTestCase() { container.mBiometricCallback.onButtonNegative() waitForIdleSync() - verify(callback).onDismissed( + verify(callback) + .onDismissed( eq(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE), eq<ByteArray?>(null), /* credentialAttestation */ eq(authContainer?.requestId ?: 0L) - ) + ) assertThat(container.parent).isNull() } @Test fun testActionTryAgain_sendsTryAgain() { - val container = initializeFingerprintContainer( - authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK - ) + val container = + initializeFingerprintContainer( + authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK + ) container.mBiometricCallback.onButtonTryAgain() waitForIdleSync() @@ -352,21 +343,24 @@ open class AuthContainerViewTest : SysuiTestCase() { container.mBiometricCallback.onError() waitForIdleSync() - verify(callback).onDismissed( + verify(callback) + .onDismissed( eq(AuthDialogCallback.DISMISSED_ERROR), eq<ByteArray?>(null), /* credentialAttestation */ eq(authContainer?.requestId ?: 0L) - ) + ) assertThat(authContainer!!.parent).isNull() } @Ignore("b/279650412") @Test fun testActionUseDeviceCredential_sendsOnDeviceCredentialPressed() { - val container = initializeFingerprintContainer( - authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or - BiometricManager.Authenticators.DEVICE_CREDENTIAL - ) + val container = + initializeFingerprintContainer( + authenticators = + BiometricManager.Authenticators.BIOMETRIC_WEAK or + BiometricManager.Authenticators.DEVICE_CREDENTIAL + ) container.mBiometricCallback.onUseDeviceCredential() waitForIdleSync() @@ -376,10 +370,12 @@ open class AuthContainerViewTest : SysuiTestCase() { @Test fun testAnimateToCredentialUI_invokesStartTransitionToCredentialUI() { - val container = initializeFingerprintContainer( - authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or - BiometricManager.Authenticators.DEVICE_CREDENTIAL - ) + val container = + initializeFingerprintContainer( + authenticators = + BiometricManager.Authenticators.BIOMETRIC_WEAK or + BiometricManager.Authenticators.DEVICE_CREDENTIAL + ) container.animateToCredentialUI(false) waitForIdleSync() @@ -395,10 +391,12 @@ open class AuthContainerViewTest : SysuiTestCase() { @Test fun testAnimateToCredentialUI_rotateCredentialUI() { - val container = initializeFingerprintContainer( - authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or - BiometricManager.Authenticators.DEVICE_CREDENTIAL - ) + val container = + initializeFingerprintContainer( + authenticators = + BiometricManager.Authenticators.BIOMETRIC_WEAK or + BiometricManager.Authenticators.DEVICE_CREDENTIAL + ) container.animateToCredentialUI(false) waitForIdleSync() @@ -437,13 +435,12 @@ open class AuthContainerViewTest : SysuiTestCase() { mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) var isButtonClicked = false val contentView = - PromptContentViewWithMoreOptionsButton.Builder() - .setMoreOptionsButtonListener( - fakeExecutor) { _, _ -> isButtonClicked = true } - .build() + PromptContentViewWithMoreOptionsButton.Builder() + .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> isButtonClicked = true } + .build() val container = - initializeFingerprintContainer(contentViewWithMoreOptionsButton = contentView) + initializeFingerprintContainer(contentViewWithMoreOptionsButton = contentView) waitForIdleSync() @@ -461,9 +458,9 @@ open class AuthContainerViewTest : SysuiTestCase() { @Test fun testShowCredentialUI_withDescription() { val container = - initializeFingerprintContainer( - authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL - ) + initializeFingerprintContainer( + authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL + ) waitForIdleSync() assertThat(container.hasCredentialView()).isTrue() @@ -475,10 +472,10 @@ open class AuthContainerViewTest : SysuiTestCase() { mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) val container = - initializeFingerprintContainer( - authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL, - verticalListContentView = PromptVerticalListContentView.Builder().build() - ) + initializeFingerprintContainer( + authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL, + verticalListContentView = PromptVerticalListContentView.Builder().build() + ) // Two-step credential view should show - // 1. biometric prompt without sensor 2. credential view ui waitForIdleSync() @@ -497,14 +494,14 @@ open class AuthContainerViewTest : SysuiTestCase() { mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) val contentView = - PromptContentViewWithMoreOptionsButton.Builder() - .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> } - .build() + PromptContentViewWithMoreOptionsButton.Builder() + .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> } + .build() val container = - initializeFingerprintContainer( - authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL, - contentViewWithMoreOptionsButton = contentView - ) + initializeFingerprintContainer( + authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL, + contentViewWithMoreOptionsButton = contentView + ) waitForIdleSync() assertThat(container.hasCredentialView()).isTrue() @@ -514,13 +511,13 @@ open class AuthContainerViewTest : SysuiTestCase() { @Test fun testCredentialViewUsesEffectiveUserId() { whenever(userManager.getCredentialOwnerProfile(anyInt())).thenReturn(200) - whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(200))).thenReturn( - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING - ) + whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(200))) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) - val container = initializeFingerprintContainer( - authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL - ) + val container = + initializeFingerprintContainer( + authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL + ) waitForIdleSync() assertThat(container.hasCredentialPatternView()).isTrue() @@ -531,9 +528,8 @@ open class AuthContainerViewTest : SysuiTestCase() { fun testCredentialUI_disablesClickingOnBackground() { val container = initializeCredentialPasswordContainer() assertThat(container.hasBiometricPrompt()).isFalse() - assertThat( - container.findViewById<View>(R.id.background)?.isImportantForAccessibility - ).isFalse() + assertThat(container.findViewById<View>(R.id.background)?.isImportantForAccessibility) + .isFalse() container.findViewById<View>(R.id.background)?.performClick() waitForIdleSync() @@ -552,7 +548,7 @@ open class AuthContainerViewTest : SysuiTestCase() { fun testLayoutParams_hasShowWhenLockedFlag() { val layoutParams = AuthContainerView.getLayoutParams(windowToken, "") assertThat((layoutParams.flags and WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED) != 0) - .isTrue() + .isTrue() } @Test @@ -590,20 +586,20 @@ open class AuthContainerViewTest : SysuiTestCase() { } private fun initializeCredentialPasswordContainer( - addToView: Boolean = true, + addToView: Boolean = true, ): TestAuthContainerView { whenever(userManager.getCredentialOwnerProfile(anyInt())).thenReturn(20) - whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(20))).thenReturn( - DevicePolicyManager.PASSWORD_QUALITY_NUMERIC - ) + whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(20))) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) // In the credential view, clicking on the background (to cancel authentication) is not // valid. Thus, the listener should be null, and it should not be in the accessibility // hierarchy. - val container = initializeFingerprintContainer( + val container = + initializeFingerprintContainer( authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL, addToView = addToView, - ) + ) waitForIdleSync() assertThat(container.hasCredentialPasswordView()).isTrue() @@ -615,26 +611,28 @@ open class AuthContainerViewTest : SysuiTestCase() { addToView: Boolean = true, verticalListContentView: PromptVerticalListContentView? = null, contentViewWithMoreOptionsButton: PromptContentViewWithMoreOptionsButton? = null, - ) = initializeContainer( - TestAuthContainerView( - authenticators = authenticators, - fingerprintProps = fingerprintSensorPropertiesInternal(), + ) = + initializeContainer( + TestAuthContainerView( + authenticators = authenticators, + fingerprintProps = fingerprintSensorPropertiesInternal(), verticalListContentView = verticalListContentView, - ), - addToView - ) + ), + addToView + ) private fun initializeCoexContainer( authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK, addToView: Boolean = true - ) = initializeContainer( - TestAuthContainerView( - authenticators = authenticators, - fingerprintProps = fingerprintSensorPropertiesInternal(), - faceProps = faceSensorPropertiesInternal() - ), - addToView - ) + ) = + initializeContainer( + TestAuthContainerView( + authenticators = authenticators, + fingerprintProps = fingerprintSensorPropertiesInternal(), + faceProps = faceSensorPropertiesInternal() + ), + addToView + ) private fun initializeContainer( view: TestAuthContainerView, @@ -655,47 +653,50 @@ open class AuthContainerViewTest : SysuiTestCase() { faceProps: List<FaceSensorPropertiesInternal> = listOf(), verticalListContentView: PromptVerticalListContentView? = null, contentViewWithMoreOptionsButton: PromptContentViewWithMoreOptionsButton? = null, - ) : AuthContainerView( - Config().apply { - mContext = this@AuthContainerViewTest.context - mCallback = callback - mSensorIds = (fingerprintProps.map { it.sensorId } + - faceProps.map { it.sensorId }).toIntArray() - mSkipAnimation = true - mPromptInfo = PromptInfo().apply { - this.authenticators = authenticators - if (verticalListContentView != null) { - this.contentView = verticalListContentView - } else if (contentViewWithMoreOptionsButton != null) { - this.contentView = contentViewWithMoreOptionsButton - } - } - mOpPackageName = OP_PACKAGE_NAME - }, - testScope.backgroundScope, - fingerprintProps, - faceProps, - wakefulnessLifecycle, - panelInteractionDetector, - userManager, - lockPatternUtils, - interactionJankMonitor, - { promptSelectorInteractor }, - PromptViewModel( - displayStateInteractor, - promptSelectorInteractor, - context, - udfpsOverlayInteractor, - biometricStatusInteractor, - udfpsUtils, - iconProvider, - activityTaskManager - ), - { credentialViewModel }, - Handler(TestableLooper.get(this).looper), - fakeExecutor, - vibrator - ) { + ) : + AuthContainerView( + Config().apply { + mContext = this@AuthContainerViewTest.context + mCallback = callback + mSensorIds = + (fingerprintProps.map { it.sensorId } + faceProps.map { it.sensorId }) + .toIntArray() + mSkipAnimation = true + mPromptInfo = + PromptInfo().apply { + this.authenticators = authenticators + if (verticalListContentView != null) { + this.contentView = verticalListContentView + } else if (contentViewWithMoreOptionsButton != null) { + this.contentView = contentViewWithMoreOptionsButton + } + } + mOpPackageName = OP_PACKAGE_NAME + }, + testScope.backgroundScope, + fingerprintProps, + faceProps, + wakefulnessLifecycle, + panelInteractionDetector, + userManager, + lockPatternUtils, + interactionJankMonitor, + { promptSelectorInteractor }, + PromptViewModel( + displayStateInteractor, + promptSelectorInteractor, + context, + udfpsOverlayInteractor, + biometricStatusInteractor, + udfpsUtils, + iconProvider, + activityTaskManager + ), + { credentialViewModel }, + Handler(TestableLooper.get(this).looper), + fakeExecutor, + vibrator + ) { override fun postOnAnimation(runnable: Runnable) { runnable.run() } @@ -717,8 +718,10 @@ open class AuthContainerViewTest : SysuiTestCase() { val layoutParams = AuthContainerView.getLayoutParams(windowToken, "") val lpFlags = layoutParams.flags - assertThat((lpFlags and WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) - != 0).isTrue() + assertThat( + (lpFlags and WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) != 0 + ) + .isTrue() } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt index 3d63c5b6d0f8..13f2c7212e36 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.biometrics.domain.interactor import android.graphics.Rect +import android.hardware.fingerprint.FingerprintManager import android.view.MotionEvent import android.view.Surface import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -51,6 +52,7 @@ class UdfpsOverlayInteractorTest : SysuiTestCase() { private lateinit var testScope: TestScope + @Mock private lateinit var fingerprintManager: FingerprintManager @Mock private lateinit var authController: AuthController @Captor private lateinit var authControllerCallback: ArgumentCaptor<AuthController.Callback> @@ -111,6 +113,7 @@ class UdfpsOverlayInteractorTest : SysuiTestCase() { context, authController, selectedUserInteractor, + fingerprintManager, testScope.backgroundScope ) testScope.runCurrent() diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt index 9dae44dc8053..7c53639a85a6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt @@ -18,6 +18,7 @@ package com.android.systemui import android.app.ActivityManager import android.app.admin.DevicePolicyManager import android.app.trust.TrustManager +import android.hardware.fingerprint.FingerprintManager import android.os.UserManager import android.service.notification.NotificationListenerService import android.util.DisplayMetrics @@ -94,6 +95,7 @@ data class TestMocksModule( @get:Provides val deviceProvisionedController: DeviceProvisionedController = mock(), @get:Provides val dozeParameters: DozeParameters = mock(), @get:Provides val dumpManager: DumpManager = mock(), + @get:Provides val fingerprintManager: FingerprintManager = mock(), @get:Provides val headsUpManager: HeadsUpManager = mock(), @get:Provides val guestResumeSessionReceiver: GuestResumeSessionReceiver = mock(), @get:Provides val keyguardBypassController: KeyguardBypassController = mock(), diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt index cbfc7686a896..ae592b968f8b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt @@ -17,17 +17,20 @@ package com.android.systemui.biometrics.domain.interactor import android.content.applicationContext +import android.hardware.fingerprint.FingerprintManager import com.android.systemui.biometrics.authController import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.user.domain.interactor.selectedUserInteractor +import com.android.systemui.util.mockito.mock val Kosmos.udfpsOverlayInteractor by Fixture { UdfpsOverlayInteractor( context = applicationContext, authController = authController, selectedUserInteractor = selectedUserInteractor, + fingerprintManager = mock<FingerprintManager>(), scope = applicationCoroutineScope, ) } diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java index d061e2d21811..fbd32a67fe6c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java @@ -31,7 +31,6 @@ import android.util.Slog; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; -import com.android.server.biometrics.sensors.fingerprint.aidl.AidlSession; import java.util.function.Supplier; @@ -203,16 +202,6 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement } } - // TODO(b/317414324): Deprecate setIgnoreDisplayTouches - protected final void resetIgnoreDisplayTouches() { - final AidlSession session = (AidlSession) getFreshDaemon(); - try { - session.getSession().setIgnoreDisplayTouches(false); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception when resetting setIgnoreDisplayTouches"); - } - } - @Override public boolean isInterruptable() { return true; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 4c86f57a190b..60cfd5a5a6ae 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -962,6 +962,19 @@ public class FingerprintService extends SystemService { provider.onUdfpsUiEvent(event, requestId, sensorId); } + @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) + @Override + public void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches) { + super.setIgnoreDisplayTouches_enforcePermission(); + + final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId); + if (provider == null) { + Slog.w(TAG, + "No matching provider for setIgnoreDisplayTouches, sensorId: " + sensorId); + return; + } + provider.setIgnoreDisplayTouches(requestId, sensorId, ignoreTouches); + } @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java index a6cf2f4b31ae..e4a99e6be72c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java @@ -134,6 +134,8 @@ public interface ServiceProvider extends void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller); + void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches); + void onPowerPressed(); @NonNull diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java index dce0175ca593..15d7a476b345 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java @@ -31,4 +31,5 @@ public interface Udfps { void onPointerUp(PointerContext pc); void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event); boolean isPointerDown(); + void setIgnoreDisplayTouches(boolean ignoreTouches); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index 72d92b974c1a..d04afdb72913 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -33,7 +33,6 @@ import android.hardware.biometrics.BiometricFingerprintConstants.FingerprintAcqu import android.hardware.biometrics.BiometricManager.Authenticators; import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.common.ICancellationSignal; -import android.hardware.biometrics.common.OperationState; import android.hardware.biometrics.events.AuthenticationAcquiredInfo; import android.hardware.biometrics.events.AuthenticationErrorInfo; import android.hardware.biometrics.events.AuthenticationFailedInfo; @@ -182,7 +181,6 @@ public class FingerprintAuthenticationClient handleLockout(authenticated); if (authenticated) { mState = STATE_STOPPED; - resetIgnoreDisplayTouches(); mSensorOverlays.hide(getSensorId()); if (reportBiometricAuthAttempts()) { mAuthenticationStateListeners.onAuthenticationSucceeded( @@ -223,7 +221,6 @@ public class FingerprintAuthenticationClient // Send the error, but do not invoke the FinishCallback yet. Since lockout is not // controlled by the HAL, the framework must stop the sensor before finishing the // client. - resetIgnoreDisplayTouches(); mSensorOverlays.hide(getSensorId()); mAuthenticationStateListeners.onAuthenticationError( new AuthenticationErrorInfo.Builder(BiometricSourceType.FINGERPRINT, @@ -275,7 +272,6 @@ public class FingerprintAuthenticationClient BiometricNotificationUtils.showBadCalibrationNotification(getContext()); } - resetIgnoreDisplayTouches(); mSensorOverlays.hide(getSensorId()); mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo .Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build() @@ -284,7 +280,6 @@ public class FingerprintAuthenticationClient @Override protected void startHalOperation() { - resetIgnoreDisplayTouches(); mSensorOverlays.show(getSensorId(), getRequestReason(), this); mAuthenticationStateListeners.onAuthenticationStarted(new AuthenticationStartedInfo .Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build() @@ -331,12 +326,6 @@ public class FingerprintAuthenticationClient if (session.hasContextMethods()) { try { session.getSession().onContextChanged(ctx); - // TODO(b/317414324): Deprecate setIgnoreDisplayTouches - if (ctx.operationState != null && ctx.operationState.getTag() - == OperationState.fingerprintOperationState) { - session.getSession().setIgnoreDisplayTouches(ctx.operationState - .getFingerprintOperationState().isHardwareIgnoringTouches); - } } catch (RemoteException e) { Slog.e(TAG, "Unable to notify context changed", e); } @@ -353,7 +342,6 @@ public class FingerprintAuthenticationClient @Override protected void stopHalOperation() { - resetIgnoreDisplayTouches(); mSensorOverlays.hide(getSensorId()); mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo .Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build() @@ -415,6 +403,15 @@ public class FingerprintAuthenticationClient } @Override + public void setIgnoreDisplayTouches(boolean ignoreTouches) { + try { + getFreshDaemon().getSession().setIgnoreDisplayTouches(ignoreTouches); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + } + + @Override public boolean isPointerDown() { return mIsPointerDown; } @@ -457,7 +454,6 @@ public class FingerprintAuthenticationClient Slog.e(TAG, "Remote exception", e); } - resetIgnoreDisplayTouches(); mSensorOverlays.hide(getSensorId()); mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo .Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build() @@ -492,7 +488,6 @@ public class FingerprintAuthenticationClient Slog.e(TAG, "Remote exception", e); } - resetIgnoreDisplayTouches(); mSensorOverlays.hide(getSensorId()); mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo .Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build() diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java index 36af5dba909f..fb48053913cf 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java @@ -87,7 +87,6 @@ public class FingerprintDetectClient extends AcquisitionClient<AidlSession> @Override protected void stopHalOperation() { - resetIgnoreDisplayTouches(); mSensorOverlays.hide(getSensorId()); mAuthenticationStateListeners.onAuthenticationStopped( new AuthenticationStoppedInfo.Builder(BiometricSourceType.FINGERPRINT, @@ -107,7 +106,6 @@ public class FingerprintDetectClient extends AcquisitionClient<AidlSession> @Override protected void startHalOperation() { - resetIgnoreDisplayTouches(); mSensorOverlays.show(getSensorId(), BiometricRequestConstants.REASON_AUTH_KEYGUARD, this); mAuthenticationStateListeners.onAuthenticationStarted( diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java index 3a72d7e9a91a..993a68fd6ff8 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java @@ -150,7 +150,6 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement controller -> controller.onEnrollmentProgress(getSensorId(), remaining)); if (remaining == 0) { - resetIgnoreDisplayTouches(); mSensorOverlays.hide(getSensorId()); mAuthenticationStateListeners.onAuthenticationStopped( new AuthenticationStoppedInfo.Builder( @@ -211,7 +210,6 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement ); super.onError(errorCode, vendorCode); - resetIgnoreDisplayTouches(); mSensorOverlays.hide(getSensorId()); mAuthenticationStateListeners.onAuthenticationStopped( new AuthenticationStoppedInfo.Builder(BiometricSourceType.FINGERPRINT, @@ -227,7 +225,6 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement @Override protected void startHalOperation() { - resetIgnoreDisplayTouches(); mSensorOverlays.show(getSensorId(), getRequestReasonFromFingerprintEnrollReason(mEnrollReason), this); mAuthenticationStateListeners.onAuthenticationStarted(new AuthenticationStartedInfo @@ -277,7 +274,6 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement @Override protected void stopHalOperation() { - resetIgnoreDisplayTouches(); mSensorOverlays.hide(getSensorId()); mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo .Builder(BiometricSourceType.FINGERPRINT, @@ -359,5 +355,14 @@ public class FingerprintEnrollClient extends EnrollClient<AidlSession> implement } @Override + public void setIgnoreDisplayTouches(boolean ignoreTouches) { + try { + getFreshDaemon().getSession().setIgnoreDisplayTouches(ignoreTouches); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to send setIgnoreDisplayTouches", e); + } + } + + @Override public void onPowerPressed() {} } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index 1bddb83b1441..12baf00c1c4a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -790,6 +790,19 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi } @Override + public void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches) { + mFingerprintSensors.get(sensorId).getScheduler().getCurrentClientIfMatches( + requestId, (client) -> { + if (!(client instanceof Udfps)) { + Slog.e(getTag(), + "setIgnoreDisplayTouches received during client: " + client); + return; + } + ((Udfps) client).setIgnoreDisplayTouches(ignoreTouches); + }); + } + + @Override public void onPowerPressed() { for (int i = 0; i < mFingerprintSensors.size(); i++) { final Sensor sensor = mFingerprintSensors.valueAt(i); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java index ecd799f44552..6ec888cd2e45 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java @@ -406,8 +406,6 @@ public class FingerprintAuthenticationClientTest { mContextInjector.getValue().accept(opContext); verify(mHal).onContextChanged(same(opContext)); - verify(mHal, times(2)).setIgnoreDisplayTouches( - opContext.operationState.getFingerprintOperationState().isHardwareIgnoringTouches); client.stopHalOperation(); |