Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 76d28152 authored by Austin Delgado's avatar Austin Delgado
Browse files

Fix Work Profile Biometric Prompt Credential crash

Test: AuthContainerViewTest
Test: CredentialInteractorImplTest
Bug: 390475533
Bug: 384084701
Flag: EXEMPT bugfix

Change-Id: I1bf3e6cf414c81e63279be917f9c646831e3273c
parent 60e12464
Loading
Loading
Loading
Loading
+7 −10
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
package com.android.systemui.biometrics

import android.app.ActivityTaskManager
import android.app.admin.DevicePolicyManager
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.hardware.biometrics.BiometricAuthenticator
@@ -43,6 +42,8 @@ import androidx.test.filters.SmallTest
import com.android.app.viewcapture.ViewCapture
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN
import com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN
import com.android.launcher3.icons.IconProvider
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
@@ -432,8 +433,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
                .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> isButtonClicked = true }
                .build()

        val container =
            initializeFingerprintContainer(contentViewWithMoreOptionsButton = contentView)
        val container = initializeFingerprintContainer()

        waitForIdleSync()

@@ -488,8 +488,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
                .build()
        val container =
            initializeFingerprintContainer(
                authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
                contentViewWithMoreOptionsButton = contentView,
                authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
            )
        waitForIdleSync()

@@ -500,8 +499,8 @@ 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.getCredentialTypeForUser(eq(200)))
            .thenReturn(CREDENTIAL_TYPE_PATTERN)

        val container =
            initializeFingerprintContainer(
@@ -578,8 +577,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
        addToView: Boolean = true
    ): TestAuthContainerView {
        whenever(userManager.getCredentialOwnerProfile(anyInt())).thenReturn(20)
        whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(20)))
            .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC)
        whenever(lockPatternUtils.getCredentialTypeForUser(eq(20))).thenReturn(CREDENTIAL_TYPE_PIN)

        // 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
@@ -599,7 +597,6 @@ open class AuthContainerViewTest : SysuiTestCase() {
        authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
        addToView: Boolean = true,
        verticalListContentView: PromptVerticalListContentView? = null,
        contentViewWithMoreOptionsButton: PromptContentViewWithMoreOptionsButton? = null,
    ) =
        initializeContainer(
            TestAuthContainerView(
+5 −5
Original line number Diff line number Diff line
@@ -135,9 +135,9 @@ class CredentialInteractorImplTest : SysuiTestCase() {
    private fun pinCredential(result: VerifyCredentialResponse, credentialOwner: Int = USER_ID) =
        runTest {
            val usedAttempts = 1
            whenever(lockPatternUtils.getCurrentFailedPasswordAttempts(eq(USER_ID)))
            whenever(lockPatternUtils.getCurrentFailedPasswordAttempts(eq(credentialOwner)))
                .thenReturn(usedAttempts)
            whenever(lockPatternUtils.verifyCredential(any(), eq(USER_ID), anyInt()))
            whenever(lockPatternUtils.verifyCredential(any(), eq(credentialOwner), anyInt()))
                .thenReturn(result)
            whenever(lockPatternUtils.verifyTiedProfileChallenge(any(), eq(USER_ID), anyInt()))
                .thenReturn(result)
@@ -170,7 +170,7 @@ class CredentialInteractorImplTest : SysuiTestCase() {
                assertThat(successfulResult).isNotNull()
                assertThat(successfulResult!!.hat).isEqualTo(result.gatekeeperHAT)

                verify(lockPatternUtils).userPresent(eq(USER_ID))
                verify(lockPatternUtils).userPresent(eq(credentialOwner))
                verify(lockPatternUtils)
                    .removeGatekeeperPasswordHandle(eq(result.gatekeeperPasswordHandle))
            } else {
@@ -190,13 +190,13 @@ class CredentialInteractorImplTest : SysuiTestCase() {
                        .hasSize(statusList.size)

                    verify(lockPatternUtils)
                        .setLockoutAttemptDeadline(eq(USER_ID), eq(result.timeout))
                        .setLockoutAttemptDeadline(eq(credentialOwner), eq(result.timeout))
                } else { // failed
                    assertThat(failedResult.error)
                        .matches(Regex("(.*)try again(.*)", RegexOption.IGNORE_CASE).toPattern())
                    assertThat(statusList).isEmpty()

                    verify(lockPatternUtils).reportFailedPasswordAttempt(eq(USER_ID))
                    verify(lockPatternUtils).reportFailedPasswordAttempt(eq(credentialOwner))
                }
            }
        }
+9 −17
Original line number Diff line number Diff line
@@ -17,13 +17,6 @@ package com.android.systemui.biometrics

import android.Manifest
import android.app.ActivityTaskManager
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Bitmap
@@ -44,6 +37,9 @@ import android.view.WindowMetrics
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityManager
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
import com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN
import com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN
import com.android.systemui.biometrics.shared.model.PromptKind

object Utils {
@@ -80,7 +76,7 @@ object Utils {
        view.notifySubtreeAccessibilityStateChanged(
            view,
            view,
            AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE
            AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE,
        )
    }

@@ -94,14 +90,10 @@ object Utils {

    @JvmStatic
    fun getCredentialType(utils: LockPatternUtils, userId: Int): PromptKind =
        when (utils.getKeyguardStoredPasswordQuality(userId)) {
            PASSWORD_QUALITY_SOMETHING -> PromptKind.Pattern
            PASSWORD_QUALITY_NUMERIC,
            PASSWORD_QUALITY_NUMERIC_COMPLEX -> PromptKind.Pin
            PASSWORD_QUALITY_ALPHABETIC,
            PASSWORD_QUALITY_ALPHANUMERIC,
            PASSWORD_QUALITY_COMPLEX,
            PASSWORD_QUALITY_MANAGED -> PromptKind.Password
        when (utils.getCredentialTypeForUser(userId)) {
            CREDENTIAL_TYPE_PATTERN -> PromptKind.Pattern
            CREDENTIAL_TYPE_PIN -> PromptKind.Pin
            CREDENTIAL_TYPE_PASSWORD -> PromptKind.Password
            else -> PromptKind.Password
        }

@@ -112,7 +104,7 @@ object Utils {
    @JvmStatic
    fun <T : SensorPropertiesInternal> findFirstSensorProperties(
        properties: List<T>?,
        sensorIds: IntArray
        sensorIds: IntArray,
    ): T? = properties?.firstOrNull { sensorIds.contains(it.sensorId) }

    @JvmStatic
+2 −3
Original line number Diff line number Diff line
@@ -72,10 +72,9 @@ constructor(
        // Request LockSettingsService to return the Gatekeeper Password in the
        // VerifyCredentialResponse so that we can request a Gatekeeper HAT with the
        // Gatekeeper Password and operationId.
        var effectiveUserId = request.userInfo.deviceCredentialOwnerId
        val effectiveUserId = request.userInfo.deviceCredentialOwnerId
        val response =
            if (Flags.privateSpaceBp() && effectiveUserId != request.userInfo.userId) {
                effectiveUserId = request.userInfo.userId
                lockPatternUtils.verifyTiedProfileChallenge(
                    credential,
                    request.userInfo.userId,
@@ -101,7 +100,7 @@ constructor(
                lockPatternUtils.verifyGatekeeperPasswordHandle(
                    pwHandle,
                    request.operationInfo.gatekeeperChallenge,
                    effectiveUserId,
                    request.userInfo.userId,
                )
            val hat = gkResponse.gatekeeperHAT
            lockPatternUtils.removeGatekeeperPasswordHandle(pwHandle)
+6 −1
Original line number Diff line number Diff line
@@ -126,7 +126,12 @@ constructor(
                is PromptKind.Biometric ->
                    BiometricPromptRequest.Biometric(
                        info = promptInfo,
                        userInfo = BiometricUserInfo(userId = userId),
                        userInfo =
                            BiometricUserInfo(
                                userId = userId,
                                deviceCredentialOwnerId =
                                    credentialInteractor.getCredentialOwnerOrSelfId(userId),
                            ),
                        operationInfo = BiometricOperationInfo(gatekeeperChallenge = challenge),
                        modalities = kind.activeModalities,
                        opPackageName = opPackageName,
Loading