Support face unlock for PS if class2 biometric and above

With this change it is checked if face unlock is supported as a class2
or class3 biometrics on the device.
If face is convenience biometrics then face unlock for
private space controller is not added.

Bug: 329044103
Test: atest UtilsTest and verified Face unlock is not added if face is convenience
Change-Id: I6e1a6557774be1173ad3ee7ff7b14d51f9fe1716
This commit is contained in:
josephpv
2024-03-13 14:53:31 +00:00
committed by Joseph Vincent
parent bc48abe0bd
commit 1791ce216b
5 changed files with 100 additions and 8 deletions

View File

@@ -54,8 +54,10 @@ import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable; import android.graphics.drawable.VectorDrawable;
import android.hardware.biometrics.SensorProperties;
import android.hardware.face.Face; import android.hardware.face.Face;
import android.hardware.face.FaceManager; import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
@@ -927,6 +929,23 @@ public final class Utils extends com.android.settingslib.Utils {
return hasFingerprintHardware(context) && hasFaceHardware(context); return hasFingerprintHardware(context) && hasFaceHardware(context);
} }
/**
* Return true if face is supported as Class 2 biometrics and above on the device, false
* otherwise.
*/
public static boolean isFaceNotConvenienceBiometric(@NonNull Context context) {
FaceManager faceManager = getFaceManagerOrNull(context);
if (faceManager != null) {
final List<FaceSensorPropertiesInternal> faceProperties =
faceManager.getSensorPropertiesInternal();
if (!faceProperties.isEmpty()) {
final FaceSensorPropertiesInternal props = faceProperties.get(0);
return props.sensorStrength != SensorProperties.STRENGTH_CONVENIENCE;
}
}
return false;
}
/** /**
* Launches an intent which may optionally have a user id defined. * Launches an intent which may optionally have a user id defined.
* @param fragment Fragment to use to launch the activity. * @param fragment Fragment to use to launch the activity.

View File

@@ -87,7 +87,8 @@ public class PrivateSpaceFacePreferenceController extends BiometricFaceStatusPre
public void displayPreference(@NonNull PreferenceScreen screen) { public void displayPreference(@NonNull PreferenceScreen screen) {
super.displayPreference(screen); super.displayPreference(screen);
Preference preference = screen.findPreference(getPreferenceKey()); Preference preference = screen.findPreference(getPreferenceKey());
if (!Utils.isMultipleBiometricsSupported(mContext)) { if (!Utils.isMultipleBiometricsSupported(mContext)
&& Utils.isFaceNotConvenienceBiometric(mContext)) {
preference.setTitle(R.string.private_space_face_title); preference.setTitle(R.string.private_space_face_title);
} }
} }

View File

@@ -89,7 +89,8 @@ public class PrivateSpaceFingerprintPreferenceController
public void displayPreference(@NonNull PreferenceScreen screen) { public void displayPreference(@NonNull PreferenceScreen screen) {
super.displayPreference(screen); super.displayPreference(screen);
Preference preference = screen.findPreference(getPreferenceKey()); Preference preference = screen.findPreference(getPreferenceKey());
if (!Utils.isMultipleBiometricsSupported(mContext)) { if (!Utils.isMultipleBiometricsSupported(mContext)
|| !Utils.isFaceNotConvenienceBiometric(mContext)) {
preference.setTitle(R.string.private_space_fingerprint_title); preference.setTitle(R.string.private_space_fingerprint_title);
} }
} }

View File

@@ -73,13 +73,14 @@ public class UseOneLockSettingsFragment extends DashboardFragment {
final List<AbstractPreferenceController> controllers = new ArrayList<>(); final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new UseOneLockControllerSwitch(context, this)); controllers.add(new UseOneLockControllerSwitch(context, this));
controllers.add(new PrivateSpaceLockController(context, this)); controllers.add(new PrivateSpaceLockController(context, this));
if (Utils.isMultipleBiometricsSupported(context)) { boolean isFaceAuthAllowed = Utils.isFaceNotConvenienceBiometric(context);
if (Utils.isMultipleBiometricsSupported(context) && isFaceAuthAllowed) {
controllers.add(new FaceFingerprintUnlockController(context, getSettingsLifecycle())); controllers.add(new FaceFingerprintUnlockController(context, getSettingsLifecycle()));
} else if (Utils.hasFingerprintHardware(context)) { } else if (Utils.hasFingerprintHardware(context)) {
controllers.add( controllers.add(
new PrivateSpaceFingerprintPreferenceController( new PrivateSpaceFingerprintPreferenceController(
context, "private_space_biometrics", getSettingsLifecycle())); context, "private_space_biometrics", getSettingsLifecycle()));
} else if (Utils.hasFaceHardware(context)) { } else if (Utils.hasFaceHardware(context) && isFaceAuthAllowed) {
controllers.add( controllers.add(
new PrivateSpaceFacePreferenceController( new PrivateSpaceFacePreferenceController(
context, "private_space_biometrics", getSettingsLifecycle())); context, "private_space_biometrics", getSettingsLifecycle()));

View File

@@ -16,6 +16,10 @@
package com.android.settings; package com.android.settings;
import static android.hardware.biometrics.SensorProperties.STRENGTH_CONVENIENCE;
import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import static android.hardware.biometrics.SensorProperties.STRENGTH_WEAK;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
@@ -43,6 +47,9 @@ import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.VectorDrawable; import android.graphics.drawable.VectorDrawable;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorProperties;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.LinkAddress; import android.net.LinkAddress;
import android.net.LinkProperties; import android.net.LinkProperties;
@@ -433,6 +440,69 @@ public class UtilsTest {
assertNull(confirmCredentialString); assertNull(confirmCredentialString);
} }
@Test
public void isFaceNotConvenienceBiometric_faceStrengthStrong_shouldReturnTrue() {
FaceManager mockFaceManager = mock(FaceManager.class);
when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mockFaceManager);
doReturn(true).when(mPackageManager).hasSystemFeature(anyString());
List<FaceSensorPropertiesInternal> props = List.of(new FaceSensorPropertiesInternal(
0 /* id */,
STRENGTH_STRONG,
1 /* maxTemplatesAllowed */,
new ArrayList<>() /* componentInfo */,
FaceSensorProperties.TYPE_UNKNOWN,
true /* supportsFaceDetection */,
true /* supportsSelfIllumination */,
false /* resetLockoutRequiresChallenge */));
doReturn(props).when(mockFaceManager).getSensorPropertiesInternal();
assertThat(Utils.isFaceNotConvenienceBiometric(mContext)).isTrue();
}
@Test
public void isFaceNotConvenienceBiometric_faceStrengthWeak_shouldReturnTrue() {
FaceManager mockFaceManager = mock(FaceManager.class);
when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mockFaceManager);
doReturn(true).when(mPackageManager).hasSystemFeature(anyString());
List<FaceSensorPropertiesInternal> props = List.of(new FaceSensorPropertiesInternal(
0 /* id */,
STRENGTH_WEAK,
1 /* maxTemplatesAllowed */,
new ArrayList<>() /* componentInfo */,
FaceSensorProperties.TYPE_UNKNOWN,
true /* supportsFaceDetection */,
true /* supportsSelfIllumination */,
false /* resetLockoutRequiresChallenge */));
doReturn(props).when(mockFaceManager).getSensorPropertiesInternal();
assertThat(Utils.isFaceNotConvenienceBiometric(mContext)).isTrue();
}
@Test
public void isFaceNotConvenienceBiometric_faceStrengthConvenience_shouldReturnFalse() {
FaceManager mockFaceManager = mock(FaceManager.class);
when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mockFaceManager);
doReturn(true).when(mPackageManager).hasSystemFeature(anyString());
List<FaceSensorPropertiesInternal> props = List.of(new FaceSensorPropertiesInternal(
0 /* id */,
STRENGTH_CONVENIENCE,
1 /* maxTemplatesAllowed */,
new ArrayList<>() /* componentInfo */,
FaceSensorProperties.TYPE_UNKNOWN,
true /* supportsFaceDetection */,
true /* supportsSelfIllumination */,
false /* resetLockoutRequiresChallenge */));
doReturn(props).when(mockFaceManager).getSensorPropertiesInternal();
assertThat(Utils.isFaceNotConvenienceBiometric(mContext)).isFalse();
}
@Test
public void isFaceNotConvenienceBiometric_faceManagerNull_shouldReturnFalse() {
when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(null);
assertThat(Utils.isFaceNotConvenienceBiometric(mContext)).isFalse();
}
private void setUpForConfirmCredentialString(boolean isEffectiveUserManagedProfile) { private void setUpForConfirmCredentialString(boolean isEffectiveUserManagedProfile) {
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager); when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
when(mMockUserManager.getCredentialOwnerProfile(USER_ID)).thenReturn(USER_ID); when(mMockUserManager.getCredentialOwnerProfile(USER_ID)).thenReturn(USER_ID);