Add bp subtitle for TYPE_CREDENTIAL

Add a subtitile for TYPE_CREDENTIAL and address comments in ag/24005347.

Test: atest BiometricServiceTest
Fixes: 291307701
Change-Id: I661af8173a6ecdf7abf924b66b33cfd0d9af687d
This commit is contained in:
Wenhui Yang
2023-07-24 23:31:22 +00:00
parent b2c12cea96
commit c8723e2e3a
4 changed files with 96 additions and 49 deletions

View File

@@ -1780,10 +1780,6 @@
<string name="biometric_dialog_default_title">Verify it\u2019s you</string>
<!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face). [CHAR LIMIT=70] -->
<string name="biometric_dialog_default_subtitle">Use your biometric to continue</string>
<!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with fingerprint. [CHAR LIMIT=70] -->
<string name="biometric_dialog_fingerprint_subtitle">Use your fingerprint to continue</string>
<!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with face. [CHAR LIMIT=70] -->
<string name="biometric_dialog_face_subtitle">Use your face to continue</string>
<!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with a biometric (e.g. fingerprint or face) or their screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=90] -->
<string name="biometric_or_screen_lock_dialog_default_subtitle">Use your biometric or screen lock to continue</string>

View File

@@ -2572,8 +2572,6 @@
<java-symbol type="string" name="biometric_or_screen_lock_app_setting_name" />
<java-symbol type="string" name="biometric_dialog_default_title" />
<java-symbol type="string" name="biometric_dialog_default_subtitle" />
<java-symbol type="string" name="biometric_dialog_face_subtitle" />
<java-symbol type="string" name="biometric_dialog_fingerprint_subtitle" />
<java-symbol type="string" name="biometric_or_screen_lock_dialog_default_subtitle" />
<java-symbol type="string" name="biometric_error_hw_unavailable" />
<java-symbol type="string" name="biometric_error_user_canceled" />

View File

@@ -1308,10 +1308,13 @@ public class BiometricService extends SystemService {
.getString(R.string.biometric_dialog_default_subtitle));
} else if (hasEligibleFingerprintSensor) {
promptInfo.setSubtitle(getContext()
.getString(R.string.biometric_dialog_fingerprint_subtitle));
.getString(R.string.fingerprint_dialog_default_subtitle));
} else if (hasEligibleFaceSensor) {
promptInfo.setSubtitle(getContext()
.getString(R.string.biometric_dialog_face_subtitle));
.getString(R.string.face_dialog_default_subtitle));
} else {
promptInfo.setSubtitle(getContext()
.getString(R.string.screen_lock_dialog_default_subtitle));
}
}

View File

@@ -16,6 +16,7 @@
package com.android.server.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_CREDENTIAL;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators;
@@ -116,9 +117,9 @@ public class BiometricServiceTest {
private static final String ERROR_LOCKOUT = "error_lockout";
private static final String FACE_SUBTITLE = "face_subtitle";
private static final String FINGERPRINT_SUBTITLE = "fingerprint_subtitle";
private static final String CREDENTIAL_SUBTITLE = "credential_subtitle";
private static final String DEFAULT_SUBTITLE = "default_subtitle";
private static final String FINGERPRINT_ACQUIRED_SENSOR_DIRTY = "sensor_dirty";
private static final int SENSOR_ID_FINGERPRINT = 0;
@@ -143,6 +144,8 @@ public class BiometricServiceTest {
@Mock
IBiometricAuthenticator mFaceAuthenticator;
@Mock
IBiometricAuthenticator mCredentialAuthenticator;
@Mock
ITrustManager mTrustManager;
@Mock
DevicePolicyManager mDevicePolicyManager;
@@ -196,10 +199,12 @@ public class BiometricServiceTest {
.thenReturn(ERROR_NOT_RECOGNIZED);
when(mResources.getString(R.string.biometric_error_user_canceled))
.thenReturn(ERROR_USER_CANCELED);
when(mContext.getString(R.string.biometric_dialog_face_subtitle))
when(mContext.getString(R.string.face_dialog_default_subtitle))
.thenReturn(FACE_SUBTITLE);
when(mContext.getString(R.string.biometric_dialog_fingerprint_subtitle))
when(mContext.getString(R.string.fingerprint_dialog_default_subtitle))
.thenReturn(FINGERPRINT_SUBTITLE);
when(mContext.getString(R.string.screen_lock_dialog_default_subtitle))
.thenReturn(CREDENTIAL_SUBTITLE);
when(mContext.getString(R.string.biometric_dialog_default_subtitle))
.thenReturn(DEFAULT_SUBTITLE);
@@ -292,7 +297,8 @@ public class BiometricServiceTest {
mBiometricService.onStart();
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
Authenticators.DEVICE_CREDENTIAL);
Authenticators.DEVICE_CREDENTIAL, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_CREDENTIAL),
@@ -312,7 +318,8 @@ public class BiometricServiceTest {
mBiometricService.onStart();
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
Authenticators.DEVICE_CREDENTIAL);
Authenticators.DEVICE_CREDENTIAL, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
assertNotNull(mBiometricService.mAuthSession);
@@ -338,7 +345,8 @@ public class BiometricServiceTest {
mBiometricService.onStart();
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */);
null /* authenticators */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_NONE),
@@ -357,7 +365,8 @@ public class BiometricServiceTest {
mFingerprintAuthenticator);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */);
null /* authenticators */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(TYPE_FINGERPRINT),
@@ -370,7 +379,8 @@ public class BiometricServiceTest {
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_WEAK);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
Authenticators.BIOMETRIC_STRONG);
Authenticators.BIOMETRIC_STRONG, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_NONE),
@@ -429,7 +439,8 @@ public class BiometricServiceTest {
mFingerprintAuthenticator);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */);
null /* authenticators */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(TYPE_FINGERPRINT),
@@ -441,9 +452,9 @@ public class BiometricServiceTest {
public void testAuthenticateFace_shouldShowSubtitleForFace() throws Exception {
setupAuthForOnly(TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */,
null);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */, true /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
assertEquals(FACE_SUBTITLE, mBiometricService.mAuthSession.mPromptInfo.getSubtitle());
@@ -453,15 +464,28 @@ public class BiometricServiceTest {
public void testAuthenticateFingerprint_shouldShowSubtitleForFingerprint() throws Exception {
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */,
null);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */, true /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
assertEquals(FINGERPRINT_SUBTITLE,
mBiometricService.mAuthSession.mPromptInfo.getSubtitle());
}
@Test
public void testAuthenticateFingerprint_shouldShowSubtitleForCredential() throws Exception {
setupAuthForOnly(TYPE_CREDENTIAL, Authenticators.DEVICE_CREDENTIAL);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */, true /* useDefaultSubtitle */,
true /* deviceCredentialAllowed */);
waitForIdle();
assertEquals(CREDENTIAL_SUBTITLE,
mBiometricService.mAuthSession.mPromptInfo.getSubtitle());
}
@Test
public void testAuthenticateBothFpAndFace_shouldShowDefaultSubtitle() throws Exception {
final int[] modalities = new int[] {
@@ -476,9 +500,9 @@ public class BiometricServiceTest {
setupAuthForMultiple(modalities, strengths);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */,
null);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */, true /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
assertEquals(DEFAULT_SUBTITLE, mBiometricService.mAuthSession.mPromptInfo.getSubtitle());
@@ -492,7 +516,8 @@ public class BiometricServiceTest {
// Disabled in user settings receives onError
when(mBiometricService.mSettingObserver.getEnabledForApps(anyInt())).thenReturn(false);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */);
null /* authenticators */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_NONE),
@@ -506,7 +531,8 @@ public class BiometricServiceTest {
anyInt() /* modality */, anyInt() /* userId */))
.thenReturn(true);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */);
null /* authenticators */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
final byte[] HAT = generateRandomHAT();
@@ -524,7 +550,8 @@ public class BiometricServiceTest {
anyInt() /* modality */, anyInt() /* userId */))
.thenReturn(false);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */);
null /* authenticators */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
mBiometricService.mAuthSession.mSensorReceiver.onAuthenticationSucceeded(
SENSOR_ID_FACE,
@@ -552,7 +579,8 @@ public class BiometricServiceTest {
throws Exception {
// Start testing the happy path
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */);
null /* authenticators */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
// Creates a pending auth session with the correct initial states
@@ -632,7 +660,8 @@ public class BiometricServiceTest {
.thenReturn(true);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
true /* requireConfirmation */,
Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK);
Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK,
false /* useDefaultSubtitle*/, false /* deviceCredentialAllowed */);
waitForIdle();
assertEquals(STATE_SHOWING_DEVICE_CREDENTIAL,
@@ -702,7 +731,8 @@ public class BiometricServiceTest {
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
true /* requireConfirmation */,
Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_STRONG);
Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_STRONG,
false /* useDefaultSubtitle */, false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(anyInt() /* modality */,
@@ -754,7 +784,8 @@ public class BiometricServiceTest {
false /* requireConfirmation */, null /* authenticators */);
invokeAuthenticate(mBiometricService.mImpl, mReceiver2, false /* requireConfirmation */,
null /* authenticators */);
null /* authenticators */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
@@ -887,7 +918,8 @@ public class BiometricServiceTest {
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */,
Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK);
Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK,
false /* useDefaultSubtitle */, false /* deviceCredentialAllowed */);
waitForIdle();
assertEquals(STATE_AUTH_CALLED, mBiometricService.mAuthSession.getState());
@@ -920,8 +952,9 @@ public class BiometricServiceTest {
public void testErrorFromHal_whilePreparingAuthentication_credentialNotAllowed()
throws Exception {
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, null /* authenticators */);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
mBiometricService.mAuthSession.mSensorReceiver.onError(
@@ -957,8 +990,9 @@ public class BiometricServiceTest {
setupAuthForOnly(TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt()))
.thenReturn(lockoutMode);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, null /* authenticators */);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
// Modality and error are sent
@@ -996,8 +1030,9 @@ public class BiometricServiceTest {
when(mFingerprintAuthenticator.getLockoutModeForUser(anyInt()))
.thenReturn(lockoutMode);
when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, null /* authenticators */);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
null /* authenticators */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
// The lockout error should be sent, instead of ERROR_NONE_ENROLLED. See b/286923477.
@@ -1014,7 +1049,8 @@ public class BiometricServiceTest {
.thenReturn(LockoutTracker.LOCKOUT_PERMANENT);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */,
Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_STRONG);
Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_STRONG,
false /* useDefaultSubtitle */, false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
@@ -1503,7 +1539,8 @@ public class BiometricServiceTest {
assertEquals(BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
invokeCanAuthenticate(mBiometricService, authenticators));
long requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, authenticators);
false /* requireConfirmation */, authenticators, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
verify(mReceiver1).onError(
eq(TYPE_FINGERPRINT),
@@ -1539,7 +1576,8 @@ public class BiometricServiceTest {
invokeCanAuthenticate(mBiometricService, authenticators));
requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */,
authenticators);
authenticators, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */);
waitForIdle();
assertTrue(Utils.isCredentialRequested(mBiometricService.mAuthSession.mPromptInfo));
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
@@ -1749,6 +1787,11 @@ public class BiometricServiceTest {
mBiometricService.mImpl.registerAuthenticator(SENSOR_ID_FACE, modality, strength,
mFaceAuthenticator);
}
if ((modality & TYPE_CREDENTIAL) != 0) {
when(mTrustManager.isDeviceSecure(anyInt(), anyInt()))
.thenReturn(true);
}
}
// TODO: Reduce duplicated code, currently we cannot start the BiometricService in setUp() for
@@ -1799,7 +1842,8 @@ public class BiometricServiceTest {
Integer authenticators) throws Exception {
// Request auth, creates a pending session
final long requestId = invokeAuthenticate(
service, receiver, requireConfirmation, authenticators);
service, receiver, requireConfirmation, authenticators,
false /* useDefaultSubtitle */, false /* deviceCredentialAllowed */);
waitForIdle();
startPendingAuthSession(mBiometricService);
@@ -1827,7 +1871,8 @@ public class BiometricServiceTest {
private static long invokeAuthenticate(IBiometricService.Stub service,
IBiometricServiceReceiver receiver, boolean requireConfirmation,
Integer authenticators) throws Exception {
Integer authenticators, boolean useDefaultSubtitle,
boolean deviceCredentialAllowed) throws Exception {
return service.authenticate(
new Binder() /* token */,
0 /* operationId */,
@@ -1835,7 +1880,8 @@ public class BiometricServiceTest {
receiver,
TEST_PACKAGE_NAME /* packageName */,
createTestPromptInfo(requireConfirmation, authenticators,
false /* checkDevicePolicy */));
false /* checkDevicePolicy */, useDefaultSubtitle,
deviceCredentialAllowed));
}
private static long invokeAuthenticateForWorkApp(IBiometricService.Stub service,
@@ -1847,16 +1893,19 @@ public class BiometricServiceTest {
receiver,
TEST_PACKAGE_NAME /* packageName */,
createTestPromptInfo(false /* requireConfirmation */, authenticators,
true /* checkDevicePolicy */));
true /* checkDevicePolicy */, false /* useDefaultSubtitle */,
false /* deviceCredentialAllowed */));
}
private static PromptInfo createTestPromptInfo(
boolean requireConfirmation,
Integer authenticators,
boolean checkDevicePolicy) {
boolean checkDevicePolicy,
boolean useDefaultSubtitle,
boolean deviceCredentialAllowed) {
final PromptInfo promptInfo = new PromptInfo();
promptInfo.setConfirmationRequested(requireConfirmation);
promptInfo.setUseDefaultSubtitle(true);
promptInfo.setUseDefaultSubtitle(useDefaultSubtitle);
if (authenticators != null) {
promptInfo.setAuthenticators(authenticators);
@@ -1864,6 +1913,7 @@ public class BiometricServiceTest {
if (checkDevicePolicy) {
promptInfo.setDisallowBiometricsIfPolicyExists(checkDevicePolicy);
}
promptInfo.setDeviceCredentialAllowed(deviceCredentialAllowed);
return promptInfo;
}