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

Commit dd28640c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Support configurable multi-stage UDFPS enrollment" into sc-v2-dev

parents c19d945d 73855e0a
Loading
Loading
Loading
Loading
+128 −48
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.biometrics.fingerprint;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
@@ -58,6 +59,8 @@ import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupcompat.util.WizardManagerHelper;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;

/**
@@ -69,11 +72,16 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
    static final String TAG_SIDECAR = "sidecar";

    private static final int PROGRESS_BAR_MAX = 10000;
    private static final int FINISH_DELAY = 250;
    /**
     * Enroll with two center touches before going to guided enrollment.
     */
    private static final int NUM_CENTER_TOUCHES = 2;

    private static final int STAGE_UNKNOWN = -1;
    private static final int STAGE_CENTER = 0;
    private static final int STAGE_GUIDED = 1;
    private static final int STAGE_FINGERTIP = 2;
    private static final int STAGE_EDGES = 3;

    @IntDef({STAGE_UNKNOWN, STAGE_CENTER, STAGE_GUIDED, STAGE_FINGERTIP, STAGE_EDGES})
    @Retention(RetentionPolicy.SOURCE)
    private @interface EnrollStage {}

    /**
     * If we don't see progress during this time, we show an error message to remind the users that
@@ -100,6 +108,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
                    .build();

    private FingerprintManager mFingerprintManager;
    private boolean mCanAssumeUdfps;
    @Nullable private ProgressBar mProgressBar;
    private ObjectAnimator mProgressAnim;
@@ -125,9 +134,9 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class);
        mFingerprintManager = getSystemService(FingerprintManager.class);
        final List<FingerprintSensorPropertiesInternal> props =
                fingerprintManager.getSensorPropertiesInternal();
                mFingerprintManager.getSensorPropertiesInternal();
        mCanAssumeUdfps = props.size() == 1 && props.get(0).isAnyUdfpsType();

        mAccessibilityManager = getSystemService(AccessibilityManager.class);
@@ -273,7 +282,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
            // UDFPS animations are owned by SystemUI
            if (progress >= PROGRESS_BAR_MAX) {
                // Wait for any animations in SysUI to finish, then proceed to next page
                getMainThreadHandler().postDelayed(mDelayedFinishRunnable, FINISH_DELAY);
                getMainThreadHandler().postDelayed(mDelayedFinishRunnable, getFinishDelay());
            }
            return;
        }
@@ -300,8 +309,55 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
    }

    private void updateTitleAndDescription() {
        if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {
        if (mCanAssumeUdfps) {
            updateTitleAndDescriptionForUdfps();
            return;
        }

        if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {
            setDescriptionText(R.string.security_settings_fingerprint_enroll_start_message);
        } else {
            setDescriptionText(R.string.security_settings_fingerprint_enroll_repeat_message);
        }
    }

    private void updateTitleAndDescriptionForUdfps() {
        switch (getCurrentStage()) {
            case STAGE_CENTER:
                setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
                setDescriptionText(R.string.security_settings_udfps_enroll_start_message);
                break;

            case STAGE_GUIDED:
                setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
                if (mIsAccessibilityEnabled) {
                    setDescriptionText(R.string.security_settings_udfps_enroll_repeat_a11y_message);
                } else {
                    setDescriptionText(R.string.security_settings_udfps_enroll_repeat_message);
                }
                break;

            case STAGE_FINGERTIP:
                setHeaderText(R.string.security_settings_udfps_enroll_fingertip_title);
                if (isStageHalfCompleted()) {
                    setDescriptionText(R.string.security_settings_fingerprint_enroll_repeat_title);
                } else {
                    setDescriptionText("");
                }
                break;

            case STAGE_EDGES:
                setHeaderText(R.string.security_settings_udfps_enroll_edge_title);
                if (isStageHalfCompleted()) {
                    setDescriptionText(
                            R.string.security_settings_fingerprint_enroll_repeat_message);
                } else {
                    setDescriptionText(R.string.security_settings_udfps_enroll_edge_message);
                }
                break;

            case STAGE_UNKNOWN:
            default:
                // setHeaderText(R.string.security_settings_fingerprint_enroll_udfps_title);
                // Don't use BiometricEnrollBase#setHeaderText, since that invokes setTitle,
                // which gets announced for a11y upon entering the page. For UDFPS, we want to
@@ -309,41 +365,61 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
                getLayout().setHeaderText(
                        R.string.security_settings_fingerprint_enroll_udfps_title);
                setDescriptionText(R.string.security_settings_udfps_enroll_start_message);

                final CharSequence description = getString(
                        R.string.security_settings_udfps_enroll_a11y);
                getLayout().getHeaderTextView().setContentDescription(description);
                setTitle(description);
            } else {
                setDescriptionText(R.string.security_settings_fingerprint_enroll_start_message);
                break;
        }
        } else if (mCanAssumeUdfps && !isCenterEnrollmentComplete()) {
            if (mIsSetupWizard) {
                setHeaderText(R.string.security_settings_udfps_enroll_title_one_more_time);
            } else {
                setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
    }
            setDescriptionText(R.string.security_settings_udfps_enroll_start_message);
        } else {
            if (mCanAssumeUdfps) {
                setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
                if (mIsAccessibilityEnabled) {
                    setDescriptionText(R.string.security_settings_udfps_enroll_repeat_a11y_message);
                } else {
                    setDescriptionText(R.string.security_settings_udfps_enroll_repeat_message);

    @EnrollStage
    private int getCurrentStage() {
        if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {
            return STAGE_UNKNOWN;
        }

        final int progressSteps = mSidecar.getEnrollmentSteps() - mSidecar.getEnrollmentRemaining();
        if (progressSteps < getStageThresholdSteps(0)) {
            return STAGE_CENTER;
        } else if (progressSteps < getStageThresholdSteps(1)) {
            return STAGE_GUIDED;
        } else if (progressSteps < getStageThresholdSteps(2)) {
            return STAGE_FINGERTIP;
        } else {
                setDescriptionText(R.string.security_settings_fingerprint_enroll_repeat_message);
            }
            return STAGE_EDGES;
        }
    }

    private boolean isCenterEnrollmentComplete() {
    private boolean isStageHalfCompleted() {
        // Prior to first enrollment step.
        if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {
            return false;
        }
        final int stepsEnrolled = mSidecar.getEnrollmentSteps() - mSidecar.getEnrollmentRemaining();
        return stepsEnrolled >= NUM_CENTER_TOUCHES;

        final int progressSteps = mSidecar.getEnrollmentSteps() - mSidecar.getEnrollmentRemaining();
        int prevThresholdSteps = 0;
        for (int i = 0; i < mFingerprintManager.getEnrollStageCount(); i++) {
            final int thresholdSteps = getStageThresholdSteps(i);
            if (progressSteps >= prevThresholdSteps && progressSteps < thresholdSteps) {
                final int adjustedProgress = progressSteps - prevThresholdSteps;
                final int adjustedThreshold = thresholdSteps - prevThresholdSteps;
                return adjustedProgress >= adjustedThreshold / 2;
            }
            prevThresholdSteps = thresholdSteps;
        }

        // After last enrollment step.
        return true;
    }

    private int getStageThresholdSteps(int index) {
        if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {
            Log.w(TAG, "getStageThresholdSteps: Enrollment not started yet");
            return 1;
        }
        return Math.round(mSidecar.getEnrollmentSteps()
                * mFingerprintManager.getEnrollStageThreshold(index));
    }

    @Override
@@ -489,8 +565,8 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
        mOrientationEventListener = null;
    }

    private final Animator.AnimatorListener mProgressAnimationListener
            = new Animator.AnimatorListener() {
    private final Animator.AnimatorListener mProgressAnimationListener =
            new Animator.AnimatorListener() {

                @Override
                public void onAnimationStart(Animator animation) { }
@@ -501,7 +577,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
                @Override
                public void onAnimationEnd(Animator animation) {
                    if (mProgressBar.getProgress() >= PROGRESS_BAR_MAX) {
                mProgressBar.postDelayed(mDelayedFinishRunnable, FINISH_DELAY);
                        mProgressBar.postDelayed(mDelayedFinishRunnable, getFinishDelay());
                    }
                }

@@ -509,6 +585,10 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
                public void onAnimationCancel(Animator animation) { }
            };

    private long getFinishDelay() {
        return mCanAssumeUdfps ? 400L : 250L;
    }

    // Give the user a chance to see progress completed before jumping to the next stage.
    private final Runnable mDelayedFinishRunnable = new Runnable() {
        @Override