Merge "Support configurable multi-stage UDFPS enrollment" into sc-v2-dev am: dd28640c0e
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/15875914
Change-Id: Ia6fce74c79b01442273fbf733141de68695dd7b2
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index 714e210..c2bcee3 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -18,6 +18,7 @@
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.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 @@
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 @@
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
+ private FingerprintManager mFingerprintManager;
private boolean mCanAssumeUdfps;
@Nullable private ProgressBar mProgressBar;
private ObjectAnimator mProgressAnim;
@@ -125,9 +134,9 @@
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 @@
// 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 @@
}
private void updateTitleAndDescription() {
+ if (mCanAssumeUdfps) {
+ updateTitleAndDescriptionForUdfps();
+ return;
+ }
+
if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {
- if (mCanAssumeUdfps) {
+ 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 @@
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);
- }
- } 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);
- }
- } else {
- setDescriptionText(R.string.security_settings_fingerprint_enroll_repeat_message);
- }
+ break;
}
}
- private boolean isCenterEnrollmentComplete() {
+ @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 {
+ return STAGE_EDGES;
+ }
+ }
+
+ 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,25 +565,29 @@
mOrientationEventListener = null;
}
- private final Animator.AnimatorListener mProgressAnimationListener
- = new Animator.AnimatorListener() {
+ private final Animator.AnimatorListener mProgressAnimationListener =
+ new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) { }
+ @Override
+ public void onAnimationStart(Animator animation) { }
- @Override
- public void onAnimationRepeat(Animator animation) { }
+ @Override
+ public void onAnimationRepeat(Animator animation) { }
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mProgressBar.getProgress() >= PROGRESS_BAR_MAX) {
- mProgressBar.postDelayed(mDelayedFinishRunnable, FINISH_DELAY);
- }
- }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mProgressBar.getProgress() >= PROGRESS_BAR_MAX) {
+ mProgressBar.postDelayed(mDelayedFinishRunnable, getFinishDelay());
+ }
+ }
- @Override
- public void onAnimationCancel(Animator animation) { }
- };
+ @Override
+ 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() {