Loading core/java/android/hardware/biometrics/flags.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -54,3 +54,10 @@ flag { description: "This flag is for API changes related to Identity Check" bug: "373424727" } flag { name: "private_space_bp" namespace: "biometrics_framework" description: "Feature flag for biometric prompt improvements in private space" bug: "365554098" } packages/SystemUI/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ <uses-permission android:name="android.permission.READ_WALLPAPER_INTERNAL" /> <!-- Used to read storage for all users --> <uses-permission android:name="android.permission.STORAGE_INTERNAL" /> <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> Loading packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt +83 −51 Original line number Diff line number Diff line Loading @@ -3,7 +3,9 @@ package com.android.systemui.biometrics.domain.interactor import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyResourcesManager import android.content.pm.UserInfo import android.hardware.biometrics.Flags import android.os.UserManager import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils Loading Loading @@ -33,6 +35,7 @@ import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit private const val USER_ID = 22 private const val OWNER_ID = 10 private const val OPERATION_ID = 100L private const val MAX_ATTEMPTS = 5 Loading Loading @@ -67,7 +70,7 @@ class CredentialInteractorImplTest : SysuiTestCase() { lockPatternUtils, userManager, devicePolicyManager, systemClock systemClock, ) } Loading Loading @@ -115,12 +118,35 @@ class CredentialInteractorImplTest : SysuiTestCase() { @Test fun pinCredentialWhenBadAndThrottled() = pinCredential(badCredential(timeout = 5_000)) private fun pinCredential(result: VerifyCredentialResponse) = runTest { @EnableFlags(Flags.FLAG_PRIVATE_SPACE_BP) @Test fun pinCredentialTiedProfileWhenGood() = pinCredential(goodCredential(), OWNER_ID) @EnableFlags(Flags.FLAG_PRIVATE_SPACE_BP) @Test fun pinCredentialTiedProfileWhenBad() = pinCredential(badCredential(), OWNER_ID) @EnableFlags(Flags.FLAG_PRIVATE_SPACE_BP) @Test fun pinCredentialTiedProfileWhenBadAndThrottled() = pinCredential(badCredential(timeout = 5_000), OWNER_ID) private fun pinCredential(result: VerifyCredentialResponse, credentialOwner: Int = USER_ID) = runTest { val usedAttempts = 1 whenever(lockPatternUtils.getCurrentFailedPasswordAttempts(eq(USER_ID))) .thenReturn(usedAttempts) whenever(lockPatternUtils.verifyCredential(any(), eq(USER_ID), anyInt())).thenReturn(result) whenever(lockPatternUtils.verifyGatekeeperPasswordHandle(anyLong(), anyLong(), eq(USER_ID))) whenever(lockPatternUtils.verifyCredential(any(), eq(USER_ID), anyInt())) .thenReturn(result) whenever(lockPatternUtils.verifyTiedProfileChallenge(any(), eq(USER_ID), anyInt())) .thenReturn(result) whenever( lockPatternUtils.verifyGatekeeperPasswordHandle( anyLong(), anyLong(), eq(USER_ID), ) ) .thenReturn(result) whenever(lockPatternUtils.setLockoutAttemptDeadline(anyInt(), anyInt())).thenAnswer { systemClock.elapsedRealtime() + (it.arguments[1] as Int) Loading @@ -130,7 +156,10 @@ class CredentialInteractorImplTest : SysuiTestCase() { // checks prevents the method from returning val statusList = mutableListOf<CredentialStatus>() interactor .verifyCredential(pinRequest(), LockscreenCredential.createPin("1234")) .verifyCredential( pinRequest(credentialOwner), LockscreenCredential.createPin("1234"), ) .toList(statusList) val last = statusList.removeLastOrNull() Loading @@ -154,10 +183,13 @@ class CredentialInteractorImplTest : SysuiTestCase() { // messages are in the throttled errors, so the final Error.error is empty assertThat(failedResult.error).isEmpty() assertThat(statusList).isNotEmpty() assertThat(statusList.filterIsInstance(CredentialStatus.Fail.Throttled::class.java)) assertThat( statusList.filterIsInstance(CredentialStatus.Fail.Throttled::class.java) ) .hasSize(statusList.size) verify(lockPatternUtils).setLockoutAttemptDeadline(eq(USER_ID), eq(result.timeout)) verify(lockPatternUtils) .setLockoutAttemptDeadline(eq(USER_ID), eq(result.timeout)) } else { // failed assertThat(failedResult.error) .matches(Regex("(.*)try again(.*)", RegexOption.IGNORE_CASE).toPattern()) Loading Loading @@ -212,11 +244,11 @@ class CredentialInteractorImplTest : SysuiTestCase() { } } private fun pinRequest(): BiometricPromptRequest.Credential.Pin = private fun pinRequest(credentialOwner: Int = USER_ID): BiometricPromptRequest.Credential.Pin = BiometricPromptRequest.Credential.Pin( promptInfo(), BiometricUserInfo(USER_ID), BiometricOperationInfo(OPERATION_ID) BiometricUserInfo(userId = USER_ID, deviceCredentialOwnerId = credentialOwner), BiometricOperationInfo(OPERATION_ID), ) private fun goodCredential( Loading packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt +6 −4 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { private val fingerprintRepository = FakeFingerprintPropertyRepository() private val promptRepository = FakePromptRepository() private val fakeExecutor = FakeExecutor(FakeSystemClock()) private val credentialInteractor = FakeCredentialInteractor() private lateinit var displayStateRepository: FakeDisplayStateRepository private lateinit var displayRepository: FakeDisplayRepository Loading @@ -99,8 +100,9 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { PromptSelectorInteractorImpl( fingerprintRepository, displayStateInteractor, credentialInteractor, promptRepository, lockPatternUtils lockPatternUtils, ) } Loading Loading @@ -134,13 +136,13 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { testScope.runTest { useBiometricsAndReset( allowCredentialFallback = true, setComponentNameForConfirmDeviceCredentialActivity = true setComponentNameForConfirmDeviceCredentialActivity = true, ) } private fun TestScope.useBiometricsAndReset( allowCredentialFallback: Boolean, setComponentNameForConfirmDeviceCredentialActivity: Boolean = false setComponentNameForConfirmDeviceCredentialActivity: Boolean = false, ) { setUserCredentialType(isPassword = true) Loading Loading @@ -357,7 +359,7 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { private fun setPrompt( info: PromptInfo = basicPromptInfo(), onSwitchToCredential: Boolean = false onSwitchToCredential: Boolean = false, ) { interactor.setPrompt( info, Loading packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +1 −1 Original line number Diff line number Diff line Loading @@ -323,7 +323,7 @@ public class AuthContainerView extends LinearLayout final boolean isLandscape = mContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; mPromptSelectorInteractorProvider = promptSelectorInteractorProvider; mPromptSelectorInteractorProvider.get().setPrompt(mConfig.mPromptInfo, mEffectiveUserId, mPromptSelectorInteractorProvider.get().setPrompt(mConfig.mPromptInfo, mConfig.mUserId, getRequestId(), biometricModalities, mConfig.mOperationId, mConfig.mOpPackageName, false /*onSwitchToCredential*/, isLandscape); Loading Loading
core/java/android/hardware/biometrics/flags.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -54,3 +54,10 @@ flag { description: "This flag is for API changes related to Identity Check" bug: "373424727" } flag { name: "private_space_bp" namespace: "biometrics_framework" description: "Feature flag for biometric prompt improvements in private space" bug: "365554098" }
packages/SystemUI/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ <uses-permission android:name="android.permission.READ_WALLPAPER_INTERNAL" /> <!-- Used to read storage for all users --> <uses-permission android:name="android.permission.STORAGE_INTERNAL" /> <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt +83 −51 Original line number Diff line number Diff line Loading @@ -3,7 +3,9 @@ package com.android.systemui.biometrics.domain.interactor import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyResourcesManager import android.content.pm.UserInfo import android.hardware.biometrics.Flags import android.os.UserManager import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils Loading Loading @@ -33,6 +35,7 @@ import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit private const val USER_ID = 22 private const val OWNER_ID = 10 private const val OPERATION_ID = 100L private const val MAX_ATTEMPTS = 5 Loading Loading @@ -67,7 +70,7 @@ class CredentialInteractorImplTest : SysuiTestCase() { lockPatternUtils, userManager, devicePolicyManager, systemClock systemClock, ) } Loading Loading @@ -115,12 +118,35 @@ class CredentialInteractorImplTest : SysuiTestCase() { @Test fun pinCredentialWhenBadAndThrottled() = pinCredential(badCredential(timeout = 5_000)) private fun pinCredential(result: VerifyCredentialResponse) = runTest { @EnableFlags(Flags.FLAG_PRIVATE_SPACE_BP) @Test fun pinCredentialTiedProfileWhenGood() = pinCredential(goodCredential(), OWNER_ID) @EnableFlags(Flags.FLAG_PRIVATE_SPACE_BP) @Test fun pinCredentialTiedProfileWhenBad() = pinCredential(badCredential(), OWNER_ID) @EnableFlags(Flags.FLAG_PRIVATE_SPACE_BP) @Test fun pinCredentialTiedProfileWhenBadAndThrottled() = pinCredential(badCredential(timeout = 5_000), OWNER_ID) private fun pinCredential(result: VerifyCredentialResponse, credentialOwner: Int = USER_ID) = runTest { val usedAttempts = 1 whenever(lockPatternUtils.getCurrentFailedPasswordAttempts(eq(USER_ID))) .thenReturn(usedAttempts) whenever(lockPatternUtils.verifyCredential(any(), eq(USER_ID), anyInt())).thenReturn(result) whenever(lockPatternUtils.verifyGatekeeperPasswordHandle(anyLong(), anyLong(), eq(USER_ID))) whenever(lockPatternUtils.verifyCredential(any(), eq(USER_ID), anyInt())) .thenReturn(result) whenever(lockPatternUtils.verifyTiedProfileChallenge(any(), eq(USER_ID), anyInt())) .thenReturn(result) whenever( lockPatternUtils.verifyGatekeeperPasswordHandle( anyLong(), anyLong(), eq(USER_ID), ) ) .thenReturn(result) whenever(lockPatternUtils.setLockoutAttemptDeadline(anyInt(), anyInt())).thenAnswer { systemClock.elapsedRealtime() + (it.arguments[1] as Int) Loading @@ -130,7 +156,10 @@ class CredentialInteractorImplTest : SysuiTestCase() { // checks prevents the method from returning val statusList = mutableListOf<CredentialStatus>() interactor .verifyCredential(pinRequest(), LockscreenCredential.createPin("1234")) .verifyCredential( pinRequest(credentialOwner), LockscreenCredential.createPin("1234"), ) .toList(statusList) val last = statusList.removeLastOrNull() Loading @@ -154,10 +183,13 @@ class CredentialInteractorImplTest : SysuiTestCase() { // messages are in the throttled errors, so the final Error.error is empty assertThat(failedResult.error).isEmpty() assertThat(statusList).isNotEmpty() assertThat(statusList.filterIsInstance(CredentialStatus.Fail.Throttled::class.java)) assertThat( statusList.filterIsInstance(CredentialStatus.Fail.Throttled::class.java) ) .hasSize(statusList.size) verify(lockPatternUtils).setLockoutAttemptDeadline(eq(USER_ID), eq(result.timeout)) verify(lockPatternUtils) .setLockoutAttemptDeadline(eq(USER_ID), eq(result.timeout)) } else { // failed assertThat(failedResult.error) .matches(Regex("(.*)try again(.*)", RegexOption.IGNORE_CASE).toPattern()) Loading Loading @@ -212,11 +244,11 @@ class CredentialInteractorImplTest : SysuiTestCase() { } } private fun pinRequest(): BiometricPromptRequest.Credential.Pin = private fun pinRequest(credentialOwner: Int = USER_ID): BiometricPromptRequest.Credential.Pin = BiometricPromptRequest.Credential.Pin( promptInfo(), BiometricUserInfo(USER_ID), BiometricOperationInfo(OPERATION_ID) BiometricUserInfo(userId = USER_ID, deviceCredentialOwnerId = credentialOwner), BiometricOperationInfo(OPERATION_ID), ) private fun goodCredential( Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt +6 −4 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { private val fingerprintRepository = FakeFingerprintPropertyRepository() private val promptRepository = FakePromptRepository() private val fakeExecutor = FakeExecutor(FakeSystemClock()) private val credentialInteractor = FakeCredentialInteractor() private lateinit var displayStateRepository: FakeDisplayStateRepository private lateinit var displayRepository: FakeDisplayRepository Loading @@ -99,8 +100,9 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { PromptSelectorInteractorImpl( fingerprintRepository, displayStateInteractor, credentialInteractor, promptRepository, lockPatternUtils lockPatternUtils, ) } Loading Loading @@ -134,13 +136,13 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { testScope.runTest { useBiometricsAndReset( allowCredentialFallback = true, setComponentNameForConfirmDeviceCredentialActivity = true setComponentNameForConfirmDeviceCredentialActivity = true, ) } private fun TestScope.useBiometricsAndReset( allowCredentialFallback: Boolean, setComponentNameForConfirmDeviceCredentialActivity: Boolean = false setComponentNameForConfirmDeviceCredentialActivity: Boolean = false, ) { setUserCredentialType(isPassword = true) Loading Loading @@ -357,7 +359,7 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { private fun setPrompt( info: PromptInfo = basicPromptInfo(), onSwitchToCredential: Boolean = false onSwitchToCredential: Boolean = false, ) { interactor.setPrompt( info, Loading
packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +1 −1 Original line number Diff line number Diff line Loading @@ -323,7 +323,7 @@ public class AuthContainerView extends LinearLayout final boolean isLandscape = mContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; mPromptSelectorInteractorProvider = promptSelectorInteractorProvider; mPromptSelectorInteractorProvider.get().setPrompt(mConfig.mPromptInfo, mEffectiveUserId, mPromptSelectorInteractorProvider.get().setPrompt(mConfig.mPromptInfo, mConfig.mUserId, getRequestId(), biometricModalities, mConfig.mOperationId, mConfig.mOpPackageName, false /*onSwitchToCredential*/, isLandscape); Loading