Update text when Active Unlock is enabled.
Update the security summary, intro, and unlock your phone summary when Active Unlock is enabled and enrolled on the device. Test: make RunSettingsRoboTests Test: manually flip flags, confirm combined page has updated strings Bug: 264812018 Change-Id: I2843e9f3aa0f38a9f2ebb18d60fed6293f9ce36e
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
android:title="@string/security_settings_biometric_preference_title">
|
||||
|
||||
<com.android.settingslib.widget.TopIntroPreference
|
||||
android:key="biometric_intro"
|
||||
android:title="@string/biometric_settings_intro" />
|
||||
|
||||
<PreferenceCategory
|
||||
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.activeunlock;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/** Listens to device name updates from the content provider and fetches the latest value. */
|
||||
public class ActiveUnlockDeviceNameListener {
|
||||
private static final String TAG = "ActiveUnlockDeviceNameListener";
|
||||
private static final String METHOD_NAME = "getDeviceName";
|
||||
private static final String DEVICE_NAME_KEY = "com.android.settings.active_unlock.device_name";
|
||||
|
||||
private final ActiveUnlockContentListener mActiveUnlockContentListener;
|
||||
public ActiveUnlockDeviceNameListener(
|
||||
Context context, ActiveUnlockContentListener.OnContentChangedListener listener) {
|
||||
mActiveUnlockContentListener = new ActiveUnlockContentListener(
|
||||
context, listener, TAG, METHOD_NAME, DEVICE_NAME_KEY);
|
||||
}
|
||||
|
||||
/** Returns whether a device is enrolled in Active Unlock. */
|
||||
public boolean hasEnrolled() {
|
||||
return mActiveUnlockContentListener.getContent() != null;
|
||||
}
|
||||
|
||||
/** Subscribes to device name updates. */
|
||||
public void subscribe() {
|
||||
mActiveUnlockContentListener.subscribe();
|
||||
}
|
||||
|
||||
/** Unsubscribes from device name updates. */
|
||||
public void unsubscribe() {
|
||||
mActiveUnlockContentListener.unsubscribe();
|
||||
}
|
||||
}
|
@@ -31,7 +31,9 @@ import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.BasePreferenceController.AvailabilityStatus;
|
||||
@@ -164,6 +166,82 @@ public class ActiveUnlockStatusUtils {
|
||||
return BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title of the combined biometric settings entity when active unlock is enabled.
|
||||
*/
|
||||
public String getTitleForActiveUnlock() {
|
||||
final boolean faceAllowed = Utils.hasFaceHardware(mContext);
|
||||
final boolean fingerprintAllowed = Utils.hasFingerprintHardware(mContext);
|
||||
return mContext.getString(getTitleRes(faceAllowed, fingerprintAllowed));
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private static int getTitleRes(boolean isFaceAllowed, boolean isFingerprintAllowed) {
|
||||
if (isFaceAllowed && isFingerprintAllowed) {
|
||||
return R.string.security_settings_biometric_preference_title;
|
||||
} else if (isFaceAllowed) {
|
||||
return R.string.security_settings_face_preference_title;
|
||||
} else if (isFingerprintAllowed) {
|
||||
return R.string.security_settings_fingerprint_preference_title;
|
||||
} else {
|
||||
// Default to original summary, but this case should never happen.
|
||||
return R.string.security_settings_biometric_preference_title;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the intro of the combined biometric settings entity when active unlock is enabled.
|
||||
*/
|
||||
public String getIntroForActiveUnlock() {
|
||||
final boolean faceAllowed = Utils.hasFaceHardware(mContext);
|
||||
final boolean fingerprintAllowed = Utils.hasFingerprintHardware(mContext);
|
||||
if (useBiometricFailureLayout()) {
|
||||
int introRes = getIntroRes(faceAllowed, fingerprintAllowed);
|
||||
return introRes == 0 ? "" : mContext.getString(introRes);
|
||||
}
|
||||
if (useUnlockIntentLayout() && (!faceAllowed || !fingerprintAllowed)) {
|
||||
return "";
|
||||
}
|
||||
return mContext.getString(R.string.biometric_settings_intro);
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private static int getIntroRes(boolean isFaceAllowed, boolean isFingerprintAllowed) {
|
||||
if (isFaceAllowed && isFingerprintAllowed) {
|
||||
return R.string.biometric_settings_intro_with_activeunlock;
|
||||
} else if (isFaceAllowed) {
|
||||
return R.string.biometric_settings_intro_with_face;
|
||||
} else if (isFingerprintAllowed) {
|
||||
return R.string.biometric_settings_intro_with_fingerprint;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the summary of the unlock device entity when active unlock is enabled.
|
||||
*/
|
||||
public String getUnlockDeviceSummaryForActiveUnlock() {
|
||||
final boolean faceAllowed = Utils.hasFaceHardware(mContext);
|
||||
final boolean fingerprintAllowed = Utils.hasFingerprintHardware(mContext);
|
||||
|
||||
return mContext.getString(getUnlockDeviceSummaryRes(faceAllowed, fingerprintAllowed));
|
||||
}
|
||||
|
||||
@StringRes
|
||||
private static int getUnlockDeviceSummaryRes(
|
||||
boolean isFaceAllowed, boolean isFingerprintAllowed) {
|
||||
if (isFaceAllowed && isFingerprintAllowed) {
|
||||
return R.string.biometric_settings_use_face_fingerprint_or_watch_preference_summary;
|
||||
} else if (isFaceAllowed) {
|
||||
return R.string.biometric_settings_use_face_or_watch_preference_summary;
|
||||
} else if (isFingerprintAllowed) {
|
||||
return R.string.biometric_settings_use_fingerprint_or_watch_preference_summary;
|
||||
} else {
|
||||
return R.string.biometric_settings_use_watch_preference_summary;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getFlagState() {
|
||||
return DeviceConfig.getProperty(DeviceConfig.NAMESPACE_REMOTE_AUTH, CONFIG_FLAG_NAME);
|
||||
}
|
||||
|
@@ -107,10 +107,7 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
|
||||
launchChooseOrConfirmLock();
|
||||
}
|
||||
|
||||
final Preference unlockPhonePreference = findPreference(getUnlockPhonePreferenceKey());
|
||||
if (unlockPhonePreference != null) {
|
||||
unlockPhonePreference.setSummary(getUseAnyBiometricSummary());
|
||||
}
|
||||
updateUnlockPhonePreferenceSummary();
|
||||
|
||||
final Preference useInAppsPreference = findPreference(getUseInAppsPreferenceKey());
|
||||
if (useInAppsPreference != null) {
|
||||
@@ -309,8 +306,15 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateUnlockPhonePreferenceSummary() {
|
||||
final Preference unlockPhonePreference = findPreference(getUnlockPhonePreferenceKey());
|
||||
if (unlockPhonePreference != null) {
|
||||
unlockPhonePreference.setSummary(getUseAnyBiometricSummary());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String getUseAnyBiometricSummary() {
|
||||
protected String getUseAnyBiometricSummary() {
|
||||
boolean isFaceAllowed = mFaceManager != null && mFaceManager.isHardwareDetected();
|
||||
boolean isFingerprintAllowed =
|
||||
mFingerprintManager != null && mFingerprintManager.isHardwareDetected();
|
||||
|
@@ -17,8 +17,15 @@ package com.android.settings.biometrics.combination;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.biometrics.activeunlock.ActiveUnlockContentListener.OnContentChangedListener;
|
||||
import com.android.settings.biometrics.activeunlock.ActiveUnlockDeviceNameListener;
|
||||
import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
@@ -32,6 +39,10 @@ public class CombinedBiometricSettings extends BiometricsSettingsBase {
|
||||
private static final String KEY_FINGERPRINT_SETTINGS = "biometric_fingerprint_settings";
|
||||
private static final String KEY_UNLOCK_PHONE = "biometric_settings_biometric_keyguard";
|
||||
private static final String KEY_USE_IN_APPS = "biometric_settings_biometric_app";
|
||||
private static final String KEY_INTRO_PREFERENCE = "biometric_intro";
|
||||
|
||||
private ActiveUnlockStatusUtils mActiveUnlockStatusUtils;
|
||||
@Nullable private ActiveUnlockDeviceNameListener mActiveUnlockDeviceNameListener;
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
@@ -40,6 +51,41 @@ public class CombinedBiometricSettings extends BiometricsSettingsBase {
|
||||
use(BiometricSettingsAppPreferenceController.class).setUserId(mUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mActiveUnlockStatusUtils = new ActiveUnlockStatusUtils(getActivity());
|
||||
if (mActiveUnlockStatusUtils.isAvailable()) {
|
||||
updateUiForActiveUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUiForActiveUnlock() {
|
||||
OnContentChangedListener listener = new OnContentChangedListener() {
|
||||
@Override
|
||||
public void onContentChanged(String newValue) {
|
||||
updateUnlockPhonePreferenceSummary();
|
||||
}
|
||||
};
|
||||
|
||||
mActiveUnlockDeviceNameListener =
|
||||
new ActiveUnlockDeviceNameListener(getActivity(), listener);
|
||||
mActiveUnlockDeviceNameListener.subscribe();
|
||||
final Preference introPreference = findPreference(KEY_INTRO_PREFERENCE);
|
||||
if (introPreference != null) {
|
||||
introPreference.setTitle(mActiveUnlockStatusUtils.getIntroForActiveUnlock());
|
||||
}
|
||||
getActivity().setTitle(mActiveUnlockStatusUtils.getTitleForActiveUnlock());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (mActiveUnlockDeviceNameListener != null) {
|
||||
mActiveUnlockDeviceNameListener.unsubscribe();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.security_settings_combined_biometric;
|
||||
@@ -75,6 +121,16 @@ public class CombinedBiometricSettings extends BiometricsSettingsBase {
|
||||
return SettingsEnums.COMBINED_BIOMETRIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUseAnyBiometricSummary() {
|
||||
// either Active Unlock is not enabled or no device is enrolled.
|
||||
if (mActiveUnlockDeviceNameListener == null
|
||||
|| !mActiveUnlockDeviceNameListener.hasEnrolled()) {
|
||||
return super.getUseAnyBiometricSummary();
|
||||
}
|
||||
return mActiveUnlockStatusUtils.getUnlockDeviceSummaryForActiveUnlock();
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new CombinedBiometricSearchIndexProvider(R.xml.security_settings_combined_biometric);
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@ import android.hardware.fingerprint.FingerprintManager;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.testutils.ActiveUnlockTestUtils;
|
||||
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
|
||||
|
||||
@@ -135,4 +136,90 @@ public class ActiveUnlockStatusUtilsTest {
|
||||
assertThat(mActiveUnlockStatusUtils.useUnlockIntentLayout()).isFalse();
|
||||
assertThat(mActiveUnlockStatusUtils.useBiometricFailureLayout()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTitle_faceEnabled_returnsFacePreferenceTitle() {
|
||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
|
||||
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||
|
||||
assertThat(mActiveUnlockStatusUtils.getTitleForActiveUnlock())
|
||||
.isEqualTo(mApplicationContext.getString(
|
||||
R.string.security_settings_face_preference_title));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTitle_fingerprintEnabled_returnsFingerprintPreferenceTitle() {
|
||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||
when(mFaceManager.isHardwareDetected()).thenReturn(false);
|
||||
|
||||
assertThat(mActiveUnlockStatusUtils.getTitleForActiveUnlock())
|
||||
.isEqualTo(mApplicationContext.getString(
|
||||
R.string.security_settings_fingerprint_preference_title));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIntro_faceEnabled_returnsIntroWithFace() {
|
||||
ActiveUnlockTestUtils.enable(
|
||||
mApplicationContext, ActiveUnlockStatusUtils.BIOMETRIC_FAILURE_LAYOUT);
|
||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
|
||||
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||
|
||||
assertThat(mActiveUnlockStatusUtils.getIntroForActiveUnlock())
|
||||
.isEqualTo(mApplicationContext.getString(
|
||||
R.string.biometric_settings_intro_with_face));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIntro_fingerprintEnabled_returnsIntroWithFingerprint() {
|
||||
ActiveUnlockTestUtils.enable(
|
||||
mApplicationContext, ActiveUnlockStatusUtils.BIOMETRIC_FAILURE_LAYOUT);
|
||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||
when(mFaceManager.isHardwareDetected()).thenReturn(false);
|
||||
|
||||
assertThat(mActiveUnlockStatusUtils.getIntroForActiveUnlock())
|
||||
.isEqualTo(mApplicationContext.getString(
|
||||
R.string.biometric_settings_intro_with_fingerprint));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIntro_unlockOnIntentAndFaceEnabled_returnsEmpty() {
|
||||
ActiveUnlockTestUtils.enable(
|
||||
mApplicationContext, ActiveUnlockStatusUtils.UNLOCK_INTENT_LAYOUT);
|
||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||
when(mFaceManager.isHardwareDetected()).thenReturn(false);
|
||||
|
||||
assertThat(mActiveUnlockStatusUtils.getIntroForActiveUnlock()).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIntro_unlockOnIntentAndFaceAndFingerprintEnabled_returnsDefault() {
|
||||
ActiveUnlockTestUtils.enable(
|
||||
mApplicationContext, ActiveUnlockStatusUtils.UNLOCK_INTENT_LAYOUT);
|
||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||
|
||||
assertThat(mActiveUnlockStatusUtils.getIntroForActiveUnlock())
|
||||
.isEqualTo(mApplicationContext.getString(
|
||||
R.string.biometric_settings_intro));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUnlockDeviceSummary_fingerprintEnabled_returnsFingerprintOrWatch() {
|
||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||
when(mFaceManager.isHardwareDetected()).thenReturn(false);
|
||||
|
||||
assertThat(mActiveUnlockStatusUtils.getUnlockDeviceSummaryForActiveUnlock())
|
||||
.isEqualTo(mApplicationContext.getString(
|
||||
R.string.biometric_settings_use_fingerprint_or_watch_preference_summary));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUnlockDeviceSummary_faceEnabled_returnsFaceOrWatch() {
|
||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
|
||||
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||
|
||||
assertThat(mActiveUnlockStatusUtils.getUnlockDeviceSummaryForActiveUnlock())
|
||||
.isEqualTo(mApplicationContext.getString(
|
||||
R.string.biometric_settings_use_face_or_watch_preference_summary));
|
||||
}
|
||||
}
|
||||
|
@@ -39,6 +39,8 @@ public final class FakeContentProvider extends ContentProvider {
|
||||
.build();
|
||||
public static final String METHOD_SUMMARY = "getSummary";
|
||||
public static final String KEY_SUMMARY = "com.android.settings.summary";
|
||||
private static final String METHOD_DEVICE_NAME = "getDeviceName";
|
||||
private static final String KEY_DEVICE_NAME = "com.android.settings.active_unlock.device_name";
|
||||
@Nullable private static String sTileSummary;
|
||||
@Nullable private static String sDeviceName;
|
||||
|
||||
@@ -50,10 +52,15 @@ public final class FakeContentProvider extends ContentProvider {
|
||||
sTileSummary = summary;
|
||||
}
|
||||
|
||||
public static void setDeviceName(String deviceName) {
|
||||
sDeviceName = deviceName;
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
Settings.Secure.putString(
|
||||
context.getContentResolver(), ActiveUnlockTestUtils.PROVIDER_SETTING, AUTHORITY);
|
||||
sTileSummary = null;
|
||||
sDeviceName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,6 +68,8 @@ public final class FakeContentProvider extends ContentProvider {
|
||||
Bundle bundle = new Bundle();
|
||||
if (METHOD_SUMMARY.equals(method)) {
|
||||
bundle.putCharSequence(KEY_SUMMARY, sTileSummary);
|
||||
} else if (METHOD_DEVICE_NAME.equals(method)) {
|
||||
bundle.putCharSequence(KEY_DEVICE_NAME, sDeviceName);
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
Reference in New Issue
Block a user