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

Commit c2a6b494 authored by Jeff Pu's avatar Jeff Pu Committed by Automerger Merge Worker
Browse files

Merge "Added the view dismissed reason due to confirm button pressing" into...

Merge "Added the view dismissed reason due to confirm button pressing" into udc-dev am: f11d2163 am: 7cfad7b5

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



Change-Id: I80018438beee5b1666200d5f2b091bf35b69b24e
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents c3a45893 7cfad7b5
Loading
Loading
Loading
Loading
+11 −3
Original line number Original line Diff line number Diff line
@@ -109,6 +109,7 @@ public abstract class AuthBiometricView extends LinearLayout implements AuthBiom
        int ACTION_ERROR = 5;
        int ACTION_ERROR = 5;
        int ACTION_USE_DEVICE_CREDENTIAL = 6;
        int ACTION_USE_DEVICE_CREDENTIAL = 6;
        int ACTION_START_DELAYED_FINGERPRINT_SENSOR = 7;
        int ACTION_START_DELAYED_FINGERPRINT_SENSOR = 7;
        int ACTION_AUTHENTICATED_AND_CONFIRMED = 8;


        /**
        /**
         * When an action has occurred. The caller will only invoke this when the callback should
         * When an action has occurred. The caller will only invoke this when the callback should
@@ -509,7 +510,8 @@ public abstract class AuthBiometricView extends LinearLayout implements AuthBiom
    }
    }


    public void updateState(@BiometricState int newState) {
    public void updateState(@BiometricState int newState) {
        Log.v(TAG, "newState: " + newState);
        Log.d(TAG, "newState: " + newState);

        mIconController.updateState(mState, newState);
        mIconController.updateState(mState, newState);


        switch (newState) {
        switch (newState) {
@@ -533,8 +535,14 @@ public abstract class AuthBiometricView extends LinearLayout implements AuthBiom
                }
                }
                announceForAccessibility(getResources()
                announceForAccessibility(getResources()
                        .getString(R.string.biometric_dialog_authenticated));
                        .getString(R.string.biometric_dialog_authenticated));
                if (mState == STATE_PENDING_CONFIRMATION) {
                    mHandler.postDelayed(() -> mCallback.onAction(
                            Callback.ACTION_AUTHENTICATED_AND_CONFIRMED),
                            getDelayAfterAuthenticatedDurationMs());
                } else {
                    mHandler.postDelayed(() -> mCallback.onAction(Callback.ACTION_AUTHENTICATED),
                    mHandler.postDelayed(() -> mCallback.onAction(Callback.ACTION_AUTHENTICATED),
                            getDelayAfterAuthenticatedDurationMs());
                            getDelayAfterAuthenticatedDurationMs());
                }
                break;
                break;


            case STATE_PENDING_CONFIRMATION:
            case STATE_PENDING_CONFIRMATION:
+3 −0
Original line number Original line Diff line number Diff line
@@ -213,6 +213,9 @@ public class AuthContainerView extends LinearLayout
                case AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR:
                case AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR:
                    mConfig.mCallback.onStartFingerprintNow(getRequestId());
                    mConfig.mCallback.onStartFingerprintNow(getRequestId());
                    break;
                    break;
                case AuthBiometricView.Callback.ACTION_AUTHENTICATED_AND_CONFIRMED:
                    animateAway(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE);
                    break;
                default:
                default:
                    Log.e(TAG, "Unhandled action: " + action);
                    Log.e(TAG, "Unhandled action: " + action);
            }
            }
+1 −1
Original line number Original line Diff line number Diff line
@@ -99,7 +99,7 @@ class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() {
        waitForIdleSync()
        waitForIdleSync()


        assertThat(biometricView.isAuthenticated).isTrue()
        assertThat(biometricView.isAuthenticated).isTrue()
        verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
        verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED_AND_CONFIRMED)
    }
    }


    @Test
    @Test
+54 −18
Original line number Original line Diff line number Diff line
@@ -76,7 +76,7 @@ import java.util.function.Function;
 */
 */
public final class AuthSession implements IBinder.DeathRecipient {
public final class AuthSession implements IBinder.DeathRecipient {
    private static final String TAG = "BiometricService/AuthSession";
    private static final String TAG = "BiometricService/AuthSession";
    private static final boolean DEBUG = false;
    private static final boolean DEBUG = true;


    /*
    /*
     * Defined in biometrics.proto
     * Defined in biometrics.proto
@@ -118,6 +118,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
    @VisibleForTesting final IBinder mToken;
    @VisibleForTesting final IBinder mToken;
    // Info to be shown on BiometricDialog when all cookies are returned.
    // Info to be shown on BiometricDialog when all cookies are returned.
    @VisibleForTesting final PromptInfo mPromptInfo;
    @VisibleForTesting final PromptInfo mPromptInfo;
    @VisibleForTesting final BiometricFrameworkStatsLogger mBiometricFrameworkStatsLogger;
    private final long mRequestId;
    private final long mRequestId;
    private final long mOperationId;
    private final long mOperationId;
    private final int mUserId;
    private final int mUserId;
@@ -164,6 +165,32 @@ public final class AuthSession implements IBinder.DeathRecipient {
            @NonNull PromptInfo promptInfo,
            @NonNull PromptInfo promptInfo,
            boolean debugEnabled,
            boolean debugEnabled,
            @NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties) {
            @NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties) {
        this(context, biometricContext, statusBarService, sysuiReceiver, keystore, random,
                clientDeathReceiver, preAuthInfo, token, requestId, operationId, userId,
                sensorReceiver, clientReceiver, opPackageName, promptInfo, debugEnabled,
                fingerprintSensorProperties, BiometricFrameworkStatsLogger.getInstance());
    }

    @VisibleForTesting
    AuthSession(@NonNull Context context,
            @NonNull BiometricContext biometricContext,
            @NonNull IStatusBarService statusBarService,
            @NonNull IBiometricSysuiReceiver sysuiReceiver,
            @NonNull KeyStore keystore,
            @NonNull Random random,
            @NonNull ClientDeathReceiver clientDeathReceiver,
            @NonNull PreAuthInfo preAuthInfo,
            @NonNull IBinder token,
            long requestId,
            long operationId,
            int userId,
            @NonNull IBiometricSensorReceiver sensorReceiver,
            @NonNull IBiometricServiceReceiver clientReceiver,
            @NonNull String opPackageName,
            @NonNull PromptInfo promptInfo,
            boolean debugEnabled,
            @NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties,
            @NonNull BiometricFrameworkStatsLogger logger) {
        Slog.d(TAG, "Creating AuthSession with: " + preAuthInfo);
        Slog.d(TAG, "Creating AuthSession with: " + preAuthInfo);
        mContext = context;
        mContext = context;
        mBiometricContext = biometricContext;
        mBiometricContext = biometricContext;
@@ -184,6 +211,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
        mDebugEnabled = debugEnabled;
        mDebugEnabled = debugEnabled;
        mFingerprintSensorProperties = fingerprintSensorProperties;
        mFingerprintSensorProperties = fingerprintSensorProperties;
        mCancelled = false;
        mCancelled = false;
        mBiometricFrameworkStatsLogger = logger;


        try {
        try {
            mClientReceiver.asBinder().linkToDeath(this, 0 /* flags */);
            mClientReceiver.asBinder().linkToDeath(this, 0 /* flags */);
@@ -708,7 +736,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
                        + ", Latency: " + latency);
                        + ", Latency: " + latency);
            }
            }


            BiometricFrameworkStatsLogger.getInstance().authenticate(
            mBiometricFrameworkStatsLogger.authenticate(
                    mBiometricContext.updateContext(new OperationContextExt(true /* isBP */),
                    mBiometricContext.updateContext(new OperationContextExt(true /* isBP */),
                            isCrypto()),
                            isCrypto()),
                    statsModality(),
                    statsModality(),
@@ -723,11 +751,17 @@ public final class AuthSession implements IBinder.DeathRecipient {
        } else {
        } else {
            final long latency = System.currentTimeMillis() - mStartTimeMs;
            final long latency = System.currentTimeMillis() - mStartTimeMs;


            int error = reason == BiometricPrompt.DISMISSED_REASON_NEGATIVE
            int error = 0;
                    ? BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON
            switch(reason) {
                    : reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL
                case BiometricPrompt.DISMISSED_REASON_NEGATIVE:
                            ? BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED
                    error = BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON;
                            : 0;
                    break;
                case BiometricPrompt.DISMISSED_REASON_USER_CANCEL:
                    error = BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED;
                    break;
                default:
            }

            if (DEBUG) {
            if (DEBUG) {
                Slog.v(TAG, "Dismissed! Modality: " + statsModality()
                Slog.v(TAG, "Dismissed! Modality: " + statsModality()
                        + ", User: " + mUserId
                        + ", User: " + mUserId
@@ -739,7 +773,8 @@ public final class AuthSession implements IBinder.DeathRecipient {
                        + ", Latency: " + latency);
                        + ", Latency: " + latency);
            }
            }
            // Auth canceled
            // Auth canceled
            BiometricFrameworkStatsLogger.getInstance().error(
            if (error != 0) {
                mBiometricFrameworkStatsLogger.error(
                        mBiometricContext.updateContext(new OperationContextExt(true /* isBP */),
                        mBiometricContext.updateContext(new OperationContextExt(true /* isBP */),
                                isCrypto()),
                                isCrypto()),
                        statsModality(),
                        statsModality(),
@@ -752,6 +787,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
                        mUserId);
                        mUserId);
            }
            }
        }
        }
    }


    void onDialogDismissed(@BiometricPrompt.DismissedReason int reason,
    void onDialogDismissed(@BiometricPrompt.DismissedReason int reason,
            @Nullable byte[] credentialAttestation) {
            @Nullable byte[] credentialAttestation) {
+88 −1
Original line number Original line Diff line number Diff line
@@ -18,6 +18,9 @@ package com.android.server.biometrics;


import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON;
import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED;
import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED;
import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_NEGATIVE;
import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_NEGATIVE;


import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED;
import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED;
@@ -32,6 +35,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.never;
@@ -45,6 +49,7 @@ import android.app.trust.ITrustManager;
import android.content.Context;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -64,7 +69,10 @@ import android.security.KeyStore;
import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;


import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricFrameworkStatsLogger;
import com.android.server.biometrics.log.OperationContextExt;


import org.junit.Before;
import org.junit.Before;
import org.junit.Test;
import org.junit.Test;
@@ -95,6 +103,7 @@ public class AuthSessionTest {
    @Mock private IBiometricSysuiReceiver mSysuiReceiver;
    @Mock private IBiometricSysuiReceiver mSysuiReceiver;
    @Mock private KeyStore mKeyStore;
    @Mock private KeyStore mKeyStore;
    @Mock private AuthSession.ClientDeathReceiver mClientDeathReceiver;
    @Mock private AuthSession.ClientDeathReceiver mClientDeathReceiver;
    @Mock private BiometricFrameworkStatsLogger mBiometricFrameworkStatsLogger;


    private Random mRandom;
    private Random mRandom;
    private IBinder mToken;
    private IBinder mToken;
@@ -395,6 +404,84 @@ public class AuthSessionTest {
                eq(FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR_BASE), eq(acquiredStrVendor));
                eq(FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR_BASE), eq(acquiredStrVendor));
    }
    }


    @Test
    public void testLogOnDialogDismissed_authenticatedWithConfirmation() throws RemoteException {
        final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);

        setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator);
        final AuthSession session = createAuthSession(mSensors,
                false /* checkDevicePolicyManager */,
                Authenticators.BIOMETRIC_STRONG,
                TEST_REQUEST_ID,
                0 /* operationId */,
                0 /* userId */);
        session.goToInitialState();
        assertEquals(STATE_AUTH_CALLED, session.getState());

        session.onDialogDismissed(DISMISSED_REASON_BIOMETRIC_CONFIRMED, null);
        verify(mBiometricFrameworkStatsLogger, times(1)).authenticate(
                (OperationContextExt) anyObject(),
                eq(BiometricsProtoEnums.MODALITY_FACE),
                eq(BiometricsProtoEnums.ACTION_UNKNOWN),
                eq(BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT),
                eq(false), /* debugEnabled */
                anyLong(), /* latency */
                eq(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED),
                eq(true), /* confirmationRequired */
                eq(0) /* userId */,
                eq(-1f) /* ambientLightLux */);
    }

    @Test
    public void testLogOnDialogDismissed_authenticatedWithoutConfirmation() throws RemoteException {
        final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);

        setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator);
        final AuthSession session = createAuthSession(mSensors,
                false /* checkDevicePolicyManager */,
                Authenticators.BIOMETRIC_STRONG,
                TEST_REQUEST_ID,
                0 /* operationId */,
                0 /* userId */);
        session.goToInitialState();
        assertEquals(STATE_AUTH_CALLED, session.getState());

        session.onDialogDismissed(DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED, null);
        verify(mBiometricFrameworkStatsLogger, never()).authenticate(
                anyObject(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyLong(), anyInt(),
                anyBoolean(), anyInt(), eq(-1f));
        verify(mBiometricFrameworkStatsLogger, never()).error(
                anyObject(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyLong(), anyInt(),
                anyInt(), anyInt());
    }

    @Test
    public void testLogOnDialogDismissed_error() throws RemoteException {
        final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);

        setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator);
        final AuthSession session = createAuthSession(mSensors,
                false /* checkDevicePolicyManager */,
                Authenticators.BIOMETRIC_STRONG,
                TEST_REQUEST_ID,
                0 /* operationId */,
                0 /* userId */);
        session.goToInitialState();
        assertEquals(STATE_AUTH_CALLED, session.getState());

        session.onDialogDismissed(DISMISSED_REASON_NEGATIVE, null);
        verify(mBiometricFrameworkStatsLogger, times(1)).error(
                (OperationContextExt) anyObject(),
                eq(BiometricsProtoEnums.MODALITY_FACE),
                eq(BiometricsProtoEnums.ACTION_AUTHENTICATE),
                eq(BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT),
                eq(false),
                anyLong(),
                eq(BIOMETRIC_ERROR_NEGATIVE_BUTTON),
                eq(0) /* vendorCode */,
                eq(0) /* userId */);
    }

    // TODO (b/208484275) : Enable these tests
    // TODO (b/208484275) : Enable these tests
    // @Test
    // @Test
    // public void testPreAuth_canAuthAndPrivacyDisabled() throws Exception {
    // public void testPreAuth_canAuthAndPrivacyDisabled() throws Exception {
@@ -498,7 +585,7 @@ public class AuthSessionTest {
        return new AuthSession(mContext, mBiometricContext, mStatusBarService, mSysuiReceiver,
        return new AuthSession(mContext, mBiometricContext, mStatusBarService, mSysuiReceiver,
                mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, mToken, requestId,
                mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, mToken, requestId,
                operationId, userId, mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo,
                operationId, userId, mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo,
                false /* debugEnabled */, mFingerprintSensorProps);
                false /* debugEnabled */, mFingerprintSensorProps, mBiometricFrameworkStatsLogger);
    }
    }


    private PromptInfo createPromptInfo(@Authenticators.Types int authenticators) {
    private PromptInfo createPromptInfo(@Authenticators.Types int authenticators) {