[Biometric Onboarding & Edu] Update face settings page
- Added a feature provider for face settings page in FaceFeatureProvider for customization - When face is deleted, disabled the settings buttons instead of hiding them. - Updated new UX style for add/remove face button. Bug: 370940762 Test: atest FaceSettingsEnrollButtonPreferenceControllerTest FaceSettingsFooterPreferenceControllerTest Test: manual - 1. Enroll face 2. Go Face Settings page and remove face 3. Enroll face again Flag: com.android.settings.flags.biometrics_onboarding_education Change-Id: I490e647523eeff2dd1a58aab07f638e3e5e0ffb8
This commit is contained in:
26
res/drawable/ic_face.xml
Normal file
26
res/drawable/ic_face.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M360,570Q339,570 324.5,555.5Q310,541 310,520Q310,499 324.5,484.5Q339,470 360,470Q381,470 395.5,484.5Q410,499 410,520Q410,541 395.5,555.5Q381,570 360,570ZM600,570Q579,570 564.5,555.5Q550,541 550,520Q550,499 564.5,484.5Q579,470 600,470Q621,470 635.5,484.5Q650,499 650,520Q650,541 635.5,555.5Q621,570 600,570ZM480,800Q614,800 707,707Q800,614 800,480Q800,456 797,433.5Q794,411 786,390Q765,395 744,397.5Q723,400 700,400Q609,400 528,361Q447,322 390,252Q358,330 298.5,387.5Q239,445 160,474Q160,476 160,477Q160,478 160,480Q160,614 253,707Q346,800 480,800ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM426,165Q468,235 540,277.5Q612,320 700,320Q714,320 727,318.5Q740,317 754,315Q712,245 640,202.5Q568,160 480,160Q466,160 453,161.5Q440,163 426,165ZM177,379Q228,350 266,304Q304,258 323,201Q272,230 234,276Q196,322 177,379ZM426,165Q426,165 426,165Q426,165 426,165Q426,165 426,165Q426,165 426,165Q426,165 426,165Q426,165 426,165Q426,165 426,165Q426,165 426,165ZM323,201Q323,201 323,201Q323,201 323,201Q323,201 323,201Q323,201 323,201Z"/>
|
||||||
|
</vector>
|
@@ -914,6 +914,14 @@
|
|||||||
<string name="security_settings_face_enroll_improve_face_alert_body_fingerprint">Delete your current face model to set up Face Unlock again.\n\nYour face model will be permanently and securely deleted.\n\nAfter deletion, you will need your fingerprint, PIN, pattern, or password to unlock your phone or for authentication in apps.</string>
|
<string name="security_settings_face_enroll_improve_face_alert_body_fingerprint">Delete your current face model to set up Face Unlock again.\n\nYour face model will be permanently and securely deleted.\n\nAfter deletion, you will need your fingerprint, PIN, pattern, or password to unlock your phone or for authentication in apps.</string>
|
||||||
<!-- Title for a category shown for the face settings page. [CHAR LIMIT=20] -->
|
<!-- Title for a category shown for the face settings page. [CHAR LIMIT=20] -->
|
||||||
<string name="security_settings_face_settings_use_face_category">Use Face Unlock for</string>
|
<string name="security_settings_face_settings_use_face_category">Use Face Unlock for</string>
|
||||||
|
<!-- Description shown on face settings page. -->
|
||||||
|
<string name="security_settings_face_description"></string>
|
||||||
|
<!-- Footer description shown on face settings page. -->
|
||||||
|
<string name="security_settings_face_footer_description_class3"></string>
|
||||||
|
<!-- Footer learn more description shown on face settings page. -->
|
||||||
|
<string name="security_settings_face_footer_learn_more_description"></string>
|
||||||
|
<!-- Footer learn more URL shown on face settings page [DO NOT TRANSLATE] -->
|
||||||
|
<string name="security_settings_face_footer_learn_more_url" translatable="false"></string>
|
||||||
<!-- Title for a category shown for the face settings page. [CHAR LIMIT=20] -->
|
<!-- Title for a category shown for the face settings page. [CHAR LIMIT=20] -->
|
||||||
<string name="security_settings_face_settings_face_category">Face</string>
|
<string name="security_settings_face_settings_face_category">Face</string>
|
||||||
<!-- Title for a category shown for the face settings page. [CHAR LIMIT=20] -->
|
<!-- Title for a category shown for the face settings page. [CHAR LIMIT=20] -->
|
||||||
@@ -948,6 +956,8 @@
|
|||||||
<string name="security_settings_face_remove_dialog_details_fingerprint_conv">Your face model will be permanently and securely deleted.\n\nAfter deletion, you will need your fingerprint, PIN, pattern, or password to unlock your phone.</string>
|
<string name="security_settings_face_remove_dialog_details_fingerprint_conv">Your face model will be permanently and securely deleted.\n\nAfter deletion, you will need your fingerprint, PIN, pattern, or password to unlock your phone.</string>
|
||||||
<!-- Subtitle shown for contextual setting face enrollment [CHAR LIMIT=NONE] -->
|
<!-- Subtitle shown for contextual setting face enrollment [CHAR LIMIT=NONE] -->
|
||||||
<string name="security_settings_face_settings_context_subtitle">Use Face Unlock to unlock your phone</string>
|
<string name="security_settings_face_settings_context_subtitle">Use Face Unlock to unlock your phone</string>
|
||||||
|
<!-- Title shown for adding face in face settings page. -->
|
||||||
|
<string name="security_settings_face_add">Add face</string>
|
||||||
|
|
||||||
<!-- Fingerprint enrollment and settings --><skip />
|
<!-- Fingerprint enrollment and settings --><skip />
|
||||||
<!-- Note: Update FingerprintEnrollParentalConsent.CONSENT_STRING_RESOURCES when any _consent_ strings are added or removed. -->
|
<!-- Note: Update FingerprintEnrollParentalConsent.CONSENT_STRING_RESOURCES when any _consent_ strings are added or removed. -->
|
||||||
|
@@ -19,6 +19,11 @@
|
|||||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
android:title="@string/security_settings_face_preference_title">
|
android:title="@string/security_settings_face_preference_title">
|
||||||
|
|
||||||
|
<com.android.settingslib.widget.TopIntroPreference
|
||||||
|
android:key="security_settings_face_description"
|
||||||
|
settings:searchable="false"
|
||||||
|
settings:isPreferenceVisible="false" />
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="biometric_settings_use_face_to"
|
android:key="biometric_settings_use_face_to"
|
||||||
android:title="@string/security_settings_face_settings_use_face_to_category"
|
android:title="@string/security_settings_face_settings_use_face_to_category"
|
||||||
@@ -37,6 +42,18 @@
|
|||||||
settings:controller="com.android.settings.biometrics.face.FaceSettingsAppsPreferenceController"/>
|
settings:controller="com.android.settings.biometrics.face.FaceSettingsAppsPreferenceController"/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="security_settings_face_enrolled_category"
|
||||||
|
android:title="@string/security_settings_face_preference_title_new"
|
||||||
|
settings:isPreferenceVisible="false">
|
||||||
|
<com.android.settings.biometrics.face.FacePreference
|
||||||
|
android:key="security_settings_face_remove"
|
||||||
|
android:title="@string/security_settings_face_preference_title_new"/>
|
||||||
|
<Preference
|
||||||
|
android:key="security_settings_face_enroll"
|
||||||
|
android:title="@string/security_settings_face_add"/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="security_settings_face_unlock_category"
|
android:key="security_settings_face_unlock_category"
|
||||||
android:title="@string/security_settings_face_settings_use_face_category"
|
android:title="@string/security_settings_face_settings_use_face_category"
|
||||||
@@ -88,13 +105,15 @@
|
|||||||
android:key="security_settings_face_delete_faces_container"
|
android:key="security_settings_face_delete_faces_container"
|
||||||
android:title="@string/security_settings_face_settings_remove_face_model"
|
android:title="@string/security_settings_face_settings_remove_face_model"
|
||||||
android:selectable="false"
|
android:selectable="false"
|
||||||
android:layout="@layout/face_remove_button"/>
|
android:layout="@layout/face_remove_button"
|
||||||
|
settings:isPreferenceVisible="false"/>
|
||||||
|
|
||||||
<com.android.settingslib.widget.LayoutPreference
|
<com.android.settingslib.widget.LayoutPreference
|
||||||
android:key="security_settings_face_enroll_faces_container"
|
android:key="security_settings_face_enroll_faces_container"
|
||||||
android:title="@string/security_settings_face_settings_enroll"
|
android:title="@string/security_settings_face_settings_enroll"
|
||||||
android:selectable="false"
|
android:selectable="false"
|
||||||
android:layout="@layout/face_enroll_button"/>
|
android:layout="@layout/face_enroll_button"
|
||||||
|
settings:isPreferenceVisible="false"/>
|
||||||
|
|
||||||
<com.android.settingslib.widget.FooterPreference
|
<com.android.settingslib.widget.FooterPreference
|
||||||
android:key="security_face_footer"
|
android:key="security_face_footer"
|
||||||
|
@@ -42,4 +42,13 @@ public interface FaceFeatureProvider {
|
|||||||
default FaceEnrollActivityClassProvider getEnrollActivityClassProvider() {
|
default FaceEnrollActivityClassProvider getEnrollActivityClassProvider() {
|
||||||
return FaceEnrollActivityClassProvider.getInstance();
|
return FaceEnrollActivityClassProvider.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the feature provider for FaceSettings page
|
||||||
|
* @return the provider
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
default FaceSettingsFeatureProvider getFaceSettingsFeatureProvider() {
|
||||||
|
return FaceSettingsFeatureProvider.getInstance();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
52
src/com/android/settings/biometrics/face/FacePreference.java
Normal file
52
src/com/android/settings/biometrics/face/FacePreference.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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.face;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settingslib.widget.TwoTargetPreference;
|
||||||
|
|
||||||
|
public class FacePreference extends TwoTargetPreference {
|
||||||
|
|
||||||
|
public FacePreference(@NonNull Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FacePreference(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FacePreference(
|
||||||
|
@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FacePreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
|
||||||
|
int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getSecondTargetResId() {
|
||||||
|
return R.layout.preference_widget_delete;
|
||||||
|
}
|
||||||
|
}
|
@@ -30,6 +30,7 @@ import android.app.admin.DevicePolicyManager;
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.res.ResourceId;
|
||||||
import android.hardware.face.FaceManager;
|
import android.hardware.face.FaceManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
@@ -73,12 +74,19 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
private static final String KEY_BIOMETRICS_SUCCESSFULLY_AUTHENTICATED =
|
private static final String KEY_BIOMETRICS_SUCCESSFULLY_AUTHENTICATED =
|
||||||
"biometrics_successfully_authenticated";
|
"biometrics_successfully_authenticated";
|
||||||
|
|
||||||
|
private static final String PREF_KEY_FACE_DESCRIPTION = "security_settings_face_description";
|
||||||
private static final String PREF_KEY_DELETE_FACE_DATA =
|
private static final String PREF_KEY_DELETE_FACE_DATA =
|
||||||
"security_settings_face_delete_faces_container";
|
"security_settings_face_delete_faces_container";
|
||||||
private static final String PREF_KEY_ENROLL_FACE_UNLOCK =
|
private static final String PREF_KEY_ENROLL_FACE_UNLOCK =
|
||||||
"security_settings_face_enroll_faces_container";
|
"security_settings_face_enroll_faces_container";
|
||||||
private static final String PREF_KEY_USE_FACE_TO_CATEGORY =
|
private static final String PREF_KEY_USE_FACE_TO_CATEGORY =
|
||||||
"biometric_settings_use_face_to";
|
"biometric_settings_use_face_to";
|
||||||
|
private static final String PREF_KEY_FACE_ENROLLED_CATEGORY =
|
||||||
|
"security_settings_face_enrolled_category";
|
||||||
|
private static final String PREF_KEY_FACE_REMOVE =
|
||||||
|
"security_settings_face_remove";
|
||||||
|
private static final String PREF_KEY_FACE_ENROLL =
|
||||||
|
"security_settings_face_enroll";
|
||||||
public static final String SECURITY_SETTINGS_FACE_MANAGE_CATEGORY =
|
public static final String SECURITY_SETTINGS_FACE_MANAGE_CATEGORY =
|
||||||
"security_settings_face_manage_category";
|
"security_settings_face_manage_category";
|
||||||
|
|
||||||
@@ -98,6 +106,9 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
private List<Preference> mTogglePreferences;
|
private List<Preference> mTogglePreferences;
|
||||||
private Preference mRemoveButton;
|
private Preference mRemoveButton;
|
||||||
private Preference mEnrollButton;
|
private Preference mEnrollButton;
|
||||||
|
private PreferenceCategory mFaceEnrolledCategory;
|
||||||
|
private Preference mFaceRemoveButton;
|
||||||
|
private Preference mFaceEnrollButton;
|
||||||
private FaceFeatureProvider mFaceFeatureProvider;
|
private FaceFeatureProvider mFaceFeatureProvider;
|
||||||
|
|
||||||
private boolean mConfirmingPassword;
|
private boolean mConfirmingPassword;
|
||||||
@@ -111,8 +122,7 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hide the "remove" button and show the "set up face authentication" button.
|
// Hide the "remove" button and show the "set up face authentication" button.
|
||||||
mRemoveButton.setVisible(false);
|
updateFaceAddAndRemovePreference(false);
|
||||||
mEnrollButton.setVisible(true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private final FaceSettingsEnrollButtonPreferenceController.Listener mEnrollListener = intent ->
|
private final FaceSettingsEnrollButtonPreferenceController.Listener mEnrollListener = intent ->
|
||||||
@@ -193,6 +203,15 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
: use(FaceSettingsLockscreenBypassPreferenceController.class);
|
: use(FaceSettingsLockscreenBypassPreferenceController.class);
|
||||||
mLockscreenController.setUserId(mUserId);
|
mLockscreenController.setUserId(mUserId);
|
||||||
|
|
||||||
|
final int descriptionResId = FeatureFactory.getFeatureFactory()
|
||||||
|
.getFaceFeatureProvider().getFaceSettingsFeatureProvider()
|
||||||
|
.getSettingPageDescription();
|
||||||
|
if (ResourceId.isValid(descriptionResId)) {
|
||||||
|
final Preference preference = findPreference(PREF_KEY_FACE_DESCRIPTION);
|
||||||
|
preference.setTitle(descriptionResId);
|
||||||
|
preference.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
final PreferenceCategory managePref =
|
final PreferenceCategory managePref =
|
||||||
findPreference(SECURITY_SETTINGS_FACE_MANAGE_CATEGORY);
|
findPreference(SECURITY_SETTINGS_FACE_MANAGE_CATEGORY);
|
||||||
Preference keyguardPref = findPreference(FaceSettingsKeyguardPreferenceController.KEY);
|
Preference keyguardPref = findPreference(FaceSettingsKeyguardPreferenceController.KEY);
|
||||||
@@ -201,8 +220,13 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
Preference confirmPref = findPreference(FaceSettingsConfirmPreferenceController.KEY);
|
Preference confirmPref = findPreference(FaceSettingsConfirmPreferenceController.KEY);
|
||||||
Preference bypassPref =
|
Preference bypassPref =
|
||||||
findPreference(mLockscreenController.getPreferenceKey());
|
findPreference(mLockscreenController.getPreferenceKey());
|
||||||
|
Preference unlockKeyguard = findPreference(
|
||||||
|
use(FaceSettingsKeyguardUnlockPreferenceController.class).getPreferenceKey());
|
||||||
|
Preference appsPref = findPreference(
|
||||||
|
use(FaceSettingsAppsPreferenceController.class).getPreferenceKey());
|
||||||
mTogglePreferences = new ArrayList<>(
|
mTogglePreferences = new ArrayList<>(
|
||||||
Arrays.asList(keyguardPref, appPref, attentionPref, confirmPref, bypassPref));
|
Arrays.asList(keyguardPref, appPref, attentionPref, confirmPref, bypassPref,
|
||||||
|
unlockKeyguard, appsPref));
|
||||||
|
|
||||||
if (RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
|
if (RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
|
||||||
getContext(), DevicePolicyManager.KEYGUARD_DISABLE_FACE, mUserId) != null) {
|
getContext(), DevicePolicyManager.KEYGUARD_DISABLE_FACE, mUserId) != null) {
|
||||||
@@ -215,9 +239,18 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
mRemoveButton = findPreference(FaceSettingsRemoveButtonPreferenceController.KEY);
|
mRemoveButton = findPreference(FaceSettingsRemoveButtonPreferenceController.KEY);
|
||||||
mEnrollButton = findPreference(FaceSettingsEnrollButtonPreferenceController.KEY);
|
mEnrollButton = findPreference(FaceSettingsEnrollButtonPreferenceController.KEY);
|
||||||
|
|
||||||
|
mFaceEnrolledCategory = findPreference(PREF_KEY_FACE_ENROLLED_CATEGORY);
|
||||||
|
mFaceRemoveButton = findPreference(PREF_KEY_FACE_REMOVE);
|
||||||
|
mFaceRemoveButton.setIcon(R.drawable.ic_face);
|
||||||
|
mFaceRemoveButton.setOnPreferenceClickListener(
|
||||||
|
use(FaceSettingsRemoveButtonPreferenceController.class));
|
||||||
|
mFaceEnrollButton = findPreference(PREF_KEY_FACE_ENROLL);
|
||||||
|
mFaceEnrollButton.setIcon(R.drawable.ic_add_24dp);
|
||||||
|
mFaceEnrollButton.setOnPreferenceClickListener(
|
||||||
|
use(FaceSettingsEnrollButtonPreferenceController.class));
|
||||||
|
|
||||||
final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
|
final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
|
||||||
mEnrollButton.setVisible(!hasEnrolled);
|
updateFaceAddAndRemovePreference(hasEnrolled);
|
||||||
mRemoveButton.setVisible(hasEnrolled);
|
|
||||||
|
|
||||||
// There is no better way to do this :/
|
// There is no better way to do this :/
|
||||||
for (AbstractPreferenceController controller : mControllers) {
|
for (AbstractPreferenceController controller : mControllers) {
|
||||||
@@ -255,8 +288,7 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
|
final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
|
||||||
mEnrollButton.setVisible(!hasEnrolled);
|
updateFaceAddAndRemovePreference(hasEnrolled);
|
||||||
mRemoveButton.setVisible(hasEnrolled);
|
|
||||||
|
|
||||||
// When the user has face id registered but failed enrolling in device lock state,
|
// When the user has face id registered but failed enrolling in device lock state,
|
||||||
// lead users directly to the confirm deletion dialog in Face Unlock settings.
|
// lead users directly to the confirm deletion dialog in Face Unlock settings.
|
||||||
@@ -264,6 +296,11 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
final boolean isReEnrollFaceUnlock = getIntent().getBooleanExtra(
|
final boolean isReEnrollFaceUnlock = getIntent().getBooleanExtra(
|
||||||
FaceSettings.KEY_RE_ENROLL_FACE, false);
|
FaceSettings.KEY_RE_ENROLL_FACE, false);
|
||||||
if (isReEnrollFaceUnlock) {
|
if (isReEnrollFaceUnlock) {
|
||||||
|
if (Flags.biometricsOnboardingEducation()) {
|
||||||
|
if (mFaceRemoveButton.isEnabled()) {
|
||||||
|
mRemoveController.onPreferenceClick(mFaceRemoveButton);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
final Button removeBtn = ((LayoutPreference) mRemoveButton).findViewById(
|
final Button removeBtn = ((LayoutPreference) mRemoveButton).findViewById(
|
||||||
R.id.security_settings_face_settings_remove_button);
|
R.id.security_settings_face_settings_remove_button);
|
||||||
if (removeBtn != null && removeBtn.isEnabled()) {
|
if (removeBtn != null && removeBtn.isEnabled()) {
|
||||||
@@ -272,6 +309,7 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
@@ -327,8 +365,7 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
});
|
});
|
||||||
|
|
||||||
final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
|
final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
|
||||||
mEnrollButton.setVisible(!hasEnrolled);
|
updateFaceAddAndRemovePreference(hasEnrolled);
|
||||||
mRemoveButton.setVisible(hasEnrolled);
|
|
||||||
final Utils.BiometricStatus biometricAuthStatus =
|
final Utils.BiometricStatus biometricAuthStatus =
|
||||||
Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
|
Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
|
||||||
mBiometricsAuthenticationRequested,
|
mBiometricsAuthenticationRequested,
|
||||||
@@ -407,6 +444,17 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
return mControllers;
|
return mControllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateFaceAddAndRemovePreference(boolean hasEnrolled) {
|
||||||
|
if (Flags.biometricsOnboardingEducation()) {
|
||||||
|
mFaceEnrolledCategory.setVisible(true);
|
||||||
|
mFaceRemoveButton.setVisible(hasEnrolled);
|
||||||
|
mFaceEnrollButton.setVisible(!hasEnrolled);
|
||||||
|
} else {
|
||||||
|
mEnrollButton.setVisible(!hasEnrolled);
|
||||||
|
mRemoveButton.setVisible(hasEnrolled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
|
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
|
||||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||||
controllers.add(new FaceSettingsKeyguardPreferenceController(context));
|
controllers.add(new FaceSettingsKeyguardPreferenceController(context));
|
||||||
|
@@ -23,6 +23,7 @@ import android.hardware.face.FaceManager;
|
|||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils;
|
import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils;
|
||||||
@@ -52,6 +53,20 @@ public class FaceSettingsAppsPreferenceController extends
|
|||||||
isChecked ? ON : OFF, getUserId());
|
isChecked ? ON : OFF, getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
super.updateState(preference);
|
||||||
|
if (!FaceSettings.isFaceHardwareDetected(mContext)) {
|
||||||
|
preference.setEnabled(false);
|
||||||
|
} else if (!mFaceManager.hasEnrolledTemplates(getUserId())) {
|
||||||
|
preference.setEnabled(false);
|
||||||
|
} else if (getRestrictingAdmin() != null) {
|
||||||
|
preference.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
preference.setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getAvailabilityStatus() {
|
public int getAvailabilityStatus() {
|
||||||
final ActiveUnlockStatusUtils activeUnlockStatusUtils =
|
final ActiveUnlockStatusUtils activeUnlockStatusUtils =
|
||||||
|
@@ -24,10 +24,12 @@ import android.content.Intent;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.core.BasePreferenceController;
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
import com.android.settings.flags.Flags;
|
||||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||||
import com.android.settingslib.widget.LayoutPreference;
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
@@ -39,10 +41,11 @@ import com.google.android.setupdesign.util.PartnerStyleHelper;
|
|||||||
* Preference controller that allows a user to enroll their face.
|
* Preference controller that allows a user to enroll their face.
|
||||||
*/
|
*/
|
||||||
public class FaceSettingsEnrollButtonPreferenceController extends BasePreferenceController
|
public class FaceSettingsEnrollButtonPreferenceController extends BasePreferenceController
|
||||||
implements View.OnClickListener {
|
implements View.OnClickListener, Preference.OnPreferenceClickListener {
|
||||||
|
|
||||||
private static final String TAG = "FaceSettings/Remove";
|
private static final String TAG = "FaceSettings/Remove";
|
||||||
static final String KEY = "security_settings_face_enroll_faces_container";
|
static final String KEY = "security_settings_face_enroll_faces_container";
|
||||||
|
static final String KEY_1 = "security_settings_face_enroll";
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
@@ -53,7 +56,7 @@ public class FaceSettingsEnrollButtonPreferenceController extends BasePreference
|
|||||||
private Listener mListener;
|
private Listener mListener;
|
||||||
|
|
||||||
public FaceSettingsEnrollButtonPreferenceController(Context context) {
|
public FaceSettingsEnrollButtonPreferenceController(Context context) {
|
||||||
this(context, KEY);
|
this(context, Flags.biometricsOnboardingEducation() ? KEY_1 : KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FaceSettingsEnrollButtonPreferenceController(Context context, String preferenceKey) {
|
public FaceSettingsEnrollButtonPreferenceController(Context context, String preferenceKey) {
|
||||||
@@ -62,9 +65,15 @@ public class FaceSettingsEnrollButtonPreferenceController extends BasePreference
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateState(Preference preference) {
|
public void updateState(@NonNull Preference preference) {
|
||||||
super.updateState(preference);
|
super.updateState(preference);
|
||||||
|
final boolean isDeviceOwnerBlockingAuth =
|
||||||
|
RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
|
||||||
|
mContext, DevicePolicyManager.KEYGUARD_DISABLE_FACE, mUserId) != null;
|
||||||
|
|
||||||
|
if (Flags.biometricsOnboardingEducation()) {
|
||||||
|
preference.setEnabled(!isDeviceOwnerBlockingAuth);
|
||||||
|
} else {
|
||||||
mButton = ((LayoutPreference) preference).findViewById(
|
mButton = ((LayoutPreference) preference).findViewById(
|
||||||
R.id.security_settings_face_settings_enroll_button);
|
R.id.security_settings_face_settings_enroll_button);
|
||||||
|
|
||||||
@@ -73,14 +82,22 @@ public class FaceSettingsEnrollButtonPreferenceController extends BasePreference
|
|||||||
}
|
}
|
||||||
|
|
||||||
mButton.setOnClickListener(this);
|
mButton.setOnClickListener(this);
|
||||||
final boolean isDeviceOwnerBlockingAuth =
|
|
||||||
RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
|
|
||||||
mContext, DevicePolicyManager.KEYGUARD_DISABLE_FACE, mUserId) != null;
|
|
||||||
mButton.setEnabled(!isDeviceOwnerBlockingAuth);
|
mButton.setEnabled(!isDeviceOwnerBlockingAuth);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
startEnrolling();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(@NonNull Preference preference) {
|
||||||
|
startEnrolling();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startEnrolling() {
|
||||||
mIsClicked = true;
|
mIsClicked = true;
|
||||||
final Intent intent = new Intent();
|
final Intent intent = new Intent();
|
||||||
intent.setClassName(SETTINGS_PACKAGE_NAME, FaceEnroll.class.getName());
|
intent.setClassName(SETTINGS_PACKAGE_NAME, FaceEnroll.class.getName());
|
||||||
|
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.face
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide features for FaceSettings page.
|
||||||
|
*/
|
||||||
|
open class FaceSettingsFeatureProvider {
|
||||||
|
/**
|
||||||
|
* Get the description shown in the Face settings page.
|
||||||
|
*/
|
||||||
|
open fun getSettingPageDescription(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the footer description for face class3 shown in the Face settings page.
|
||||||
|
*/
|
||||||
|
open fun getSettingPageFooterDescriptionClass3(): Int {
|
||||||
|
return com.android.settings.R.string.security_settings_face_settings_footer_class3
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the footer learn more description shown in the Face settings page.
|
||||||
|
*/
|
||||||
|
open fun getSettingPageFooterLearnMoreDescription(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the footer learn more URL.
|
||||||
|
*/
|
||||||
|
open fun getSettingPageFooterLearnMoreUrl(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
val instance = FaceSettingsFeatureProvider()
|
||||||
|
}
|
||||||
|
}
|
@@ -19,11 +19,13 @@ package com.android.settings.biometrics.face;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.res.ResourceId;
|
||||||
import android.hardware.biometrics.SensorProperties;
|
import android.hardware.biometrics.SensorProperties;
|
||||||
import android.hardware.face.FaceManager;
|
import android.hardware.face.FaceManager;
|
||||||
import android.hardware.face.FaceSensorPropertiesInternal;
|
import android.hardware.face.FaceSensorPropertiesInternal;
|
||||||
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
|
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -35,6 +37,7 @@ import com.android.settings.core.BasePreferenceController;
|
|||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.utils.AnnotationSpan;
|
import com.android.settings.utils.AnnotationSpan;
|
||||||
import com.android.settingslib.HelpUtils;
|
import com.android.settingslib.HelpUtils;
|
||||||
|
import com.android.settingslib.widget.FooterPreference;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -82,14 +85,15 @@ public class FaceSettingsFooterPreferenceController extends BasePreferenceContro
|
|||||||
mContext, mContext.getString(R.string.help_url_face), getClass().getName());
|
mContext, mContext.getString(R.string.help_url_face), getClass().getName());
|
||||||
final AnnotationSpan.LinkInfo linkInfo =
|
final AnnotationSpan.LinkInfo linkInfo =
|
||||||
new AnnotationSpan.LinkInfo(mContext, ANNOTATION_URL, helpIntent);
|
new AnnotationSpan.LinkInfo(mContext, ANNOTATION_URL, helpIntent);
|
||||||
|
final FaceSettingsFeatureProvider featureProvider = FeatureFactory.getFeatureFactory()
|
||||||
int footerRes;
|
.getFaceFeatureProvider().getFaceSettingsFeatureProvider();
|
||||||
|
final int footerRes;
|
||||||
boolean isAttentionSupported = mProvider.isAttentionSupported(mContext);
|
boolean isAttentionSupported = mProvider.isAttentionSupported(mContext);
|
||||||
if (Utils.isPrivateProfile(mUserId, mContext)) {
|
if (Utils.isPrivateProfile(mUserId, mContext)) {
|
||||||
footerRes = R.string.private_space_face_settings_footer;
|
footerRes = R.string.private_space_face_settings_footer;
|
||||||
} else if (mIsFaceStrong) {
|
} else if (mIsFaceStrong) {
|
||||||
footerRes = isAttentionSupported
|
footerRes = isAttentionSupported
|
||||||
? R.string.security_settings_face_settings_footer_class3
|
? featureProvider.getSettingPageFooterDescriptionClass3()
|
||||||
: R.string.security_settings_face_settings_footer_attention_not_supported;
|
: R.string.security_settings_face_settings_footer_attention_not_supported;
|
||||||
} else {
|
} else {
|
||||||
footerRes = isAttentionSupported
|
footerRes = isAttentionSupported
|
||||||
@@ -98,6 +102,20 @@ public class FaceSettingsFooterPreferenceController extends BasePreferenceContro
|
|||||||
}
|
}
|
||||||
preference.setTitle(AnnotationSpan.linkify(
|
preference.setTitle(AnnotationSpan.linkify(
|
||||||
mContext.getText(footerRes), linkInfo));
|
mContext.getText(footerRes), linkInfo));
|
||||||
|
|
||||||
|
final int learnMoreRes = featureProvider.getSettingPageFooterLearnMoreDescription();
|
||||||
|
final int learnMoreUrlRes = featureProvider.getSettingPageFooterLearnMoreUrl();
|
||||||
|
if (ResourceId.isValid(learnMoreRes)
|
||||||
|
&& ResourceId.isValid(learnMoreUrlRes)
|
||||||
|
&& preference instanceof FooterPreference) {
|
||||||
|
final Intent learnMoreIntent = HelpUtils.getHelpIntent(
|
||||||
|
mContext, mContext.getString(learnMoreUrlRes), getClass().getName());
|
||||||
|
final View.OnClickListener learnMoreClickListener = (v) -> {
|
||||||
|
mContext.startActivityForResult(KEY, learnMoreIntent, 0, null);
|
||||||
|
};
|
||||||
|
((FooterPreference) preference).setLearnMoreAction(learnMoreClickListener);
|
||||||
|
((FooterPreference) preference).setLearnMoreText(mContext.getString(learnMoreRes));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUserId(int userId) {
|
public void setUserId(int userId) {
|
||||||
|
@@ -19,9 +19,11 @@ package com.android.settings.biometrics.face;
|
|||||||
import static android.provider.Settings.Secure.FACE_KEYGUARD_ENABLED;
|
import static android.provider.Settings.Secure.FACE_KEYGUARD_ENABLED;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.hardware.face.FaceManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils;
|
import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils;
|
||||||
@@ -32,9 +34,12 @@ public class FaceSettingsKeyguardUnlockPreferenceController extends
|
|||||||
private static final int OFF = 0;
|
private static final int OFF = 0;
|
||||||
private static final int DEFAULT = ON;
|
private static final int DEFAULT = ON;
|
||||||
|
|
||||||
|
private FaceManager mFaceManager;
|
||||||
|
|
||||||
public FaceSettingsKeyguardUnlockPreferenceController(
|
public FaceSettingsKeyguardUnlockPreferenceController(
|
||||||
@NonNull Context context, @NonNull String key) {
|
@NonNull Context context, @NonNull String key) {
|
||||||
super(context, key);
|
super(context, key);
|
||||||
|
mFaceManager = Utils.getFaceManagerOrNull(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -49,6 +54,20 @@ public class FaceSettingsKeyguardUnlockPreferenceController extends
|
|||||||
FACE_KEYGUARD_ENABLED, isChecked ? ON : OFF, getUserId());
|
FACE_KEYGUARD_ENABLED, isChecked ? ON : OFF, getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
super.updateState(preference);
|
||||||
|
if (!FaceSettings.isFaceHardwareDetected(mContext)) {
|
||||||
|
preference.setEnabled(false);
|
||||||
|
} else if (!mFaceManager.hasEnrolledTemplates(getUserId())) {
|
||||||
|
preference.setEnabled(false);
|
||||||
|
} else if (getRestrictingAdmin() != null) {
|
||||||
|
preference.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
preference.setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getAvailabilityStatus() {
|
public int getAvailabilityStatus() {
|
||||||
final ActiveUnlockStatusUtils activeUnlockStatusUtils =
|
final ActiveUnlockStatusUtils activeUnlockStatusUtils =
|
||||||
|
@@ -31,6 +31,7 @@ import android.widget.Button;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import android.window.OnBackInvokedCallback;
|
import android.window.OnBackInvokedCallback;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -40,6 +41,7 @@ import com.android.settings.SettingsActivity;
|
|||||||
import com.android.settings.biometrics.BiometricUtils;
|
import com.android.settings.biometrics.BiometricUtils;
|
||||||
import com.android.settings.core.BasePreferenceController;
|
import com.android.settings.core.BasePreferenceController;
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||||
|
import com.android.settings.flags.Flags;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
import com.android.settingslib.widget.LayoutPreference;
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
@@ -54,10 +56,11 @@ import java.util.List;
|
|||||||
* will likely change if multiple enrollments are allowed/supported.
|
* will likely change if multiple enrollments are allowed/supported.
|
||||||
*/
|
*/
|
||||||
public class FaceSettingsRemoveButtonPreferenceController extends BasePreferenceController
|
public class FaceSettingsRemoveButtonPreferenceController extends BasePreferenceController
|
||||||
implements View.OnClickListener {
|
implements View.OnClickListener, Preference.OnPreferenceClickListener {
|
||||||
|
|
||||||
private static final String TAG = "FaceSettings/Remove";
|
private static final String TAG = "FaceSettings/Remove";
|
||||||
static final String KEY = "security_settings_face_delete_faces_container";
|
static final String KEY = "security_settings_face_delete_faces_container";
|
||||||
|
static final String KEY_1 = "security_settings_face_remove";
|
||||||
|
|
||||||
public static class ConfirmRemoveDialog extends InstrumentedDialogFragment
|
public static class ConfirmRemoveDialog extends InstrumentedDialogFragment
|
||||||
implements OnBackInvokedCallback {
|
implements OnBackInvokedCallback {
|
||||||
@@ -173,7 +176,11 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
|||||||
if (remaining == 0) {
|
if (remaining == 0) {
|
||||||
final List<Face> faces = mFaceManager.getEnrolledFaces(mUserId);
|
final List<Face> faces = mFaceManager.getEnrolledFaces(mUserId);
|
||||||
if (!faces.isEmpty()) {
|
if (!faces.isEmpty()) {
|
||||||
|
if (Flags.biometricsOnboardingEducation()) {
|
||||||
|
mPreference.setEnabled(true);
|
||||||
|
} else {
|
||||||
mButton.setEnabled(true);
|
mButton.setEnabled(true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mRemoving = false;
|
mRemoving = false;
|
||||||
mListener.onRemoved();
|
mListener.onRemoved();
|
||||||
@@ -189,7 +196,11 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||||
|
if (Flags.biometricsOnboardingEducation()) {
|
||||||
|
mPreference.setEnabled(false);
|
||||||
|
} else {
|
||||||
mButton.setEnabled(false);
|
mButton.setEnabled(false);
|
||||||
|
}
|
||||||
final List<Face> faces = mFaceManager.getEnrolledFaces(mUserId);
|
final List<Face> faces = mFaceManager.getEnrolledFaces(mUserId);
|
||||||
if (faces.isEmpty()) {
|
if (faces.isEmpty()) {
|
||||||
Log.e(TAG, "No faces");
|
Log.e(TAG, "No faces");
|
||||||
@@ -201,8 +212,12 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
|||||||
|
|
||||||
// Remove the first/only face
|
// Remove the first/only face
|
||||||
mFaceUpdater.remove(faces.get(0), mUserId, mRemovalCallback);
|
mFaceUpdater.remove(faces.get(0), mUserId, mRemovalCallback);
|
||||||
|
} else {
|
||||||
|
if (Flags.biometricsOnboardingEducation()) {
|
||||||
|
mPreference.setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
mButton.setEnabled(true);
|
mButton.setEnabled(true);
|
||||||
|
}
|
||||||
mRemoving = false;
|
mRemoving = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +239,7 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
|||||||
}
|
}
|
||||||
|
|
||||||
public FaceSettingsRemoveButtonPreferenceController(Context context) {
|
public FaceSettingsRemoveButtonPreferenceController(Context context) {
|
||||||
this(context, KEY);
|
this(context, Flags.biometricsOnboardingEducation() ? KEY_1 : KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUserId(int userId) {
|
public void setUserId(int userId) {
|
||||||
@@ -232,10 +247,11 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateState(Preference preference) {
|
public void updateState(@NonNull Preference preference) {
|
||||||
super.updateState(preference);
|
super.updateState(preference);
|
||||||
|
|
||||||
mPreference = preference;
|
mPreference = preference;
|
||||||
|
if (!Flags.biometricsOnboardingEducation()) {
|
||||||
mButton = ((LayoutPreference) preference)
|
mButton = ((LayoutPreference) preference)
|
||||||
.findViewById(R.id.security_settings_face_settings_remove_button);
|
.findViewById(R.id.security_settings_face_settings_remove_button);
|
||||||
|
|
||||||
@@ -244,6 +260,7 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
|||||||
}
|
}
|
||||||
|
|
||||||
mButton.setOnClickListener(this);
|
mButton.setOnClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
// If there is already a ConfirmRemoveDialog showing, reset the listener since the
|
// If there is already a ConfirmRemoveDialog showing, reset the listener since the
|
||||||
// controller has been recreated.
|
// controller has been recreated.
|
||||||
@@ -256,12 +273,21 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
|||||||
removeDialog.setOnClickListener(mOnConfirmDialogClickListener);
|
removeDialog.setOnClickListener(mOnConfirmDialogClickListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FaceSettings.isFaceHardwareDetected(mContext)) {
|
final boolean isFaceHardwareDetected = FaceSettings.isFaceHardwareDetected(mContext);
|
||||||
|
if (Flags.biometricsOnboardingEducation()) {
|
||||||
|
if (!isFaceHardwareDetected) {
|
||||||
|
mPreference.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
mPreference.setEnabled(!mRemoving);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isFaceHardwareDetected) {
|
||||||
mButton.setEnabled(false);
|
mButton.setEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
mButton.setEnabled(!mRemoving);
|
mButton.setEnabled(!mRemoving);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getAvailabilityStatus() {
|
public int getAvailabilityStatus() {
|
||||||
@@ -270,12 +296,23 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPreferenceKey() {
|
public String getPreferenceKey() {
|
||||||
return KEY;
|
return Flags.biometricsOnboardingEducation() ? KEY_1 : KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (v == mButton) {
|
if (v == mButton) {
|
||||||
|
showRemoveDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(@NonNull Preference preference) {
|
||||||
|
showRemoveDialog();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showRemoveDialog() {
|
||||||
mMetricsFeatureProvider.logClickedPreference(mPreference, getMetricsCategory());
|
mMetricsFeatureProvider.logClickedPreference(mPreference, getMetricsCategory());
|
||||||
mRemoving = true;
|
mRemoving = true;
|
||||||
ConfirmRemoveDialog confirmRemoveDialog =
|
ConfirmRemoveDialog confirmRemoveDialog =
|
||||||
@@ -284,7 +321,6 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
|
|||||||
confirmRemoveDialog.show(mActivity.getSupportFragmentManager(),
|
confirmRemoveDialog.show(mActivity.getSupportFragmentManager(),
|
||||||
ConfirmRemoveDialog.class.getName());
|
ConfirmRemoveDialog.class.getName());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void setListener(Listener listener) {
|
public void setListener(Listener listener) {
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
|
@@ -32,6 +32,8 @@ import android.hardware.face.FaceSensorPropertiesInternal;
|
|||||||
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
|
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
import android.platform.test.annotations.DisableFlags;
|
||||||
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
@@ -60,6 +62,8 @@ import java.util.List;
|
|||||||
public class FaceSettingsFooterPreferenceControllerTest {
|
public class FaceSettingsFooterPreferenceControllerTest {
|
||||||
@Rule
|
@Rule
|
||||||
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||||
|
@Rule
|
||||||
|
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||||
private static final String PREF_KEY = "security_face_footer";
|
private static final String PREF_KEY = "security_face_footer";
|
||||||
@Mock
|
@Mock
|
||||||
private FaceManager mFaceManager;
|
private FaceManager mFaceManager;
|
||||||
@@ -140,6 +144,7 @@ public class FaceSettingsFooterPreferenceControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@DisableFlags(com.android.settings.flags.Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
|
||||||
public void testString_faceClass3() throws RemoteException {
|
public void testString_faceClass3() throws RemoteException {
|
||||||
setupHasFaceFeature();
|
setupHasFaceFeature();
|
||||||
displayFaceSettingsFooterPreferenceController();
|
displayFaceSettingsFooterPreferenceController();
|
||||||
|
@@ -24,6 +24,7 @@ import static org.mockito.Mockito.verify;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
|
import androidx.preference.Preference;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -43,6 +44,8 @@ public class FaceSettingsEnrollButtonPreferenceControllerTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private Button mButton;
|
private Button mButton;
|
||||||
@Mock
|
@Mock
|
||||||
|
private Preference mPreference;
|
||||||
|
@Mock
|
||||||
private FaceSettingsEnrollButtonPreferenceController.Listener mListener;
|
private FaceSettingsEnrollButtonPreferenceController.Listener mListener;
|
||||||
|
|
||||||
private FaceSettingsEnrollButtonPreferenceController mController;
|
private FaceSettingsEnrollButtonPreferenceController mController;
|
||||||
@@ -65,4 +68,12 @@ public class FaceSettingsEnrollButtonPreferenceControllerTest {
|
|||||||
assertThat(mController.isClicked()).isTrue();
|
assertThat(mController.isClicked()).isTrue();
|
||||||
verify(mListener).onStartEnrolling(any());
|
verify(mListener).onStartEnrolling(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceClick() {
|
||||||
|
mController.onPreferenceClick(mPreference);
|
||||||
|
|
||||||
|
assertThat(mController.isClicked()).isTrue();
|
||||||
|
verify(mListener).onStartEnrolling(any());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user