SUW enrolls FP before Face

Test: During SUW verified Fingerprint enrollment
comes before face.
Test: During SUW enrolled multiple fingerprints than 1 face.
Test: Skipped and cancelled on every possible screen to ensure behavior
was correct.
Bug: 228607474

Change-Id: I4c50763a804fe4eb9d62451eb2f957545857723e
This commit is contained in:
Joshua McCloskey
2022-04-18 19:16:10 +00:00
parent c18637a51f
commit 1dd4f54d58
10 changed files with 158 additions and 68 deletions

View File

@@ -32,7 +32,6 @@ import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.BiometricManager.BiometricError;
import android.hardware.biometrics.SensorProperties;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
@@ -211,12 +210,6 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
// required check if setup has completed instead.
final boolean isSettingUp = isSetupWizard || (mParentalOptionsRequired
&& !WizardManagerHelper.isUserSetupComplete(this));
if (isSettingUp && isMultiSensor && mIsFaceEnrollable) {
if (props.sensorStrength == SensorProperties.STRENGTH_CONVENIENCE) {
Log.i(TAG, "Excluding face from SuW enrollment (STRENGTH_CONVENIENCE)");
mIsFaceEnrollable = false;
}
}
}
}
if (mHasFeatureFingerprint) {

View File

@@ -254,6 +254,7 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity {
intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, mFromSettingsSummary);
intent.putExtra(EXTRA_KEY_CHALLENGE, mChallenge);
intent.putExtra(EXTRA_KEY_SENSOR_ID, mSensorId);
BiometricUtils.copyMultiBiometricExtras(getIntent(), intent);
if (mUserId != UserHandle.USER_NULL) {
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
}

View File

@@ -24,7 +24,6 @@ import android.hardware.biometrics.BiometricAuthenticator;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
@@ -303,9 +302,17 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
final boolean cameFromMultiBioFpAuthAddAnother =
requestCode == BiometricUtils.REQUEST_ADD_ANOTHER
&& BiometricUtils.isMultiBiometricFingerprintEnrollmentFlow(this);
if (requestCode == BIOMETRIC_FIND_SENSOR_REQUEST) {
if (isResultSkipOrFinished(resultCode)) {
if (isResultFinished(resultCode)) {
handleBiometricResultSkipOrFinished(resultCode, data);
} else if (isResultSkipped(resultCode)) {
if (!BiometricUtils.tryStartingNextBiometricEnroll(this,
ENROLL_NEXT_BIOMETRIC_REQUEST, "BIOMETRIC_FIND_SENSOR_SKIPPED")) {
handleBiometricResultSkipOrFinished(resultCode, data);
}
} else if (resultCode == RESULT_TIMEOUT) {
setResult(resultCode, data);
finish();
@@ -353,10 +360,22 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
}
} else if (requestCode == LEARN_MORE_REQUEST) {
overridePendingTransition(R.anim.sud_slide_back_in, R.anim.sud_slide_back_out);
} else if (requestCode == ENROLL_NEXT_BIOMETRIC_REQUEST) {
Log.d(TAG, "ENROLL_NEXT_BIOMETRIC_REQUEST, result: " + resultCode);
if (isResultSkipOrFinished(resultCode)) {
} else if (requestCode == ENROLL_NEXT_BIOMETRIC_REQUEST
|| cameFromMultiBioFpAuthAddAnother) {
if (isResultFinished(resultCode)) {
handleBiometricResultSkipOrFinished(resultCode, data);
} else if (isResultSkipped(resultCode)) {
if (requestCode == BiometricUtils.REQUEST_ADD_ANOTHER) {
// If we came from an add another request, it still might
// be possible to add another biometric. Check if we can.
if (checkMaxEnrolled() != 0) {
// If we can't enroll any more biometrics, than skip
// this one.
handleBiometricResultSkipOrFinished(resultCode, data);
}
} else {
handleBiometricResultSkipOrFinished(resultCode, data);
}
} else if (resultCode != RESULT_CANCELED) {
setResult(resultCode, data);
finish();
@@ -365,9 +384,17 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
super.onActivityResult(requestCode, resultCode, data);
}
private static boolean isResultSkipped(int resultCode) {
return resultCode == RESULT_SKIP
|| resultCode == SetupSkipDialog.RESULT_SKIP;
}
private static boolean isResultFinished(int resultCode) {
return resultCode == RESULT_FINISHED;
}
private static boolean isResultSkipOrFinished(int resultCode) {
return resultCode == RESULT_SKIP || resultCode == SetupSkipDialog.RESULT_SKIP
|| resultCode == RESULT_FINISHED;
return isResultSkipped(resultCode) || isResultFinished(resultCode);
}
private void handleBiometricResultSkipOrFinished(int resultCode, @Nullable Intent data) {
@@ -375,6 +402,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
&& data.getBooleanExtra(
MultiBiometricEnrollHelper.EXTRA_SKIP_PENDING_ENROLL, false)) {
getIntent().removeExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE);
getIntent().removeExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT);
}
if (resultCode == RESULT_SKIP) {

View File

@@ -51,6 +51,12 @@ import com.google.android.setupcompat.util.WizardManagerHelper;
*/
public class BiometricUtils {
private static final String TAG = "BiometricUtils";
/**
* Request was sent for starting another enrollment of a previously
* enrolled biometric of the same type.
*/
public static int REQUEST_ADD_ANOTHER = 7;
/**
* Given the result from confirming or choosing a credential, request Gatekeeper to generate
* a HardwareAuthToken with the Gatekeeper Password together with a biometric challenge.
@@ -223,38 +229,66 @@ public class BiometricUtils {
}
/**
* Used for checking if a multi-biometric enrollment flow starts with Face and
* ends with Fingerprint.
*
* @param activity Activity that we want to check
* @return True if the activity is going through a multi-biometric enrollment flow.
* @return True if the activity is going through a multi-biometric enrollment flow, that starts
* with Face.
*/
public static boolean isMultiBiometricEnrollmentFlow(@NonNull Activity activity) {
public static boolean isMultiBiometricFaceEnrollmentFlow(@NonNull Activity activity) {
return activity.getIntent().hasExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE);
}
/**
* Used for checking if a multi-biometric enrollment flowstarts with Fingerprint
* and ends with Face.
*
* @param activity Activity that we want to check
* @return True if the activity is going through a multi-biometric enrollment flow, that starts
* with Fingerprint.
*/
public static boolean isMultiBiometricFingerprintEnrollmentFlow(@NonNull Activity activity) {
return activity.getIntent().hasExtra(
MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT);
}
public static void copyMultiBiometricExtras(@NonNull Intent fromIntent,
@NonNull Intent toIntent) {
final PendingIntent pendingIntent = (PendingIntent) fromIntent.getExtra(
PendingIntent pendingIntent = (PendingIntent) fromIntent.getExtra(
MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE, null);
if (pendingIntent != null) {
toIntent.putExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE, pendingIntent);
toIntent.putExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE,
pendingIntent);
}
pendingIntent = (PendingIntent) fromIntent.getExtra(
MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT, null);
if (pendingIntent != null) {
toIntent.putExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT,
pendingIntent);
}
}
/**
* If the current biometric enrollment (e.g. face) should be followed by another one (e.g.
* fingerprint) (see {@link #isMultiBiometricEnrollmentFlow(Activity)}), retrieves the
* PendingIntent pointing to the next enrollment and starts it. The caller will receive the
* result in onActivityResult.
* If the current biometric enrollment (e.g. face/fingerprint) should be followed by another
* one (e.g. fingerprint/face) retrieves the PendingIntent pointing to the next enrollment
* and starts it. The caller will receive the result in onActivityResult.
* @return true if the next enrollment was started
*/
public static boolean tryStartingNextBiometricEnroll(@NonNull Activity activity,
int requestCode, String debugReason) {
Log.d(TAG, "tryStartingNextBiometricEnroll, debugReason: " + debugReason);
final PendingIntent pendingIntent = (PendingIntent) activity.getIntent()
PendingIntent pendingIntent = (PendingIntent) activity.getIntent()
.getExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FACE);
if (pendingIntent == null) {
pendingIntent = (PendingIntent) activity.getIntent()
.getExtra(MultiBiometricEnrollHelper.EXTRA_ENROLL_AFTER_FINGERPRINT);
}
if (pendingIntent != null) {
try {
Log.d(TAG, "Starting pendingIntent: " + pendingIntent);
IntentSender intentSender = pendingIntent.getIntentSender();
activity.startIntentSenderForResult(intentSender, requestCode,
null /* fillInIntent */, 0 /* flagMask */, 0 /* flagValues */,

View File

@@ -37,6 +37,7 @@ public class MultiBiometricEnrollHelper {
private static final int REQUEST_FINGERPRINT_ENROLL = 3001;
public static final String EXTRA_ENROLL_AFTER_FACE = "enroll_after_face";
public static final String EXTRA_ENROLL_AFTER_FINGERPRINT = "enroll_after_finger";
public static final String EXTRA_SKIP_PENDING_ENROLL = "skip_pending_enroll";
@NonNull private final FragmentActivity mActivity;
@@ -55,10 +56,10 @@ public class MultiBiometricEnrollHelper {
}
void startNextStep() {
if (mRequestEnrollFace) {
launchFaceEnroll();
} else if (mRequestEnrollFingerprint) {
if (mRequestEnrollFingerprint) {
launchFingerprintEnroll();
} else if (mRequestEnrollFace) {
launchFaceEnroll();
} else {
mActivity.setResult(BiometricEnrollIntroduction.RESULT_SKIP);
mActivity.finish();
@@ -74,20 +75,6 @@ public class MultiBiometricEnrollHelper {
mActivity.getIntent());
faceIntent.putExtra(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
faceIntent.putExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
if (mRequestEnrollFingerprint) {
// Give FaceEnroll a pendingIntent pointing to fingerprint enrollment, so that it
// can be started when user skips or finishes face enrollment. FLAG_UPDATE_CURRENT
// ensures it is launched with the most recent values.
final Intent fpIntent = BiometricUtils.getFingerprintIntroIntent(mActivity,
mActivity.getIntent());
fpIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, mGkPwHandle);
final PendingIntent fpAfterFaceIntent = PendingIntent.getActivity(mActivity,
0 /* requestCode */, fpIntent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
faceIntent.putExtra(EXTRA_ENROLL_AFTER_FACE, fpAfterFaceIntent);
}
BiometricUtils.launchEnrollForResult(mActivity, faceIntent, REQUEST_FACE_ENROLL,
hardwareAuthToken, mGkPwHandle, mUserId);
});
@@ -103,6 +90,19 @@ public class MultiBiometricEnrollHelper {
mActivity.getIntent());
intent.putExtra(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId);
intent.putExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge);
if (mRequestEnrollFace) {
// Give FingerprintEnroll a pendingIntent pointing to face enrollment, so that it
// can be started when user skips or finishes fingerprint enrollment.
// FLAG_UPDATE_CURRENT ensures it is launched with the most recent values.
final Intent faceIntent = BiometricUtils.getFaceIntroIntent(mActivity,
mActivity.getIntent());
faceIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, mGkPwHandle);
final PendingIntent faceAfterFp = PendingIntent.getActivity(mActivity,
0 /* requestCode */, faceIntent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
intent.putExtra(EXTRA_ENROLL_AFTER_FINGERPRINT, faceAfterFp);
}
BiometricUtils.launchEnrollForResult(mActivity, intent, REQUEST_FINGERPRINT_ENROLL,
hardwareAuthToken, mGkPwHandle, mUserId);
}));

View File

@@ -41,8 +41,10 @@ import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollActivity;
import com.android.settings.biometrics.BiometricEnrollIntroduction;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.MultiBiometricEnrollHelper;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.password.SetupSkipDialog;
import com.android.settings.utils.SensorPrivacyManagerHelper;
import com.android.settingslib.RestrictedLockUtilsInternal;
@@ -167,6 +169,19 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
Log.v(TAG, "cameraPrivacyEnabled : " + cameraPrivacyEnabled);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// If user has skipped or finished enrolling, don't restart enrollment.
final boolean isEnrollRequest = requestCode == BIOMETRIC_FIND_SENSOR_REQUEST
|| requestCode == ENROLL_NEXT_BIOMETRIC_REQUEST;
final boolean isResultSkipOrFinished = resultCode == RESULT_SKIP
|| resultCode == SetupSkipDialog.RESULT_SKIP || resultCode == RESULT_FINISHED;
if (isEnrollRequest && isResultSkipOrFinished) {
data = setSkipPendingEnroll(data);
}
super.onActivityResult(requestCode, resultCode, data);
}
protected boolean generateChallengeOnCreate() {
return true;
}
@@ -387,4 +402,13 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
protected int getMoreButtonTextRes() {
return R.string.security_settings_face_enroll_introduction_more;
}
@NonNull
protected static Intent setSkipPendingEnroll(@Nullable Intent data) {
if (data == null) {
data = new Intent();
}
data.putExtra(MultiBiometricEnrollHelper.EXTRA_SKIP_PENDING_ENROLL, true);
return data;
}
}

View File

@@ -31,6 +31,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.google.android.setupcompat.template.FooterBarMixin;
@@ -47,8 +48,6 @@ public class FingerprintEnrollFinish extends BiometricEnrollBase {
private static final String ACTION_FINGERPRINT_SETTINGS =
"android.settings.FINGERPRINT_SETTINGS";
@VisibleForTesting
static final int REQUEST_ADD_ANOTHER = 1;
@VisibleForTesting
static final String FINGERPRINT_SUGGESTION_ACTIVITY =
"com.android.settings.SetupFingerprintSuggestionActivity";
@@ -160,13 +159,13 @@ public class FingerprintEnrollFinish extends BiometricEnrollBase {
}
private void onAddAnotherButtonClick(View view) {
startActivityForResult(getFingerprintEnrollingIntent(), REQUEST_ADD_ANOTHER);
startActivityForResult(getFingerprintEnrollingIntent(), BiometricUtils.REQUEST_ADD_ANOTHER);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
updateFingerprintSuggestionEnableState();
if (requestCode == REQUEST_ADD_ANOTHER && resultCode != RESULT_CANCELED) {
if (requestCode == BiometricUtils.REQUEST_ADD_ANOTHER && resultCode != RESULT_CANCELED) {
setResult(resultCode, data);
finish();
} else {

View File

@@ -42,7 +42,6 @@ import com.android.settings.biometrics.BiometricEnrollIntroduction;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.MultiBiometricEnrollHelper;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.password.SetupSkipDialog;
import com.android.settingslib.HelpUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
@@ -106,28 +105,31 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// If user has skipped or finished enrolling, don't restart enrollment.
final boolean isEnrollRequest = requestCode == BIOMETRIC_FIND_SENSOR_REQUEST
|| requestCode == ENROLL_NEXT_BIOMETRIC_REQUEST;
final boolean isResultSkipOrFinished = resultCode == RESULT_SKIP
|| resultCode == SetupSkipDialog.RESULT_SKIP || resultCode == RESULT_FINISHED;
if (isEnrollRequest && isResultSkipOrFinished) {
data = setSkipPendingEnroll(data);
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onCancelButtonClick(View view) {
// User has explicitly canceled enroll. Don't restart it automatically.
Intent data = setSkipPendingEnroll(new Intent());
setResult(RESULT_SKIP, data);
finish();
if (!BiometricUtils.tryStartingNextBiometricEnroll(
this, ENROLL_NEXT_BIOMETRIC_REQUEST, "cancel")) {
super.onCancelButtonClick(view);
}
}
@Override
protected void onSkipButtonClick(View view) {
onCancelButtonClick(view);
if (!BiometricUtils.tryStartingNextBiometricEnroll(
this, ENROLL_NEXT_BIOMETRIC_REQUEST, "skipped")) {
super.onSkipButtonClick(view);
}
}
@Override
protected void onFinishedEnrolling(@Nullable Intent data) {
if (!BiometricUtils.tryStartingNextBiometricEnroll(
this, ENROLL_NEXT_BIOMETRIC_REQUEST, "finished")) {
super.onFinishedEnrolling(data);
}
}
@StringRes
@@ -269,6 +271,7 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
@Override
protected Intent getEnrollingIntent() {
final Intent intent = new Intent(this, FingerprintEnrollFindSensor.class);
BiometricUtils.copyMultiBiometricExtras(getIntent(), intent);
if (BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
BiometricUtils.getGatekeeperPasswordHandle(getIntent()));

View File

@@ -31,6 +31,7 @@ import androidx.fragment.app.FragmentManager;
import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.password.ChooseLockSettingsHelper;
@@ -45,6 +46,7 @@ public class SetupFingerprintEnrollFindSensor extends FingerprintEnrollFindSenso
if (mUserId != UserHandle.USER_NULL) {
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
}
BiometricUtils.copyMultiBiometricExtras(getIntent(), intent);
SetupWizardUtils.copySetupExtras(getIntent(), intent);
return intent;
}

View File

@@ -62,8 +62,10 @@ public class SetupFingerprintEnrollIntroduction extends FingerprintEnrollIntrodu
@Override
protected Intent getEnrollingIntent() {
final Intent intent = new Intent(this, SetupFingerprintEnrollFindSensor.class);
BiometricUtils.copyMultiBiometricExtras(getIntent(), intent);
if (BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) {
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
intent.putExtra(
ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
BiometricUtils.getGatekeeperPasswordHandle(getIntent()));
}
SetupWizardUtils.copySetupExtras(getIntent(), intent);
@@ -118,18 +120,22 @@ public class SetupFingerprintEnrollIntroduction extends FingerprintEnrollIntrodu
if (isKeyguardSecure()) {
// If the keyguard is already set up securely (maybe the user added a backup screen
// lock and skipped fingerprint), return RESULT_SKIP directly.
if (!BiometricUtils.tryStartingNextBiometricEnroll(
this, ENROLL_NEXT_BIOMETRIC_REQUEST, "cancel")) {
resultCode = RESULT_SKIP;
data = mAlreadyHadLockScreenSetup ? null : getMetricIntent(null);
setResult(resultCode, data);
finish();
return;
}
} else {
resultCode = SetupSkipDialog.RESULT_SKIP;
data = null;
data = setSkipPendingEnroll(null);
setResult(resultCode, data);
finish();
}
// User has explicitly canceled enroll. Don't restart it automatically.
data = setSkipPendingEnroll(data);
setResult(resultCode, data);
finish();
}
/**