Merge changes from topic "biometric-security"

* changes:
  Implementation for BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED
  Add API constant for BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED
This commit is contained in:
Kevin Chyn
2020-02-11 01:20:00 +00:00
committed by Android (Google) Code Review
9 changed files with 228 additions and 94 deletions

View File

@@ -17033,6 +17033,7 @@ package android.hardware.biometrics {
field public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE = 1; // 0x1
field public static final int BIOMETRIC_ERROR_NONE_ENROLLED = 11; // 0xb
field public static final int BIOMETRIC_ERROR_NO_HARDWARE = 12; // 0xc
field public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; // 0xf
field public static final int BIOMETRIC_SUCCESS = 0; // 0x0
}
@@ -17067,6 +17068,7 @@ package android.hardware.biometrics {
field public static final int BIOMETRIC_ERROR_NO_BIOMETRICS = 11; // 0xb
field public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14; // 0xe
field public static final int BIOMETRIC_ERROR_NO_SPACE = 4; // 0x4
field public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; // 0xf
field public static final int BIOMETRIC_ERROR_TIMEOUT = 3; // 0x3
field public static final int BIOMETRIC_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
field public static final int BIOMETRIC_ERROR_USER_CANCELED = 10; // 0xa

View File

@@ -131,6 +131,14 @@ public interface BiometricConstants {
*/
int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14;
/**
* A security vulnerability has been discovered and the sensor is unavailable until a
* security update has addressed this issue. This error can be received if for example,
* authentication was requested with {@link Authenticators#BIOMETRIC_STRONG}, but the
* sensor's strength can currently only meet {@link Authenticators#BIOMETRIC_WEAK}.
*/
int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15;
/**
* This constant is only used by SystemUI. It notifies SystemUI that authentication was paused
* because the authentication attempt was unsuccessful.

View File

@@ -17,6 +17,7 @@
package android.hardware.biometrics;
import android.app.KeyguardManager;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.face.FaceManager;
/**
@@ -141,6 +142,15 @@ public interface BiometricFaceConstants {
*/
public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14;
/**
* A security vulnerability has been discovered and the sensor is unavailable until a
* security update has addressed this issue. This error can be received if for example,
* authentication was requested with {@link Authenticators#BIOMETRIC_STRONG}, but the
* sensor's strength can currently only meet {@link Authenticators#BIOMETRIC_WEAK}.
* @hide
*/
int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15;
/**
* @hide
*/

View File

@@ -18,6 +18,7 @@ package android.hardware.biometrics;
import android.app.KeyguardManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.fingerprint.FingerprintManager;
/**
@@ -127,6 +128,15 @@ public interface BiometricFingerprintConstants {
*/
public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14;
/**
* A security vulnerability has been discovered and the sensor is unavailable until a
* security update has addressed this issue. This error can be received if for example,
* authentication was requested with {@link Authenticators#BIOMETRIC_STRONG}, but the
* sensor's strength can currently only meet {@link Authenticators#BIOMETRIC_WEAK}.
* @hide
*/
public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15;
/**
* @hide
*/

View File

@@ -61,10 +61,20 @@ public class BiometricManager {
public static final int BIOMETRIC_ERROR_NO_HARDWARE =
BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT;
/**
* A security vulnerability has been discovered and the sensor is unavailable until a
* security update has addressed this issue. This error can be received if for example,
* authentication was requested with {@link Authenticators#BIOMETRIC_STRONG}, but the
* sensor's strength can currently only meet {@link Authenticators#BIOMETRIC_WEAK}.
*/
public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED =
BiometricConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED;
@IntDef({BIOMETRIC_SUCCESS,
BIOMETRIC_ERROR_HW_UNAVAILABLE,
BIOMETRIC_ERROR_NONE_ENROLLED,
BIOMETRIC_ERROR_NO_HARDWARE})
BIOMETRIC_ERROR_NO_HARDWARE,
BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED})
@interface BiometricError {}
/**

View File

@@ -25,6 +25,7 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
import static android.hardware.biometrics.BiometricManager.Authenticators;
import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.UserSwitchObserver;
@@ -83,6 +84,25 @@ public class BiometricService extends SystemService {
static final String TAG = "BiometricService";
private static final boolean DEBUG = true;
private static final int BIOMETRIC_NO_HARDWARE = 0;
private static final int BIOMETRIC_OK = 1;
private static final int BIOMETRIC_DISABLED_BY_DEVICE_POLICY = 2;
private static final int BIOMETRIC_INSUFFICIENT_STRENGTH = 3;
private static final int BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE = 4;
private static final int BIOMETRIC_HARDWARE_NOT_DETECTED = 5;
private static final int BIOMETRIC_NOT_ENROLLED = 6;
private static final int BIOMETRIC_NOT_ENABLED_FOR_APPS = 7;
@IntDef({BIOMETRIC_NO_HARDWARE,
BIOMETRIC_OK,
BIOMETRIC_DISABLED_BY_DEVICE_POLICY,
BIOMETRIC_INSUFFICIENT_STRENGTH,
BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE,
BIOMETRIC_HARDWARE_NOT_DETECTED,
BIOMETRIC_NOT_ENROLLED,
BIOMETRIC_NOT_ENABLED_FOR_APPS})
@interface BiometricStatus {}
private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2;
private static final int MSG_ON_AUTHENTICATION_REJECTED = 3;
private static final int MSG_ON_ERROR = 4;
@@ -206,7 +226,7 @@ public class BiometricService extends SystemService {
}
boolean isAllowDeviceCredential() {
return Utils.isDeviceCredentialAllowed(mBundle);
return Utils.isCredentialRequested(mBundle);
}
}
@@ -372,16 +392,20 @@ public class BiometricService extends SystemService {
* strength.
* @return a bitfield, see {@link Authenticators}
*/
public int getActualStrength() {
int getActualStrength() {
return OEMStrength | updatedStrength;
}
boolean isDowngraded() {
return OEMStrength != updatedStrength;
}
/**
* Stores the updated strength, which takes effect whenever {@link #getActualStrength()}
* is checked.
* @param newStrength
*/
public void updateStrength(int newStrength) {
void updateStrength(int newStrength) {
String log = "updateStrength: Before(" + toString() + ")";
updatedStrength = newStrength;
log += " After(" + toString() + ")";
@@ -1007,6 +1031,79 @@ public class BiometricService extends SystemService {
return isBiometricDisabled;
}
private static int biometricStatusToBiometricConstant(@BiometricStatus int status) {
switch (status) {
case BIOMETRIC_NO_HARDWARE:
return BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT;
case BIOMETRIC_OK:
return BiometricConstants.BIOMETRIC_SUCCESS;
case BIOMETRIC_DISABLED_BY_DEVICE_POLICY:
return BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
case BIOMETRIC_INSUFFICIENT_STRENGTH:
return BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT;
case BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE:
return BiometricConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED;
case BIOMETRIC_HARDWARE_NOT_DETECTED:
return BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
case BIOMETRIC_NOT_ENROLLED:
return BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS;
case BIOMETRIC_NOT_ENABLED_FOR_APPS:
return BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
default:
return BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
}
}
/**
* Returns the status of the authenticator, with errors returned in a specific priority order.
* For example, {@link #BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE} is only returned
* if it has enrollments, and is enabled for apps.
*
* We should only return the modality if the authenticator should be exposed. e.g.
* BIOMETRIC_NOT_ENROLLED_FOR_APPS should not expose the authenticator's type.
*
* @return A Pair with `first` being modality, and `second` being @BiometricStatus
*/
private Pair<Integer, Integer> getStatusForBiometricAuthenticator(
AuthenticatorWrapper authenticator, int userId, String opPackageName,
boolean checkDevicePolicyManager, int requestedStrength) {
if (checkDevicePolicyManager) {
if (isBiometricDisabledByDevicePolicy(authenticator.modality, userId)) {
return new Pair<>(TYPE_NONE, BIOMETRIC_DISABLED_BY_DEVICE_POLICY);
}
}
final boolean wasStrongEnough =
Utils.isAtLeastStrength(authenticator.OEMStrength, requestedStrength);
final boolean isStrongEnough =
Utils.isAtLeastStrength(authenticator.getActualStrength(), requestedStrength);
if (wasStrongEnough && !isStrongEnough) {
return new Pair<>(authenticator.modality,
BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE);
} else if (!wasStrongEnough) {
return new Pair<>(TYPE_NONE, BIOMETRIC_INSUFFICIENT_STRENGTH);
}
try {
if (!authenticator.impl.isHardwareDetected(opPackageName)) {
return new Pair<>(authenticator.modality, BIOMETRIC_HARDWARE_NOT_DETECTED);
}
if (!authenticator.impl.hasEnrolledTemplates(userId, opPackageName)) {
return new Pair<>(authenticator.modality, BIOMETRIC_NOT_ENROLLED);
}
} catch (RemoteException e) {
return new Pair<>(authenticator.modality, BIOMETRIC_HARDWARE_NOT_DETECTED);
}
if (!isEnabledForApp(authenticator.modality, userId)) {
return new Pair<>(TYPE_NONE, BIOMETRIC_NOT_ENABLED_FOR_APPS);
}
return new Pair<>(authenticator.modality, BIOMETRIC_OK);
}
/**
* Depending on the requested authentication (credential/biometric combination), checks their
* availability.
@@ -1029,10 +1126,9 @@ public class BiometricService extends SystemService {
private Pair<Integer, Integer> checkAndGetAuthenticators(int userId, Bundle bundle,
String opPackageName, boolean checkDevicePolicyManager) throws RemoteException {
final boolean biometricRequested = Utils.isBiometricAllowed(bundle);
final boolean credentialRequested = Utils.isDeviceCredentialAllowed(bundle);
final boolean biometricRequested = Utils.isBiometricRequested(bundle);
final boolean credentialRequested = Utils.isCredentialRequested(bundle);
final boolean biometricOk;
final boolean credentialOk = mTrustManager.isDeviceSecure(userId);
// Assuming that biometric authenticators are listed in priority-order, the rest of this
@@ -1041,96 +1137,56 @@ public class BiometricService extends SystemService {
// the correct error. Error strings that are modality-specific should also respect the
// priority-order.
// Find first biometric authenticator that's strong enough, detected, enrolled, and enabled.
boolean disabledByDevicePolicy = false;
boolean hasSufficientStrength = false;
boolean isHardwareDetected = false;
boolean hasTemplatesEnrolled = false;
boolean enabledForApps = false;
int firstBiometricModality = TYPE_NONE;
@BiometricStatus int firstBiometricStatus = BIOMETRIC_NO_HARDWARE;
int biometricModality = TYPE_NONE;
@BiometricStatus int biometricStatus = BIOMETRIC_NO_HARDWARE;
int modality = TYPE_NONE;
int firstHwAvailable = TYPE_NONE;
for (AuthenticatorWrapper authenticator : mAuthenticators) {
final int actualStrength = authenticator.getActualStrength();
final int requestedStrength = Utils.getPublicBiometricStrength(bundle);
Pair<Integer, Integer> result = getStatusForBiometricAuthenticator(
authenticator, userId, opPackageName, checkDevicePolicyManager,
requestedStrength);
if (isBiometricDisabledByDevicePolicy(authenticator.modality, userId)) {
disabledByDevicePolicy = true;
continue;
}
disabledByDevicePolicy = false;
biometricStatus = result.second;
if (!Utils.isAtLeastStrength(actualStrength, requestedStrength)) {
continue;
}
hasSufficientStrength = true;
Slog.d(TAG, "Authenticator ID: " + authenticator.id
+ " Modality: " + authenticator.modality
+ " ReportedModality: " + result.first
+ " Status: " + biometricStatus);
if (!authenticator.impl.isHardwareDetected(opPackageName)) {
continue;
}
isHardwareDetected = true;
if (firstHwAvailable == TYPE_NONE) {
// Store the first one since we want to return the error in correct
// priority order.
firstHwAvailable = authenticator.modality;
if (firstBiometricModality == TYPE_NONE) {
firstBiometricModality = result.first;
firstBiometricStatus = biometricStatus;
}
if (!authenticator.impl.hasEnrolledTemplates(userId, opPackageName)) {
continue;
if (biometricStatus == BIOMETRIC_OK) {
biometricModality = result.first;
break;
}
hasTemplatesEnrolled = true;
if (!isEnabledForApp(authenticator.modality, userId)) {
continue;
}
enabledForApps = true;
modality = authenticator.modality;
break;
}
biometricOk = !disabledByDevicePolicy
&& hasSufficientStrength && isHardwareDetected
&& hasTemplatesEnrolled && enabledForApps;
Slog.d(TAG, "checkAndGetAuthenticators: user=" + userId
+ " checkDevicePolicyManager=" + checkDevicePolicyManager
+ " isHardwareDetected=" + isHardwareDetected
+ " hasTemplatesEnrolled=" + hasTemplatesEnrolled
+ " enabledForApps=" + enabledForApps
+ " disabledByDevicePolicy=" + disabledByDevicePolicy);
if (biometricRequested && credentialRequested) {
if (credentialOk || biometricOk) {
if (!biometricOk) {
if (credentialOk || biometricStatus == BIOMETRIC_OK) {
if (biometricStatus != BIOMETRIC_OK) {
// If there's a problem with biometrics but device credential is
// allowed, only show credential UI.
bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED,
Authenticators.DEVICE_CREDENTIAL);
}
return new Pair<>(modality, BiometricConstants.BIOMETRIC_SUCCESS);
return new Pair<>(biometricModality, BiometricConstants.BIOMETRIC_SUCCESS);
} else {
return new Pair<>(firstHwAvailable,
return new Pair<>(firstBiometricModality,
BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS);
}
} else if (biometricRequested) {
if (biometricOk) {
return new Pair<>(modality, BiometricConstants.BIOMETRIC_SUCCESS);
} else if (disabledByDevicePolicy) {
return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE);
} else if (!hasSufficientStrength) {
return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT);
} else if (!isHardwareDetected) {
return new Pair<>(firstHwAvailable,
BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE);
} else if (!hasTemplatesEnrolled) {
return new Pair<>(firstHwAvailable,
BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS);
} else if (!enabledForApps) {
return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE);
if (biometricStatus == BIOMETRIC_OK) {
return new Pair<>(biometricModality,
biometricStatusToBiometricConstant(biometricStatus));
} else {
Slog.e(TAG, "Unexpected case");
return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE);
return new Pair<>(firstBiometricModality,
biometricStatusToBiometricConstant(firstBiometricStatus));
}
} else if (credentialRequested) {
if (credentialOk) {

View File

@@ -80,7 +80,7 @@ public class Utils {
* @param authenticators composed of one or more values from {@link Authenticators}
* @return true if device credential is allowed.
*/
public static boolean isDeviceCredentialAllowed(@Authenticators.Types int authenticators) {
public static boolean isCredentialRequested(@Authenticators.Types int authenticators) {
return (authenticators & Authenticators.DEVICE_CREDENTIAL) != 0;
}
@@ -88,8 +88,8 @@ public class Utils {
* @param bundle should be first processed by {@link #combineAuthenticatorBundles(Bundle)}
* @return true if device credential is allowed.
*/
public static boolean isDeviceCredentialAllowed(Bundle bundle) {
return isDeviceCredentialAllowed(bundle.getInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED));
public static boolean isCredentialRequested(Bundle bundle) {
return isCredentialRequested(bundle.getInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED));
}
/**
@@ -120,7 +120,7 @@ public class Utils {
* @param bundle should be first processed by {@link #combineAuthenticatorBundles(Bundle)}
* @return true if biometric authentication is allowed.
*/
public static boolean isBiometricAllowed(Bundle bundle) {
public static boolean isBiometricRequested(Bundle bundle) {
return getPublicBiometricStrength(bundle) != 0;
}
@@ -169,7 +169,7 @@ public class Utils {
// should be set.
final int biometricBits = authenticators & Authenticators.BIOMETRIC_MIN_STRENGTH;
if (biometricBits == Authenticators.EMPTY_SET
&& isDeviceCredentialAllowed(authenticators)) {
&& isCredentialRequested(authenticators)) {
return true;
} else if (biometricBits == Authenticators.BIOMETRIC_STRONG) {
return true;
@@ -209,6 +209,9 @@ public class Utils {
case BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT:
biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
break;
case BiometricConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED:
biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED;
break;
default:
Slog.e(BiometricService.TAG, "Unhandled result code: " + biometricConstantsCode);
biometricManagerCode = BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;

View File

@@ -283,7 +283,7 @@ public class BiometricServiceTest {
null /* authenticators */);
waitForIdle();
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_NONE),
eq(BiometricAuthenticator.TYPE_FINGERPRINT),
eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE),
eq(0 /* vendorCode */));
}
@@ -1117,14 +1117,14 @@ public class BiometricServiceTest {
// STRONG-only auth is not available
int authenticators = Authenticators.BIOMETRIC_STRONG;
assertEquals(BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE,
assertEquals(BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
invokeCanAuthenticate(mBiometricService, authenticators));
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
authenticators);
waitForIdle();
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_NONE),
eq(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT),
eq(BiometricAuthenticator.TYPE_FINGERPRINT),
eq(BiometricPrompt.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED),
eq(0) /* vendorCode */);
// Request for weak auth works
@@ -1154,7 +1154,7 @@ public class BiometricServiceTest {
false /* requireConfirmation */,
authenticators);
waitForIdle();
assertTrue(Utils.isDeviceCredentialAllowed(mBiometricService.mCurrentAuthSession.mBundle));
assertTrue(Utils.isCredentialRequested(mBiometricService.mCurrentAuthSession.mBundle));
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
eq(mBiometricService.mCurrentAuthSession.mBundle),
any(IBiometricServiceReceiverInternal.class),
@@ -1162,6 +1162,28 @@ public class BiometricServiceTest {
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME));
// Un-downgrading the authenticator allows successful strong auth
for (BiometricService.AuthenticatorWrapper wrapper : mBiometricService.mAuthenticators) {
if (wrapper.id == testId) {
wrapper.updateStrength(Authenticators.BIOMETRIC_STRONG);
}
}
resetReceiver();
authenticators = Authenticators.BIOMETRIC_STRONG;
assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
invokeCanAuthenticate(mBiometricService, authenticators));
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, authenticators);
waitForIdle();
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
eq(mBiometricService.mCurrentAuthSession.mBundle),
any(IBiometricServiceReceiverInternal.class),
eq(BiometricAuthenticator.TYPE_FINGERPRINT /* biometricModality */),
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME));
}
@Test(expected = IllegalStateException.class)
@@ -1244,6 +1266,19 @@ public class BiometricServiceTest {
BiometricService.STATE_AUTH_STARTED);
}
@Test
public void testAuthentication_normalAppIgnoresDevicePolicy() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
when(mDevicePolicyManager
.getKeyguardDisabledFeatures(any() /* admin */, anyInt() /* userHandle */))
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, Authenticators.BIOMETRIC_STRONG);
waitForIdle();
assertEquals(mBiometricService.mCurrentAuthSession.mState,
BiometricService.STATE_AUTH_STARTED);
}
@Test
public void testWorkAuthentication_faceWorksIfNotDisabledByDevicePolicyManager()
throws Exception {

View File

@@ -91,31 +91,31 @@ public class UtilsTest {
@Test
public void testIsDeviceCredentialAllowed_withIntegerFlags() {
int authenticators = 0;
assertFalse(Utils.isDeviceCredentialAllowed(authenticators));
assertFalse(Utils.isCredentialRequested(authenticators));
authenticators |= Authenticators.DEVICE_CREDENTIAL;
assertTrue(Utils.isDeviceCredentialAllowed(authenticators));
assertTrue(Utils.isCredentialRequested(authenticators));
authenticators |= Authenticators.BIOMETRIC_WEAK;
assertTrue(Utils.isDeviceCredentialAllowed(authenticators));
assertTrue(Utils.isCredentialRequested(authenticators));
}
@Test
public void testIsDeviceCredentialAllowed_withBundle() {
Bundle bundle = new Bundle();
assertFalse(Utils.isDeviceCredentialAllowed(bundle));
assertFalse(Utils.isCredentialRequested(bundle));
int authenticators = 0;
bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators);
assertFalse(Utils.isDeviceCredentialAllowed(bundle));
assertFalse(Utils.isCredentialRequested(bundle));
authenticators |= Authenticators.DEVICE_CREDENTIAL;
bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators);
assertTrue(Utils.isDeviceCredentialAllowed(bundle));
assertTrue(Utils.isCredentialRequested(bundle));
authenticators |= Authenticators.BIOMETRIC_WEAK;
bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators);
assertTrue(Utils.isDeviceCredentialAllowed(bundle));
assertTrue(Utils.isCredentialRequested(bundle));
}
@Test
@@ -140,14 +140,14 @@ public class UtilsTest {
for (int i = 0; i <= 7; i++) {
int authenticators = 1 << i;
bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators);
assertTrue(Utils.isBiometricAllowed(bundle));
assertTrue(Utils.isBiometricRequested(bundle));
}
// The rest of the bits are not allowed to integrate with the public APIs
for (int i = 8; i < 32; i++) {
int authenticators = 1 << i;
bundle.putInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED, authenticators);
assertFalse(Utils.isBiometricAllowed(bundle));
assertFalse(Utils.isBiometricRequested(bundle));
}
}