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

Commit 56614a85 authored by Austin Delgado's avatar Austin Delgado
Browse files

Add metrics within Biometric Prompt

Bug: 429187906
Test: atest AuthControllerTest
Test: atest PromptSelectorInteractorTest
Flag: EXEMPT bugfix
Change-Id: I9e02d45e7d9784dfdaa018fcabafbb697f70f236
parent 8a7128cf
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -824,7 +824,7 @@ public class AuthControllerTest extends SysuiTestCase {
        showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);

        // THEN callback should be received
        verify(callback).onBiometricPromptShown();
        verify(callback).onBiometricPromptShown(any());
    }

    @Test
@@ -840,7 +840,7 @@ public class AuthControllerTest extends SysuiTestCase {
                mAuthController.mCurrentDialog.getRequestId());

        // THEN callback should be received
        verify(callback).onBiometricPromptDismissed();
        verify(callback).onBiometricPromptDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
    }

    @Test
@@ -854,7 +854,8 @@ public class AuthControllerTest extends SysuiTestCase {
        mAuthController.hideAuthenticationDialog(mAuthController.mCurrentDialog.getRequestId());

        // THEN callback should be received
        verify(callback).onBiometricPromptDismissed();
        verify(callback).onBiometricPromptDismissed(
                BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
    }

    @Test
+3 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.biometrics.data.repository

import android.hardware.biometrics.BiometricPrompt
import android.hardware.biometrics.PromptInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -82,11 +83,11 @@ class PromptRepositoryImplTest : SysuiTestCase() {
            withArgCaptor<AuthController.Callback> {
                verify(authController).addCallback(capture())

                value.onBiometricPromptShown()
                value.onBiometricPromptShown(PromptInfo())
                runCurrent()
                assertThat(values).containsExactly(true, true)

                value.onBiometricPromptDismissed()
                value.onBiometricPromptDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL)
                runCurrent()
                assertThat(values).containsExactly(true, true, false).inOrder()

+88 −0
Original line number Diff line number Diff line
@@ -25,11 +25,13 @@ import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.PromptVerticalListContentView
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
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.SysuiTestCase
import com.android.systemui.biometrics.BiometricPromptLogger
import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
@@ -42,6 +44,8 @@ import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.display.domain.interactor.DisplayStateInteractor
import com.android.systemui.display.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.display.shared.model.DisplayRotation
import com.android.systemui.log.SessionTracker
import com.android.systemui.shared.system.SysUiStatsLog
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
@@ -55,6 +59,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.eq
import org.mockito.kotlin.verify

@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -77,6 +83,9 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() {

    @Mock private lateinit var lockPatternUtils: LockPatternUtils
    @Mock private lateinit var biometricManager: BiometricManager
    @Mock private lateinit var sessionTracker: SessionTracker
    @Mock private lateinit var biometricPromptLogger: BiometricPromptLogger
    @Mock private lateinit var instanceId: InstanceId

    private val testScope = TestScope()
    private val fingerprintRepository = FakeFingerprintPropertyRepository()
@@ -110,7 +119,11 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() {
                lockPatternUtils,
                biometricManager,
                testScope.backgroundScope,
                sessionTracker,
                biometricPromptLogger,
            )

        whenever(sessionTracker.getSessionId(any())).thenReturn(instanceId)
    }

    private fun basicPromptInfo() =
@@ -303,6 +316,81 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() {
            verifyUnset()
        }

    @Test
    fun switchToCredential() =
        testScope.runTest {
            setUserCredentialType(isPassword = true)

            val promptKind by collectLastValue(interactor.promptKind)
            val currentView by collectLastValue(interactor.currentView)
            assertThat(promptKind).isEqualTo(PromptKind.None)

            setPrompt(onSwitchToCredential = false)
            interactor.onSwitchToCredential()

            assertThat(promptKind).isEqualTo(PromptKind.Password)
            assertThat(currentView).isEqualTo(BiometricPromptView.CREDENTIAL)
            verify(biometricPromptLogger)
                .logPromptEvent(
                    eq(instanceId),
                    eq(
                        SysUiStatsLog
                            .BIOMETRIC_PROMPT_EVENT__EVENT__EVENT_TYPE_CREDENTIAL_VIEW_SHOWN
                    ),
                )

            interactor.resetPrompt(REQUEST_ID)
            verifyUnset()
        }

    @Test
    fun switchToFallback() =
        testScope.runTest {
            setUserCredentialType(isPassword = true)

            val promptKind by collectLastValue(interactor.promptKind)
            val currentView by collectLastValue(interactor.currentView)
            assertThat(promptKind).isEqualTo(PromptKind.None)

            setPrompt(onSwitchToCredential = false)
            interactor.onSwitchToFallback()

            assertThat(promptKind!!.isBiometric()).isTrue()
            assertThat(currentView).isEqualTo(BiometricPromptView.FALLBACK)
            verify(biometricPromptLogger)
                .logPromptEvent(
                    eq(instanceId),
                    eq(SysUiStatsLog.BIOMETRIC_PROMPT_EVENT__EVENT__EVENT_TYPE_FALLBACK_VIEW_SHOWN),
                )

            interactor.resetPrompt(REQUEST_ID)
            verifyUnset()
        }

    @Test
    fun switchToAuth() =
        testScope.runTest {
            setUserCredentialType(isPassword = true)

            val promptKind by collectLastValue(interactor.promptKind)
            val currentView by collectLastValue(interactor.currentView)
            assertThat(promptKind).isEqualTo(PromptKind.None)

            setPrompt(onSwitchToCredential = true)
            interactor.onSwitchToAuth()

            assertThat(promptKind!!.isBiometric()).isTrue()
            assertThat(currentView).isEqualTo(BiometricPromptView.BIOMETRIC)
            verify(biometricPromptLogger)
                .logPromptEvent(
                    eq(instanceId),
                    eq(SysUiStatsLog.BIOMETRIC_PROMPT_EVENT__EVENT__EVENT_TYPE_BIOMETRIC_VIEW_SHOWN),
                )

            interactor.resetPrompt(REQUEST_ID)
            verifyUnset()
        }

    @Test
    fun promptKind_isCredential_whenBiometricIsNotAllowed() =
        testScope.runTest {
+14 −4
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.PromptInfo;
import android.os.RemoteException;
import android.testing.TestableLooper;

@@ -44,6 +46,7 @@ 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.biometrics.BiometricPromptLogger;
import com.android.systemui.process.ProcessWrapper;
import com.android.systemui.statusbar.policy.KeyguardStateController;

@@ -71,6 +74,8 @@ public class SessionTrackerTest extends SysuiTestCase {
    private UiEventLogger mUiEventLogger;
    @Mock
    private ProcessWrapper mProcessWrapper;
    @Mock
    private BiometricPromptLogger mBiometricPromptLogger;

    @Captor
    ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
@@ -97,7 +102,8 @@ public class SessionTrackerTest extends SysuiTestCase {
                mKeyguardUpdateMonitor,
                mKeyguardStateController,
                mUiEventLogger,
                mProcessWrapper
                mProcessWrapper,
                mBiometricPromptLogger
        );
    }

@@ -137,7 +143,8 @@ public class SessionTrackerTest extends SysuiTestCase {
        captureAuthControllerCallback();

        // WHEN auth controller shows the biometric prompt
        mAuthControllerCallback.onBiometricPromptShown();
        PromptInfo promptInfo = new PromptInfo();
        mAuthControllerCallback.onBiometricPromptShown(promptInfo);

        // THEN the biometric prompt session has a session id
        assertNotNull(mSessionTracker.getSessionId(SESSION_BIOMETRIC_PROMPT));
@@ -145,6 +152,7 @@ public class SessionTrackerTest extends SysuiTestCase {
        // THEN session started event gets sent to status bar service
        verify(mStatusBarService).onSessionStarted(
                eq(SESSION_BIOMETRIC_PROMPT), any(InstanceId.class));
        verify(mBiometricPromptLogger).logPromptStart(any(InstanceId.class), eq(promptInfo));
    }

    @Test
@@ -154,13 +162,15 @@ public class SessionTrackerTest extends SysuiTestCase {
        captureAuthControllerCallback();

        // WHEN auth controller shows the biometric prompt and then hides it
        mAuthControllerCallback.onBiometricPromptShown();
        mAuthControllerCallback.onBiometricPromptDismissed();
        int reason = BiometricPrompt.DISMISSED_REASON_USER_CANCEL;
        mAuthControllerCallback.onBiometricPromptShown(new PromptInfo());
        mAuthControllerCallback.onBiometricPromptDismissed(reason);

        // THEN the biometric prompt session no longer has a session id
        assertNull(mSessionTracker.getSessionId(SESSION_BIOMETRIC_PROMPT));

        // THEN session end event gets sent to status bar service
        verify(mBiometricPromptLogger).logPromptEnd(any(InstanceId.class), eq(reason));
        verify(mStatusBarService).onSessionEnded(
                eq(SESSION_BIOMETRIC_PROMPT), any(InstanceId.class));
    }
+18 −4
Original line number Diff line number Diff line
@@ -232,7 +232,7 @@ public class AuthController implements
            mCurrentDialog = null;

            for (Callback cb : mCallbacks) {
                cb.onBiometricPromptDismissed();
                cb.onBiometricPromptDismissed(reason);
            }

            try {
@@ -1165,7 +1165,7 @@ public class AuthController implements

        mCurrentDialog.dismissFromSystemServer();
        for (Callback cb : mCallbacks) {
            cb.onBiometricPromptDismissed();
            cb.onBiometricPromptDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
        }

        // BiometricService will have already sent the callback to the client in this case.
@@ -1291,7 +1291,7 @@ public class AuthController implements

        mReceiver = (IBiometricSysuiReceiver) args.arg2;
        for (Callback cb : mCallbacks) {
            cb.onBiometricPromptShown();
            cb.onBiometricPromptShown(promptInfo);
        }
        mCurrentDialog = newDialog;

@@ -1345,7 +1345,7 @@ public class AuthController implements
        }

        for (Callback cb : mCallbacks) {
            cb.onBiometricPromptDismissed();
            cb.onBiometricPromptDismissed(reason);
        }

        mReceiver = null;
@@ -1457,11 +1457,25 @@ public class AuthController implements
         */
        default void onBiometricPromptShown() {}

        /**
         * Called when the biometric prompt starts showing.
         */
        default void onBiometricPromptShown(PromptInfo promptInfo) {
            onBiometricPromptShown();
        }

        /**
         * Called when the biometric prompt is no longer showing.
         */
        default void onBiometricPromptDismissed() {}

        /**
         * Called when the biometric prompt is no longer showing.
         */
        default void onBiometricPromptDismissed(@BiometricPrompt.DismissedReason int reason) {
            onBiometricPromptDismissed();
        }

        /**
         * Called when the location of the fingerprint sensor changes. The location in pixels can
         * change due to resolution changes.
Loading