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

Commit b833b503 authored by Chandru S's avatar Chandru S Committed by Automerger Merge Worker
Browse files

Merge "Add FP running state and FP sensor type information to...

Merge "Add FP running state and FP sensor type information to DeviceEntryFPAuthRepository" into udc-dev am: 8b884802

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22254595



Change-Id: I93bdf406123ed02b886cafd621326a1d46ade1df
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 1f376b2a 8b884802
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -2476,8 +2476,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
     * not enrolled udfps. This may be false if called before onAllAuthenticatorsRegistered.
     */
    public boolean isUdfpsSupported() {
        return mAuthController.getUdfpsProps() != null
                && !mAuthController.getUdfpsProps().isEmpty();
        return mAuthController.isUdfpsSupported();
    }

    /**
@@ -2492,8 +2491,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
     * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered.
     */
    public boolean isSfpsSupported() {
        return mAuthController.getSfpsProps() != null
                && !mAuthController.getSfpsProps().isEmpty();
        return mAuthController.isSfpsSupported();
    }

    /**
+30 −0
Original line number Diff line number Diff line
@@ -984,6 +984,36 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
        return mSidefpsProps;
    }

    /**
     * @return true if udfps HW is supported on this device. Can return true even if the user has
     * not enrolled udfps. This may be false if called before onAllAuthenticatorsRegistered.
     */
    public boolean isUdfpsSupported() {
        return getUdfpsProps() != null && !getUdfpsProps().isEmpty();
    }

    /**
     * @return true if sfps HW is supported on this device. Can return true even if the user has
     * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered.
     */
    public boolean isSfpsSupported() {
        return getSfpsProps() != null && !getSfpsProps().isEmpty();
    }

    /**
     * @return true if rear fps HW is supported on this device. Can return true even if the user has
     * not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered.
     */
    public boolean isRearFpsSupported() {
        for (FingerprintSensorPropertiesInternal prop: mFpProps) {
            if (prop.sensorType == TYPE_REAR) {
                return true;
            }
        }
        return false;
    }


    private String getErrorString(@Modality int modality, int error, int vendorCode) {
        switch (modality) {
            case TYPE_FACE:
+46 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.hardware.biometrics.BiometricSourceType
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.Dumpable
import com.android.systemui.biometrics.AuthController
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
@@ -29,6 +30,7 @@ import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
@@ -37,6 +39,17 @@ import kotlinx.coroutines.flow.stateIn
interface DeviceEntryFingerprintAuthRepository {
    /** Whether the device entry fingerprint auth is locked out. */
    val isLockedOut: StateFlow<Boolean>

    /**
     * Whether the fingerprint sensor is currently listening, this doesn't mean that the user is
     * actively authenticating.
     */
    val isRunning: Flow<Boolean>

    /**
     * Fingerprint sensor type present on the device, null if fingerprint sensor is not available.
     */
    val availableFpSensorType: BiometricType?
}

/**
@@ -50,6 +63,7 @@ interface DeviceEntryFingerprintAuthRepository {
class DeviceEntryFingerprintAuthRepositoryImpl
@Inject
constructor(
    val authController: AuthController,
    val keyguardUpdateMonitor: KeyguardUpdateMonitor,
    @Application scope: CoroutineScope,
    dumpManager: DumpManager,
@@ -63,6 +77,12 @@ constructor(
        pw.println("isLockedOut=${isLockedOut.value}")
    }

    override val availableFpSensorType: BiometricType?
        get() =
            if (authController.isUdfpsSupported) BiometricType.UNDER_DISPLAY_FINGERPRINT
            else if (authController.isSfpsSupported) BiometricType.SIDE_FINGERPRINT
            else if (authController.isRearFpsSupported) BiometricType.REAR_FINGERPRINT else null

    override val isLockedOut: StateFlow<Boolean> =
        conflatedCallbackFlow {
                val sendLockoutUpdate =
@@ -89,6 +109,32 @@ constructor(
            }
            .stateIn(scope, started = SharingStarted.Eagerly, initialValue = false)

    override val isRunning: Flow<Boolean>
        get() = conflatedCallbackFlow {
            val callback =
                object : KeyguardUpdateMonitorCallback() {
                    override fun onBiometricRunningStateChanged(
                        running: Boolean,
                        biometricSourceType: BiometricSourceType?
                    ) {
                        if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
                            trySendWithFailureLogging(
                                running,
                                TAG,
                                "Fingerprint running state changed"
                            )
                        }
                    }
                }
            keyguardUpdateMonitor.registerCallback(callback)
            trySendWithFailureLogging(
                keyguardUpdateMonitor.isFingerprintDetectionRunning,
                TAG,
                "Initial fingerprint running state"
            )
            awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
        }

    companion object {
        const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl"
    }
+3 −8
Original line number Diff line number Diff line
@@ -1360,9 +1360,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
    public void startsListeningForSfps_whenKeyguardIsVisible_ifRequireInteractiveToAuthEnabled()
            throws RemoteException {
        // SFPS supported and enrolled
        final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
        props.add(newFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON));
        when(mAuthController.getSfpsProps()).thenReturn(props);
        when(mAuthController.isSfpsSupported()).thenReturn(true);
        when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);

        // WHEN require interactive to auth is disabled, and keyguard is not awake
@@ -1401,9 +1399,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
    public void notListeningForSfps_whenGoingToSleep_ifRequireInteractiveToAuthEnabled()
            throws RemoteException {
        // GIVEN SFPS supported and enrolled
        final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
        props.add(newFingerprintSensorPropertiesInternal(TYPE_POWER_BUTTON));
        when(mAuthController.getSfpsProps()).thenReturn(props);
        when(mAuthController.isSfpsSupported()).thenReturn(true);
        when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);

        // GIVEN Preconditions for sfps auth to run
@@ -2843,8 +2839,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
    }

    private void givenUdfpsSupported() {
        Assert.assertFalse(mFingerprintSensorProperties.isEmpty());
        when(mAuthController.getUdfpsProps()).thenReturn(mFingerprintSensorProperties);
        when(mAuthController.isUdfpsSupported()).thenReturn(true);
        Assert.assertTrue(mKeyguardUpdateMonitor.isUdfpsSupported());
    }

+68 −4
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dump.DumpManager
import com.android.systemui.util.mockito.whenever
@@ -37,6 +38,7 @@ import org.junit.runners.JUnit4
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

@@ -46,7 +48,9 @@ import org.mockito.MockitoAnnotations
class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
    @Mock private lateinit var dumpManager: DumpManager
    @Captor private lateinit var callbackCaptor: ArgumentCaptor<KeyguardUpdateMonitorCallback>
    @Mock private lateinit var authController: AuthController
    @Captor
    private lateinit var updateMonitorCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>

    private lateinit var testScope: TestScope

@@ -59,6 +63,7 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {

        underTest =
            DeviceEntryFingerprintAuthRepositoryImpl(
                authController,
                keyguardUpdateMonitor,
                testScope.backgroundScope,
                dumpManager,
@@ -67,7 +72,7 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {

    @After
    fun tearDown() {
        verify(keyguardUpdateMonitor).removeCallback(callbackCaptor.value)
        //        verify(keyguardUpdateMonitor).removeCallback(updateMonitorCallback.value)
    }

    @Test
@@ -76,8 +81,8 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
            val isLockedOutValue = collectLastValue(underTest.isLockedOut)
            runCurrent()

            verify(keyguardUpdateMonitor).registerCallback(callbackCaptor.capture())
            val callback = callbackCaptor.value
            verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
            val callback = updateMonitorCallback.value
            whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(true)

            callback.onLockedOutStateChanged(BiometricSourceType.FACE)
@@ -90,4 +95,63 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
            callback.onLockedOutStateChanged(BiometricSourceType.FINGERPRINT)
            assertThat(isLockedOutValue()).isFalse()
        }

    @Test
    fun fpRunningStateIsPropagated() =
        testScope.runTest {
            val isRunning = collectLastValue(underTest.isRunning)
            whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning).thenReturn(true)

            // Initial value is available
            assertThat(isRunning()).isTrue()

            verify(keyguardUpdateMonitor, atLeastOnce())
                .registerCallback(updateMonitorCallback.capture())
            invokeOnCallback {
                it.onBiometricRunningStateChanged(false, BiometricSourceType.FINGERPRINT)
            }

            assertThat(isRunning()).isFalse()

            invokeOnCallback { it.onBiometricRunningStateChanged(true, BiometricSourceType.FACE) }

            assertThat(isRunning()).isFalse()

            updateMonitorCallback.value.onBiometricRunningStateChanged(
                true,
                BiometricSourceType.FINGERPRINT
            )
            assertThat(isRunning()).isTrue()
        }

    private fun invokeOnCallback(action: (KeyguardUpdateMonitorCallback) -> Unit) {
        updateMonitorCallback.allValues.forEach { action(it) }
    }

    @Test
    fun enabledFingerprintTypeProvidesTheCorrectOutput() =
        testScope.runTest {
            whenever(authController.isSfpsSupported).thenReturn(true)
            whenever(authController.isUdfpsSupported).thenReturn(false)
            whenever(authController.isRearFpsSupported).thenReturn(false)

            assertThat(underTest.availableFpSensorType).isEqualTo(BiometricType.SIDE_FINGERPRINT)

            whenever(authController.isSfpsSupported).thenReturn(false)
            whenever(authController.isUdfpsSupported).thenReturn(true)
            whenever(authController.isRearFpsSupported).thenReturn(false)

            assertThat(underTest.availableFpSensorType)
                .isEqualTo(BiometricType.UNDER_DISPLAY_FINGERPRINT)

            whenever(authController.isSfpsSupported).thenReturn(false)
            whenever(authController.isUdfpsSupported).thenReturn(false)
            whenever(authController.isRearFpsSupported).thenReturn(true)

            assertThat(underTest.availableFpSensorType).isEqualTo(BiometricType.REAR_FINGERPRINT)

            whenever(authController.isRearFpsSupported).thenReturn(false)

            assertThat(underTest.availableFpSensorType).isNull()
        }
}
Loading