Merge "Disable combined controller only if all modalities require consent" into sc-v2-dev am: b84b7d586a

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/16265888

Change-Id: Idb41f923cdbe1ebc251a1c033d8066404898f768
This commit is contained in:
TreeHugger Robot
2021-11-18 03:41:27 +00:00
committed by Automerger Merge Worker
5 changed files with 81 additions and 22 deletions

View File

@@ -242,12 +242,11 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
} }
} }
// start enrollment process if we haven't bailed out yet
if (mParentalOptionsRequired && mParentalOptions == null) { if (mParentalOptionsRequired && mParentalOptions == null) {
mParentalConsentHelper = new ParentalConsentHelper( mParentalConsentHelper = new ParentalConsentHelper(mGkPwHandle);
mIsFaceEnrollable, mIsFingerprintEnrollable, mGkPwHandle);
setOrConfirmCredentialsNow(); setOrConfirmCredentialsNow();
} else { } else {
// Start enrollment process if we haven't bailed out yet
startEnroll(); startEnroll();
} }
} }
@@ -263,7 +262,10 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
private void startEnrollWith(@Authenticators.Types int authenticators, boolean setupWizard) { private void startEnrollWith(@Authenticators.Types int authenticators, boolean setupWizard) {
// If the caller is not setup wizard, and the user has something enrolled, finish. // If the caller is not setup wizard, and the user has something enrolled, finish.
if (!setupWizard) { // Allow parental consent flow to skip this check, since one modality could be consented
// and another non-consented. This can also happen if the restriction is applied when
// enrollments already exists.
if (!setupWizard && !mParentalOptionsRequired) {
final BiometricManager bm = getSystemService(BiometricManager.class); final BiometricManager bm = getSystemService(BiometricManager.class);
final @BiometricError int result = bm.canAuthenticate(authenticators); final @BiometricError int result = bm.canAuthenticate(authenticators);
if (result != BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) { if (result != BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) {
@@ -330,6 +332,25 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
// single enrollment is handled entirely by the launched activity // single enrollment is handled entirely by the launched activity
// this handles multi enroll or if parental consent is required // this handles multi enroll or if parental consent is required
if (mParentalConsentHelper != null) { if (mParentalConsentHelper != null) {
// Lazily retrieve the values from ParentalControlUtils, since the value may not be
// ready in onCreate.
final boolean faceConsentRequired = ParentalControlsUtils
.parentConsentRequired(this, BiometricAuthenticator.TYPE_FACE) != null;
final boolean fpConsentRequired = ParentalControlsUtils
.parentConsentRequired(this, BiometricAuthenticator.TYPE_FINGERPRINT) != null;
final boolean requestFaceConsent = faceConsentRequired && mHasFeatureFace;
final boolean requestFpConsent = fpConsentRequired && mHasFeatureFingerprint;
Log.d(TAG, "faceConsentRequired: " + faceConsentRequired
+ ", fpConsentRequired: " + fpConsentRequired
+ ", hasFeatureFace: " + mHasFeatureFace
+ ", hasFeatureFingerprint: " + mHasFeatureFingerprint
+ ", faceEnrollable: " + mIsFaceEnrollable
+ ", fpEnrollable: " + mIsFingerprintEnrollable);
mParentalConsentHelper.setConsentRequirement(requestFaceConsent, requestFpConsent);
handleOnActivityResultWhileConsenting(requestCode, resultCode, data); handleOnActivityResultWhileConsenting(requestCode, resultCode, data);
} else { } else {
handleOnActivityResultWhileEnrolling(requestCode, resultCode, data); handleOnActivityResultWhileEnrolling(requestCode, resultCode, data);
@@ -362,10 +383,18 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
final boolean isStillPrompting = mParentalConsentHelper.launchNext( final boolean isStillPrompting = mParentalConsentHelper.launchNext(
this, REQUEST_CHOOSE_OPTIONS, resultCode, data); this, REQUEST_CHOOSE_OPTIONS, resultCode, data);
if (!isStillPrompting) { if (!isStillPrompting) {
Log.d(TAG, "Enrollment consent options set, starting enrollment");
mParentalOptions = mParentalConsentHelper.getConsentResult(); mParentalOptions = mParentalConsentHelper.getConsentResult();
mParentalConsentHelper = null; mParentalConsentHelper = null;
startEnroll(); Log.d(TAG, "Enrollment consent options set, starting enrollment: "
+ mParentalOptions);
// Note that we start enrollment with CONVENIENCE instead of the default
// of WEAK in startEnroll(), since we want to allow enrollment for any
// sensor as long as it has been consented for. We should eventually
// clean up this logic and do something like pass in the parental consent
// result, so that we can request enrollment for specific sensors, but
// that's quite a large and risky change to the startEnrollWith() logic.
startEnrollWith(Authenticators.BIOMETRIC_CONVENIENCE,
WizardManagerHelper.isAnySetupWizard(getIntent()));
} }
} else { } else {
Log.d(TAG, "Unknown or cancelled parental consent"); Log.d(TAG, "Unknown or cancelled parental consent");

View File

@@ -52,8 +52,8 @@ public class ParentalConsentHelper {
private static final String KEY_FINGERPRINT_CONSENT_STRINGS = "fingerprint_strings"; private static final String KEY_FINGERPRINT_CONSENT_STRINGS = "fingerprint_strings";
private static final String KEY_IRIS_CONSENT_STRINGS = "iris_strings"; private static final String KEY_IRIS_CONSENT_STRINGS = "iris_strings";
private final boolean mRequireFace; private boolean mRequireFace;
private final boolean mRequireFingerprint; private boolean mRequireFingerprint;
private long mGkPwHandle; private long mGkPwHandle;
@Nullable @Nullable
@@ -64,15 +64,19 @@ public class ParentalConsentHelper {
/** /**
* Helper for aggregating user consent. * Helper for aggregating user consent.
* *
* @param requireFace if face consent should be shown
* @param requireFingerprint if fingerprint consent should be shown
* @param gkPwHandle for launched intents * @param gkPwHandle for launched intents
*/ */
public ParentalConsentHelper(boolean requireFace, boolean requireFingerprint, public ParentalConsentHelper(@Nullable Long gkPwHandle) {
@Nullable Long gkPwHandle) { mGkPwHandle = gkPwHandle != null ? gkPwHandle : 0L;
}
/**
* @param requireFace if face consent should be shown
* @param requireFingerprint if fingerprint consent should be shown
*/
public void setConsentRequirement(boolean requireFace, boolean requireFingerprint) {
mRequireFace = requireFace; mRequireFace = requireFace;
mRequireFingerprint = requireFingerprint; mRequireFingerprint = requireFingerprint;
mGkPwHandle = gkPwHandle != null ? gkPwHandle : 0L;
} }
/** /**

View File

@@ -104,12 +104,34 @@ public class CombinedBiometricStatusPreferenceController extends
private void updateStateInternal() { private void updateStateInternal() {
// This controller currently is shown if fingerprint&face exist on the device. If this // This controller currently is shown if fingerprint&face exist on the device. If this
// changes in the future, the modalities passed into the below will need to be updated. // changes in the future, the modalities passed into the below will need to be updated.
updateStateInternal(ParentalControlsUtils.parentConsentRequired(mContext,
BiometricAuthenticator.TYPE_FACE | BiometricAuthenticator.TYPE_FINGERPRINT)); final RestrictedLockUtils.EnforcedAdmin faceAdmin = ParentalControlsUtils
.parentConsentRequired(mContext, BiometricAuthenticator.TYPE_FACE);
final RestrictedLockUtils.EnforcedAdmin fpAdmin = ParentalControlsUtils
.parentConsentRequired(mContext, BiometricAuthenticator.TYPE_FINGERPRINT);
// If the admins are non-null, they are actually always the same. Just the helper class
// we create above always return the admin, instead of a boolean.
final boolean faceConsentRequired = faceAdmin != null;
final boolean fpConsentRequired = fpAdmin != null;
final RestrictedLockUtils.EnforcedAdmin admin = faceAdmin != null ? faceAdmin : fpAdmin;
updateStateInternal(admin, faceConsentRequired, fpConsentRequired);
} }
@VisibleForTesting @VisibleForTesting
void updateStateInternal(@Nullable RestrictedLockUtils.EnforcedAdmin enforcedAdmin) { void updateStateInternal(@Nullable RestrictedLockUtils.EnforcedAdmin enforcedAdmin,
boolean faceConsentRequired, boolean fpConsentRequired) {
// Disable the preference (and show the consent flow) only if consent is required for all
// modalities. Otherwise, users will not be able to enter and modify settings for modalities
// which have already been consented. In any case, the controllers for the modalities which
// have not yet been consented will be disabled in the combined page anyway - users can
// go through the consent+enrollment flow from there.
final boolean disablePreference = faceConsentRequired && fpConsentRequired;
if (!disablePreference) {
enforcedAdmin = null;
}
if (mPreference != null) { if (mPreference != null) {
mPreference.setDisabledByAdmin(enforcedAdmin); mPreference.setDisabledByAdmin(enforcedAdmin);
} }

View File

@@ -104,12 +104,16 @@ public class CombinedBiometricStatusPreferenceControllerTest {
RestrictedLockUtils.EnforcedAdmin admin = mock(RestrictedLockUtils.EnforcedAdmin.class); RestrictedLockUtils.EnforcedAdmin admin = mock(RestrictedLockUtils.EnforcedAdmin.class);
mController.mPreference = restrictedPreference; mController.mPreference = restrictedPreference;
mController.updateStateInternal(admin); mController.updateStateInternal(admin, true, true);
verify(restrictedPreference).setDisabledByAdmin(eq(admin)); verify(restrictedPreference).setDisabledByAdmin(eq(admin));
reset(admin); mController.updateStateInternal(admin, true, false);
verify(restrictedPreference).setDisabledByAdmin(eq(null));
mController.updateStateInternal(null /* enforcedAdmin */); mController.updateStateInternal(admin, false, true);
verify(restrictedPreference, never()).setDisabledByAdmin(any()); verify(restrictedPreference).setDisabledByAdmin(eq(null));
mController.updateStateInternal(admin, false, false);
verify(restrictedPreference).setDisabledByAdmin(eq(null));
} }
} }

View File

@@ -167,8 +167,8 @@ public class ParentalConsentHelperTest {
} }
// initial consent status // initial consent status
final ParentalConsentHelper helper = final ParentalConsentHelper helper = new ParentalConsentHelper(gkpw);
new ParentalConsentHelper(requireFace, requireFingerprint, gkpw); helper.setConsentRequirement(requireFace, requireFingerprint);
assertThat(ParentalConsentHelper.hasFaceConsent(helper.getConsentResult())) assertThat(ParentalConsentHelper.hasFaceConsent(helper.getConsentResult()))
.isFalse(); .isFalse();
assertThat(ParentalConsentHelper.hasFingerprintConsent(helper.getConsentResult())) assertThat(ParentalConsentHelper.hasFingerprintConsent(helper.getConsentResult()))