Loading services/core/java/com/android/server/biometrics/PreAuthInfo.java +16 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_ANY_BIOMETRIC; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_CREDENTIAL; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; Loading @@ -35,6 +36,7 @@ import android.os.RemoteException; import android.os.UserManager; import android.util.Pair; import android.util.Slog; import android.view.Display; import com.android.internal.R; import com.android.server.biometrics.sensors.LockoutTracker; Loading Loading @@ -397,7 +399,11 @@ class PreAuthInfo { cameraPrivacyEnabled = mBiometricCameraManager.isCameraPrivacyEnabled(); } if (mBiometricRequested && credentialRequested) { if (com.android.server.biometrics.Flags.biometricPromptExternalDisplay() && isExternalDisplay()) { status = BIOMETRIC_HARDWARE_NOT_DETECTED; modality = TYPE_ANY_BIOMETRIC | TYPE_CREDENTIAL; } else if (mBiometricRequested && credentialRequested) { if (credentialAvailable || !eligibleSensors.isEmpty()) { for (BiometricSensor sensor : eligibleSensors) { modality |= sensor.modality; Loading Loading @@ -480,6 +486,15 @@ class PreAuthInfo { getInternalStatus().second)); } private boolean isExternalDisplay() { try { return context.getDisplay().getType() == Display.TYPE_EXTERNAL; } catch (UnsupportedOperationException e) { Slog.d(TAG, "Exception thrown when checking display type " + e); return false; } } /** Returns if mandatory biometrics authentication is in effect */ boolean getIsMandatoryBiometricsAuthentication() { return mIsMandatoryBiometricsAuthentication; Loading services/core/java/com/android/server/biometrics/biometrics.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -51,3 +51,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "biometric_prompt_external_display" namespace: "biometrics_framework" description: "This flag returns error code when biometric prompt is requested on external display." bug: "421237594" metadata { purpose: PURPOSE_BUGFIX } } services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java +47 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.biometrics; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_ANY_BIOMETRIC; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_CREDENTIAL; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE; Loading @@ -40,6 +42,8 @@ import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.Flags; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.PromptInfo; import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.IDisplayManager; import android.os.RemoteException; import android.os.UserManager; import android.platform.test.annotations.Presubmit; Loading @@ -47,6 +51,9 @@ import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.Pair; import android.view.Display; import android.view.DisplayInfo; import androidx.test.filters.SmallTest; Loading Loading @@ -92,6 +99,8 @@ public class PreAuthInfoTest { BiometricCameraManager mBiometricCameraManager; @Mock UserManager mUserManager; @Mock IDisplayManager mDisplayManager; @Before public void setup() throws RemoteException { Loading @@ -114,6 +123,35 @@ public class PreAuthInfoTest { when(mBiometricCameraManager.isAnyCameraUnavailable()).thenReturn(false); when(mContext.getResources()).thenReturn(mResources); when(mResources.getString(anyInt())).thenReturn(TEST_PACKAGE_NAME); setContextDisplayWithType(Display.TYPE_INTERNAL); } @Test @RequiresFlagsEnabled( com.android.server.biometrics.Flags.FLAG_BIOMETRIC_PROMPT_EXTERNAL_DISPLAY) public void testAuthentication_whenExternalDisplay() throws RemoteException { setContextDisplayWithType(Display.TYPE_EXTERNAL); final BiometricSensor faceSensor = getFaceSensor(); final BiometricSensor fingerprintSensor = getFingerprintSensor(); final PromptInfo promptInfo = new PromptInfo(); promptInfo.setConfirmationRequested(false /* requireConfirmation */); promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG); promptInfo.setDisallowBiometricsIfPolicyExists(false /* checkDevicePolicy */); final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, List.of(faceSensor, fingerprintSensor), USER_ID, promptInfo, TEST_PACKAGE_NAME, false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager, mUserManager); final Pair<Integer, Integer> preAuthenticateStatus = preAuthInfo.getPreAuthenticateStatus(); //Should return hardware unavailable even if there are eligible sensors assertThat(preAuthInfo.eligibleSensors).hasSize(2); assertThat(preAuthInfo.getCanAuthenticateResult()).isEqualTo( BIOMETRIC_ERROR_HW_UNAVAILABLE); assertThat(preAuthenticateStatus.first).isEqualTo( TYPE_ANY_BIOMETRIC | TYPE_CREDENTIAL); assertThat(preAuthenticateStatus.second).isEqualTo(BIOMETRIC_ERROR_HW_UNAVAILABLE); } @Test Loading Loading @@ -505,6 +543,15 @@ public class PreAuthInfoTest { .isEqualTo(BIOMETRIC_NOT_ENABLED_FOR_APPS); } private void setContextDisplayWithType(int type) { final DisplayInfo displayInfo = new DisplayInfo(); displayInfo.type = type; final Display display = new Display(new DisplayManagerGlobal(mDisplayManager), 0 /* displayId */, displayInfo, mResources); when(mContext.getDisplay()).thenReturn(display); } private BiometricSensor getFingerprintSensor() { BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FINGERPRINT, TYPE_FINGERPRINT, BiometricManager.Authenticators.BIOMETRIC_STRONG, Loading Loading
services/core/java/com/android/server/biometrics/PreAuthInfo.java +16 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_ANY_BIOMETRIC; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_CREDENTIAL; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; Loading @@ -35,6 +36,7 @@ import android.os.RemoteException; import android.os.UserManager; import android.util.Pair; import android.util.Slog; import android.view.Display; import com.android.internal.R; import com.android.server.biometrics.sensors.LockoutTracker; Loading Loading @@ -397,7 +399,11 @@ class PreAuthInfo { cameraPrivacyEnabled = mBiometricCameraManager.isCameraPrivacyEnabled(); } if (mBiometricRequested && credentialRequested) { if (com.android.server.biometrics.Flags.biometricPromptExternalDisplay() && isExternalDisplay()) { status = BIOMETRIC_HARDWARE_NOT_DETECTED; modality = TYPE_ANY_BIOMETRIC | TYPE_CREDENTIAL; } else if (mBiometricRequested && credentialRequested) { if (credentialAvailable || !eligibleSensors.isEmpty()) { for (BiometricSensor sensor : eligibleSensors) { modality |= sensor.modality; Loading Loading @@ -480,6 +486,15 @@ class PreAuthInfo { getInternalStatus().second)); } private boolean isExternalDisplay() { try { return context.getDisplay().getType() == Display.TYPE_EXTERNAL; } catch (UnsupportedOperationException e) { Slog.d(TAG, "Exception thrown when checking display type " + e); return false; } } /** Returns if mandatory biometrics authentication is in effect */ boolean getIsMandatoryBiometricsAuthentication() { return mIsMandatoryBiometricsAuthentication; Loading
services/core/java/com/android/server/biometrics/biometrics.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -51,3 +51,13 @@ flag { purpose: PURPOSE_BUGFIX } } flag { name: "biometric_prompt_external_display" namespace: "biometrics_framework" description: "This flag returns error code when biometric prompt is requested on external display." bug: "421237594" metadata { purpose: PURPOSE_BUGFIX } }
services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java +47 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.biometrics; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_ANY_BIOMETRIC; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_CREDENTIAL; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE; Loading @@ -40,6 +42,8 @@ import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.Flags; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.PromptInfo; import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.IDisplayManager; import android.os.RemoteException; import android.os.UserManager; import android.platform.test.annotations.Presubmit; Loading @@ -47,6 +51,9 @@ import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.Pair; import android.view.Display; import android.view.DisplayInfo; import androidx.test.filters.SmallTest; Loading Loading @@ -92,6 +99,8 @@ public class PreAuthInfoTest { BiometricCameraManager mBiometricCameraManager; @Mock UserManager mUserManager; @Mock IDisplayManager mDisplayManager; @Before public void setup() throws RemoteException { Loading @@ -114,6 +123,35 @@ public class PreAuthInfoTest { when(mBiometricCameraManager.isAnyCameraUnavailable()).thenReturn(false); when(mContext.getResources()).thenReturn(mResources); when(mResources.getString(anyInt())).thenReturn(TEST_PACKAGE_NAME); setContextDisplayWithType(Display.TYPE_INTERNAL); } @Test @RequiresFlagsEnabled( com.android.server.biometrics.Flags.FLAG_BIOMETRIC_PROMPT_EXTERNAL_DISPLAY) public void testAuthentication_whenExternalDisplay() throws RemoteException { setContextDisplayWithType(Display.TYPE_EXTERNAL); final BiometricSensor faceSensor = getFaceSensor(); final BiometricSensor fingerprintSensor = getFingerprintSensor(); final PromptInfo promptInfo = new PromptInfo(); promptInfo.setConfirmationRequested(false /* requireConfirmation */); promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG); promptInfo.setDisallowBiometricsIfPolicyExists(false /* checkDevicePolicy */); final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, List.of(faceSensor, fingerprintSensor), USER_ID, promptInfo, TEST_PACKAGE_NAME, false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager, mUserManager); final Pair<Integer, Integer> preAuthenticateStatus = preAuthInfo.getPreAuthenticateStatus(); //Should return hardware unavailable even if there are eligible sensors assertThat(preAuthInfo.eligibleSensors).hasSize(2); assertThat(preAuthInfo.getCanAuthenticateResult()).isEqualTo( BIOMETRIC_ERROR_HW_UNAVAILABLE); assertThat(preAuthenticateStatus.first).isEqualTo( TYPE_ANY_BIOMETRIC | TYPE_CREDENTIAL); assertThat(preAuthenticateStatus.second).isEqualTo(BIOMETRIC_ERROR_HW_UNAVAILABLE); } @Test Loading Loading @@ -505,6 +543,15 @@ public class PreAuthInfoTest { .isEqualTo(BIOMETRIC_NOT_ENABLED_FOR_APPS); } private void setContextDisplayWithType(int type) { final DisplayInfo displayInfo = new DisplayInfo(); displayInfo.type = type; final Display display = new Display(new DisplayManagerGlobal(mDisplayManager), 0 /* displayId */, displayInfo, mResources); when(mContext.getDisplay()).thenReturn(display); } private BiometricSensor getFingerprintSensor() { BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FINGERPRINT, TYPE_FINGERPRINT, BiometricManager.Authenticators.BIOMETRIC_STRONG, Loading