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

Commit 9b51bbe6 authored by Wenhui Yang's avatar Wenhui Yang Committed by Automerger Merge Worker
Browse files

Merge "Update bp subtitle base on modality" into udc-d1-dev am: 5e84bc9a

parents 9026cad3 5e84bc9a
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1786,6 +1786,10 @@
    <string name="biometric_dialog_default_title">Verify it\u2019s you</string>
    <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face). [CHAR LIMIT=70] -->
    <string name="biometric_dialog_default_subtitle">Use your biometric to continue</string>
    <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with fingerprint. [CHAR LIMIT=70] -->
    <string name="biometric_dialog_fingerprint_subtitle">Use your fingerprint to continue</string>
    <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with face. [CHAR LIMIT=70] -->
    <string name="biometric_dialog_face_subtitle">Use your face to continue</string>
    <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face) or their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=90] -->
    <string name="biometric_or_screen_lock_dialog_default_subtitle">Use your biometric or screen lock to continue</string>

+2 −0
Original line number Diff line number Diff line
@@ -2567,6 +2567,8 @@
  <java-symbol type="string" name="biometric_or_screen_lock_app_setting_name" />
  <java-symbol type="string" name="biometric_dialog_default_title" />
  <java-symbol type="string" name="biometric_dialog_default_subtitle" />
  <java-symbol type="string" name="biometric_dialog_face_subtitle" />
  <java-symbol type="string" name="biometric_dialog_fingerprint_subtitle" />
  <java-symbol type="string" name="biometric_or_screen_lock_dialog_default_subtitle" />
  <java-symbol type="string" name="biometric_error_hw_unavailable" />
  <java-symbol type="string" name="biometric_error_user_canceled" />
+30 −17
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.server.biometrics;

import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators;

import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_IDLE;
@@ -369,7 +371,7 @@ public class BiometricService extends SystemService {
        public boolean getConfirmationAlwaysRequired(@BiometricAuthenticator.Modality int modality,
                int userId) {
            switch (modality) {
                case BiometricAuthenticator.TYPE_FACE:
                case TYPE_FACE:
                    if (!mFaceAlwaysRequireConfirmation.containsKey(userId)) {
                        onChange(true /* selfChange */,
                                FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
@@ -567,22 +569,6 @@ public class BiometricService extends SystemService {

            Utils.combineAuthenticatorBundles(promptInfo);

            // Set the default title if necessary.
            if (promptInfo.isUseDefaultTitle()) {
                if (TextUtils.isEmpty(promptInfo.getTitle())) {
                    promptInfo.setTitle(getContext()
                            .getString(R.string.biometric_dialog_default_title));
                }
            }

            // Set the default subtitle if necessary.
            if (promptInfo.isUseDefaultSubtitle()) {
                if (TextUtils.isEmpty(promptInfo.getSubtitle())) {
                    promptInfo.setSubtitle(getContext()
                            .getString(R.string.biometric_dialog_default_subtitle));
                }
            }

            final long requestId = mRequestCounter.get();
            mHandler.post(() -> handleAuthenticate(
                    token, requestId, operationId, userId, receiver, opPackageName, promptInfo));
@@ -1302,6 +1288,33 @@ public class BiometricService extends SystemService {
                        opPackageName, promptInfo.isDisallowBiometricsIfPolicyExists(),
                        getContext(), mBiometricCameraManager);

                // Set the default title if necessary.
                if (promptInfo.isUseDefaultTitle()) {
                    if (TextUtils.isEmpty(promptInfo.getTitle())) {
                        promptInfo.setTitle(getContext()
                                .getString(R.string.biometric_dialog_default_title));
                    }
                }

                final int eligible = preAuthInfo.getEligibleModalities();
                final boolean hasEligibleFingerprintSensor =
                        (eligible & TYPE_FINGERPRINT) == TYPE_FINGERPRINT;
                final boolean hasEligibleFaceSensor = (eligible & TYPE_FACE) == TYPE_FACE;

                // Set the subtitle according to the modality.
                if (promptInfo.isUseDefaultSubtitle()) {
                    if (hasEligibleFingerprintSensor && hasEligibleFaceSensor) {
                        promptInfo.setSubtitle(getContext()
                                .getString(R.string.biometric_dialog_default_subtitle));
                    } else if (hasEligibleFingerprintSensor) {
                        promptInfo.setSubtitle(getContext()
                                .getString(R.string.biometric_dialog_fingerprint_subtitle));
                    } else if (hasEligibleFaceSensor) {
                        promptInfo.setSubtitle(getContext()
                                .getString(R.string.biometric_dialog_face_subtitle));
                    }
                }

                final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus();

                Slog.d(TAG, "handleAuthenticate: modality(" + preAuthStatus.first
+84 −25
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.biometrics;

import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
@@ -113,6 +114,10 @@ public class BiometricServiceTest {
    private static final String ERROR_UNABLE_TO_PROCESS = "error_unable_to_process";
    private static final String ERROR_USER_CANCELED = "error_user_canceled";
    private static final String ERROR_LOCKOUT = "error_lockout";
    private static final String FACE_SUBTITLE = "face_subtitle";
    private static final String FINGERPRINT_SUBTITLE = "fingerprint_subtitle";
    private static final String DEFAULT_SUBTITLE = "default_subtitle";


    private static final String FINGERPRINT_ACQUIRED_SENSOR_DIRTY = "sensor_dirty";

@@ -191,6 +196,12 @@ public class BiometricServiceTest {
                .thenReturn(ERROR_NOT_RECOGNIZED);
        when(mResources.getString(R.string.biometric_error_user_canceled))
                .thenReturn(ERROR_USER_CANCELED);
        when(mContext.getString(R.string.biometric_dialog_face_subtitle))
                .thenReturn(FACE_SUBTITLE);
        when(mContext.getString(R.string.biometric_dialog_fingerprint_subtitle))
                .thenReturn(FINGERPRINT_SUBTITLE);
        when(mContext.getString(R.string.biometric_dialog_default_subtitle))
                .thenReturn(DEFAULT_SUBTITLE);

        when(mWindowManager.getDefaultDisplay()).thenReturn(
                new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY,
@@ -211,7 +222,7 @@ public class BiometricServiceTest {

    @Test
    public void testClientBinderDied_whenPaused() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);

        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                true /* requireConfirmation */, null /* authenticators */);
@@ -238,7 +249,7 @@ public class BiometricServiceTest {

    @Test
    public void testClientBinderDied_whenAuthenticating() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);

        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                true /* requireConfirmation */, null /* authenticators */);
@@ -374,7 +385,7 @@ public class BiometricServiceTest {

        final int[] modalities = new int[] {
                TYPE_FINGERPRINT,
                BiometricAuthenticator.TYPE_FACE,
                TYPE_FACE,
        };

        final int[] strengths = new int[] {
@@ -426,10 +437,57 @@ public class BiometricServiceTest {
                eq(0 /* vendorCode */));
    }

    @Test
    public void testAuthenticateFace_shouldShowSubtitleForFace() throws Exception {
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);

        invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
                false /* requireConfirmation */,
                null);
        waitForIdle();

        assertEquals(FACE_SUBTITLE, mBiometricService.mAuthSession.mPromptInfo.getSubtitle());
    }

    @Test
    public void testAuthenticateFingerprint_shouldShowSubtitleForFingerprint() throws Exception {
        setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);

        invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
                false /* requireConfirmation */,
                null);
        waitForIdle();

        assertEquals(FINGERPRINT_SUBTITLE,
                mBiometricService.mAuthSession.mPromptInfo.getSubtitle());
    }

    @Test
    public void testAuthenticateBothFpAndFace_shouldShowDefaultSubtitle() throws Exception {
        final int[] modalities = new int[] {
                TYPE_FINGERPRINT,
                TYPE_FACE,
        };

        final int[] strengths = new int[] {
                Authenticators.BIOMETRIC_WEAK,
                Authenticators.BIOMETRIC_STRONG,
        };

        setupAuthForMultiple(modalities, strengths);

        invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
                false /* requireConfirmation */,
                null);
        waitForIdle();

        assertEquals(DEFAULT_SUBTITLE, mBiometricService.mAuthSession.mPromptInfo.getSubtitle());
    }

    @Test
    public void testAuthenticateFace_respectsUserSetting()
            throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);

        // Disabled in user settings receives onError
        when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false);
@@ -568,7 +626,7 @@ public class BiometricServiceTest {

    @Test
    public void testAuthenticate_noBiometrics_credentialAllowed() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false);
        when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
                .thenReturn(true);
@@ -595,13 +653,13 @@ public class BiometricServiceTest {

    @Test
    public void testAuthenticate_happyPathWithConfirmation_strongBiometric() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        testAuthenticate_happyPathWithConfirmation(true /* isStrongBiometric */);
    }

    @Test
    public void testAuthenticate_happyPathWithConfirmation_weakBiometric() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_WEAK);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_WEAK);
        testAuthenticate_happyPathWithConfirmation(false /* isStrongBiometric */);
    }

@@ -637,7 +695,7 @@ public class BiometricServiceTest {

    @Test
    public void testAuthenticate_no_Biometrics_noCredential() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false);
        when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
                .thenReturn(false);
@@ -655,7 +713,7 @@ public class BiometricServiceTest {
    @Test
    public void testRejectFace_whenAuthenticating_notifiesSystemUIAndClient_thenPaused()
            throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                false /* requireConfirmation */, null /* authenticators */);

@@ -663,7 +721,7 @@ public class BiometricServiceTest {
        waitForIdle();

        verify(mBiometricService.mStatusBarService).onBiometricError(
                eq(BiometricAuthenticator.TYPE_FACE),
                eq(TYPE_FACE),
                eq(BiometricConstants.BIOMETRIC_PAUSED_REJECTED),
                eq(0 /* vendorCode */));
        verify(mReceiver1).onAuthenticationFailed();
@@ -691,7 +749,7 @@ public class BiometricServiceTest {

    @Test
    public void testRequestAuthentication_whenAlreadyAuthenticating() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                false /* requireConfirmation */, null /* authenticators */);

@@ -700,7 +758,7 @@ public class BiometricServiceTest {
        waitForIdle();

        verify(mReceiver1).onError(
                eq(BiometricAuthenticator.TYPE_FACE),
                eq(TYPE_FACE),
                eq(BiometricPrompt.BIOMETRIC_ERROR_CANCELED),
                eq(0) /* vendorCode */);
        verify(mBiometricService.mStatusBarService).hideAuthenticationDialog(eq(TEST_REQUEST_ID));
@@ -710,7 +768,7 @@ public class BiometricServiceTest {

    @Test
    public void testErrorHalTimeout_whenAuthenticating_entersPausedState() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                false /* requireConfirmation */, null /* authenticators */);

@@ -723,7 +781,7 @@ public class BiometricServiceTest {

        assertEquals(STATE_AUTH_PAUSED, mBiometricService.mAuthSession.getState());
        verify(mBiometricService.mStatusBarService).onBiometricError(
                eq(BiometricAuthenticator.TYPE_FACE),
                eq(TYPE_FACE),
                eq(BiometricConstants.BIOMETRIC_ERROR_TIMEOUT),
                eq(0 /* vendorCode */));
        // Timeout does not count as fail as per BiometricPrompt documentation.
@@ -759,7 +817,7 @@ public class BiometricServiceTest {

    @Test
    public void testErrorFromHal_whenPaused_notifiesSystemUIAndClient() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                false /* requireConfirmation */, null /* authenticators */);

@@ -777,7 +835,7 @@ public class BiometricServiceTest {

        // Client receives error immediately
        verify(mReceiver1).onError(
                eq(BiometricAuthenticator.TYPE_FACE),
                eq(TYPE_FACE),
                eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED),
                eq(0 /* vendorCode */));
        // Dialog is hidden immediately
@@ -926,7 +984,7 @@ public class BiometricServiceTest {
            int biometricPromptError) throws Exception {
        final int[] modalities = new int[] {
                TYPE_FINGERPRINT,
                BiometricAuthenticator.TYPE_FACE,
                TYPE_FACE,
        };

        final int[] strengths = new int[] {
@@ -1123,7 +1181,7 @@ public class BiometricServiceTest {

    @Test
    public void testDismissedReasonNegative_whilePaused_invokeHalCancel() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                false /* requireConfirmation */, null /* authenticators */);

@@ -1142,7 +1200,7 @@ public class BiometricServiceTest {

    @Test
    public void testDismissedReasonUserCancel_whilePaused_invokesHalCancel() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                false /* requireConfirmation */, null /* authenticators */);

@@ -1161,7 +1219,7 @@ public class BiometricServiceTest {

    @Test
    public void testDismissedReasonUserCancel_whenPendingConfirmation() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                true /* requireConfirmation */, null /* authenticators */);

@@ -1175,7 +1233,7 @@ public class BiometricServiceTest {
        verify(mBiometricService.mSensors.get(0).impl)
                .cancelAuthenticationFromService(any(), any(), anyLong());
        verify(mReceiver1).onError(
                eq(BiometricAuthenticator.TYPE_FACE),
                eq(TYPE_FACE),
                eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
                eq(0 /* vendorCode */));
        verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
@@ -1296,7 +1354,7 @@ public class BiometricServiceTest {

    @Test
    public void testCanAuthenticate_whenBiometricsNotEnabledForApps() throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false);
        when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
                .thenReturn(true);
@@ -1590,7 +1648,7 @@ public class BiometricServiceTest {
    @Test
    public void testWorkAuthentication_faceWorksIfNotDisabledByDevicePolicyManager()
            throws Exception {
        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
        when(mDevicePolicyManager
                .getKeyguardDisabledFeatures(any() /* admin*/, anyInt() /* userHandle */))
                .thenReturn(~DevicePolicyManager.KEYGUARD_DISABLE_FACE);
@@ -1683,7 +1741,7 @@ public class BiometricServiceTest {
                    mFingerprintAuthenticator);
        }

        if ((modality & BiometricAuthenticator.TYPE_FACE) != 0) {
        if ((modality & TYPE_FACE) != 0) {
            when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(enrolled);
            when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true);
            when(mFaceAuthenticator.getLockoutModeForUser(anyInt()))
@@ -1715,7 +1773,7 @@ public class BiometricServiceTest {
                        strength, mFingerprintAuthenticator);
            }

            if ((modality & BiometricAuthenticator.TYPE_FACE) != 0) {
            if ((modality & TYPE_FACE) != 0) {
                when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
                when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true);
                mBiometricService.mImpl.registerAuthenticator(SENSOR_ID_FACE, modality,
@@ -1798,6 +1856,7 @@ public class BiometricServiceTest {
            boolean checkDevicePolicy) {
        final PromptInfo promptInfo = new PromptInfo();
        promptInfo.setConfirmationRequested(requireConfirmation);
        promptInfo.setUseDefaultSubtitle(true);

        if (authenticators != null) {
            promptInfo.setAuthenticators(authenticators);