diff --git a/res/values/strings.xml b/res/values/strings.xml index 80b0e8aad8e..e6f4341bb9e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -955,6 +955,8 @@ Fingerprint Fingerprints + + Use fingerprint to diff --git a/res/xml/security_settings_fingerprint.xml b/res/xml/security_settings_fingerprint.xml index 701d493e749..2868351f802 100644 --- a/res/xml/security_settings_fingerprint.xml +++ b/res/xml/security_settings_fingerprint.xml @@ -19,6 +19,11 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/security_settings_fingerprint_preference_title"> + + items = mFingerprintManager.getEnrolledFingerprints(mUserId); final int fingerprintCount = items.size(); for (int i = 0; i < fingerprintCount; i++) { @@ -785,8 +800,7 @@ public class FingerprintSettings extends SubSettings { mFingerprintsEnrolledCategory.addPreference(pref); pref.setOnPreferenceChangeListener(this); } - mAddFingerprintPreference = findPreference(mIsExpressiveThemeStyle - ? KEY_FINGERPRINT_ADD_EXPRESSIVE : KEY_FINGERPRINT_ADD); + mAddFingerprintPreference = findPreference(getAddFingerprintPreferenceKey()); setupAddFingerprintPreference(); return keyToReturn; } @@ -839,18 +853,31 @@ public class FingerprintSettings extends SubSettings { } private void updateFingerprintUnlockCategoryVisibility() { - final boolean fingerprintUnlockCategoryAvailable = - mFingerprintUnlockCategoryPreferenceController.isAvailable(); - if (mFingerprintUnlockCategory.isVisible() != fingerprintUnlockCategoryAvailable) { - mFingerprintUnlockCategory.setVisible(fingerprintUnlockCategoryAvailable); - } + final int categoryStatus = + mFingerprintUnlockCategoryPreferenceController.getAvailabilityStatus(); + updatePreferenceVisibility(categoryStatus, mFingerprintUnlockCategory); + if (mRequireScreenOnToAuthPreferenceController != null) { - mRequireScreenOnToAuthPreference.setVisible( - mRequireScreenOnToAuthPreferenceController.isAvailable()); + final int status = + mRequireScreenOnToAuthPreferenceController.getAvailabilityStatus(); + updatePreferenceVisibility(status, mRequireScreenOnToAuthPreference); } if (mScreenOffUnlockUdfpsPreferenceController != null) { - mScreenOffUnlockUdfpsPreference.setVisible( - mScreenOffUnlockUdfpsPreferenceController.isAvailable()); + final int status = + mScreenOffUnlockUdfpsPreferenceController.getAvailabilityStatus(); + updatePreferenceVisibility(status, mScreenOffUnlockUdfpsPreference); + } + } + + private void updatePreferenceVisibility(int availabilityStatus, Preference preference) { + if (availabilityStatus == AVAILABLE) { + preference.setVisible(true); + preference.setEnabled(true); + } else if (availabilityStatus == CONDITIONALLY_UNAVAILABLE) { + preference.setVisible(true); + preference.setEnabled(false); + } else { + preference.setVisible(false); } } @@ -898,8 +925,29 @@ public class FingerprintSettings extends SubSettings { .setOnPreferenceChangeListener(fingerprintAppController); } + private void updateUseFingerprintToEnableStatus() { + final PreferenceCategory category = + findPreference(KEY_BIOMETRICS_USE_FINGERPRINT_TO_CATEGORY); + if (!category.isVisible()) { + return; + } + final boolean hasFingerprintEnrolled = + mFingerprintManager.getEnrolledFingerprints(mUserId).size() > 0; + + final FingerprintSettingsKeyguardUnlockPreferenceController fpUnlockController = + use(FingerprintSettingsKeyguardUnlockPreferenceController.class); + findPreference(fpUnlockController.getPreferenceKey()) + .setEnabled(hasFingerprintEnrolled); + + final FingerprintSettingsAppsPreferenceController fingerprintAppController = + use(FingerprintSettingsAppsPreferenceController.class); + findPreference(fingerprintAppController.getPreferenceKey()) + .setEnabled(hasFingerprintEnrolled); + } + private void updatePreferencesAfterFingerprintRemoved() { updateAddPreference(); + updateUseFingerprintToEnableStatus(); if (isSfps() || (screenOffUnlockUdfps() && isScreenOffUnlcokSupported())) { updateFingerprintUnlockCategoryVisibility(); } @@ -911,8 +959,7 @@ public class FingerprintSettings extends SubSettings { return; // Activity went away } - mAddFingerprintPreference = findPreference( - mIsExpressiveThemeStyle ? KEY_FINGERPRINT_ADD_EXPRESSIVE : KEY_FINGERPRINT_ADD); + mAddFingerprintPreference = findPreference(getAddFingerprintPreferenceKey()); if (mAddFingerprintPreference == null) { return; // b/275519315 Skip if updateAddPreference() invoke before addPreference() @@ -945,11 +992,11 @@ public class FingerprintSettings extends SubSettings { findPreference(KEY_FINGERPRINT_ADD_EXPRESSIVE); if (nonExpressiveBtnPreference != null) { - nonExpressiveBtnPreference.setVisible(!mIsExpressiveThemeStyle); + nonExpressiveBtnPreference.setVisible(!shouldShowExpressiveAddFingerprintPref()); } if (expressiveBtnPreference != null) { - expressiveBtnPreference.setVisible(mIsExpressiveThemeStyle); + expressiveBtnPreference.setVisible(shouldShowExpressiveAddFingerprintPref()); } } @@ -1053,7 +1100,7 @@ public class FingerprintSettings extends SubSettings { @Override public boolean onPreferenceTreeClick(Preference pref) { final String key = pref.getKey(); - if (!mIsExpressiveThemeStyle && KEY_FINGERPRINT_ADD.equals(key)) { + if (KEY_FINGERPRINT_ADD.equals(key)) { mIsEnrolling = true; Intent intent = new Intent(); intent.setClassName(SETTINGS_PACKAGE_NAME, @@ -1451,6 +1498,16 @@ public class FingerprintSettings extends SubSettings { return Utils.isPrivateProfile(mUserId, getContext()); } + private String getAddFingerprintPreferenceKey() { + return shouldShowExpressiveAddFingerprintPref() + ? KEY_FINGERPRINT_ADD_EXPRESSIVE : KEY_FINGERPRINT_ADD; + } + + private boolean shouldShowExpressiveAddFingerprintPref() { + return Flags.biometricsOnboardingEducation() && mIsExpressiveThemeStyle + && mFingerprintManager.hasEnrolledTemplates(mUserId); + } + public static class DeleteFingerprintDialog extends InstrumentedDialogFragment implements DialogInterface.OnClickListener { diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java index 2cd92fc03e4..e53ba85bea5 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsAppsPreferenceController.java @@ -23,6 +23,7 @@ import android.hardware.fingerprint.FingerprintManager; import android.provider.Settings; import androidx.annotation.NonNull; +import androidx.preference.Preference; import com.android.settings.Utils; import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils; @@ -53,6 +54,20 @@ public class FingerprintSettingsAppsPreferenceController isChecked ? ON : OFF, getUserId()); } + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (!FingerprintSettings.isFingerprintHardwareDetected(mContext)) { + preference.setEnabled(false); + } else if (!mFingerprintManager.hasEnrolledTemplates(getUserId())) { + preference.setEnabled(false); + } else if (getRestrictingAdmin() != null) { + preference.setEnabled(false); + } else { + preference.setEnabled(true); + } + } + @Override public int getAvailabilityStatus() { final ActiveUnlockStatusUtils activeUnlockStatusUtils = diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFeatureProvider.kt b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFeatureProvider.kt new file mode 100644 index 00000000000..3138a0bbe00 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFeatureProvider.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.biometrics.fingerprint + +import com.android.settings.R + +/** + * Provide features for FingerprintSettings page. + */ +open class FingerprintSettingsFeatureProvider { + /** + * Get the description shown in the FingerprintSetting page. + */ + open fun getSettingPageDescription(): Int { + return 0 + } + + /** + * Get the learn more description shown in the footer of the FingerprintSetting page. + */ + open fun getSettingPageFooterLearnMoreDescription(): Int { + return R.string.security_settings_fingerprint_settings_footer_learn_more + } + + companion object { + @JvmStatic + val instance = FingerprintSettingsFeatureProvider() + } +} \ No newline at end of file diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java index 55c75abbcae..6b17584320f 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsKeyguardUnlockPreferenceController.java @@ -19,9 +19,11 @@ package com.android.settings.biometrics.fingerprint; import static android.provider.Settings.Secure.FINGERPRINT_KEYGUARD_ENABLED; import android.content.Context; +import android.hardware.fingerprint.FingerprintManager; import android.provider.Settings; import androidx.annotation.NonNull; +import androidx.preference.Preference; import com.android.settings.Utils; import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils; @@ -33,9 +35,12 @@ public class FingerprintSettingsKeyguardUnlockPreferenceController private static final int OFF = 0; private static final int DEFAULT = ON; + private FingerprintManager mFingerprintManager; + public FingerprintSettingsKeyguardUnlockPreferenceController( @NonNull Context context, @NonNull String key) { super(context, key); + mFingerprintManager = Utils.getFingerprintManagerOrNull(context); } @Override @@ -50,6 +55,20 @@ public class FingerprintSettingsKeyguardUnlockPreferenceController FINGERPRINT_KEYGUARD_ENABLED, isChecked ? ON : OFF, getUserId()); } + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (!FingerprintSettings.isFingerprintHardwareDetected(mContext)) { + preference.setEnabled(false); + } else if (!mFingerprintManager.hasEnrolledTemplates(getUserId())) { + preference.setEnabled(false); + } else if (getRestrictingAdmin() != null) { + preference.setEnabled(false); + } else { + preference.setEnabled(true); + } + } + @Override public int getAvailabilityStatus() { final ActiveUnlockStatusUtils activeUnlockStatusUtils = 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 02825d2aa50..47ba523c7b2 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java @@ -135,16 +135,20 @@ public class FingerprintSettingsFragmentTest { @Mock private Vibrator mVibrator; + private FingerprintSettingsFeatureProvider mFingerprintSettingsFeatureProvider; + + private FakeFeatureFactory mFakeFeatureFactory; private FingerprintAuthenticateSidecar mFingerprintAuthenticateSidecar; private FingerprintRemoveSidecar mFingerprintRemoveSidecar; @Before public void setUp() { ShadowUtils.setFingerprintManager(mFingerprintManager); - FakeFeatureFactory.setupForTest(); + mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mContext = spy(ApplicationProvider.getApplicationContext()); mFragment = spy(new FingerprintSettingsFragment()); + mFingerprintSettingsFeatureProvider = new FingerprintSettingsFeatureProvider(); doReturn(mContext).when(mFragment).getContext(); doReturn(mBiometricManager).when(mContext).getSystemService(BiometricManager.class); doReturn(true).when(mFingerprintManager).isHardwareDetected(); @@ -152,6 +156,9 @@ public class FingerprintSettingsFragmentTest { when(mBiometricManager.canAuthenticate(PRIMARY_USER_ID, BiometricManager.Authenticators.IDENTITY_CHECK)) .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE); + when(mFakeFeatureFactory.getFingerprintFeatureProvider() + .getFingerprintSettingsFeatureProvider()) + .thenReturn(mFingerprintSettingsFeatureProvider); } @After