Loading core/java/android/hardware/biometrics/BiometricManager.java +36 −0 Original line number Diff line number Diff line Loading @@ -766,6 +766,42 @@ public class BiometricManager { } } /** * Registers listener for changes to Identity Check state. * @param listener Listener for changes to Identity Check state * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public void registerIdentityCheckStateListener(IIdentityCheckStateListener listener) { if (mService != null) { try { mService.registerIdentityCheckStateListener(listener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { Slog.w(TAG, "registerIdentityCheckStateListener(): Service not connected"); } } /** * Unregisters listener for changes to Identity Check state. * @param listener Listener for changes to Identity Check state * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public void unregisterIdentityCheckStateListener(IIdentityCheckStateListener listener) { if (mService != null) { try { mService.unregisterIdentityCheckStateListener(listener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { Slog.w(TAG, "unregisterIdentityCheckStateListener(): Service not connected"); } } /** * Requests all {@link Authenticators.Types#BIOMETRIC_STRONG} sensors to have their Loading core/java/android/hardware/biometrics/IAuthService.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.hardware.biometrics; import android.hardware.biometrics.AuthenticationStateListener; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.IIdentityCheckStateListener; import android.hardware.biometrics.IdentityCheckStatus; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; Loading Loading @@ -82,6 +83,12 @@ interface IAuthService { // Unregister listener for changes to authentication state. void unregisterAuthenticationStateListener(AuthenticationStateListener listener); // Register listener for when Identity Check state changes. void registerIdentityCheckStateListener(IIdentityCheckStateListener listener); // Unregister listener for when Identity Check state changes. void unregisterIdentityCheckStateListener(IIdentityCheckStateListener listener); // Requests all BIOMETRIC_STRONG sensors to have their authenticatorId invalidated for the // specified user. This happens when enrollments have been added on devices with multiple // biometric sensors. Loading core/java/android/hardware/biometrics/IBiometricService.aidl +9 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.hardware.biometrics; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IIdentityCheckStateListener; import android.hardware.biometrics.IdentityCheckStatus; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; Loading Loading @@ -77,6 +78,14 @@ interface IBiometricService { @EnforcePermission("USE_BIOMETRIC_INTERNAL") void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback); // Register listener for when Identity Check state changes. @EnforcePermission("USE_BIOMETRIC_INTERNAL") void registerIdentityCheckStateListener(IIdentityCheckStateListener listener); // Unregister listener for when Identity Check state changes. @EnforcePermission("USE_BIOMETRIC_INTERNAL") void unregisterIdentityCheckStateListener(IIdentityCheckStateListener listener); // Notify BiometricService when <Biometric>Service is ready to start the prepared client. // Client lifecycle is still managed in <Biometric>Service. @EnforcePermission("USE_BIOMETRIC_INTERNAL") Loading core/java/android/hardware/biometrics/IIdentityCheckStateListener.aidl 0 → 100644 +38 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware.biometrics; /** * Interface for handling state changes related to Identity Check. * @hide */ oneway interface IIdentityCheckStateListener { @VintfStability @Backing(type="int") enum WatchRangingState { /** Watch ranging is idle */ WATCH_RANGING_IDLE = 0, /** Watch has been found within range */ WATCH_RANGING_SUCCESSFUL = 1, /** Watch ranging has started */ WATCH_RANGING_STARTED = 2, /** Watch ranging has stopped */ WATCH_RANGING_STOPPED = 3, } /** Defines behavior for when the watch ranging state has changed */ void onWatchRangingStateChanged(WatchRangingState state); } No newline at end of file packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +37 −0 Original line number Diff line number Diff line Loading @@ -305,6 +305,43 @@ open class AuthContainerViewTest : SysuiTestCase() { ) } @Test fun testActionCredentialMatched_dismissesWhenCredentialAllowed() { val container = initializeFingerprintContainer( authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK ) val attestation = ByteArray(10) container.onCredentialMatched(attestation, true) waitForIdleSync() verify(callback) .onDismissed( eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED), eq(attestation), eq(authContainer?.requestId ?: 0L), ) } @Test @EnableFlags(Flags.FLAG_BP_FALLBACK_OPTIONS) fun testActionCredentialMatched_doesNotDismissWhenCredentialNotAllowed() { val container = initializeFingerprintContainer( authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK ) val attestation = ByteArray(10) container.onCredentialMatched(attestation, false) waitForIdleSync() verify(callback, never()) .onDismissed( eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED), eq(attestation), eq(authContainer?.requestId ?: 0L), ) } @Test fun testActionError_sendsDismissedError() { val container = initializeFingerprintContainer() Loading Loading
core/java/android/hardware/biometrics/BiometricManager.java +36 −0 Original line number Diff line number Diff line Loading @@ -766,6 +766,42 @@ public class BiometricManager { } } /** * Registers listener for changes to Identity Check state. * @param listener Listener for changes to Identity Check state * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public void registerIdentityCheckStateListener(IIdentityCheckStateListener listener) { if (mService != null) { try { mService.registerIdentityCheckStateListener(listener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { Slog.w(TAG, "registerIdentityCheckStateListener(): Service not connected"); } } /** * Unregisters listener for changes to Identity Check state. * @param listener Listener for changes to Identity Check state * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) public void unregisterIdentityCheckStateListener(IIdentityCheckStateListener listener) { if (mService != null) { try { mService.unregisterIdentityCheckStateListener(listener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { Slog.w(TAG, "unregisterIdentityCheckStateListener(): Service not connected"); } } /** * Requests all {@link Authenticators.Types#BIOMETRIC_STRONG} sensors to have their Loading
core/java/android/hardware/biometrics/IAuthService.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.hardware.biometrics; import android.hardware.biometrics.AuthenticationStateListener; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.IIdentityCheckStateListener; import android.hardware.biometrics.IdentityCheckStatus; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; Loading Loading @@ -82,6 +83,12 @@ interface IAuthService { // Unregister listener for changes to authentication state. void unregisterAuthenticationStateListener(AuthenticationStateListener listener); // Register listener for when Identity Check state changes. void registerIdentityCheckStateListener(IIdentityCheckStateListener listener); // Unregister listener for when Identity Check state changes. void unregisterIdentityCheckStateListener(IIdentityCheckStateListener listener); // Requests all BIOMETRIC_STRONG sensors to have their authenticatorId invalidated for the // specified user. This happens when enrollments have been added on devices with multiple // biometric sensors. Loading
core/java/android/hardware/biometrics/IBiometricService.aidl +9 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.hardware.biometrics; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricServiceReceiver; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IIdentityCheckStateListener; import android.hardware.biometrics.IdentityCheckStatus; import android.hardware.biometrics.IInvalidationCallback; import android.hardware.biometrics.ITestSession; Loading Loading @@ -77,6 +78,14 @@ interface IBiometricService { @EnforcePermission("USE_BIOMETRIC_INTERNAL") void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback); // Register listener for when Identity Check state changes. @EnforcePermission("USE_BIOMETRIC_INTERNAL") void registerIdentityCheckStateListener(IIdentityCheckStateListener listener); // Unregister listener for when Identity Check state changes. @EnforcePermission("USE_BIOMETRIC_INTERNAL") void unregisterIdentityCheckStateListener(IIdentityCheckStateListener listener); // Notify BiometricService when <Biometric>Service is ready to start the prepared client. // Client lifecycle is still managed in <Biometric>Service. @EnforcePermission("USE_BIOMETRIC_INTERNAL") Loading
core/java/android/hardware/biometrics/IIdentityCheckStateListener.aidl 0 → 100644 +38 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware.biometrics; /** * Interface for handling state changes related to Identity Check. * @hide */ oneway interface IIdentityCheckStateListener { @VintfStability @Backing(type="int") enum WatchRangingState { /** Watch ranging is idle */ WATCH_RANGING_IDLE = 0, /** Watch has been found within range */ WATCH_RANGING_SUCCESSFUL = 1, /** Watch ranging has started */ WATCH_RANGING_STARTED = 2, /** Watch ranging has stopped */ WATCH_RANGING_STOPPED = 3, } /** Defines behavior for when the watch ranging state has changed */ void onWatchRangingStateChanged(WatchRangingState state); } No newline at end of file
packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +37 −0 Original line number Diff line number Diff line Loading @@ -305,6 +305,43 @@ open class AuthContainerViewTest : SysuiTestCase() { ) } @Test fun testActionCredentialMatched_dismissesWhenCredentialAllowed() { val container = initializeFingerprintContainer( authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK ) val attestation = ByteArray(10) container.onCredentialMatched(attestation, true) waitForIdleSync() verify(callback) .onDismissed( eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED), eq(attestation), eq(authContainer?.requestId ?: 0L), ) } @Test @EnableFlags(Flags.FLAG_BP_FALLBACK_OPTIONS) fun testActionCredentialMatched_doesNotDismissWhenCredentialNotAllowed() { val container = initializeFingerprintContainer( authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK ) val attestation = ByteArray(10) container.onCredentialMatched(attestation, false) waitForIdleSync() verify(callback, never()) .onDismissed( eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED), eq(attestation), eq(authContainer?.requestId ?: 0L), ) } @Test fun testActionError_sendsDismissedError() { val container = initializeFingerprintContainer() Loading