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

Commit 18759aec authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I471bb058,I06abe274,Ia4375434,I3575ac29 into main

* changes:
  Implement face auth error try again button
  Implement face auth success confirm button
  Secure lock device implementation for legacy keyguard
  Bouncer message updates for secure lock device
parents 5abaab5c d6793291
Loading
Loading
Loading
Loading
+80 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.keyguard
import android.app.admin.DevicePolicyManager
import android.content.res.Configuration
import android.media.AudioManager
import android.platform.test.annotations.EnableFlags
import android.security.Flags.FLAG_SECURE_LOCK_DEVICE
import android.telephony.TelephonyManager
import android.testing.TestableLooper.RunWithLooper
import android.testing.TestableResources
@@ -73,6 +75,8 @@ import com.android.systemui.scene.shared.model.FakeSceneDataSource
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.securelockdevice.data.repository.fakeSecureLockDeviceRepository
import com.android.systemui.securelockdevice.domain.interactor.secureLockDeviceInteractor
import com.android.systemui.shade.domain.interactor.enableSingleShade
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.DevicePostureController
@@ -94,6 +98,7 @@ import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.util.wrapper.LockPatternCheckerWrapper
import com.android.systemui.window.domain.interactor.windowRootViewBlurInteractor
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -166,6 +171,9 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
    @Mock private lateinit var bouncerInteractor: BouncerInteractor
    @Mock private lateinit var lockPatternChecker: LockPatternCheckerWrapper

    @Captor
    private lateinit var keyguardUpdateMonitorCallbackCaptor:
        ArgumentCaptor<KeyguardUpdateMonitorCallback>
    @Captor
    private lateinit var swipeListenerArgumentCaptor:
        ArgumentCaptor<KeyguardSecurityContainer.SwipeListener>
@@ -196,7 +204,6 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
        testableResources.resources.configuration.orientation = Configuration.ORIENTATION_UNDEFINED
        whenever(view.context).thenReturn(mContext)
        whenever(view.resources).thenReturn(testableResources.resources)

        val lp = FrameLayout.LayoutParams(/* width= */ 0, /* height= */ 0)
        lp.gravity = 0
        whenever(view.layoutParams).thenReturn(lp)
@@ -297,6 +304,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
                { deviceEntryInteractor },
                { kosmos.windowRootViewBlurInteractor },
                { bouncerInteractor },
                { kosmos.secureLockDeviceInteractor },
            )
    }

@@ -686,6 +694,37 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
        verify(viewFlipperController).getSecurityView(eq(SecurityMode.SimPin), any(), any())
    }

    @Test
    @DisableSceneContainer
    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    fun keyguardDoesNotDismiss_onPrimaryAuthSuccess_ifSecureLockDeviceEnabled() =
        kosmos.testScope.runTest {
            val isSecureLockDeviceEnabled by
                collectLastValue(kosmos.secureLockDeviceInteractor.isSecureLockDeviceEnabled)

            kosmos.fakeSecureLockDeviceRepository.onSecureLockDeviceEnabled()
            runCurrent()

            assertThat(isSecureLockDeviceEnabled).isTrue()

            // GIVEN current security mode has been set to PIN
            underTest.showSecurityScreen(SecurityMode.PIN)

            // WHEN a primary auth success requests to dismiss the security screen
            kosmos.fakeSecureLockDeviceRepository.onSuccessfulPrimaryAuth()
            val keyguardDone =
                underTest.showNextSecurityScreenOrFinish(
                    /* authenticated= */ true,
                    TARGET_USER_ID,
                    /* bypassSecondaryLockScreen= */ true,
                    SecurityMode.PIN,
                )
            runCurrent()

            // THEN no action has happened, which will not dismiss the security screens
            assertThat(keyguardDone).isEqualTo(false)
        }

    @Test
    @DisableSceneContainer
    fun onSwipeUp_forwardsItToFaceAuthInteractor() {
@@ -882,6 +921,38 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
        verify(view).updateSecurityViewFlipper()
    }

    @Test
    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @DisableSceneContainer
    fun reinflateViewFlipper_onSecureLockDeviceBiometricAuthViewShownOrInterrupted() {
        // On shown
        val onViewInflatedCallback = KeyguardSecurityViewFlipperController.OnViewInflatedCallback {}
        underTest.showSecureLockDeviceView(onViewInflatedCallback)
        verify(viewFlipperController).clearViews()
        verify(viewFlipperController)
            .getSecurityView(
                eq(SecurityMode.SecureLockDeviceBiometricAuth),
                any(),
                onViewInflatedCallbackArgumentCaptor.capture(),
            )
        onViewInflatedCallbackArgumentCaptor.value.onViewInflated(inputViewController)
        verify(view).updateSecurityViewFlipper()

        clearInvocations(view)
        clearInvocations(viewFlipperController)

        // On hidden (e.g. back gesture, dozing, biometric lockout, etc)
        kosmos.fakeSecureLockDeviceRepository.setRequiresPrimaryAuthForSecureLockDevice(true)

        underTest.onSecureLockDeviceBiometricAuthInterrupted(onViewInflatedCallback)
        verify(viewFlipperController).clearViews()
        verify(viewFlipperController)
            .getSecurityView(any(), any(), onViewInflatedCallbackArgumentCaptor.capture())
        onViewInflatedCallbackArgumentCaptor.value.onViewInflated(inputViewController)
        verify(view).updateSecurityViewFlipper()
        verify(viewMediatorCallback).resetKeyguard()
    }

    @Test
    @DisableSceneContainer
    fun setExpansion_setsAlpha() {
@@ -1113,6 +1184,14 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
            )
    }

    private val registeredKeyguardUpdateMonitorCallback: KeyguardUpdateMonitorCallback
        get() {
            underTest.onViewAttached()
            verify(keyguardUpdateMonitor)
                .registerCallback(keyguardUpdateMonitorCallbackCaptor.capture())
            return keyguardUpdateMonitorCallbackCaptor.value
        }

    private val registeredSwipeListener: KeyguardSecurityContainer.SwipeListener
        get() {
            underTest.onViewAttached()
+7 −0
Original line number Diff line number Diff line
@@ -117,6 +117,13 @@ class AuthenticationRepositoryTest : SysuiTestCase() {
            mobileConnectionsRepository.fake.isAnySimSecure.value = true
            assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Sim)
            assertThat(underTest.getAuthenticationMethod()).isEqualTo(AuthenticationMethodModel.Sim)

            setSecurityModeAndDispatchBroadcast(
                KeyguardSecurityModel.SecurityMode.SecureLockDeviceBiometricAuth
            )
            assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Biometric)
            assertThat(underTest.getAuthenticationMethod())
                .isEqualTo(AuthenticationMethodModel.Biometric)
        }

    @Test
+97 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.bouncer.domain.interactor

import android.platform.test.annotations.EnableFlags
import android.security.Flags.FLAG_SECURE_LOCK_DEVICE
import android.telecom.TelecomManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -27,14 +29,23 @@ import com.android.internal.util.emergencyAffordanceManager
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Pin
import com.android.systemui.biometrics.data.repository.facePropertyRepository
import com.android.systemui.biometrics.shared.model.BiometricModality
import com.android.systemui.biometrics.shared.model.FaceSensorInfo
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel
import com.android.systemui.bouncer.shared.model.SecureLockDeviceBouncerActionButtonModel
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.securelockdevice.data.repository.fakeSecureLockDeviceRepository
import com.android.systemui.securelockdevice.ui.viewmodel.secureLockDeviceBiometricAuthContentViewModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
@@ -44,6 +55,7 @@ import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.whenever
import com.android.telecom.telecomManager
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -222,6 +234,91 @@ class BouncerActionButtonInteractorTest : SysuiTestCase() {
            assertThat(actionButton).isNull()
        }

    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @Test
    fun showsConfirmButtonAfterFaceAuthSuccessInSecureLockDevice() =
        testScope.runTest {
            val underTest = kosmos.bouncerActionButtonInteractor
            val secureLockDeviceActionButton by
                collectLastValue(underTest.secureLockDeviceActionButton)
            val activateViewModelJob = launch {
                kosmos.secureLockDeviceBiometricAuthContentViewModel.activate()
            }
            kosmos.fakeAuthenticationRepository.setAuthenticationMethod(Pin)
            kosmos.fakeSecureLockDeviceRepository.onSecureLockDeviceEnabled()
            runCurrent()

            // After PIN auth
            kosmos.fakeSecureLockDeviceRepository.onSuccessfulPrimaryAuth()
            runCurrent()

            // After face auth success
            kosmos.secureLockDeviceBiometricAuthContentViewModel.showAuthenticated(
                modality = BiometricModality.Face
            )
            runCurrent()

            assertThat(
                    secureLockDeviceActionButton
                        is
                        SecureLockDeviceBouncerActionButtonModel.ConfirmStrongBiometricAuthButtonModel
                )
                .isTrue()
            activateViewModelJob.cancel()
        }

    @EnableFlags(FLAG_SECURE_LOCK_DEVICE)
    @Test
    fun showsTryAgainButtonOnFaceAuthFailure_hidesAfterButtonClicked_duringSecureLockDevice() =
        testScope.runTest {
            val underTest = kosmos.bouncerActionButtonInteractor
            val secureLockDeviceActionButton by
                collectLastValue(underTest.secureLockDeviceActionButton)
            val activateViewModelJob = launch {
                kosmos.secureLockDeviceBiometricAuthContentViewModel.activate()
            }
            kosmos.fakeAuthenticationRepository.setAuthenticationMethod(Pin)
            kosmos.fakeSecureLockDeviceRepository.onSecureLockDeviceEnabled()
            runCurrent()

            // Only face auth is allowed & enrolled to allow retry
            kosmos.biometricSettingsRepository.setIsFaceAuthCurrentlyAllowed(true)
            kosmos.biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
            kosmos.facePropertyRepository.setSensorInfo(
                FaceSensorInfo(id = 0, strength = SensorStrength.STRONG)
            )
            kosmos.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
            runCurrent()

            // After PIN auth
            kosmos.fakeSecureLockDeviceRepository.onSuccessfulPrimaryAuth()
            runCurrent()

            // After face auth error
            kosmos.secureLockDeviceBiometricAuthContentViewModel.showTemporaryError(
                authenticateAfterError = false,
                failedModality = BiometricModality.Face,
            )
            runCurrent()

            assertThat(
                    secureLockDeviceActionButton
                        is SecureLockDeviceBouncerActionButtonModel.TryAgainButtonModel
                )
                .isTrue()

            // After clicking try again button
            kosmos.secureLockDeviceBiometricAuthContentViewModel.onTryAgainButtonClicked()
            runCurrent()

            assertThat(
                    secureLockDeviceActionButton
                        is SecureLockDeviceBouncerActionButtonModel.TryAgainButtonModel
                )
                .isFalse()
            activateViewModelJob.cancel()
        }

    companion object {
        private const val MESSAGE_EMERGENCY_CALL = "Emergency"
        private const val MESSAGE_RETURN_TO_CALL = "Return to call"
+465 −67

File changed.

Preview size limit exceeded, changes collapsed.

+297 −2

File changed.

Preview size limit exceeded, changes collapsed.

Loading