• 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_FACE;
20 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
21 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CONTENT_VIEW_MORE_OPTIONS_BUTTON;
22 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON;
23 import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED;
24 import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED;
25 import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS;
26 import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_NEGATIVE;
27 import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_USER_CANCEL;
28 
29 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED;
30 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PAUSED;
31 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED;
32 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED_UI_SHOWING;
33 import static com.android.server.biometrics.BiometricServiceStateProto.STATE_ERROR_PENDING_SYSUI;
34 
35 import static com.google.common.truth.Truth.assertThat;
36 
37 import static junit.framework.Assert.assertEquals;
38 import static junit.framework.Assert.assertFalse;
39 import static junit.framework.Assert.assertTrue;
40 
41 import static org.mockito.ArgumentMatchers.any;
42 import static org.mockito.ArgumentMatchers.anyBoolean;
43 import static org.mockito.ArgumentMatchers.anyInt;
44 import static org.mockito.ArgumentMatchers.anyLong;
45 import static org.mockito.ArgumentMatchers.eq;
46 import static org.mockito.Mockito.mock;
47 import static org.mockito.Mockito.never;
48 import static org.mockito.Mockito.times;
49 import static org.mockito.Mockito.verify;
50 import static org.mockito.Mockito.when;
51 
52 import android.annotation.NonNull;
53 import android.app.admin.DevicePolicyManager;
54 import android.app.trust.ITrustManager;
55 import android.content.res.Resources;
56 import android.hardware.biometrics.BiometricConstants;
57 import android.hardware.biometrics.BiometricManager;
58 import android.hardware.biometrics.BiometricManager.Authenticators;
59 import android.hardware.biometrics.BiometricsProtoEnums;
60 import android.hardware.biometrics.ComponentInfoInternal;
61 import android.hardware.biometrics.IBiometricAuthenticator;
62 import android.hardware.biometrics.IBiometricSensorReceiver;
63 import android.hardware.biometrics.IBiometricServiceReceiver;
64 import android.hardware.biometrics.IBiometricSysuiReceiver;
65 import android.hardware.biometrics.PromptInfo;
66 import android.hardware.biometrics.SensorProperties;
67 import android.hardware.fingerprint.FingerprintManager;
68 import android.hardware.fingerprint.FingerprintSensorProperties;
69 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
70 import android.os.Binder;
71 import android.os.IBinder;
72 import android.os.RemoteException;
73 import android.os.UserManager;
74 import android.platform.test.annotations.Presubmit;
75 import android.security.KeyStoreAuthorization;
76 import android.testing.TestableContext;
77 
78 import androidx.test.filters.SmallTest;
79 import androidx.test.platform.app.InstrumentationRegistry;
80 
81 import com.android.internal.R;
82 import com.android.internal.statusbar.IStatusBarService;
83 import com.android.internal.util.FrameworkStatsLog;
84 import com.android.server.biometrics.log.BiometricContext;
85 import com.android.server.biometrics.log.BiometricFrameworkStatsLogger;
86 import com.android.server.biometrics.log.OperationContextExt;
87 
88 import org.junit.Before;
89 import org.junit.Rule;
90 import org.junit.Test;
91 import org.mockito.Mock;
92 import org.mockito.MockitoAnnotations;
93 
94 import java.util.ArrayList;
95 import java.util.List;
96 import java.util.Random;
97 import java.util.function.Consumer;
98 
99 @Presubmit
100 @SmallTest
101 public class AuthSessionTest {
102 
103     private static final String TEST_PACKAGE = "test_package";
104     private static final long TEST_REQUEST_ID = 22;
105     private static final String ACQUIRED_STRING = "test_acquired_info_callback";
106     private static final String ACQUIRED_STRING_VENDOR = "test_acquired_info_callback_vendor";
107 
108     @Rule
109     public final TestableContext mContext = new TestableContext(
110             InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
111     @Mock private Resources mResources;
112     @Mock private BiometricContext mBiometricContext;
113     @Mock private ITrustManager mTrustManager;
114     @Mock private DevicePolicyManager mDevicePolicyManager;
115     @Mock private BiometricService.SettingObserver mSettingObserver;
116     @Mock private IBiometricSensorReceiver mSensorReceiver;
117     @Mock private IBiometricServiceReceiver mClientReceiver;
118     @Mock private IStatusBarService mStatusBarService;
119     @Mock private IBiometricSysuiReceiver mSysuiReceiver;
120     @Mock private KeyStoreAuthorization mKeyStoreAuthorization;
121     @Mock private AuthSession.ClientDeathReceiver mClientDeathReceiver;
122     @Mock private BiometricFrameworkStatsLogger mBiometricFrameworkStatsLogger;
123     @Mock private BiometricCameraManager mBiometricCameraManager;
124     @Mock private UserManager mUserManager;
125     @Mock private BiometricManager mBiometricManager;
126 
127     private Random mRandom;
128     private IBinder mToken;
129 
130     // Assume all tests can be done with the same set of sensors for now.
131     @NonNull private List<BiometricSensor> mSensors;
132     @NonNull private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProps;
133 
134     @Before
setUp()135     public void setUp() throws Exception {
136         MockitoAnnotations.initMocks(this);
137         mContext.addMockSystemService(BiometricManager.class, mBiometricManager);
138         mContext.getOrCreateTestableResources().addOverride(R.string.fingerprint_acquired_partial,
139                 ACQUIRED_STRING);
140         mContext.getOrCreateTestableResources().addOverride(R.array.fingerprint_acquired_vendor,
141                 new String[]{ACQUIRED_STRING_VENDOR});
142         when(mClientReceiver.asBinder()).thenReturn(mock(Binder.class));
143         when(mBiometricContext.updateContext(any(), anyBoolean()))
144                 .thenAnswer(invocation -> invocation.getArgument(0));
145         mRandom = new Random();
146         mToken = new Binder();
147         mSensors = new ArrayList<>();
148         mFingerprintSensorProps = new ArrayList<>();
149     }
150 
151     @Test
testNewAuthSession_eligibleSensorsSetToStateUnknown()152     public void testNewAuthSession_eligibleSensorsSetToStateUnknown() throws RemoteException {
153         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_REAR);
154         setupFace(1 /* id */, false /* confirmationAlwaysRequired */,
155                 mock(IBiometricAuthenticator.class));
156 
157         final AuthSession session = createAuthSession(mSensors,
158                 false /* checkDevicePolicyManager */,
159                 Authenticators.BIOMETRIC_STRONG,
160                 TEST_REQUEST_ID,
161                 0 /* operationId */,
162                 0 /* userId */);
163 
164         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
165             assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState());
166         }
167     }
168 
169     @Test
testStartNewAuthSession()170     public void testStartNewAuthSession() throws RemoteException {
171         setupFace(0 /* id */, false /* confirmationAlwaysRequired */,
172                 mock(IBiometricAuthenticator.class));
173         setupFingerprint(1 /* id */, FingerprintSensorProperties.TYPE_REAR);
174 
175         final boolean requireConfirmation = true;
176         final long operationId = 123;
177         final int userId = 10;
178 
179         final AuthSession session = createAuthSession(mSensors,
180                 false /* checkDevicePolicyManager */,
181                 Authenticators.BIOMETRIC_STRONG,
182                 TEST_REQUEST_ID,
183                 operationId,
184                 userId);
185         assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size());
186 
187         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
188             assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState());
189             assertEquals(0, sensor.getCookie());
190         }
191 
192         session.goToInitialState();
193         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
194             assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
195             assertTrue("Cookie must be >0", sensor.getCookie() > 0);
196             verify(sensor.impl).prepareForAuthentication(
197                     eq(sensor.confirmationSupported() && requireConfirmation),
198                     eq(mToken),
199                     eq(operationId),
200                     eq(userId),
201                     eq(mSensorReceiver),
202                     eq(TEST_PACKAGE),
203                     eq(TEST_REQUEST_ID),
204                     eq(sensor.getCookie()),
205                     anyBoolean() /* allowBackgroundAuthentication */,
206                     anyBoolean() /* isForLegacyFingerprintManager */,
207                     eq(false) /* isMandatoryBiometrics */);
208         }
209 
210         final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie();
211         session.onCookieReceived(cookie1);
212         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
213             if (cookie1 == sensor.getCookie()) {
214                 assertEquals(BiometricSensor.STATE_COOKIE_RETURNED, sensor.getSensorState());
215             } else {
216                 assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
217             }
218         }
219         assertFalse(session.allCookiesReceived());
220 
221         final int cookie2 = session.mPreAuthInfo.eligibleSensors.get(1).getCookie();
222         session.onCookieReceived(cookie2);
223         assertTrue(session.allCookiesReceived());
224 
225 
226         // for multi-sensor face then fingerprint is the default policy
227         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
228             if (sensor.modality == TYPE_FACE) {
229                 verify(sensor.impl).startPreparedClient(eq(sensor.getCookie()));
230                 assertEquals(BiometricSensor.STATE_AUTHENTICATING, sensor.getSensorState());
231             } else if (sensor.modality == TYPE_FINGERPRINT) {
232                 assertEquals(BiometricSensor.STATE_COOKIE_RETURNED, sensor.getSensorState());
233             }
234         }
235     }
236 
237     @Test
testOnErrorReceived_lockoutError()238     public void testOnErrorReceived_lockoutError() throws RemoteException {
239         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_REAR);
240         setupFace(1 /* id */, false /* confirmationAlwaysRequired */,
241                 mock(IBiometricAuthenticator.class));
242         final AuthSession session = createAuthSession(mSensors,
243                 false /* checkDevicePolicyManager */,
244                 Authenticators.BIOMETRIC_STRONG,
245                 TEST_REQUEST_ID,
246                 0 /* operationId */,
247                 0 /* userId */);
248         session.goToInitialState();
249         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
250             assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
251             session.onCookieReceived(
252                     session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie());
253         }
254         assertTrue(session.allCookiesReceived());
255         assertEquals(STATE_AUTH_STARTED, session.getState());
256 
257         // Either of strong sensor's lockout should cancel both sensors.
258         final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie();
259         session.onErrorReceived(0, cookie1, BiometricConstants.BIOMETRIC_ERROR_LOCKOUT, 0);
260         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
261             assertEquals(BiometricSensor.STATE_CANCELING, sensor.getSensorState());
262         }
263         assertEquals(STATE_ERROR_PENDING_SYSUI, session.getState());
264 
265         // If the sensor is STATE_CANCELING, delayed onAuthenticationRejected() shouldn't change the
266         // session state to STATE_AUTH_PAUSED.
267         session.onAuthenticationRejected(1);
268         assertEquals(STATE_ERROR_PENDING_SYSUI, session.getState());
269     }
270 
271     @Test
testOnErrorReceivedBeforeOnDialogAnimatedIn()272     public void testOnErrorReceivedBeforeOnDialogAnimatedIn() throws RemoteException {
273         final int fingerprintId = 0;
274         final int faceId = 1;
275         setupFingerprint(fingerprintId, FingerprintSensorProperties.TYPE_REAR);
276         setupFace(faceId, true /* confirmationAlwaysRequired */,
277                 mock(IBiometricAuthenticator.class));
278         final AuthSession session = createAuthSession(mSensors,
279                 false /* checkDevicePolicyManager */,
280                 Authenticators.BIOMETRIC_STRONG,
281                 TEST_REQUEST_ID,
282                 0 /* operationId */,
283                 0 /* userId */);
284         session.goToInitialState();
285 
286         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
287             assertThat(sensor.getSensorState()).isEqualTo(BiometricSensor.STATE_WAITING_FOR_COOKIE);
288             session.onCookieReceived(
289                     session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie());
290         }
291         assertThat(session.allCookiesReceived()).isTrue();
292         assertThat(session.getState()).isEqualTo(STATE_AUTH_STARTED);
293 
294         final BiometricSensor faceSensor = session.mPreAuthInfo.eligibleSensors.get(faceId);
295         final BiometricSensor fingerprintSensor = session.mPreAuthInfo.eligibleSensors.get(
296                 fingerprintId);
297         final int cookie = faceSensor.getCookie();
298         session.onErrorReceived(0, cookie, BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL, 0);
299 
300         assertThat(faceSensor.getSensorState()).isEqualTo(BiometricSensor.STATE_STOPPED);
301         assertThat(session.getState()).isEqualTo(STATE_ERROR_PENDING_SYSUI);
302 
303         session.onDialogAnimatedIn(true);
304 
305         assertThat(session.getState()).isEqualTo(STATE_AUTH_STARTED_UI_SHOWING);
306         assertThat(fingerprintSensor.getSensorState()).isEqualTo(
307                 BiometricSensor.STATE_AUTHENTICATING);
308     }
309 
310     @Test
testOnRejectionReceivedBeforeOnDialogAnimatedIn()311     public void testOnRejectionReceivedBeforeOnDialogAnimatedIn() throws RemoteException {
312         final int fingerprintId = 0;
313         final int faceId = 1;
314         setupFingerprint(fingerprintId, FingerprintSensorProperties.TYPE_REAR);
315         setupFace(faceId, false /* confirmationAlwaysRequired */,
316                 mock(IBiometricAuthenticator.class));
317         final AuthSession session = createAuthSession(mSensors,
318                 false /* checkDevicePolicyManager */,
319                 Authenticators.BIOMETRIC_STRONG,
320                 TEST_REQUEST_ID,
321                 0 /* operationId */,
322                 0 /* userId */);
323         session.goToInitialState();
324 
325         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
326             assertThat(sensor.getSensorState()).isEqualTo(BiometricSensor.STATE_WAITING_FOR_COOKIE);
327             session.onCookieReceived(
328                     session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie());
329         }
330         assertThat(session.allCookiesReceived()).isTrue();
331         assertThat(session.getState()).isEqualTo(STATE_AUTH_STARTED);
332 
333         final BiometricSensor faceSensor = session.mPreAuthInfo.eligibleSensors.get(faceId);
334         final BiometricSensor fingerprintSensor = session.mPreAuthInfo.eligibleSensors.get(
335                 fingerprintId);
336         session.onAuthenticationRejected(faceId);
337 
338         assertThat(faceSensor.getSensorState()).isEqualTo(BiometricSensor.STATE_CANCELING);
339         assertThat(session.getState()).isEqualTo(STATE_AUTH_PAUSED);
340 
341         session.onDialogAnimatedIn(true);
342 
343         assertThat(session.getState()).isEqualTo(STATE_AUTH_STARTED_UI_SHOWING);
344         assertThat(fingerprintSensor.getSensorState()).isEqualTo(
345                 BiometricSensor.STATE_AUTHENTICATING);
346     }
347 
348     @Test
testCancelReducesAppetiteForCookies()349     public void testCancelReducesAppetiteForCookies() throws Exception {
350         setupFace(0 /* id */, false /* confirmationAlwaysRequired */,
351                 mock(IBiometricAuthenticator.class));
352         setupFingerprint(1 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
353 
354         final AuthSession session = createAuthSession(mSensors,
355                 false /* checkDevicePolicyManager */,
356                 Authenticators.BIOMETRIC_STRONG,
357                 TEST_REQUEST_ID,
358                 44 /* operationId */,
359                 2 /* userId */);
360 
361         session.goToInitialState();
362 
363         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
364             assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
365         }
366 
367         session.onCancelAuthSession(false /* force */);
368 
369         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
370             session.onCookieReceived(sensor.getCookie());
371             assertEquals(BiometricSensor.STATE_CANCELING, sensor.getSensorState());
372         }
373     }
374 
375     @Test
testMultiAuth_singleSensor_fingerprintSensorStartsAfterDialogAnimationCompletes()376     public void testMultiAuth_singleSensor_fingerprintSensorStartsAfterDialogAnimationCompletes()
377             throws Exception {
378         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
379         testMultiAuth_fingerprintSensorStartsAfterUINotifies(true /* startFingerprintNow */);
380     }
381 
382     @Test
testMultiAuth_singleSensor_fingerprintSensorDoesNotStartAfterDialogAnimationCompletes()383     public void testMultiAuth_singleSensor_fingerprintSensorDoesNotStartAfterDialogAnimationCompletes()
384             throws Exception {
385         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
386         testMultiAuth_fingerprintSensorStartsAfterUINotifies(false /* startFingerprintNow */);
387     }
388 
389     @Test
testMultiAuth_fingerprintSensorStartsAfterDialogAnimationCompletes()390     public void testMultiAuth_fingerprintSensorStartsAfterDialogAnimationCompletes()
391             throws Exception {
392         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
393         setupFace(1 /* id */, false, mock(IBiometricAuthenticator.class));
394         testMultiAuth_fingerprintSensorStartsAfterUINotifies(true /* startFingerprintNow */);
395     }
396 
397     @Test
testMultiAuth_fingerprintSensorDoesNotStartAfterDialogAnimationCompletes()398     public void testMultiAuth_fingerprintSensorDoesNotStartAfterDialogAnimationCompletes()
399             throws Exception {
400         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
401         setupFace(1 /* id */, false, mock(IBiometricAuthenticator.class));
402         testMultiAuth_fingerprintSensorStartsAfterUINotifies(false /* startFingerprintNow */);
403     }
404 
testMultiAuth_fingerprintSensorStartsAfterUINotifies(boolean startFingerprintNow)405     public void testMultiAuth_fingerprintSensorStartsAfterUINotifies(boolean startFingerprintNow)
406             throws Exception {
407         final long operationId = 123;
408         final int userId = 10;
409         final int fingerprintSensorId = mSensors.stream()
410                 .filter(s -> s.modality == TYPE_FINGERPRINT)
411                 .map(s -> s.id)
412                 .findFirst()
413                 .orElse(-1);
414 
415         final AuthSession session = createAuthSession(mSensors,
416                 false /* checkDevicePolicyManager */,
417                 Authenticators.BIOMETRIC_STRONG,
418                 TEST_REQUEST_ID,
419                 operationId,
420                 userId);
421         assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size());
422 
423         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
424             assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState());
425             assertEquals(0, sensor.getCookie());
426         }
427 
428         session.goToInitialState();
429 
430         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
431             assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
432             session.onCookieReceived(
433                     session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie());
434             if (fingerprintSensorId == sensor.id) {
435                 assertEquals(BiometricSensor.STATE_COOKIE_RETURNED, sensor.getSensorState());
436             } else {
437                 assertEquals(BiometricSensor.STATE_AUTHENTICATING, sensor.getSensorState());
438             }
439         }
440         assertTrue(session.allCookiesReceived());
441 
442         // fingerprint sensor does not start even if all cookies are received
443         assertEquals(STATE_AUTH_STARTED, session.getState());
444         verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(),
445                 anyBoolean(), anyBoolean(), anyInt(), anyLong(), any(), anyLong());
446 
447         // Notify AuthSession that the UI is shown. Then, fingerprint sensor should be started.
448         session.onDialogAnimatedIn(startFingerprintNow);
449         assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState());
450         assertEquals(startFingerprintNow ? BiometricSensor.STATE_AUTHENTICATING
451                         : BiometricSensor.STATE_COOKIE_RETURNED,
452                 session.mPreAuthInfo.eligibleSensors.get(fingerprintSensorId).getSensorState());
453         verify(mBiometricContext).updateContext((OperationContextExt) any(),
454                 eq(session.isCrypto()));
455 
456         // start fingerprint sensor if it was delayed
457         if (!startFingerprintNow) {
458             session.onStartFingerprint();
459             assertEquals(BiometricSensor.STATE_AUTHENTICATING,
460                     session.mPreAuthInfo.eligibleSensors.get(fingerprintSensorId).getSensorState());
461         }
462     }
463 
464     @Test
testOnDialogAnimatedInDoesNothingDuringInvalidState()465     public void testOnDialogAnimatedInDoesNothingDuringInvalidState() throws Exception {
466         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
467         final long operationId = 123;
468         final int userId = 10;
469 
470         final AuthSession session = createAuthSession(mSensors,
471                 false /* checkDevicePolicyManager */,
472                 Authenticators.BIOMETRIC_STRONG,
473                 TEST_REQUEST_ID,
474                 operationId,
475                 userId);
476         final IBiometricAuthenticator impl = session.mPreAuthInfo.eligibleSensors.get(0).impl;
477 
478         session.goToInitialState();
479         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
480             assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
481             session.onCookieReceived(
482                     session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie());
483         }
484         assertTrue(session.allCookiesReceived());
485         assertEquals(STATE_AUTH_STARTED, session.getState());
486         verify(impl, never()).startPreparedClient(anyInt());
487 
488         // First invocation should start the client monitor.
489         session.onDialogAnimatedIn(true /* startFingerprintNow */);
490         assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState());
491         verify(impl).startPreparedClient(anyInt());
492 
493         // Subsequent invocations should not start the client monitor again.
494         session.onDialogAnimatedIn(true /* startFingerprintNow */);
495         session.onDialogAnimatedIn(false /* startFingerprintNow */);
496         session.onDialogAnimatedIn(true /* startFingerprintNow */);
497         assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState());
498         verify(impl, times(1)).startPreparedClient(anyInt());
499     }
500 
501     @Test
testCancelAuthentication_whenStateAuthCalled_invokesCancel()502     public void testCancelAuthentication_whenStateAuthCalled_invokesCancel()
503             throws RemoteException {
504         testInvokesCancel(session -> session.onCancelAuthSession(false /* force */));
505     }
506 
507     @Test
testCancelAuthentication_whenStateAuthForcedCalled_invokesCancel()508     public void testCancelAuthentication_whenStateAuthForcedCalled_invokesCancel()
509             throws RemoteException {
510         testInvokesCancel(session -> session.onCancelAuthSession(true /* force */));
511     }
512 
513     @Test
testCancelAuthentication_whenDialogDismissed()514     public void testCancelAuthentication_whenDialogDismissed() throws RemoteException {
515         testInvokesCancel(session -> session.onDialogDismissed(DISMISSED_REASON_NEGATIVE, null));
516     }
517 
518     @Test
testCallbackOnAcquired()519     public void testCallbackOnAcquired() throws RemoteException {
520         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_REAR);
521 
522         final AuthSession session = createAuthSession(mSensors,
523                 false /* checkDevicePolicyManager */,
524                 Authenticators.BIOMETRIC_STRONG,
525                 TEST_REQUEST_ID,
526                 0 /* operationId */,
527                 0 /* userId */);
528 
529         session.onAcquired(0, FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL, 0);
530         verify(mStatusBarService).onBiometricHelp(anyInt(), eq(ACQUIRED_STRING));
531         verify(mClientReceiver).onAcquired(eq(1), eq(ACQUIRED_STRING));
532 
533         session.onAcquired(0, FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR, 0);
534         verify(mStatusBarService).onBiometricHelp(anyInt(), eq(ACQUIRED_STRING_VENDOR));
535         verify(mClientReceiver).onAcquired(
536                 eq(FingerprintManager.FINGERPRINT_ACQUIRED_VENDOR_BASE),
537                 eq(ACQUIRED_STRING_VENDOR));
538     }
539 
540     @Test
testLogOnDialogDismissed_authenticatedWithConfirmation()541     public void testLogOnDialogDismissed_authenticatedWithConfirmation() throws RemoteException {
542         final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);
543 
544         setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator);
545         final AuthSession session = createAuthSession(mSensors,
546                 false /* checkDevicePolicyManager */,
547                 Authenticators.BIOMETRIC_STRONG,
548                 TEST_REQUEST_ID,
549                 0 /* operationId */,
550                 0 /* userId */);
551         session.goToInitialState();
552         assertEquals(STATE_AUTH_CALLED, session.getState());
553 
554         session.onDialogDismissed(DISMISSED_REASON_BIOMETRIC_CONFIRMED, null);
555         verify(mBiometricFrameworkStatsLogger, times(1)).authenticate(
556                 (OperationContextExt) any(),
557                 eq(BiometricsProtoEnums.MODALITY_FACE),
558                 eq(BiometricsProtoEnums.ACTION_UNKNOWN),
559                 eq(BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT),
560                 eq(false), /* debugEnabled */
561                 anyLong(), /* latency */
562                 eq(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED),
563                 eq(true), /* confirmationRequired */
564                 eq(0) /* userId */,
565                 eq(-1f) /* ambientLightLux */);
566     }
567 
568     @Test
testLogOnDialogDismissed_authenticatedWithoutConfirmation()569     public void testLogOnDialogDismissed_authenticatedWithoutConfirmation() throws RemoteException {
570         final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);
571 
572         setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator);
573         final AuthSession session = createAuthSession(mSensors,
574                 false /* checkDevicePolicyManager */,
575                 Authenticators.BIOMETRIC_STRONG,
576                 TEST_REQUEST_ID,
577                 0 /* operationId */,
578                 0 /* userId */);
579         session.goToInitialState();
580         assertEquals(STATE_AUTH_CALLED, session.getState());
581 
582         session.onDialogDismissed(DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED, null);
583         verify(mBiometricFrameworkStatsLogger, never()).authenticate(
584                 any(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyLong(), anyInt(),
585                 anyBoolean(), anyInt(), eq(-1f));
586         verify(mBiometricFrameworkStatsLogger, never()).error(
587                 any(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyLong(), anyInt(),
588                 anyInt(), anyInt());
589     }
590 
591     @Test
testLogOnDialogDismissed_negativeButton()592     public void testLogOnDialogDismissed_negativeButton() throws RemoteException {
593         final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);
594 
595         setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator);
596         final AuthSession session = createAuthSession(mSensors,
597                 false /* checkDevicePolicyManager */,
598                 Authenticators.BIOMETRIC_STRONG,
599                 TEST_REQUEST_ID,
600                 0 /* operationId */,
601                 0 /* userId */);
602         session.goToInitialState();
603         assertEquals(STATE_AUTH_CALLED, session.getState());
604 
605         session.onDialogDismissed(DISMISSED_REASON_NEGATIVE, null);
606         verify(mBiometricFrameworkStatsLogger, times(1)).error(
607                 (OperationContextExt) any(),
608                 eq(BiometricsProtoEnums.MODALITY_FACE),
609                 eq(BiometricsProtoEnums.ACTION_AUTHENTICATE),
610                 eq(BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT),
611                 eq(false),
612                 anyLong(),
613                 eq(BIOMETRIC_ERROR_NEGATIVE_BUTTON),
614                 eq(0) /* vendorCode */,
615                 eq(0) /* userId */);
616     }
617 
618     @Test
testLogOnDialogDismissed_contentViewMoreOptionsButton()619     public void testLogOnDialogDismissed_contentViewMoreOptionsButton() throws RemoteException {
620         final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);
621 
622         setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator);
623         final AuthSession session = createAuthSession(mSensors,
624                 false /* checkDevicePolicyManager */,
625                 Authenticators.BIOMETRIC_STRONG,
626                 TEST_REQUEST_ID,
627                 0 /* operationId */,
628                 0 /* userId */);
629         session.goToInitialState();
630         assertEquals(STATE_AUTH_CALLED, session.getState());
631 
632         session.onDialogDismissed(DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS, null);
633         verify(mBiometricFrameworkStatsLogger, times(1)).error(
634                 (OperationContextExt) any(),
635                 eq(BiometricsProtoEnums.MODALITY_FACE),
636                 eq(BiometricsProtoEnums.ACTION_AUTHENTICATE),
637                 eq(BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT),
638                 eq(false),
639                 anyLong(),
640                 eq(BIOMETRIC_ERROR_CONTENT_VIEW_MORE_OPTIONS_BUTTON),
641                 eq(0) /* vendorCode */,
642                 eq(0) /* userId */);
643     }
644 
645     @Test
onErrorReceivedAfterOnTryAgainPressedWhenSensorsAuthenticating()646     public void onErrorReceivedAfterOnTryAgainPressedWhenSensorsAuthenticating() throws Exception {
647         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
648         setupFace(1 /* id */, false, mock(IBiometricAuthenticator.class));
649         final long operationId = 123;
650         final int userId = 10;
651         final AuthSession session = createAuthSession(mSensors,
652                 false /* checkDevicePolicyManager */,
653                 Authenticators.BIOMETRIC_STRONG,
654                 TEST_REQUEST_ID,
655                 operationId,
656                 userId);
657         session.goToInitialState();
658         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
659             session.onCookieReceived(
660                     session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie());
661         }
662         session.onDialogAnimatedIn(true /* startFingerprintNow */);
663 
664         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
665             assertEquals(BiometricSensor.STATE_AUTHENTICATING, sensor.getSensorState());
666         }
667         session.onTryAgainPressed();
668         session.onErrorReceived(0 /* sensorId */,
669                 session.mPreAuthInfo.eligibleSensors.get(0 /* sensorId */).getCookie(),
670                 BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT, 0);
671 
672         verify(mStatusBarService).onBiometricError(anyInt(), anyInt(), anyInt());
673     }
674 
675     @Test
onErrorReceivedAfterOnTryAgainPressedWhenSensorStopped()676     public void onErrorReceivedAfterOnTryAgainPressedWhenSensorStopped() throws Exception {
677         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
678         setupFace(1 /* id */, false, mock(IBiometricAuthenticator.class));
679         final long operationId = 123;
680         final int userId = 10;
681         final AuthSession session = createAuthSession(mSensors,
682                 false /* checkDevicePolicyManager */,
683                 Authenticators.BIOMETRIC_STRONG,
684                 TEST_REQUEST_ID,
685                 operationId,
686                 userId);
687         session.goToInitialState();
688         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
689             session.onCookieReceived(
690                     session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie());
691         }
692         session.onDialogAnimatedIn(true /* startFingerprintNow */);
693 
694         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
695             sensor.goToStoppedStateIfCookieMatches(sensor.getCookie(),
696                     BiometricConstants.BIOMETRIC_ERROR_TIMEOUT);
697             assertEquals(BiometricSensor.STATE_STOPPED, sensor.getSensorState());
698         }
699 
700         session.onTryAgainPressed();
701         session.onErrorReceived(0 /* sensorId */,
702                 session.mPreAuthInfo.eligibleSensors.get(0 /* sensorId */).getCookie(),
703                 BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT, 0);
704 
705         verify(mStatusBarService, never()).onBiometricError(anyInt(), anyInt(), anyInt());
706     }
707 
708     @Test
onAuthReceivedWhileWaitingForConfirmation_SFPS()709     public void onAuthReceivedWhileWaitingForConfirmation_SFPS() throws Exception {
710         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_POWER_BUTTON);
711         setupFace(1 /* id */, false, mock(IBiometricAuthenticator.class));
712         final long operationId = 123;
713         final int userId = 10;
714         final AuthSession session = createAuthSession(mSensors,
715                 false /* checkDevicePolicyManager */,
716                 Authenticators.BIOMETRIC_STRONG,
717                 TEST_REQUEST_ID,
718                 operationId,
719                 userId);
720         session.goToInitialState();
721         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
722             session.onCookieReceived(
723                     session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie());
724         }
725         session.onDialogAnimatedIn(true /* startFingerprintNow */);
726 
727         // Face succeeds
728         session.onAuthenticationSucceeded(1, true, null);
729         verify(mStatusBarService).onBiometricAuthenticated(TYPE_FACE);
730         for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
731             if (sensor.modality == FingerprintSensorProperties.TYPE_POWER_BUTTON) {
732                 assertEquals(BiometricSensor.STATE_AUTHENTICATING, sensor.getSensorState());
733             }
734         }
735 
736         // SFPS succeeds
737         session.onAuthenticationSucceeded(0, true, null);
738         verify(mStatusBarService).onBiometricAuthenticated(TYPE_FINGERPRINT);
739     }
740 
741     @Test
onDialogDismissedResetLockout_Confirmed()742     public void onDialogDismissedResetLockout_Confirmed() throws Exception {
743         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_POWER_BUTTON);
744         setupFace(1 /* id */, false, mock(IBiometricAuthenticator.class));
745         final long operationId = 123;
746         final int userId = 10;
747         final AuthSession session = createAuthSession(mSensors,
748                 false /* checkDevicePolicyManager */,
749                 Authenticators.BIOMETRIC_STRONG,
750                 TEST_REQUEST_ID,
751                 operationId,
752                 userId);
753         session.goToInitialState();
754         session.onDialogAnimatedIn(true /* startFingerprintNow */);
755 
756         // Face succeeds
757         session.onAuthenticationSucceeded(1, true, new byte[1]);
758 
759         // Dismiss through confirmation
760         session.onDialogDismissed(DISMISSED_REASON_BIOMETRIC_CONFIRMED, null);
761 
762         verify(mBiometricManager).resetLockoutTimeBound(any(), any(), anyInt(), anyInt(), any());
763     }
764 
765     @Test
onDialogDismissedResetLockout_Cancelled()766     public void onDialogDismissedResetLockout_Cancelled() throws Exception {
767         setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_POWER_BUTTON);
768         setupFace(1 /* id */, false, mock(IBiometricAuthenticator.class));
769         final long operationId = 123;
770         final int userId = 10;
771         final AuthSession session = createAuthSession(mSensors,
772                 false /* checkDevicePolicyManager */,
773                 Authenticators.BIOMETRIC_STRONG,
774                 TEST_REQUEST_ID,
775                 operationId,
776                 userId);
777         session.goToInitialState();
778         session.onDialogAnimatedIn(true /* startFingerprintNow */);
779 
780         // Face succeeds
781         session.onAuthenticationSucceeded(1, true, new byte[1]);
782 
783         // User cancel after success
784         session.onDialogDismissed(DISMISSED_REASON_USER_CANCEL, null);
785 
786         verify(mBiometricManager).resetLockoutTimeBound(any(), any(), anyInt(), anyInt(), any());
787     }
788 
789     // TODO (b/208484275) : Enable these tests
790     // @Test
791     // public void testPreAuth_canAuthAndPrivacyDisabled() throws Exception {
792     //     SensorPrivacyManager manager = ExtendedMockito.mock(SensorPrivacyManager.class);
793     //     when(manager
794     //             .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, anyInt()))
795     //             .thenReturn(false);
796     //     when(mContext.getSystemService(SensorPrivacyManager.class))
797     //             .thenReturn(manager);
798     //     setupFace(1 /* id */, false /* confirmationAlwaysRequired */,
799     //             mock(IBiometricAuthenticator.class));
800     //     final PromptInfo promptInfo = createPromptInfo(Authenticators.BIOMETRIC_STRONG);
801     //     final PreAuthInfo preAuthInfo = createPreAuthInfo(mSensors, 0, promptInfo, false);
802     //     assertEquals(BiometricManager.BIOMETRIC_SUCCESS, preAuthInfo.getCanAuthenticateResult());
803     //     for (BiometricSensor sensor : preAuthInfo.eligibleSensors) {
804     //         assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState());
805     //     }
806     // }
807 
808     // @Test
809     // public void testPreAuth_cannotAuthAndPrivacyEnabled() throws Exception {
810     //     SensorPrivacyManager manager = ExtendedMockito.mock(SensorPrivacyManager.class);
811     //     when(manager
812     //             .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, anyInt()))
813     //             .thenReturn(true);
814     //     when(mContext.getSystemService(SensorPrivacyManager.class))
815     //             .thenReturn(manager);
816     //     setupFace(1 /* id */, false /* confirmationAlwaysRequired */,
817     //             mock(IBiometricAuthenticator.class));
818     //     final PromptInfo promptInfo = createPromptInfo(Authenticators.BIOMETRIC_STRONG);
819     //     final PreAuthInfo preAuthInfo = createPreAuthInfo(mSensors, 0, promptInfo, false);
820     //     assertEquals(BiometricManager.BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED,
821     //             preAuthInfo.getCanAuthenticateResult());
822     //     // Even though canAuth returns privacy enabled, we should still be able to authenticate.
823     //     for (BiometricSensor sensor : preAuthInfo.eligibleSensors) {
824     //         assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState());
825     //     }
826     // }
827 
828     // @Test
829     // public void testPreAuth_canAuthAndPrivacyEnabledCredentialEnabled() throws Exception {
830     //     SensorPrivacyManager manager = ExtendedMockito.mock(SensorPrivacyManager.class);
831     //     when(manager
832     //             .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, anyInt()))
833     //             .thenReturn(true);
834     //     when(mContext.getSystemService(SensorPrivacyManager.class))
835     //             .thenReturn(manager);
836     //     setupFace(1 /* id */, false /* confirmationAlwaysRequired */,
837     //             mock(IBiometricAuthenticator.class));
838     //     final PromptInfo promptInfo =
839     //             createPromptInfo(Authenticators.BIOMETRIC_STRONG
840     //             | Authenticators. DEVICE_CREDENTIAL);
841     //     final PreAuthInfo preAuthInfo = createPreAuthInfo(mSensors, 0, promptInfo, false);
842     //     assertEquals(BiometricManager.BIOMETRIC_SUCCESS, preAuthInfo.getCanAuthenticateResult());
843     //     for (BiometricSensor sensor : preAuthInfo.eligibleSensors) {
844     //         assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState());
845     //     }
846     // }
847 
testInvokesCancel(Consumer<AuthSession> sessionConsumer)848     private void testInvokesCancel(Consumer<AuthSession> sessionConsumer) throws RemoteException {
849         final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class);
850 
851         setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator);
852         final AuthSession session = createAuthSession(mSensors,
853                 false /* checkDevicePolicyManager */,
854                 Authenticators.BIOMETRIC_STRONG,
855                 TEST_REQUEST_ID,
856                 0 /* operationId */,
857                 0 /* userId */);
858 
859         session.goToInitialState();
860         assertEquals(STATE_AUTH_CALLED, session.getState());
861 
862         sessionConsumer.accept(session);
863 
864         verify(faceAuthenticator).cancelAuthenticationFromService(
865                 eq(mToken), eq(TEST_PACKAGE), eq(TEST_REQUEST_ID));
866     }
867 
createPreAuthInfo(List<BiometricSensor> sensors, int userId, PromptInfo promptInfo, boolean checkDevicePolicyManager)868     private PreAuthInfo createPreAuthInfo(List<BiometricSensor> sensors, int userId,
869             PromptInfo promptInfo, boolean checkDevicePolicyManager) throws RemoteException {
870         return PreAuthInfo.create(mTrustManager,
871                 mDevicePolicyManager,
872                 mSettingObserver,
873                 sensors,
874                 userId,
875                 promptInfo,
876                 TEST_PACKAGE,
877                 checkDevicePolicyManager,
878                 mContext,
879                 mBiometricCameraManager,
880                 mUserManager);
881     }
882 
createAuthSession(List<BiometricSensor> sensors, boolean checkDevicePolicyManager, @Authenticators.Types int authenticators, long requestId, long operationId, int userId)883     private AuthSession createAuthSession(List<BiometricSensor> sensors,
884             boolean checkDevicePolicyManager, @Authenticators.Types int authenticators,
885             long requestId, long operationId, int userId) throws RemoteException {
886 
887         final PromptInfo promptInfo = createPromptInfo(authenticators);
888 
889         final PreAuthInfo preAuthInfo = createPreAuthInfo(sensors, userId, promptInfo,
890                 checkDevicePolicyManager);
891         return new AuthSession(mContext, mBiometricContext, mStatusBarService, mSysuiReceiver,
892                 mKeyStoreAuthorization, mRandom, mClientDeathReceiver, preAuthInfo, mToken,
893                 requestId, operationId, userId, mSensorReceiver, mClientReceiver, TEST_PACKAGE,
894                 promptInfo, false /* debugEnabled */, mFingerprintSensorProps,
895                 mBiometricFrameworkStatsLogger);
896     }
897 
createPromptInfo(@uthenticators.Types int authenticators)898     private PromptInfo createPromptInfo(@Authenticators.Types int authenticators) {
899         PromptInfo promptInfo = new PromptInfo();
900         promptInfo.setAuthenticators(authenticators);
901         return promptInfo;
902     }
903 
setupFingerprint(int id, @FingerprintSensorProperties.SensorType int type)904     private void setupFingerprint(int id, @FingerprintSensorProperties.SensorType int type)
905             throws RemoteException {
906         IBiometricAuthenticator fingerprintAuthenticator = mock(IBiometricAuthenticator.class);
907         when(fingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true);
908         when(fingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
909         mSensors.add(new BiometricSensor(mContext, id,
910                 TYPE_FINGERPRINT /* modality */,
911                 Authenticators.BIOMETRIC_STRONG /* strength */,
912                 fingerprintAuthenticator) {
913             @Override
914             boolean confirmationAlwaysRequired(int userId) {
915                 return false; // no-op / unsupported
916             }
917 
918             @Override
919             boolean confirmationSupported() {
920                 return false; // fingerprint does not support confirmation
921             }
922         });
923 
924         final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
925         componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
926                 "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
927                 "00000001" /* serialNumber */, "" /* softwareVersion */));
928         componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
929                 "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
930                 "vendor/version/revision" /* softwareVersion */));
931 
932         mFingerprintSensorProps.add(new FingerprintSensorPropertiesInternal(id,
933                 SensorProperties.STRENGTH_STRONG,
934                 5 /* maxEnrollmentsPerUser */,
935                 componentInfo,
936                 type,
937                 false /* resetLockoutRequiresHardwareAuthToken */));
938 
939         when(mSettingObserver.getEnabledForApps(anyInt(), anyInt())).thenReturn(true);
940     }
941 
setupFace(int id, boolean confirmationAlwaysRequired, IBiometricAuthenticator authenticator)942     private void setupFace(int id, boolean confirmationAlwaysRequired,
943             IBiometricAuthenticator authenticator) throws RemoteException {
944         when(authenticator.isHardwareDetected(any())).thenReturn(true);
945         when(authenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
946         mSensors.add(new BiometricSensor(mContext, id,
947                 TYPE_FACE /* modality */,
948                 Authenticators.BIOMETRIC_STRONG /* strength */,
949                 authenticator) {
950             @Override
951             boolean confirmationAlwaysRequired(int userId) {
952                 return confirmationAlwaysRequired;
953             }
954 
955             @Override
956             boolean confirmationSupported() {
957                 return true;
958             }
959         });
960 
961         when(mSettingObserver.getEnabledForApps(anyInt(), anyInt())).thenReturn(true);
962     }
963 }
964