From 92ea474b8631b4c0de770f05c8218284d5ace1e8 Mon Sep 17 00:00:00 2001 From: Diya Bera Date: Mon, 12 Aug 2024 02:40:37 +0000 Subject: [PATCH] Add mandatory biometric prompt to platform surfaces (5/N) 1. For biometric settings, request biometric prompt only after successful credential verification and no auth request after enrollment 2. Differentiate between mandatory biometrics ineffective error and other biometric errors Flag: android.hardware.biometrics.flags.mandatory_biometrics Bug: 358176202 Bug: 358179610 Test: atest UtilsTest DevelopmentSettingsDashboardFragmentTest MainClearTest BuildNumberPreferenceControllerTest CombinedBiometricProfileSettingsTest Change-Id: I778dd5403dd5ab64d8cc39bd88b22c4d39182e94 --- src/com/android/settings/MainClear.java | 11 +++-- src/com/android/settings/Utils.java | 46 ++++++++++++------ .../combination/BiometricsSettingsBase.java | 48 ++++++------------- .../biometrics/face/FaceSettings.java | 29 +++++------ .../fingerprint/FingerprintSettings.java | 39 +++++---------- .../DevelopmentSettingsDashboardFragment.java | 15 ++++-- .../BuildNumberPreferenceController.java | 14 +++--- .../settings/password/ChooseLockGeneric.java | 13 +++-- .../com/android/settings/MainClearTest.java | 34 +++++++++++-- .../src/com/android/settings/UtilsTest.java | 28 +++++------ .../CombinedBiometricProfileSettingsTest.java | 4 +- .../FingerprintSettingsFragmentTest.java | 17 ++++--- .../BuildNumberPreferenceControllerTest.java | 43 ++++++++++++++++- 13 files changed, 205 insertions(+), 136 deletions(-) diff --git a/src/com/android/settings/MainClear.java b/src/com/android/settings/MainClear.java index ab7a7146329..711d7943ffa 100644 --- a/src/com/android/settings/MainClear.java +++ b/src/com/android/settings/MainClear.java @@ -183,13 +183,16 @@ public class MainClear extends InstrumentedFragment implements OnGlobalLayoutLis if (requestCode == KEYGUARD_REQUEST) { final int userId = getActivity().getUserId(); - if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(), - false /* biometricsSuccessfullyAuthenticated */, - false /* biometricsAuthenticationRequested */, - userId)) { + final Utils.BiometricStatus biometricAuthStatus = + Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(), + false /* biometricsAuthenticationRequested */, + userId); + if (biometricAuthStatus == Utils.BiometricStatus.OK) { Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRICS_REQUEST, userId, false /* hideBackground */); return; + } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { + return; } } diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index badcb63791c..3646938e1f8 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -199,6 +199,15 @@ public final class Utils extends com.android.settingslib.Utils { return ActivityManager.isUserAMonkey(); } + /** + * Enum for returning biometric status. + * {@link OK} no error detected when requesting mandatory biometrics authentication + * {@link NOT_ACTIVE} mandatory biometrics is not active + * {@link LOCKOUT} biometric sensors are in lockout mode + * {@link ERROR} corresponds to other errors + */ + public enum BiometricStatus {OK, NOT_ACTIVE, LOCKOUT, ERROR} + /** * Returns whether the device is voice-capable (meaning, it is also a phone). */ @@ -1489,34 +1498,41 @@ public final class Utils extends com.android.settingslib.Utils { /** * Request biometric authentication if all requirements for mandatory biometrics is satisfied. * - * @param context of the corresponding activity/fragment - * @param biometricsSuccessfullyAuthenticated if the user has already authenticated using - * biometrics - * @param biometricsAuthenticationRequested if the activity/fragment has already requested for - * biometric prompt - * @param userId user id for the authentication request - * @return true if all requirements for mandatory biometrics is satisfied + * @param context of the corresponding activity/fragment + * @param biometricsAuthenticationRequested if the activity/fragment has already requested for + * biometric prompt + * @param userId user id for the authentication request + * @return biometric status when mandatory biometrics authentication is requested */ - public static boolean requestBiometricAuthenticationForMandatoryBiometrics( + public static BiometricStatus requestBiometricAuthenticationForMandatoryBiometrics( @NonNull Context context, - boolean biometricsSuccessfullyAuthenticated, boolean biometricsAuthenticationRequested, int userId) { final BiometricManager biometricManager = context.getSystemService(BiometricManager.class); if (biometricManager == null) { Log.e(TAG, "Biometric Manager is null."); - return false; + return BiometricStatus.NOT_ACTIVE; } final int status = biometricManager.canAuthenticate(userId, BiometricManager.Authenticators.MANDATORY_BIOMETRICS); - return android.hardware.biometrics.Flags.mandatoryBiometrics() - && status == BiometricManager.BIOMETRIC_SUCCESS - && !biometricsSuccessfullyAuthenticated - && !biometricsAuthenticationRequested; + if (android.hardware.biometrics.Flags.mandatoryBiometrics() + && !biometricsAuthenticationRequested) { + switch(status) { + case BiometricManager.BIOMETRIC_SUCCESS: + return BiometricStatus.OK; + case BiometricManager.BIOMETRIC_ERROR_LOCKOUT: + return BiometricStatus.LOCKOUT; + case BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE: + return BiometricStatus.NOT_ACTIVE; + default: + return BiometricStatus.ERROR; + } + } + return BiometricStatus.NOT_ACTIVE; } /** * Launch biometric prompt for mandatory biometrics. Call - * {@link #requestBiometricAuthenticationForMandatoryBiometrics(Context, boolean, boolean, int)} + * {@link #requestBiometricAuthenticationForMandatoryBiometrics(Context, boolean, int)} * to check if all requirements for mandatory biometrics is satisfied * before launching biometric prompt. * diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java index 11194ce92dc..43b5da28044 100644 --- a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java +++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java @@ -75,14 +75,11 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { @VisibleForTesting static final String RETRY_PREFERENCE_BUNDLE = "retry_preference_bundle"; private static final String BIOMETRICS_AUTH_REQUESTED = "biometrics_auth_requested"; - private static final String BIOMETRICS_AUTHENTICATED_SUCCESSFULLY = - "biometrics_authenticated_successfully"; protected int mUserId; protected long mGkPwHandle; private boolean mConfirmCredential; private boolean mBiometricsAuthenticationRequested; - private boolean mBiometricsSuccessfullyAuthenticated; @Nullable private FaceManager mFaceManager; @Nullable private FingerprintManager mFingerprintManager; // Do not finish() if choosing/confirming credential, showing fp/face settings, or launching @@ -120,9 +117,6 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { mGkPwHandle = BiometricUtils.getGatekeeperPasswordHandle(getIntent()); } - mBiometricsSuccessfullyAuthenticated = getIntent().getBooleanExtra( - BIOMETRICS_AUTHENTICATED_SUCCESSFULLY, false); - if (savedInstanceState != null) { mConfirmCredential = savedInstanceState.getBoolean(SAVE_STATE_CONFIRM_CREDETIAL); mDoNotFinishActivity = savedInstanceState.getBoolean(DO_NOT_FINISH_ACTIVITY); @@ -135,21 +129,12 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { } mBiometricsAuthenticationRequested = savedInstanceState.getBoolean( BIOMETRICS_AUTH_REQUESTED); - mBiometricsSuccessfullyAuthenticated = savedInstanceState.getBoolean( - BIOMETRICS_AUTHENTICATED_SUCCESSFULLY); } if (mGkPwHandle == 0L && !mConfirmCredential) { mConfirmCredential = true; launchChooseOrConfirmLock(); - } else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics( - getActivity(), mBiometricsSuccessfullyAuthenticated, - mBiometricsAuthenticationRequested, mUserId)) { - mBiometricsAuthenticationRequested = true; - Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST, - mUserId, true /* hideBackground */); } - updateUnlockPhonePreferenceSummary(); final Preference useInAppsPreference = findPreference(getUseInAppsPreferenceKey()); @@ -161,13 +146,6 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { @Override public void onResume() { super.onResume(); - if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(), - mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested, mUserId) - && mGkPwHandle != 0L) { - mBiometricsAuthenticationRequested = true; - Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST, - mUserId, true /* hideBackground */); - } if (!mConfirmCredential) { mDoNotFinishActivity = false; } @@ -204,9 +182,6 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { extras.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token); extras.putInt(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId); extras.putLong(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge); - extras.putBoolean( - BiometricEnrollBase.EXTRA_BIOMETRICS_AUTHENTICATED_SUCCESSFULLY, - mBiometricsSuccessfullyAuthenticated); onFaceOrFingerprintPreferenceTreeClick(preference); } catch (IllegalStateException e) { if (retry) { @@ -236,9 +211,6 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { final Bundle extras = preference.getExtras(); extras.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token); extras.putLong(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge); - extras.putBoolean( - BiometricEnrollBase.EXTRA_BIOMETRICS_AUTHENTICATED_SUCCESSFULLY, - mBiometricsSuccessfullyAuthenticated); onFaceOrFingerprintPreferenceTreeClick(preference); } catch (IllegalStateException e) { if (retry) { @@ -323,8 +295,6 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { } outState.putBoolean(BIOMETRICS_AUTH_REQUESTED, mBiometricsAuthenticationRequested); - outState.putBoolean(BIOMETRICS_AUTHENTICATED_SUCCESSFULLY, - mBiometricsSuccessfullyAuthenticated); } @Override @@ -342,6 +312,20 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { com.google.android.setupdesign.R.anim.sud_slide_next_out); retryPreferenceKey(mRetryPreferenceKey, mRetryPreferenceExtra); } + final Utils.BiometricStatus biometricAuthStatus = + Utils.requestBiometricAuthenticationForMandatoryBiometrics( + getActivity(), + mBiometricsAuthenticationRequested, + mUserId); + if (biometricAuthStatus == Utils.BiometricStatus.OK) { + mBiometricsAuthenticationRequested = true; + Utils.launchBiometricPromptForMandatoryBiometrics(this, + BIOMETRIC_AUTH_REQUEST, + mUserId, true /* hideBackground */); + } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { + finish(); + return; + } } else { Log.d(getLogTag(), "Data null or GK PW missing."); finish(); @@ -354,9 +338,7 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { mRetryPreferenceExtra = null; } else if (requestCode == BIOMETRIC_AUTH_REQUEST) { mBiometricsAuthenticationRequested = false; - if (resultCode == RESULT_OK) { - mBiometricsSuccessfullyAuthenticated = true; - } else { + if (resultCode != RESULT_OK) { finish(); } } diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java index bcd523142be..d42b570b30d 100644 --- a/src/com/android/settings/biometrics/face/FaceSettings.java +++ b/src/com/android/settings/biometrics/face/FaceSettings.java @@ -23,7 +23,6 @@ import static com.android.settings.Utils.isPrivateProfile; import static com.android.settings.biometrics.BiometricEnrollBase.BIOMETRIC_AUTH_REQUEST; import static com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST; import static com.android.settings.biometrics.BiometricEnrollBase.ENROLL_REQUEST; -import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_BIOMETRICS_AUTHENTICATED_SUCCESSFULLY; import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED; import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_TIMEOUT; @@ -98,7 +97,6 @@ public class FaceSettings extends DashboardFragment { private boolean mConfirmingPassword; private boolean mBiometricsAuthenticationRequested; - private boolean mBiometricsSuccessfullyAuthenticated; private final FaceSettingsRemoveButtonPreferenceController.Listener mRemovalListener = () -> { @@ -150,8 +148,6 @@ public class FaceSettings extends DashboardFragment { public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putByteArray(KEY_TOKEN, mToken); - outState.putBoolean(KEY_BIOMETRICS_SUCCESSFULLY_AUTHENTICATED, - mBiometricsSuccessfullyAuthenticated); } @Override @@ -171,8 +167,6 @@ public class FaceSettings extends DashboardFragment { mToken = getIntent().getByteArrayExtra(KEY_TOKEN); mSensorId = getIntent().getIntExtra(BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, -1); mChallenge = getIntent().getLongExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, 0L); - mBiometricsSuccessfullyAuthenticated = getIntent().getBooleanExtra( - EXTRA_BIOMETRICS_AUTHENTICATED_SUCCESSFULLY, false); mUserId = getActivity().getIntent().getIntExtra( Intent.EXTRA_USER_ID, UserHandle.myUserId()); @@ -241,8 +235,6 @@ public class FaceSettings extends DashboardFragment { if (savedInstanceState != null) { mToken = savedInstanceState.getByteArray(KEY_TOKEN); - mBiometricsSuccessfullyAuthenticated = savedInstanceState.getBoolean( - KEY_BIOMETRICS_SUCCESSFULLY_AUTHENTICATED); } } @@ -288,12 +280,6 @@ public class FaceSettings extends DashboardFragment { Log.e(TAG, "Password not set"); finish(); } - } else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(), - mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested, - mUserId)) { - mBiometricsAuthenticationRequested = true; - Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST, - mUserId, true /* hideBackground */); } else { mAttentionController.setToken(mToken); mEnrollController.setToken(mToken); @@ -330,6 +316,17 @@ public class FaceSettings extends DashboardFragment { final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId); mEnrollButton.setVisible(!hasEnrolled); mRemoveButton.setVisible(hasEnrolled); + final Utils.BiometricStatus biometricAuthStatus = + Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(), + mBiometricsAuthenticationRequested, + mUserId); + if (biometricAuthStatus == Utils.BiometricStatus.OK) { + Utils.launchBiometricPromptForMandatoryBiometrics(this, + BIOMETRIC_AUTH_REQUEST, + mUserId, true /* hideBackground */); + } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { + finish(); + } } } else if (requestCode == ENROLL_REQUEST) { if (resultCode == RESULT_TIMEOUT) { @@ -338,9 +335,7 @@ public class FaceSettings extends DashboardFragment { } } else if (requestCode == BIOMETRIC_AUTH_REQUEST) { mBiometricsAuthenticationRequested = false; - if (resultCode == RESULT_OK) { - mBiometricsSuccessfullyAuthenticated = true; - } else { + if (resultCode != RESULT_OK) { finish(); } } diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index 526ae8f6ed0..125691fbf1c 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -239,8 +239,6 @@ public class FingerprintSettings extends SubSettings { "security_settings_fingerprint_footer"; private static final String KEY_BIOMETRICS_AUTHENTICATION_REQUESTED = "biometrics_authentication_requested"; - private static final String KEY_BIOMETRICS_SUCCESSFULLY_AUTHENTICATED = - "biometrics_successfully_authenticated"; private static final int MSG_REFRESH_FINGERPRINT_TEMPLATES = 1000; private static final int MSG_FINGER_AUTH_SUCCESS = 1001; @@ -276,7 +274,6 @@ public class FingerprintSettings extends SubSettings { private byte[] mToken; private boolean mLaunchedConfirm; private boolean mBiometricsAuthenticationRequested; - private boolean mBiometricsSuccessfullyAuthenticated; private boolean mHasFirstEnrolled = true; private Drawable mHighlightDrawable; private int mUserId; @@ -451,8 +448,6 @@ public class FingerprintSettings extends SubSettings { ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); mChallenge = activity.getIntent() .getLongExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, -1L); - mBiometricsSuccessfullyAuthenticated = getIntent().getBooleanExtra( - BiometricEnrollBase.EXTRA_BIOMETRICS_AUTHENTICATED_SUCCESSFULLY, false); mAuthenticateSidecar = (FingerprintAuthenticateSidecar) getFragmentManager().findFragmentByTag(TAG_AUTHENTICATE_SIDECAR); @@ -494,8 +489,6 @@ public class FingerprintSettings extends SubSettings { mIsEnrolling = savedInstanceState.getBoolean(KEY_IS_ENROLLING, mIsEnrolling); mHasFirstEnrolled = savedInstanceState.getBoolean(KEY_HAS_FIRST_ENROLLED, mHasFirstEnrolled); - mBiometricsSuccessfullyAuthenticated = savedInstanceState.getBoolean( - KEY_BIOMETRICS_SUCCESSFULLY_AUTHENTICATED); mBiometricsAuthenticationRequested = savedInstanceState.getBoolean( KEY_BIOMETRICS_AUTHENTICATION_REQUESTED); } @@ -506,12 +499,6 @@ public class FingerprintSettings extends SubSettings { if (mToken == null) { mLaunchedConfirm = true; launchChooseOrConfirmLock(); - } else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(), - mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested, - mUserId)) { - mBiometricsAuthenticationRequested = true; - Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST, - mUserId, true /* hideBackground */); } else if (!mHasFirstEnrolled) { mIsEnrolling = true; addFirstFingerprint(null); @@ -801,14 +788,6 @@ public class FingerprintSettings extends SubSettings { mCalibrator = FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider() .getUdfpsEnrollCalibrator(getActivity().getApplicationContext(), null, null); - - if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(), - mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested, - mUserId)) { - mBiometricsAuthenticationRequested = true; - Utils.launchBiometricPromptForMandatoryBiometrics(this, - BIOMETRIC_AUTH_REQUEST, mUserId, true /* hideBackground */); - } } private void updatePreferences() { @@ -858,8 +837,6 @@ public class FingerprintSettings extends SubSettings { outState.putBoolean(KEY_HAS_FIRST_ENROLLED, mHasFirstEnrolled); outState.putBoolean(KEY_BIOMETRICS_AUTHENTICATION_REQUESTED, mBiometricsAuthenticationRequested); - outState.putBoolean(KEY_BIOMETRICS_SUCCESSFULLY_AUTHENTICATED, - mBiometricsSuccessfullyAuthenticated); } @Override @@ -1023,6 +1000,18 @@ public class FingerprintSettings extends SubSettings { updateAddPreference(); }); } + final Utils.BiometricStatus biometricAuthStatus = + Utils.requestBiometricAuthenticationForMandatoryBiometrics( + getActivity(), + mBiometricsAuthenticationRequested, + mUserId); + if (biometricAuthStatus == Utils.BiometricStatus.OK) { + Utils.launchBiometricPromptForMandatoryBiometrics(this, + BIOMETRIC_AUTH_REQUEST, + mUserId, true /* hideBackground */); + } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { + finish(); + } } else { Log.d(TAG, "Data null or GK PW missing"); finish(); @@ -1075,9 +1064,7 @@ public class FingerprintSettings extends SubSettings { updateAddPreference(); } else if (requestCode == BIOMETRIC_AUTH_REQUEST) { mBiometricsAuthenticationRequested = false; - if (resultCode == RESULT_OK) { - mBiometricsSuccessfullyAuthenticated = true; - } else { + if (resultCode != RESULT_OK) { finish(); } } diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index 666d24dc50c..0df822af185 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -365,12 +365,19 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra if (isChecked != developmentEnabledState) { if (isChecked) { final int userId = getContext().getUserId(); - if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getContext(), - mIsBiometricsAuthenticated, - false /* biometricsAuthenticationRequested */, userId)) { + + final Utils.BiometricStatus biometricAuthStatus = + Utils.requestBiometricAuthenticationForMandatoryBiometrics( + getContext(), + mIsBiometricsAuthenticated, + userId); + if (biometricAuthStatus == Utils.BiometricStatus.OK) { mSwitchBar.setChecked(false); Utils.launchBiometricPromptForMandatoryBiometrics(this, - REQUEST_BIOMETRIC_PROMPT, userId, false /* hideBackground */); + REQUEST_BIOMETRIC_PROMPT, + userId, false /* hideBackground */); + } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { + mSwitchBar.setChecked(false); } else { //Reset biometrics once enable dialog is shown mIsBiometricsAuthenticated = false; diff --git a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java index cf6b3e33e76..a9f94b49b45 100644 --- a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java +++ b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java @@ -225,13 +225,15 @@ public class BuildNumberPreferenceController extends BasePreferenceController im if (requestCode == REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF && resultCode == Activity.RESULT_OK) { final int userId = mContext.getUserId(); - if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext, - false /* biometricsSuccessfullyAuthenticated */, - false /* biometricsAuthenticationRequested */, - userId)) { + final Utils.BiometricStatus biometricAuthStatus = + Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext, + false /* biometricsAuthenticationRequested */, + userId); + if (biometricAuthStatus == Utils.BiometricStatus.OK) { Utils.launchBiometricPromptForMandatoryBiometrics(mFragment, - REQUEST_IDENTITY_CHECK_FOR_DEV_PREF, userId, false /* hideBackground */); - } else { + REQUEST_IDENTITY_CHECK_FOR_DEV_PREF, + userId, false /* hideBackground */); + } else if (biometricAuthStatus == Utils.BiometricStatus.NOT_ACTIVE) { enableDevelopmentSettings(); } } else if (requestCode == REQUEST_IDENTITY_CHECK_FOR_DEV_PREF diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index 34c0731184e..09091102f24 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -491,11 +491,16 @@ public class ChooseLockGeneric extends SettingsActivity { ? data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD) : null; updatePreferencesOrFinish(false /* isRecreatingActivity */); - if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getContext(), - mBiometricsAuthSuccessful, mWaitingForConfirmation, mUserId)) { - mWaitingForConfirmation = true; - Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST, + final Utils.BiometricStatus biometricAuthStatus = + Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(), + false /* biometricsAuthenticationRequested */, + mUserId); + if (biometricAuthStatus == Utils.BiometricStatus.OK) { + Utils.launchBiometricPromptForMandatoryBiometrics(this, + BIOMETRIC_AUTH_REQUEST, mUserId, true /* hideBackground */); + } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { + finish(); } } else if (requestCode == BIOMETRIC_AUTH_REQUEST) { if (resultCode == Activity.RESULT_OK) { diff --git a/tests/robotests/src/com/android/settings/MainClearTest.java b/tests/robotests/src/com/android/settings/MainClearTest.java index 26a430b161c..b705ae14cac 100644 --- a/tests/robotests/src/com/android/settings/MainClearTest.java +++ b/tests/robotests/src/com/android/settings/MainClearTest.java @@ -142,7 +142,7 @@ public class MainClearTest { when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager); when(mBiometricManager.canAuthenticate(anyInt(), eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS))) - .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE); + .thenReturn(BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE); } @After @@ -388,6 +388,30 @@ public class MainClearTest { verify(mMainClear, times(0)).showFinalConfirmation(); } + @Test + @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS) + public void testOnActivityResultInternal_keyguardRequestNotTriggeringBiometricPrompt_lockoutError() { + when(mContext.getResources()).thenReturn(mResources); + when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager); + when(mResources.getString(anyInt())).thenReturn(TEST_ACCOUNT_NAME); + when(mBiometricManager.canAuthenticate(anyInt(), + eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS))) + .thenReturn(BiometricManager.BIOMETRIC_ERROR_LOCKOUT); + doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST)); + doNothing().when(mMainClear).startActivityForResult(any(), anyInt()); + doReturn(mMockActivity).when(mMainClear).getActivity(); + doReturn(mContext).when(mMainClear).getContext(); + + mMainClear + .onActivityResultInternal(MainClear.KEYGUARD_REQUEST, Activity.RESULT_OK, null); + + verify(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST)); + verify(mMainClear, never()).startActivityForResult(any(), eq(MainClear.BIOMETRICS_REQUEST)); + verify(mMainClear, never()).establishInitialState(); + verify(mMainClear, never()).getAccountConfirmationIntent(); + verify(mMainClear, never()).showFinalConfirmation(); + } + @Test public void testOnActivityResultInternal_biometricRequestTriggeringFinalConfirmation() { doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.BIOMETRICS_REQUEST)); @@ -397,10 +421,10 @@ public class MainClearTest { mMainClear .onActivityResultInternal(MainClear.BIOMETRICS_REQUEST, Activity.RESULT_OK, null); - verify(mMainClear, times(1)).isValidRequestCode(eq(MainClear.BIOMETRICS_REQUEST)); - verify(mMainClear, times(0)).establishInitialState(); - verify(mMainClear, times(1)).getAccountConfirmationIntent(); - verify(mMainClear, times(1)).showFinalConfirmation(); + verify(mMainClear).isValidRequestCode(eq(MainClear.BIOMETRICS_REQUEST)); + verify(mMainClear, never()).establishInitialState(); + verify(mMainClear).getAccountConfirmationIntent(); + verify(mMainClear).showFinalConfirmation(); } @Test diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java index 2aeb9063b1e..107a1b333df 100644 --- a/tests/robotests/src/com/android/settings/UtilsTest.java +++ b/tests/robotests/src/com/android/settings/UtilsTest.java @@ -530,40 +530,40 @@ public class UtilsTest { @Test @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS) - public void testRequestBiometricAuthentication_biometricManagerNull_shouldReturnFalse() { + public void testRequestBiometricAuthentication_biometricManagerNull_shouldReturnNotActive() { when(mContext.getSystemService(BiometricManager.class)).thenReturn(null); assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext, - false /* biometricsSuccessfullyAuthenticated */, - false /* biometricsAuthenticationRequested */, USER_ID)).isFalse(); + false /* biometricsAuthenticationRequested */, USER_ID)).isEqualTo( + Utils.BiometricStatus.NOT_ACTIVE); } @Test @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS) - public void testRequestBiometricAuthentication_biometricManagerReturnsSuccess_shouldReturnTrue() { + public void testRequestBiometricAuthentication_biometricManagerReturnsSuccess_shouldReturnOk() { when(mBiometricManager.canAuthenticate(USER_ID, BiometricManager.Authenticators.MANDATORY_BIOMETRICS)) .thenReturn(BiometricManager.BIOMETRIC_SUCCESS); - final boolean requestBiometricAuthenticationForMandatoryBiometrics = + final Utils.BiometricStatus requestBiometricAuthenticationForMandatoryBiometrics = Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext, - false /* biometricsSuccessfullyAuthenticated */, - false /* biometricsAuthenticationRequested */, USER_ID); - assertThat(requestBiometricAuthenticationForMandatoryBiometrics).isTrue(); + false /* biometricsAuthenticationRequested */, USER_ID); + assertThat(requestBiometricAuthenticationForMandatoryBiometrics).isEqualTo( + Utils.BiometricStatus.OK); } @Test @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS) - public void testRequestBiometricAuthentication_biometricManagerReturnsError_shouldReturnFalse() { + public void testRequestBiometricAuthentication_biometricManagerReturnsError_shouldReturnError() { when(mBiometricManager.canAuthenticate(anyInt(), eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS))) .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE); assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext, - false /* biometricsSuccessfullyAuthenticated */, - false /* biometricsAuthenticationRequested */, USER_ID)).isFalse(); + false /* biometricsAuthenticationRequested */, USER_ID)).isEqualTo( + Utils.BiometricStatus.ERROR); } @Test @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS) - public void testRequestBiometricAuthentication_biometricManagerReturnsSuccessForDifferentUser_shouldReturnFalse() { + public void testRequestBiometricAuthentication_biometricManagerReturnsSuccessForDifferentUser_shouldReturnError() { when(mBiometricManager.canAuthenticate(anyInt(), eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS))) .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE); @@ -571,8 +571,8 @@ public class UtilsTest { BiometricManager.Authenticators.MANDATORY_BIOMETRICS)) .thenReturn(BiometricManager.BIOMETRIC_SUCCESS); assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext, - false /* biometricsSuccessfullyAuthenticated */, - false /* biometricsAuthenticationRequested */, USER_ID)).isFalse(); + false /* biometricsAuthenticationRequested */, USER_ID)).isEqualTo( + Utils.BiometricStatus.ERROR); } @Test diff --git a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java index 4f8860e8832..b4605c74785 100644 --- a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java @@ -129,7 +129,7 @@ public class CombinedBiometricProfileSettingsTest { doReturn(mBiometricManager).when(mActivity).getSystemService(BiometricManager.class); when(mBiometricManager.canAuthenticate(anyInt(), eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS))) - .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE); + .thenReturn(BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE); ReflectionHelpers.setField(mFragment, "mDashboardFeatureProvider", FakeFeatureFactory.setupForTest().dashboardFeatureProvider); @@ -187,6 +187,8 @@ public class CombinedBiometricProfileSettingsTest { mFragment.onAttach(mContext); mFragment.onCreate(null); + mFragment.onActivityResult(CONFIRM_REQUEST, RESULT_FINISHED, + new Intent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 1L)); verify(mFragment).startActivityForResult(intentArgumentCaptor.capture(), eq(BiometricsSettingsBase.BIOMETRIC_AUTH_REQUEST)); diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java index ca76c1e6069..0e1bcf6348c 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java @@ -20,6 +20,8 @@ import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWE import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; import static com.android.settings.biometrics.BiometricEnrollBase.BIOMETRIC_AUTH_REQUEST; +import static com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST; +import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED; import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment; import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.CHOOSE_LOCK_GENERIC_REQUEST; import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.KEY_REQUIRE_SCREEN_ON_TO_AUTH; @@ -146,7 +148,7 @@ public class FingerprintSettingsFragmentTest { doReturn(mBiometricManager).when(mContext).getSystemService(BiometricManager.class); doReturn(true).when(mFingerprintManager).isHardwareDetected(); doReturn(mVibrator).when(mContext).getSystemService(Vibrator.class); - when(mBiometricManager.canAuthenticate( + when(mBiometricManager.canAuthenticate(PRIMARY_USER_ID, BiometricManager.Authenticators.MANDATORY_BIOMETRICS)) .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE); } @@ -170,20 +172,23 @@ public class FingerprintSettingsFragmentTest { } @Test + @Ignore("b/353706169") @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS) public void testLaunchBiometricPromptForFingerprint() { - when(mBiometricManager.canAuthenticate( + when(mBiometricManager.canAuthenticate(PRIMARY_USER_ID, BiometricManager.Authenticators.MANDATORY_BIOMETRICS)) .thenReturn(BiometricManager.BIOMETRIC_SUCCESS); - + doNothing().when(mFingerprintManager).generateChallenge(anyInt(), any()); + when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true); setUpFragment(false); - ArgumentCaptor intentArgumentCaptor = ArgumentCaptor.forClass( - Intent.class); + ArgumentCaptor intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); + mFragment.onActivityResult(CONFIRM_REQUEST, RESULT_FINISHED, + new Intent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 1L)); verify(mFragment).startActivityForResult(intentArgumentCaptor.capture(), eq(BIOMETRIC_AUTH_REQUEST)); - Intent intent = intentArgumentCaptor.getValue(); + final Intent intent = intentArgumentCaptor.getValue(); assertThat(intent.getComponent().getClassName()).isEqualTo( ConfirmDeviceCredentialActivity.InternalActivity.class.getName()); } diff --git a/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java index 326627a6247..34878e1ef2c 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java @@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -32,6 +33,7 @@ import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.Flags; import android.os.Looper; import android.os.UserManager; +import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; @@ -193,6 +195,7 @@ public class BuildNumberPreferenceControllerTest { @Test @UiThreadTest + @RequiresFlagsDisabled(Flags.FLAG_MANDATORY_BIOMETRICS) public void onActivityResult_confirmPasswordRequestCompleted_enableDevPref() { when(mUserManager.isAdminUser()).thenReturn(true); @@ -206,7 +209,6 @@ public class BuildNumberPreferenceControllerTest { } @Test - @UiThreadTest @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS) public void onActivityResult_confirmPasswordRequestCompleted_launchBiometricPrompt() { when(mUserManager.isAdminUser()).thenReturn(true); @@ -225,6 +227,45 @@ public class BuildNumberPreferenceControllerTest { eq(BuildNumberPreferenceController.REQUEST_IDENTITY_CHECK_FOR_DEV_PREF)); } + @Test + @UiThreadTest + @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS) + public void onActivityResult_confirmPasswordRequestCompleted_mandatoryBiometricsError() { + when(mUserManager.isAdminUser()).thenReturn(true); + when(mBiometricManager.canAuthenticate(mContext.getUserId(), + BiometricManager.Authenticators.MANDATORY_BIOMETRICS)) + .thenReturn(BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE); + + final boolean activityResultHandled = mController.onActivityResult( + BuildNumberPreferenceController.REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF, + Activity.RESULT_OK, + null); + + assertThat(activityResultHandled).isTrue(); + verify(mFragment, never()).startActivityForResult(any(), + eq(BuildNumberPreferenceController.REQUEST_IDENTITY_CHECK_FOR_DEV_PREF)); + } + + @Test + @UiThreadTest + @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS) + public void onActivityResult_confirmPasswordRequestCompleted_lockoutError() { + when(mUserManager.isAdminUser()).thenReturn(true); + when(mBiometricManager.canAuthenticate(mContext.getUserId(), + BiometricManager.Authenticators.MANDATORY_BIOMETRICS)) + .thenReturn(BiometricManager.BIOMETRIC_ERROR_LOCKOUT); + + final boolean activityResultHandled = mController.onActivityResult( + BuildNumberPreferenceController.REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF, + Activity.RESULT_OK, + null); + + assertThat(activityResultHandled).isTrue(); + verify(mFragment, never()).startActivityForResult(any(), + eq(BuildNumberPreferenceController.REQUEST_IDENTITY_CHECK_FOR_DEV_PREF)); + assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isFalse(); + } + @Test public void onActivityResult_confirmBiometricAuthentication_enableDevPref() { when(mUserManager.isAdminUser()).thenReturn(true);