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
This commit is contained in:
@@ -107,7 +107,10 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
// intent will include this extra containing a bundle of the form:
|
// intent will include this extra containing a bundle of the form:
|
||||||
// "modality" -> consented (boolean).
|
// "modality" -> consented (boolean).
|
||||||
public static final String EXTRA_PARENTAL_CONSENT_STATUS = "consent_status";
|
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_CONFIRMING_CREDENTIALS = "confirming_credentials";
|
||||||
private static final String SAVED_STATE_IS_SINGLE_ENROLLING =
|
private static final String SAVED_STATE_IS_SINGLE_ENROLLING =
|
||||||
"is_single_enrolling";
|
"is_single_enrolling";
|
||||||
@@ -130,6 +133,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
private boolean mIsFingerprintEnrollable = false;
|
private boolean mIsFingerprintEnrollable = false;
|
||||||
private boolean mParentalOptionsRequired = false;
|
private boolean mParentalOptionsRequired = false;
|
||||||
private boolean mSkipReturnToParent = false;
|
private boolean mSkipReturnToParent = false;
|
||||||
|
private boolean mLaunchFaceEnrollFirst = false;
|
||||||
private Bundle mParentalOptions;
|
private Bundle mParentalOptions;
|
||||||
@Nullable private Long mGkPwHandle;
|
@Nullable private Long mGkPwHandle;
|
||||||
@Nullable private ParentalConsentHelper mParentalConsentHelper;
|
@Nullable private ParentalConsentHelper mParentalConsentHelper;
|
||||||
@@ -214,6 +218,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
|
|
||||||
mParentalOptionsRequired = intent.getBooleanExtra(EXTRA_REQUIRE_PARENTAL_CONSENT, false);
|
mParentalOptionsRequired = intent.getBooleanExtra(EXTRA_REQUIRE_PARENTAL_CONSENT, false);
|
||||||
mSkipReturnToParent = intent.getBooleanExtra(EXTRA_SKIP_RETURN_TO_PARENT, false);
|
mSkipReturnToParent = intent.getBooleanExtra(EXTRA_SKIP_RETURN_TO_PARENT, false);
|
||||||
|
mLaunchFaceEnrollFirst = intent.getBooleanExtra(EXTRA_LAUNCH_FACE_ENROLL_FIRST, false);
|
||||||
|
|
||||||
// determine what can be enrolled
|
// determine what can be enrolled
|
||||||
final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
final boolean isSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
|
||||||
@@ -221,6 +226,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
|
|
||||||
Log.d(TAG, "parentalOptionsRequired: " + mParentalOptionsRequired
|
Log.d(TAG, "parentalOptionsRequired: " + mParentalOptionsRequired
|
||||||
+ ", skipReturnToParent: " + mSkipReturnToParent
|
+ ", skipReturnToParent: " + mSkipReturnToParent
|
||||||
|
+ ", launchFaceEnrollFirst: " + mLaunchFaceEnrollFirst
|
||||||
+ ", isSetupWizard: " + isSetupWizard
|
+ ", isSetupWizard: " + isSetupWizard
|
||||||
+ ", isMultiSensor: " + isMultiSensor);
|
+ ", isMultiSensor: " + isMultiSensor);
|
||||||
|
|
||||||
@@ -356,7 +362,8 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
} else if (canUseFace || canUseFingerprint) {
|
} else if (canUseFace || canUseFingerprint) {
|
||||||
if (mGkPwHandle == null) {
|
if (mGkPwHandle == null) {
|
||||||
setOrConfirmCredentialsNow();
|
setOrConfirmCredentialsNow();
|
||||||
} else if (canUseFingerprint && mIsFingerprintEnrollable) {
|
} else if (canUseFingerprint && mIsFingerprintEnrollable
|
||||||
|
&& !(canUseFace && mIsFaceEnrollable && mLaunchFaceEnrollFirst)) {
|
||||||
launchFingerprintOnlyEnroll();
|
launchFingerprintOnlyEnroll();
|
||||||
} else if (canUseFace && mIsFaceEnrollable) {
|
} else if (canUseFace && mIsFaceEnrollable) {
|
||||||
launchFaceOnlyEnroll();
|
launchFaceOnlyEnroll();
|
||||||
@@ -510,7 +517,8 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
int requestCode, int resultCode, Intent data) {
|
int requestCode, int resultCode, Intent data) {
|
||||||
|
|
||||||
Log.d(TAG, "handleOnActivityResultWhileEnrolling, request = " + requestCode + ""
|
Log.d(TAG, "handleOnActivityResultWhileEnrolling, request = " + requestCode + ""
|
||||||
+ ", resultCode = " + resultCode);
|
+ ", resultCode = " + resultCode + ", launchFaceEnrollFirst="
|
||||||
|
+ mLaunchFaceEnrollFirst);
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case REQUEST_HANDOFF_PARENT:
|
case REQUEST_HANDOFF_PARENT:
|
||||||
setResult(RESULT_OK, newResultIntent());
|
setResult(RESULT_OK, newResultIntent());
|
||||||
@@ -526,7 +534,8 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
// SetupFingerprintEnrollIntroduction/FingerprintEnrollmentActivity
|
// SetupFingerprintEnrollIntroduction/FingerprintEnrollmentActivity
|
||||||
TransitionHelper.applyForwardTransition(this, TRANSITION_FADE_THROUGH);
|
TransitionHelper.applyForwardTransition(this, TRANSITION_FADE_THROUGH);
|
||||||
updateGatekeeperPasswordHandle(data);
|
updateGatekeeperPasswordHandle(data);
|
||||||
if (mIsFingerprintEnrollable) {
|
if (mIsFingerprintEnrollable
|
||||||
|
&& !(mIsFaceEnrollable && mLaunchFaceEnrollFirst)) {
|
||||||
launchFingerprintOnlyEnroll();
|
launchFingerprintOnlyEnroll();
|
||||||
} else {
|
} else {
|
||||||
launchFaceOnlyEnroll();
|
launchFaceOnlyEnroll();
|
||||||
@@ -548,7 +557,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
}
|
}
|
||||||
if ((resultCode == BiometricEnrollBase.RESULT_SKIP
|
if ((resultCode == BiometricEnrollBase.RESULT_SKIP
|
||||||
|| resultCode == BiometricEnrollBase.RESULT_FINISHED)
|
|| resultCode == BiometricEnrollBase.RESULT_FINISHED)
|
||||||
&& mIsFaceEnrollable) {
|
&& mIsFaceEnrollable && !mLaunchFaceEnrollFirst) {
|
||||||
// Apply forward animation during the transition from
|
// Apply forward animation during the transition from
|
||||||
// SetupFingerprintEnroll*/FingerprintEnrollmentActivity to
|
// SetupFingerprintEnroll*/FingerprintEnrollmentActivity to
|
||||||
// SetupFaceEnrollIntroduction
|
// SetupFaceEnrollIntroduction
|
||||||
@@ -556,6 +565,9 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
mIsPreviousEnrollmentCanceled =
|
mIsPreviousEnrollmentCanceled =
|
||||||
resultCode != BiometricEnrollBase.RESULT_FINISHED;
|
resultCode != BiometricEnrollBase.RESULT_FINISHED;
|
||||||
launchFaceOnlyEnroll();
|
launchFaceOnlyEnroll();
|
||||||
|
} else if (resultCode == Activity.RESULT_CANCELED && mIsFaceEnrollable
|
||||||
|
&& mLaunchFaceEnrollFirst) {
|
||||||
|
launchFaceOnlyEnroll();
|
||||||
} else {
|
} else {
|
||||||
notifySafetyIssueActionLaunchedIfNeeded(resultCode);
|
notifySafetyIssueActionLaunchedIfNeeded(resultCode);
|
||||||
finishOrLaunchHandToParent(resultCode);
|
finishOrLaunchHandToParent(resultCode);
|
||||||
@@ -563,7 +575,14 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
|
|||||||
break;
|
break;
|
||||||
case REQUEST_SINGLE_ENROLL_FACE:
|
case REQUEST_SINGLE_ENROLL_FACE:
|
||||||
mIsSingleEnrolling = false;
|
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;
|
mIsPreviousEnrollmentCanceled = true;
|
||||||
launchFingerprintOnlyEnroll();
|
launchFingerprintOnlyEnroll();
|
||||||
} else {
|
} else {
|
||||||
|
@@ -43,6 +43,7 @@ import com.android.internal.widget.LockPatternUtils;
|
|||||||
import com.android.internal.widget.VerifyCredentialResponse;
|
import com.android.internal.widget.VerifyCredentialResponse;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SetupWizardUtils;
|
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.FingerprintEnroll;
|
||||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
|
import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
|
||||||
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
|
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
|
||||||
@@ -282,9 +283,7 @@ public class BiometricUtils {
|
|||||||
*/
|
*/
|
||||||
public static Intent getFaceIntroIntent(@NonNull Context context,
|
public static Intent getFaceIntroIntent(@NonNull Context context,
|
||||||
@NonNull Intent activityIntent) {
|
@NonNull Intent activityIntent) {
|
||||||
final Intent intent = new Intent(context,
|
final Intent intent = new Intent(context, FaceEnroll.class);
|
||||||
FeatureFactory.getFeatureFactory().getFaceFeatureProvider()
|
|
||||||
.getEnrollActivityClassProvider().getNext());
|
|
||||||
WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent);
|
WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent);
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
@@ -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.hasComponent;
|
||||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
|
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_BIOMETRICS;
|
||||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
|
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
|
||||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
|
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.face.FaceSensorPropertiesInternal;
|
||||||
import android.hardware.fingerprint.FingerprintManager;
|
import android.hardware.fingerprint.FingerprintManager;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
@@ -145,7 +147,7 @@ public class BiometricEnrollActivityTest {
|
|||||||
assumeTrue(mHasFace || mHasFingerprint);
|
assumeTrue(mHasFace || mHasFingerprint);
|
||||||
|
|
||||||
setPin();
|
setPin();
|
||||||
final Intent intent = getIntent(true /* useInternal */);
|
final Intent intent = getIntent(true /* useInternal */, null);
|
||||||
LockPatternChecker.verifyCredential(new LockPatternUtils(mContext),
|
LockPatternChecker.verifyCredential(new LockPatternUtils(mContext),
|
||||||
LockscreenCredential.createPin(TEST_PIN), UserHandle.myUserId(),
|
LockscreenCredential.createPin(TEST_PIN), UserHandle.myUserId(),
|
||||||
LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, (response, timeoutMs) -> {
|
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
|
@Test
|
||||||
public void launchWithStrongBiometricAllowed_doNotEnrollWeak() throws Exception {
|
public void launchWithStrongBiometricAllowed_doNotEnrollWeak() throws Exception {
|
||||||
assumeTrue(mHasFace || mHasFingerprint);
|
assumeTrue(mHasFace || mHasFingerprint);
|
||||||
@@ -184,13 +206,22 @@ public class BiometricEnrollActivityTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Intent getIntent() {
|
private Intent getIntent() {
|
||||||
return getIntent(false /* useInternal */);
|
return getIntent(false /* useInternal */, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Intent getIntent(boolean useInternal) {
|
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, Bundle bundle) {
|
||||||
final Intent intent = new Intent(mContext, useInternal
|
final Intent intent = new Intent(mContext, useInternal
|
||||||
? BiometricEnrollActivity.InternalActivity.class : BiometricEnrollActivity.class);
|
? BiometricEnrollActivity.InternalActivity.class : BiometricEnrollActivity.class);
|
||||||
intent.setAction(ACTION_BIOMETRIC_ENROLL);
|
intent.setAction(ACTION_BIOMETRIC_ENROLL);
|
||||||
|
if (bundle != null && !bundle.isEmpty()) {
|
||||||
|
intent.putExtras(bundle);
|
||||||
|
}
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user