Merge "Fix flicker of “touch to unlock anytime” toggle" into udc-dev am: 2b44fc26d1

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

Change-Id: I8e492529fa8d41f7d76f63148129c73c89b501c6
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Grace Cheng
2023-04-27 02:42:58 +00:00
committed by Automerger Merge Worker
7 changed files with 357 additions and 59 deletions

View File

@@ -19,10 +19,21 @@
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/security_settings_fingerprint_preference_title">
<PreferenceCategory
android:key="security_settings_fingerprints_enrolled"
settings:controller="com.android.settings.biometrics.fingerprint.FingerprintsEnrolledCategoryPreferenceController">
</PreferenceCategory>
<androidx.preference.Preference
android:key="key_fingerprint_add"
android:title="@string/fingerprint_add_title"
android:icon="@drawable/ic_add_24dp"/>
<PreferenceCategory
android:key="security_settings_fingerprint_unlock_category"
android:title="@string/security_settings_fingerprint_settings_preferences_category"
settings:controller="com.android.settings.biometrics.fingerprint.FingerprintUnlockCategoryPreferenceController">
settings:controller="com.android.settings.biometrics.fingerprint.FingerprintUnlockCategoryController"
settings:isPreferenceVisible="false">
<com.android.settingslib.RestrictedSwitchPreference
android:key="security_settings_require_screen_on_to_auth"
@@ -32,4 +43,8 @@
settings:controller="com.android.settings.biometrics.fingerprint.FingerprintSettingsRequireScreenOnToAuthPreferenceController" />
</PreferenceCategory>
<PreferenceCategory
android:key="security_settings_fingerprint_footer">
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -171,8 +171,12 @@ public class FingerprintSettings extends SubSettings {
private static final String KEY_IS_ENROLLING = "is_enrolled";
private static final String KEY_REQUIRE_SCREEN_ON_TO_AUTH =
"security_settings_require_screen_on_to_auth";
private static final String KEY_FINGERPRINTS_ENROLLED_CATEGORY =
"security_settings_fingerprints_enrolled";
private static final String KEY_FINGERPRINT_UNLOCK_CATEGORY =
"security_settings_fingerprint_unlock_category";
private static final String KEY_FINGERPRINT_UNLOCK_FOOTER =
"security_settings_fingerprint_footer";
private static final int MSG_REFRESH_FINGERPRINT_TEMPLATES = 1000;
private static final int MSG_FINGER_AUTH_SUCCESS = 1001;
@@ -189,10 +193,15 @@ public class FingerprintSettings extends SubSettings {
protected static final boolean DEBUG = false;
private List<AbstractPreferenceController> mControllers;
private FingerprintUnlockCategoryController
mFingerprintUnlockCategoryPreferenceController;
private FingerprintSettingsRequireScreenOnToAuthPreferenceController
mRequireScreenOnToAuthPreferenceController;
private Preference mAddFingerprintPreference;
private RestrictedSwitchPreference mRequireScreenOnToAuthPreference;
private PreferenceCategory mFingerprintsEnrolledCategory;
private PreferenceCategory mFingerprintUnlockCategory;
private PreferenceCategory mFingerprintUnlockFooter;
private FingerprintManager mFingerprintManager;
private FingerprintUpdater mFingerprintUpdater;
@@ -259,9 +268,6 @@ public class FingerprintSettings extends SubSettings {
}
private void updateDialog() {
if (isSfps()) {
setRequireScreenOnToAuthVisibility();
}
RenameDialog renameDialog = (RenameDialog) getFragmentManager().
findFragmentByTag(RenameDialog.class.getName());
if (renameDialog != null) {
@@ -277,7 +283,8 @@ public class FingerprintSettings extends SubSettings {
case MSG_REFRESH_FINGERPRINT_TEMPLATES:
removeFingerprintPreference(msg.arg1);
updateAddPreference();
retryFingerprint();
updateFingerprintUnlockCategoryVisibility();
updatePreferences();
break;
case MSG_FINGER_AUTH_SUCCESS:
highlightFingerprintItem(msg.arg1);
@@ -423,6 +430,9 @@ public class FingerprintSettings extends SubSettings {
addFirstFingerprint(null);
}
}
final PreferenceScreen root = getPreferenceScreen();
root.removeAll();
addPreferencesFromResource(getPreferenceScreenResId());
updateFooterColumns(activity);
}
@@ -512,48 +522,33 @@ public class FingerprintSettings extends SubSettings {
*/
private PreferenceScreen createPreferenceHierarchy() {
PreferenceScreen root = getPreferenceScreen();
if (root != null) {
root.removeAll();
}
final String fpPrefKey = addFingerprintItemPreferences(root);
if (isSfps()) {
scrollToPreference(fpPrefKey);
}
addPreferencesFromResource(getPreferenceScreenResId());
mRequireScreenOnToAuthPreference = findPreference(KEY_REQUIRE_SCREEN_ON_TO_AUTH);
mFingerprintUnlockCategory = findPreference(KEY_FINGERPRINT_UNLOCK_CATEGORY);
for (AbstractPreferenceController controller : mControllers) {
((FingerprintSettingsPreferenceController) controller).setUserId(mUserId);
}
mRequireScreenOnToAuthPreference.setChecked(
mRequireScreenOnToAuthPreferenceController.isChecked());
mRequireScreenOnToAuthPreference.setOnPreferenceChangeListener(
(preference, newValue) -> {
boolean isChecked = ((SwitchPreference) preference).isChecked();
mRequireScreenOnToAuthPreferenceController.setChecked(!isChecked);
return true;
});
mFingerprintUnlockCategory.setVisible(false);
if (isSfps()) {
setRequireScreenOnToAuthVisibility();
}
addFingerprintPreferences(root);
setPreferenceScreen(root);
return root;
}
private void setRequireScreenOnToAuthVisibility() {
int fingerprintsEnrolled = mFingerprintManager.getEnrolledFingerprints(mUserId).size();
final boolean removalInProgress = mRemovalSidecar.inProgress();
// Removing last remaining fingerprint
if (fingerprintsEnrolled == 0 && removalInProgress) {
mFingerprintUnlockCategory.setVisible(false);
} else {
mFingerprintUnlockCategory.setVisible(true);
private void addFingerprintPreferences(PreferenceGroup root) {
final String fpPrefKey = addFingerprintItemPreferences(root);
if (isSfps()) {
scrollToPreference(fpPrefKey);
addFingerprintUnlockCategory();
}
for (AbstractPreferenceController controller : mControllers) {
if (controller instanceof FingerprintSettingsPreferenceController) {
((FingerprintSettingsPreferenceController) controller).setUserId(mUserId);
} else if (controller instanceof FingerprintUnlockCategoryController) {
((FingerprintUnlockCategoryController) controller).setUserId(mUserId);
}
}
createFooterPreference(root);
}
private String addFingerprintItemPreferences(PreferenceGroup root) {
root.removeAll();
mFingerprintsEnrolledCategory = findPreference(KEY_FINGERPRINTS_ENROLLED_CATEGORY);
if (mFingerprintsEnrolledCategory != null) {
mFingerprintsEnrolledCategory.removeAll();
}
String keyToReturn = KEY_FINGERPRINT_ADD;
final List<Fingerprint> items = mFingerprintManager.getEnrolledFingerprints(mUserId);
final int fingerprintCount = items.size();
@@ -576,22 +571,46 @@ public class FingerprintSettings extends SubSettings {
if (mFingerprintsRenaming.containsKey(item.getBiometricId())) {
pref.setTitle(mFingerprintsRenaming.get(item.getBiometricId()));
}
root.addPreference(pref);
mFingerprintsEnrolledCategory.addPreference(pref);
pref.setOnPreferenceChangeListener(this);
}
Preference addPreference = new Preference(root.getContext());
addPreference.setKey(KEY_FINGERPRINT_ADD);
addPreference.setTitle(R.string.fingerprint_add_title);
addPreference.setIcon(R.drawable.ic_add_24dp);
root.addPreference(addPreference);
addPreference.setOnPreferenceChangeListener(this);
updateAddPreference();
createFooterPreference(root);
mAddFingerprintPreference = findPreference(KEY_FINGERPRINT_ADD);
setupAddFingerprintPreference();
return keyToReturn;
}
private void setupAddFingerprintPreference() {
mAddFingerprintPreference.setOnPreferenceChangeListener(this);
updateAddPreference();
}
private void addFingerprintUnlockCategory() {
mFingerprintUnlockCategory = findPreference(KEY_FINGERPRINT_UNLOCK_CATEGORY);
setupFingerprintUnlockCategoryPreferences();
updateFingerprintUnlockCategoryVisibility();
}
private void updateFingerprintUnlockCategoryVisibility() {
final boolean mFingerprintUnlockCategoryAvailable =
mFingerprintUnlockCategoryPreferenceController.isAvailable();
if (mFingerprintUnlockCategory.isVisible() != mFingerprintUnlockCategoryAvailable) {
mFingerprintUnlockCategory.setVisible(
mFingerprintUnlockCategoryAvailable);
}
}
private void setupFingerprintUnlockCategoryPreferences() {
mRequireScreenOnToAuthPreference = findPreference(KEY_REQUIRE_SCREEN_ON_TO_AUTH);
mRequireScreenOnToAuthPreference.setChecked(
mRequireScreenOnToAuthPreferenceController.isChecked());
mRequireScreenOnToAuthPreference.setOnPreferenceChangeListener(
(preference, newValue) -> {
final boolean isChecked = ((SwitchPreference) preference).isChecked();
mRequireScreenOnToAuthPreferenceController.setChecked(!isChecked);
return true;
});
}
private void updateAddPreference() {
if (getActivity() == null) {
return; // Activity went away
@@ -612,8 +631,8 @@ public class FingerprintSettings extends SubSettings {
final boolean removalInProgress = mRemovalSidecar.inProgress();
CharSequence maxSummary = tooMany ?
getContext().getString(R.string.fingerprint_add_max, max) : "";
addPreference.setSummary(maxSummary);
addPreference.setEnabled(!tooMany && !removalInProgress && mToken != null);
mAddFingerprintPreference.setSummary(maxSummary);
mAddFingerprintPreference.setEnabled(!tooMany && !removalInProgress && mToken != null);
}
private void createFooterPreference(PreferenceGroup root) {
@@ -621,6 +640,10 @@ public class FingerprintSettings extends SubSettings {
if (context == null) {
return;
}
mFingerprintUnlockFooter = findPreference(KEY_FINGERPRINT_UNLOCK_FOOTER);
if (mFingerprintUnlockFooter != null) {
mFingerprintUnlockFooter.removeAll();
}
for (int i = 0; i < mFooterColumns.size(); ++i) {
final FooterColumn column = mFooterColumns.get(i);
final FooterPreference footer = new FooterPreference.Builder(context)
@@ -634,7 +657,7 @@ public class FingerprintSettings extends SubSettings {
footer.setLearnMoreText(column.mLearnMoreOverrideText);
}
}
root.addPreference(footer);
mFingerprintUnlockFooter.addPreference(footer);
}
}
@@ -815,11 +838,17 @@ public class FingerprintSettings extends SubSettings {
private List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
mFingerprintUnlockCategoryPreferenceController =
new FingerprintUnlockCategoryController(
context,
KEY_FINGERPRINT_UNLOCK_CATEGORY
);
mRequireScreenOnToAuthPreferenceController =
new FingerprintSettingsRequireScreenOnToAuthPreferenceController(
context,
KEY_REQUIRE_SCREEN_ON_TO_AUTH
);
controllers.add(mFingerprintUnlockCategoryPreferenceController);
controllers.add(mRequireScreenOnToAuthPreferenceController);
return controllers;
}

View File

@@ -94,7 +94,7 @@ public class FingerprintSettingsRequireScreenOnToAuthPreferenceController
&& mFingerprintManager.isHardwareDetected()
&& mFingerprintManager.isPowerbuttonFps()) {
return mFingerprintManager.hasEnrolledTemplates(getUserId())
? AVAILABLE : DISABLED_DEPENDENT_SETTING;
? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
} else {
return UNSUPPORTED_ON_DEVICE;
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2023 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 android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
/**
* Preference controller that controls the fingerprint unlock features to be shown / be hidden.
*/
public class FingerprintUnlockCategoryController extends BasePreferenceController {
private static final String TAG = "FingerprintUnlockCategoryPreferenceController";
private int mUserId;
@VisibleForTesting
protected FingerprintManager mFingerprintManager;
public FingerprintUnlockCategoryController(Context context, String key) {
super(context, key);
mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
}
@Override
public int getAvailabilityStatus() {
if (mFingerprintManager != null
&& mFingerprintManager.isHardwareDetected()
&& mFingerprintManager.isPowerbuttonFps()) {
return mFingerprintManager.hasEnrolledTemplates(getUserId())
? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
} else {
return UNSUPPORTED_ON_DEVICE;
}
}
public void setUserId(int userId) {
mUserId = userId;
}
protected int getUserId() {
return mUserId;
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2023 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 android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
/**
* Preference controller that controls the enrolled fingerprints to be shown / be hidden.
*/
public class FingerprintsEnrolledCategoryPreferenceController extends BasePreferenceController {
private static final String TAG = "FingerprintsEnrolledCategoryPreferenceController";
private int mUserId;
@VisibleForTesting
protected FingerprintManager mFingerprintManager;
public FingerprintsEnrolledCategoryPreferenceController(Context context, String key) {
super(context, key);
mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
}
@Override
public int getAvailabilityStatus() {
if (mFingerprintManager != null
&& mFingerprintManager.isHardwareDetected()) {
return mFingerprintManager.hasEnrolledTemplates(getUserId())
? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
} else {
return UNSUPPORTED_ON_DEVICE;
}
}
public void setUserId(int userId) {
mUserId = userId;
}
protected int getUserId() {
return mUserId;
}
}

View File

@@ -17,7 +17,7 @@
package com.android.settings.biometrics.fingerprint;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
@@ -103,15 +103,15 @@ public class FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest {
}
@Test
public void isAvailable_isDisabled_whenSfpsHardwareDetected_AndNoEnrolledFingerprints() {
public void isUnavailable_isDisabled_whenSfpsHardwareDetected_AndNoEnrolledFingerprints() {
assertThat(mController.isAvailable()).isEqualTo(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isSfps_hasEnrolledTemplates(
true /* isHardwareDetected */,
true /* isPowerbuttonFps */,
false /* hasEnrolledTemplates */);
assertThat(mController.isAvailable()).isEqualTo(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
assertThat(mController.isAvailable()).isEqualTo(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
@@ -122,7 +122,7 @@ public class FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest {
false /* isHardwareDetected */,
true /* isPowerbuttonFps */,
true /* hasEnrolledTemplates */);
assertThat(mController.isAvailable()).isFalse();
assertThat(mController.isAvailable()).isEqualTo(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2023 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 static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settingslib.RestrictedSwitchPreference;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowUtils.class})
public class FingerprintSettingsUnlockCategoryControllerTest {
@Mock
private FingerprintManager mFingerprintManager;
@Mock
private PackageManager mPackageManager;
@Mock
private RestrictedSwitchPreference mPreference;
private Context mContext;
private FingerprintSettingsRequireScreenOnToAuthPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(eq(Context.FINGERPRINT_SERVICE))).thenReturn(
mFingerprintManager);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
mController = spy(new FingerprintSettingsRequireScreenOnToAuthPreferenceController(mContext,
"test_key"));
ReflectionHelpers.setField(mController, "mFingerprintManager", mFingerprintManager);
}
@After
public void tearDown() {
ShadowUtils.reset();
}
@Test
public void isAvailable_isEnabled_whenSfpsHardwareDetected_AndHasEnrolledFingerprints() {
assertThat(mController.isAvailable()).isEqualTo(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isSfps_hasEnrolledTemplates(
true /* isHardwareDetected */,
true /* isPowerbuttonFps */,
true /* hasEnrolledTemplates */);
assertThat(mController.isAvailable()).isEqualTo(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void isUnavailable_isDisabled_whenSfpsHardwareDetected_AndNoEnrolledFingerprints() {
assertThat(mController.isAvailable()).isEqualTo(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isSfps_hasEnrolledTemplates(
true /* isHardwareDetected */,
true /* isPowerbuttonFps */,
false /* hasEnrolledTemplates */);
assertThat(mController.isAvailable()).isEqualTo(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void isUnavailable_whenHardwareNotDetected() {
assertThat(mController.isAvailable()).isFalse();
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isSfps_hasEnrolledTemplates(
false /* isHardwareDetected */,
true /* isPowerbuttonFps */,
true /* hasEnrolledTemplates */);
assertThat(mController.isAvailable()).isEqualTo(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
public void isUnavailable_onNonSfpsDevice() {
assertThat(mController.isAvailable()).isFalse();
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
configure_hardwareDetected_isSfps_hasEnrolledTemplates(
true /* isHardwareDetected */,
false /* isPowerbuttonFps */,
true /* hasEnrolledTemplates */);
assertThat(mController.isAvailable()).isFalse();
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
private void configure_hardwareDetected_isSfps_hasEnrolledTemplates(
boolean isHardwareDetected, boolean isPowerbuttonFps, boolean hasEnrolledTemplates) {
when(mFingerprintManager.isHardwareDetected()).thenReturn(isHardwareDetected);
when(mFingerprintManager.isPowerbuttonFps()).thenReturn(isPowerbuttonFps);
when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(hasEnrolledTemplates);
}
}