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

Commit 52874a64 authored by Shawn Lin's avatar Shawn Lin
Browse files

Support the ability to enroll face unlock first

Add a new EXTRA value to indicate whehter the face enrollment should be
launched first.

Bug: 370940762
Test: atest BiometricEnrollActivityTest
Flag: com.android.settings.flags.biometrics_onboarding_education
Change-Id: I7c85212c7fbcc6fe9dd53a26515412623c80ecbf
parent 11b78c6f
Loading
Loading
Loading
Loading
+25 −6
Original line number Diff line number Diff line
@@ -107,7 +107,10 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
    // intent will include this extra containing a bundle of the form:
    // "modality" -> consented (boolean).
    public static final String EXTRA_PARENTAL_CONSENT_STATUS = "consent_status";

    // Whether the face enrollment should be launched first when there are multiple biometrics
    // supported.
    public static final String EXTRA_LAUNCH_FACE_ENROLL_FIRST =
            "launch_face_enroll_first";
    private static final String SAVED_STATE_CONFIRMING_CREDENTIALS = "confirming_credentials";
    private static final String SAVED_STATE_IS_SINGLE_ENROLLING =
            "is_single_enrolling";
@@ -130,6 +133,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
    private boolean mIsFingerprintEnrollable = false;
    private boolean mParentalOptionsRequired = false;
    private boolean mSkipReturnToParent = false;
    private boolean mLaunchFaceEnrollFirst = false;
    private Bundle mParentalOptions;
    @Nullable private Long mGkPwHandle;
    @Nullable private ParentalConsentHelper mParentalConsentHelper;
@@ -214,6 +218,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {

        mParentalOptionsRequired = intent.getBooleanExtra(EXTRA_REQUIRE_PARENTAL_CONSENT, false);
        mSkipReturnToParent = intent.getBooleanExtra(EXTRA_SKIP_RETURN_TO_PARENT, false);
        mLaunchFaceEnrollFirst = intent.getBooleanExtra(EXTRA_LAUNCH_FACE_ENROLL_FIRST, false);

        // determine what can be enrolled
        final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
@@ -221,6 +226,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {

        Log.d(TAG, "parentalOptionsRequired: " + mParentalOptionsRequired
                + ", skipReturnToParent: " + mSkipReturnToParent
                + ", launchFaceEnrollFirst: " + mLaunchFaceEnrollFirst
                + ", isSetupWizard: " + isSetupWizard
                + ", isMultiSensor: " + isMultiSensor);

@@ -356,7 +362,8 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
        } else if (canUseFace || canUseFingerprint) {
            if (mGkPwHandle == null) {
                setOrConfirmCredentialsNow();
            } else if (canUseFingerprint && mIsFingerprintEnrollable) {
            } else if (canUseFingerprint && mIsFingerprintEnrollable
                    && !(canUseFace && mIsFaceEnrollable && mLaunchFaceEnrollFirst)) {
                launchFingerprintOnlyEnroll();
            } else if (canUseFace && mIsFaceEnrollable) {
                launchFaceOnlyEnroll();
@@ -510,7 +517,8 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
            int requestCode, int resultCode, Intent data) {

        Log.d(TAG, "handleOnActivityResultWhileEnrolling, request = " + requestCode + ""
                + ", resultCode = " + resultCode);
                + ", resultCode = " + resultCode + ", launchFaceEnrollFirst="
                + mLaunchFaceEnrollFirst);
        switch (requestCode) {
            case REQUEST_HANDOFF_PARENT:
                setResult(RESULT_OK, newResultIntent());
@@ -526,7 +534,8 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
                    // SetupFingerprintEnrollIntroduction/FingerprintEnrollmentActivity
                    TransitionHelper.applyForwardTransition(this, TRANSITION_FADE_THROUGH);
                    updateGatekeeperPasswordHandle(data);
                    if (mIsFingerprintEnrollable) {
                    if (mIsFingerprintEnrollable
                            && !(mIsFaceEnrollable && mLaunchFaceEnrollFirst)) {
                        launchFingerprintOnlyEnroll();
                    } else {
                        launchFaceOnlyEnroll();
@@ -548,7 +557,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
                }
                if ((resultCode == BiometricEnrollBase.RESULT_SKIP
                        || resultCode == BiometricEnrollBase.RESULT_FINISHED)
                        && mIsFaceEnrollable) {
                        && mIsFaceEnrollable && !mLaunchFaceEnrollFirst) {
                    // Apply forward animation during the transition from
                    // SetupFingerprintEnroll*/FingerprintEnrollmentActivity to
                    // SetupFaceEnrollIntroduction
@@ -556,6 +565,9 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
                    mIsPreviousEnrollmentCanceled =
                            resultCode != BiometricEnrollBase.RESULT_FINISHED;
                    launchFaceOnlyEnroll();
                } else if (resultCode == Activity.RESULT_CANCELED && mIsFaceEnrollable
                        && mLaunchFaceEnrollFirst) {
                    launchFaceOnlyEnroll();
                } else {
                    notifySafetyIssueActionLaunchedIfNeeded(resultCode);
                    finishOrLaunchHandToParent(resultCode);
@@ -563,7 +575,14 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
                break;
            case REQUEST_SINGLE_ENROLL_FACE:
                mIsSingleEnrolling = false;
                if (resultCode == Activity.RESULT_CANCELED && mIsFingerprintEnrollable) {
                if ((resultCode == BiometricEnrollBase.RESULT_SKIP
                        || resultCode == BiometricEnrollBase.RESULT_FINISHED)
                        && mIsFingerprintEnrollable && mLaunchFaceEnrollFirst) {
                    mIsPreviousEnrollmentCanceled =
                            resultCode != BiometricEnrollBase.RESULT_FINISHED;
                    launchFingerprintOnlyEnroll();
                } else if (resultCode == Activity.RESULT_CANCELED && mIsFingerprintEnrollable
                        && !mLaunchFaceEnrollFirst) {
                    mIsPreviousEnrollmentCanceled = true;
                    launchFingerprintOnlyEnroll();
                } else {
+2 −3
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
import com.android.settings.biometrics.face.FaceEnroll;
import com.android.settings.biometrics.fingerprint.FingerprintEnroll;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
@@ -282,9 +283,7 @@ public class BiometricUtils {
     */
    public static Intent getFaceIntroIntent(@NonNull Context context,
            @NonNull Intent activityIntent) {
        final Intent intent = new Intent(context,
                FeatureFactory.getFeatureFactory().getFaceFeatureProvider()
                        .getEnrollActivityClassProvider().getNext());
        final Intent intent = new Intent(context, FaceEnroll.class);
        WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent);
        return intent;
    }
+34 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static androidx.test.espresso.intent.Intents.intended;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;

import static com.android.settings.biometrics.BiometricEnrollActivity.EXTRA_LAUNCH_FACE_ENROLL_FIRST;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
@@ -39,6 +40,7 @@ import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;

@@ -145,7 +147,7 @@ public class BiometricEnrollActivityTest {
        assumeTrue(mHasFace || mHasFingerprint);

        setPin();
        final Intent intent = getIntent(true /* useInternal */);
        final Intent intent = getIntent(true /* useInternal */, null);
        LockPatternChecker.verifyCredential(new LockPatternUtils(mContext),
                LockscreenCredential.createPin(TEST_PIN), UserHandle.myUserId(),
                LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, (response, timeoutMs) -> {
@@ -162,6 +164,26 @@ public class BiometricEnrollActivityTest {
        }
    }

    @Test
    public void launchWithPinAndPwHandle_confirmsPin_firstEnrollmentIsFace() throws Exception {
        assumeTrue(mHasFace && mHasFingerprint);

        setPin();
        final Intent intent = getFaceEnrollFirstIntent();
        LockPatternChecker.verifyCredential(new LockPatternUtils(mContext),
                LockscreenCredential.createPin(TEST_PIN), UserHandle.myUserId(),
                LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, (response, timeoutMs) -> {
                    assertThat(response.containsGatekeeperPasswordHandle()).isTrue();
                    intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
                            response.getGatekeeperPasswordHandle());
                }).get();

        try (ActivityScenario<BiometricEnrollActivity> scenario =
                     ActivityScenario.launch(intent)) {
            intended(hasComponent(FaceEnroll.class.getName()));
        }
    }

    @Test
    public void launchWithStrongBiometricAllowed_doNotEnrollWeak() throws Exception {
        assumeTrue(mHasFace || mHasFingerprint);
@@ -184,13 +206,22 @@ public class BiometricEnrollActivityTest {
    }

    private Intent getIntent() {
        return getIntent(false /* useInternal */);
        return getIntent(false /* useInternal */, null);
    }

    private Intent getFaceEnrollFirstIntent() {
        final Bundle bundle = new Bundle();
        bundle.putBoolean(EXTRA_LAUNCH_FACE_ENROLL_FIRST, true);
        return getIntent(true /* useInternal */, bundle);
    }

    private Intent getIntent(boolean useInternal) {
    private Intent getIntent(boolean useInternal, Bundle bundle) {
        final Intent intent = new Intent(mContext, useInternal
                ? BiometricEnrollActivity.InternalActivity.class : BiometricEnrollActivity.class);
        intent.setAction(ACTION_BIOMETRIC_ENROLL);
        if (bundle != null && !bundle.isEmpty()) {
            intent.putExtras(bundle);
        }
        return intent;
    }