• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.biometrics;
18 
19 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_CREDENTIAL;
20 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
21 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
22 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS;
23 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
24 
25 import android.annotation.IntDef;
26 import android.annotation.NonNull;
27 import android.app.admin.DevicePolicyManager;
28 import android.app.trust.ITrustManager;
29 import android.content.Context;
30 import android.hardware.biometrics.BiometricAuthenticator;
31 import android.hardware.biometrics.BiometricManager;
32 import android.hardware.biometrics.Flags;
33 import android.hardware.biometrics.PromptInfo;
34 import android.os.RemoteException;
35 import android.os.UserManager;
36 import android.util.Pair;
37 import android.util.Slog;
38 
39 import com.android.internal.R;
40 import com.android.server.biometrics.sensors.LockoutTracker;
41 
42 import java.lang.annotation.Retention;
43 import java.lang.annotation.RetentionPolicy;
44 import java.util.ArrayList;
45 import java.util.List;
46 
47 /**
48  * Class representing the calling client's request. Additionally, derives/calculates
49  * preliminary info that would be useful in helping serve this request. Note that generating
50  * the PreAuthInfo should not change any sensor state.
51  */
52 class PreAuthInfo {
53     static final int AUTHENTICATOR_OK = 1;
54     static final int BIOMETRIC_NO_HARDWARE = 2;
55     static final int BIOMETRIC_DISABLED_BY_DEVICE_POLICY = 3;
56     static final int BIOMETRIC_INSUFFICIENT_STRENGTH = 4;
57     static final int BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE = 5;
58     static final int BIOMETRIC_HARDWARE_NOT_DETECTED = 6;
59     static final int BIOMETRIC_NOT_ENROLLED = 7;
60     static final int BIOMETRIC_NOT_ENABLED_FOR_APPS = 8;
61     static final int CREDENTIAL_NOT_ENROLLED = 9;
62     static final int BIOMETRIC_LOCKOUT_TIMED = 10;
63     static final int BIOMETRIC_LOCKOUT_PERMANENT = 11;
64     static final int BIOMETRIC_SENSOR_PRIVACY_ENABLED = 12;
65     static final int MANDATORY_BIOMETRIC_UNAVAILABLE_ERROR = 13;
66     private static final String TAG = "BiometricService/PreAuthInfo";
67     final boolean credentialRequested;
68     // Sensors that can be used for this request (e.g. strong enough, enrolled, enabled).
69     final List<BiometricSensor> eligibleSensors;
70     // Sensors that cannot be used for this request. Pair<BiometricSensor, AuthenticatorStatus>
71     final List<Pair<BiometricSensor, Integer>> ineligibleSensors;
72     final boolean credentialAvailable;
73     final boolean confirmationRequested;
74     final boolean ignoreEnrollmentState;
75     final int userId;
76     final int callingUserId;
77     final Context context;
78     private final boolean mBiometricRequested;
79     private final int mBiometricStrengthRequested;
80     private final BiometricCameraManager mBiometricCameraManager;
81     private final boolean mOnlyMandatoryBiometricsRequested;
82     private final boolean mIsMandatoryBiometricsAuthentication;
83 
PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested, boolean credentialRequested, List<BiometricSensor> eligibleSensors, List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable, PromptInfo promptInfo, int userId, int callingUserId, Context context, BiometricCameraManager biometricCameraManager, boolean isOnlyMandatoryBiometricsRequested, boolean isMandatoryBiometricsAuthentication)84     private PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested,
85             boolean credentialRequested, List<BiometricSensor> eligibleSensors,
86             List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable,
87             PromptInfo promptInfo, int userId, int callingUserId, Context context,
88             BiometricCameraManager biometricCameraManager,
89             boolean isOnlyMandatoryBiometricsRequested,
90             boolean isMandatoryBiometricsAuthentication) {
91         mBiometricRequested = biometricRequested;
92         mBiometricStrengthRequested = biometricStrengthRequested;
93         mBiometricCameraManager = biometricCameraManager;
94         this.credentialRequested = credentialRequested;
95 
96         this.eligibleSensors = eligibleSensors;
97         this.ineligibleSensors = ineligibleSensors;
98         this.credentialAvailable = credentialAvailable;
99         this.confirmationRequested = promptInfo.isConfirmationRequested();
100         this.ignoreEnrollmentState = promptInfo.isIgnoreEnrollmentState();
101         this.userId = userId;
102         this.callingUserId = callingUserId;
103         this.context = context;
104         this.mOnlyMandatoryBiometricsRequested = isOnlyMandatoryBiometricsRequested;
105         this.mIsMandatoryBiometricsAuthentication = isMandatoryBiometricsAuthentication;
106     }
107 
create(ITrustManager trustManager, DevicePolicyManager devicePolicyManager, BiometricService.SettingObserver settingObserver, List<BiometricSensor> sensors, int userId, PromptInfo promptInfo, String opPackageName, boolean checkDevicePolicyManager, Context context, BiometricCameraManager biometricCameraManager, UserManager userManager)108     static PreAuthInfo create(ITrustManager trustManager,
109             DevicePolicyManager devicePolicyManager,
110             BiometricService.SettingObserver settingObserver,
111             List<BiometricSensor> sensors,
112             int userId, PromptInfo promptInfo, String opPackageName,
113             boolean checkDevicePolicyManager, Context context,
114             BiometricCameraManager biometricCameraManager,
115             UserManager userManager)
116             throws RemoteException {
117 
118         final boolean isOnlyMandatoryBiometricsRequested = promptInfo.getAuthenticators()
119                 == BiometricManager.Authenticators.IDENTITY_CHECK;
120         boolean isMandatoryBiometricsAuthentication = false;
121 
122         final int effectiveUserId;
123         if (Flags.effectiveUserBp()) {
124             effectiveUserId = userManager.getCredentialOwnerProfile(userId);
125         } else {
126             effectiveUserId = userId;
127         }
128 
129         if (dropCredentialFallback(promptInfo.getAuthenticators(),
130                 settingObserver.getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(
131                         effectiveUserId), trustManager)) {
132             isMandatoryBiometricsAuthentication = true;
133             promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
134             if (promptInfo.getNegativeButtonText() == null) {
135                 promptInfo.setNegativeButtonText(context.getString(R.string.cancel));
136             }
137         }
138 
139         final boolean biometricRequested = Utils.isBiometricRequested(promptInfo);
140         final int requestedStrength = Utils.getPublicBiometricStrength(promptInfo);
141         final boolean credentialRequested = Utils.isCredentialRequested(promptInfo);
142 
143         final boolean credentialAvailable = trustManager.isDeviceSecure(userId,
144                 context.getDeviceId());
145 
146         // Assuming that biometric authenticators are listed in priority-order, the rest of this
147         // function will attempt to find the first authenticator that's as strong or stronger than
148         // the requested strength, available, enrolled, and enabled. The tricky part is returning
149         // the correct error. Error strings that are modality-specific should also respect the
150         // priority-order.
151 
152         final List<BiometricSensor> eligibleSensors = new ArrayList<>();
153         final List<Pair<BiometricSensor, Integer>> ineligibleSensors = new ArrayList<>();
154 
155         if (biometricRequested) {
156             for (BiometricSensor sensor : sensors) {
157 
158                 @AuthenticatorStatus int status = getStatusForBiometricAuthenticator(
159                         devicePolicyManager, settingObserver, sensor, effectiveUserId,
160                         opPackageName, checkDevicePolicyManager, requestedStrength,
161                         promptInfo.getAllowedSensorIds(), promptInfo.isIgnoreEnrollmentState(),
162                         biometricCameraManager);
163 
164                 Slog.d(TAG, "Package: " + opPackageName
165                         + " Sensor ID: " + sensor.id
166                         + " Modality: " + sensor.modality
167                         + " User id: " + effectiveUserId
168                         + " Status: " + status);
169 
170                 // A sensor with privacy enabled will still be eligible to
171                 // authenticate with biometric prompt. This is so the framework can display
172                 // a sensor privacy error message to users after briefly showing the
173                 // Biometric Prompt.
174                 //
175                 // Note: if only a certain sensor is required and the privacy is enabled,
176                 // canAuthenticate() will return false.
177                 if (status == AUTHENTICATOR_OK) {
178                     eligibleSensors.add(sensor);
179                 } else {
180                     ineligibleSensors.add(new Pair<>(sensor, status));
181                 }
182             }
183         }
184 
185         return new PreAuthInfo(biometricRequested, requestedStrength, credentialRequested,
186                 eligibleSensors, ineligibleSensors, credentialAvailable, promptInfo,
187                 effectiveUserId, userId, context, biometricCameraManager,
188                 isOnlyMandatoryBiometricsRequested, isMandatoryBiometricsAuthentication);
189     }
190 
dropCredentialFallback(int authenticators, boolean isMandatoryBiometricsEnabled, ITrustManager trustManager)191     private static boolean dropCredentialFallback(int authenticators,
192             boolean isMandatoryBiometricsEnabled, ITrustManager trustManager) {
193         final boolean isMandatoryBiometricsRequested =
194                 (authenticators & BiometricManager.Authenticators.IDENTITY_CHECK)
195                         == BiometricManager.Authenticators.IDENTITY_CHECK;
196         if (Flags.mandatoryBiometrics() && isMandatoryBiometricsEnabled
197                 && isMandatoryBiometricsRequested) {
198             try {
199                 final boolean isInSignificantPlace = trustManager.isInSignificantPlace();
200                 return !isInSignificantPlace;
201             } catch (RemoteException e) {
202                 Slog.e(TAG, "Remote exception while trying to check "
203                         + "if user is in a trusted location.");
204             }
205         }
206 
207         return false;
208     }
209 
210     /**
211      * Returns the status of the authenticator, with errors returned in a specific priority order.
212      * For example, {@link #BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE} is only returned
213      * if it has enrollments, and is enabled for apps.
214      *
215      * @return @AuthenticatorStatus
216      */
217     private static @AuthenticatorStatus
getStatusForBiometricAuthenticator( DevicePolicyManager devicePolicyManager, BiometricService.SettingObserver settingObserver, BiometricSensor sensor, int userId, String opPackageName, boolean checkDevicePolicyManager, int requestedStrength, @NonNull List<Integer> requestedSensorIds, boolean ignoreEnrollmentState, BiometricCameraManager biometricCameraManager)218     int getStatusForBiometricAuthenticator(
219             DevicePolicyManager devicePolicyManager,
220             BiometricService.SettingObserver settingObserver,
221             BiometricSensor sensor, int userId, String opPackageName,
222             boolean checkDevicePolicyManager, int requestedStrength,
223             @NonNull List<Integer> requestedSensorIds,
224             boolean ignoreEnrollmentState, BiometricCameraManager biometricCameraManager) {
225 
226         if (!requestedSensorIds.isEmpty() && !requestedSensorIds.contains(sensor.id)) {
227             return BIOMETRIC_NO_HARDWARE;
228         }
229 
230         final boolean wasStrongEnough =
231                 Utils.isAtLeastStrength(sensor.oemStrength, requestedStrength);
232         final boolean isStrongEnough =
233                 Utils.isAtLeastStrength(sensor.getCurrentStrength(), requestedStrength);
234 
235         if (wasStrongEnough && !isStrongEnough) {
236             return BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE;
237         } else if (!wasStrongEnough) {
238             return BIOMETRIC_INSUFFICIENT_STRENGTH;
239         }
240 
241         if (sensor.modality == TYPE_FACE && biometricCameraManager.isAnyCameraUnavailable()) {
242             return BIOMETRIC_HARDWARE_NOT_DETECTED;
243         }
244 
245         try {
246             if (!sensor.impl.isHardwareDetected(opPackageName)) {
247                 return BIOMETRIC_HARDWARE_NOT_DETECTED;
248             }
249 
250             if (!sensor.impl.hasEnrolledTemplates(userId, opPackageName)
251                     && !ignoreEnrollmentState) {
252                 return BIOMETRIC_NOT_ENROLLED;
253             }
254 
255             if (biometricCameraManager != null && sensor.modality == TYPE_FACE) {
256                 if (biometricCameraManager.isCameraPrivacyEnabled()) {
257                     //Camera privacy is enabled as the access is disabled
258                     return BIOMETRIC_SENSOR_PRIVACY_ENABLED;
259                 }
260             }
261 
262             final @LockoutTracker.LockoutMode int lockoutMode =
263                     sensor.impl.getLockoutModeForUser(userId);
264             if (lockoutMode == LockoutTracker.LOCKOUT_TIMED) {
265                 return BIOMETRIC_LOCKOUT_TIMED;
266             } else if (lockoutMode == LockoutTracker.LOCKOUT_PERMANENT) {
267                 return BIOMETRIC_LOCKOUT_PERMANENT;
268             }
269         } catch (RemoteException e) {
270             return BIOMETRIC_HARDWARE_NOT_DETECTED;
271         }
272 
273         if (!isEnabledForApp(settingObserver, sensor.modality, userId)) {
274             return BIOMETRIC_NOT_ENABLED_FOR_APPS;
275         }
276 
277         if (checkDevicePolicyManager) {
278             if (isBiometricDisabledByDevicePolicy(devicePolicyManager, sensor.modality, userId)) {
279                 return BIOMETRIC_DISABLED_BY_DEVICE_POLICY;
280             }
281         }
282 
283         return AUTHENTICATOR_OK;
284     }
285 
isEnabledForApp(BiometricService.SettingObserver settingObserver, @BiometricAuthenticator.Modality int modality, int userId)286     private static boolean isEnabledForApp(BiometricService.SettingObserver settingObserver,
287             @BiometricAuthenticator.Modality int modality, int userId) {
288         return settingObserver.getEnabledForApps(userId, modality);
289     }
290 
isBiometricDisabledByDevicePolicy( DevicePolicyManager devicePolicyManager, @BiometricAuthenticator.Modality int modality, int effectiveUserId)291     private static boolean isBiometricDisabledByDevicePolicy(
292             DevicePolicyManager devicePolicyManager, @BiometricAuthenticator.Modality int modality,
293             int effectiveUserId) {
294         final int biometricToCheck = mapModalityToDevicePolicyType(modality);
295         if (biometricToCheck == DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE) {
296             throw new IllegalStateException("Modality unknown to devicePolicyManager: " + modality);
297         }
298         final int devicePolicyDisabledFeatures =
299                 devicePolicyManager.getKeyguardDisabledFeatures(null, effectiveUserId);
300         final boolean isBiometricDisabled =
301                 (biometricToCheck & devicePolicyDisabledFeatures) != 0;
302         Slog.w(TAG, "isBiometricDisabledByDevicePolicy(" + modality + "," + effectiveUserId
303                 + ")=" + isBiometricDisabled);
304         return isBiometricDisabled;
305     }
306 
307     /**
308      * @param modality one of {@link BiometricAuthenticator#TYPE_FINGERPRINT},
309      *                 {@link BiometricAuthenticator#TYPE_IRIS} or
310      *                 {@link BiometricAuthenticator#TYPE_FACE}
311      */
mapModalityToDevicePolicyType(int modality)312     private static int mapModalityToDevicePolicyType(int modality) {
313         switch (modality) {
314             case TYPE_FINGERPRINT:
315                 return DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
316             case TYPE_IRIS:
317                 return DevicePolicyManager.KEYGUARD_DISABLE_IRIS;
318             case TYPE_FACE:
319                 return DevicePolicyManager.KEYGUARD_DISABLE_FACE;
320             default:
321                 Slog.e(TAG, "Error modality=" + modality);
322                 return DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
323         }
324     }
325 
calculateErrorByPriority()326     private Pair<BiometricSensor, Integer> calculateErrorByPriority() {
327         Pair<BiometricSensor, Integer> sensorNotEnrolled = null;
328         Pair<BiometricSensor, Integer> sensorLockout = null;
329         Pair<BiometricSensor, Integer> hardwareNotDetected = null;
330         Pair<BiometricSensor, Integer> biometricAppNotAllowed = null;
331         for (Pair<BiometricSensor, Integer> pair : ineligibleSensors) {
332             final int status = pair.second;
333             if (status == BIOMETRIC_LOCKOUT_TIMED || status == BIOMETRIC_LOCKOUT_PERMANENT) {
334                 sensorLockout = pair;
335             }
336             if (status == BIOMETRIC_NOT_ENROLLED) {
337                 sensorNotEnrolled = pair;
338             }
339             if (status == BIOMETRIC_HARDWARE_NOT_DETECTED) {
340                 hardwareNotDetected = pair;
341             }
342             if (status == BIOMETRIC_NOT_ENABLED_FOR_APPS) {
343                 biometricAppNotAllowed = pair;
344             }
345         }
346 
347         // If there is a sensor locked out, prioritize lockout over other sensor's error.
348         // See b/286923477.
349         if (sensorLockout != null) {
350             return sensorLockout;
351         }
352 
353         if (hardwareNotDetected != null) {
354             return hardwareNotDetected;
355         }
356 
357         if (Flags.mandatoryBiometrics() && biometricAppNotAllowed != null) {
358             return biometricAppNotAllowed;
359         }
360 
361         // If the caller requested STRONG, and the device contains both STRONG and non-STRONG
362         // sensors, prioritize BIOMETRIC_NOT_ENROLLED over the weak sensor's
363         // BIOMETRIC_INSUFFICIENT_STRENGTH error.
364         if (sensorNotEnrolled != null) {
365             return sensorNotEnrolled;
366         }
367         return ineligibleSensors.get(0);
368     }
369 
370     /**
371      * With {@link PreAuthInfo} generated with the requested authenticators from the public API
372      * surface, combined with the actual sensor/credential and user/system settings, calculate the
373      * internal {@link AuthenticatorStatus} that should be returned to the client. Note that this
374      * will need to be converted into the public API constant.
375      *
376      * @return Pair<Modality, Error> with error being the internal {@link AuthenticatorStatus} code
377      */
getInternalStatus()378     private Pair<Integer, Integer> getInternalStatus() {
379         @AuthenticatorStatus final int status;
380         @BiometricAuthenticator.Modality int modality = TYPE_NONE;
381 
382         boolean cameraPrivacyEnabled = false;
383         if (mBiometricCameraManager != null) {
384             cameraPrivacyEnabled = mBiometricCameraManager.isCameraPrivacyEnabled();
385         }
386 
387         if (mBiometricRequested && credentialRequested) {
388             if (credentialAvailable || !eligibleSensors.isEmpty()) {
389                 for (BiometricSensor sensor : eligibleSensors) {
390                     modality |= sensor.modality;
391                 }
392 
393                 if (credentialAvailable) {
394                     modality |= TYPE_CREDENTIAL;
395                     status = AUTHENTICATOR_OK;
396                 } else if (modality == TYPE_FACE && cameraPrivacyEnabled) {
397                     // If the only modality requested is face, credential is unavailable,
398                     // and the face sensor privacy is enabled then return
399                     // BIOMETRIC_SENSOR_PRIVACY_ENABLED.
400                     //
401                     // Note: This sensor will not be eligible for calls to authenticate.
402                     status = BIOMETRIC_SENSOR_PRIVACY_ENABLED;
403                 } else {
404                     status = AUTHENTICATOR_OK;
405                 }
406             } else {
407                 // Pick the first sensor error if it exists
408                 if (!ineligibleSensors.isEmpty()) {
409                     final Pair<BiometricSensor, Integer> pair = calculateErrorByPriority();
410                     modality |= pair.first.modality;
411                     status = pair.second;
412                 } else {
413                     modality |= TYPE_CREDENTIAL;
414                     status = CREDENTIAL_NOT_ENROLLED;
415                 }
416             }
417         } else if (mBiometricRequested) {
418             if (!eligibleSensors.isEmpty()) {
419                 for (BiometricSensor sensor : eligibleSensors) {
420                     modality |= sensor.modality;
421                 }
422                 if (modality == TYPE_FACE && cameraPrivacyEnabled) {
423                     // If the only modality requested is face and the privacy is enabled
424                     // then return BIOMETRIC_SENSOR_PRIVACY_ENABLED.
425                     //
426                     // Note: This sensor will not be eligible for calls to authenticate.
427                     status = BIOMETRIC_SENSOR_PRIVACY_ENABLED;
428                 } else {
429                     status = AUTHENTICATOR_OK;
430                 }
431             } else {
432                 // Pick the first sensor error if it exists
433                 if (!ineligibleSensors.isEmpty()) {
434                     final Pair<BiometricSensor, Integer> pair = calculateErrorByPriority();
435                     modality |= pair.first.modality;
436                     status = pair.second;
437                 } else {
438                     modality |= TYPE_NONE;
439                     status = BIOMETRIC_NO_HARDWARE;
440                 }
441             }
442         } else if (credentialRequested) {
443             modality |= TYPE_CREDENTIAL;
444             status = credentialAvailable ? AUTHENTICATOR_OK : CREDENTIAL_NOT_ENROLLED;
445         } else if (Flags.mandatoryBiometrics() && mOnlyMandatoryBiometricsRequested
446                 && !mIsMandatoryBiometricsAuthentication) {
447             status = MANDATORY_BIOMETRIC_UNAVAILABLE_ERROR;
448         } else {
449             // This should not be possible via the public API surface and is here mainly for
450             // "correctness". An exception should have been thrown before getting here.
451             Slog.e(TAG, "No authenticators requested");
452             status = BIOMETRIC_NO_HARDWARE;
453         }
454         Slog.d(TAG, "getCanAuthenticateInternal Modality: " + modality
455                 + " AuthenticatorStatus: " + status);
456 
457         return new Pair<>(modality, status);
458     }
459 
460     /**
461      * @return public BiometricManager result for the current request.
462      */
463     @BiometricManager.BiometricError
getCanAuthenticateResult()464     int getCanAuthenticateResult() {
465         // TODO: Convert this directly
466         return Utils.biometricConstantsToBiometricManager(
467                 Utils.authenticatorStatusToBiometricConstant(
468                         getInternalStatus().second));
469     }
470 
471     /** Returns if mandatory biometrics authentication is in effect */
getIsMandatoryBiometricsAuthentication()472     boolean getIsMandatoryBiometricsAuthentication() {
473         return mIsMandatoryBiometricsAuthentication;
474     }
475 
476 
477     /**
478      * For the given request, generate the appropriate reason why authentication cannot be started.
479      * Note that for some errors, modality is intentionally cleared.
480      *
481      * @return Pair<Modality, Error> with modality being filtered if necessary, and error
482      * being one of the public {@link android.hardware.biometrics.BiometricConstants} codes.
483      */
getPreAuthenticateStatus()484     Pair<Integer, Integer> getPreAuthenticateStatus() {
485         final Pair<Integer, Integer> internalStatus = getInternalStatus();
486 
487         final int publicError = Utils.authenticatorStatusToBiometricConstant(internalStatus.second);
488         int modality = internalStatus.first;
489         switch (internalStatus.second) {
490             case AUTHENTICATOR_OK:
491             case BIOMETRIC_NO_HARDWARE:
492             case BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE:
493             case BIOMETRIC_HARDWARE_NOT_DETECTED:
494             case BIOMETRIC_NOT_ENROLLED:
495             case CREDENTIAL_NOT_ENROLLED:
496             case BIOMETRIC_LOCKOUT_TIMED:
497             case BIOMETRIC_LOCKOUT_PERMANENT:
498             case BIOMETRIC_SENSOR_PRIVACY_ENABLED:
499                 break;
500 
501             case BIOMETRIC_DISABLED_BY_DEVICE_POLICY:
502             case BIOMETRIC_INSUFFICIENT_STRENGTH:
503             case BIOMETRIC_NOT_ENABLED_FOR_APPS:
504             default:
505                 modality = TYPE_NONE;
506                 break;
507         }
508 
509         return new Pair<>(modality, publicError);
510     }
511 
512     /**
513      * @return true if SystemUI should show the credential UI.
514      */
shouldShowCredential()515     boolean shouldShowCredential() {
516         return credentialRequested && credentialAvailable;
517     }
518 
519     /**
520      * @return bitmask representing the modalities that are running or could be running for the
521      * current session.
522      */
523     @BiometricAuthenticator.Modality
getEligibleModalities()524     int getEligibleModalities() {
525         @BiometricAuthenticator.Modality int modalities = 0;
526         for (BiometricSensor sensor : eligibleSensors) {
527             modalities |= sensor.modality;
528         }
529 
530         if (credentialRequested && credentialAvailable) {
531             modalities |= TYPE_CREDENTIAL;
532         }
533         return modalities;
534     }
535 
numSensorsWaitingForCookie()536     int numSensorsWaitingForCookie() {
537         int numWaiting = 0;
538         for (BiometricSensor sensor : eligibleSensors) {
539             if (sensor.getSensorState() == BiometricSensor.STATE_WAITING_FOR_COOKIE) {
540                 Slog.d(TAG, "Sensor ID: " + sensor.id
541                         + " Waiting for cookie: " + sensor.getCookie());
542                 numWaiting++;
543             }
544         }
545         return numWaiting;
546     }
547 
548     @Override
toString()549     public String toString() {
550         StringBuilder string = new StringBuilder(
551                 "BiometricRequested: " + mBiometricRequested
552                         + ", StrengthRequested: " + mBiometricStrengthRequested
553                         + ", CredentialRequested: " + credentialRequested);
554         string.append(", Eligible:{");
555         for (BiometricSensor sensor : eligibleSensors) {
556             string.append(sensor.id).append(" ");
557         }
558         string.append("}");
559 
560         string.append(", Ineligible:{");
561         for (Pair<BiometricSensor, Integer> ineligible : ineligibleSensors) {
562             string.append(ineligible.first).append(":").append(ineligible.second).append(" ");
563         }
564         string.append("}");
565 
566         string.append(", CredentialAvailable: ").append(credentialAvailable);
567         string.append(", ");
568         return string.toString();
569     }
570 
571     @IntDef({AUTHENTICATOR_OK,
572             BIOMETRIC_NO_HARDWARE,
573             BIOMETRIC_DISABLED_BY_DEVICE_POLICY,
574             BIOMETRIC_INSUFFICIENT_STRENGTH,
575             BIOMETRIC_INSUFFICIENT_STRENGTH_AFTER_DOWNGRADE,
576             BIOMETRIC_HARDWARE_NOT_DETECTED,
577             BIOMETRIC_NOT_ENROLLED,
578             BIOMETRIC_NOT_ENABLED_FOR_APPS,
579             CREDENTIAL_NOT_ENROLLED,
580             BIOMETRIC_LOCKOUT_TIMED,
581             BIOMETRIC_LOCKOUT_PERMANENT,
582             BIOMETRIC_SENSOR_PRIVACY_ENABLED,
583             MANDATORY_BIOMETRIC_UNAVAILABLE_ERROR})
584     @Retention(RetentionPolicy.SOURCE)
585     @interface AuthenticatorStatus {
586     }
587 }
588