1 /*
2  * Copyright (C) 2016 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.systemui.statusbar;
18 
19 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
20 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
21 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK;
22 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT;
23 import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT;
24 
25 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
26 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
27 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
28 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
29 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
30 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE;
31 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP;
32 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
33 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_LOGOUT;
34 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
35 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_PERSISTENT_UNLOCK_MESSAGE;
36 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRANSIENT;
37 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
38 import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_OFF;
39 import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_TURNING_ON;
40 
41 import static com.google.common.truth.Truth.assertThat;
42 
43 import static org.junit.Assert.assertFalse;
44 import static org.junit.Assert.assertTrue;
45 import static org.mockito.ArgumentMatchers.any;
46 import static org.mockito.ArgumentMatchers.anyBoolean;
47 import static org.mockito.ArgumentMatchers.anyInt;
48 import static org.mockito.ArgumentMatchers.anyObject;
49 import static org.mockito.ArgumentMatchers.anyString;
50 import static org.mockito.ArgumentMatchers.eq;
51 import static org.mockito.Mockito.clearInvocations;
52 import static org.mockito.Mockito.mock;
53 import static org.mockito.Mockito.never;
54 import static org.mockito.Mockito.reset;
55 import static org.mockito.Mockito.times;
56 import static org.mockito.Mockito.verify;
57 import static org.mockito.Mockito.verifyNoMoreInteractions;
58 import static org.mockito.Mockito.when;
59 
60 import android.content.Intent;
61 import android.content.pm.UserInfo;
62 import android.graphics.Color;
63 import android.hardware.biometrics.BiometricFaceConstants;
64 import android.hardware.biometrics.BiometricFingerprintConstants;
65 import android.hardware.biometrics.BiometricSourceType;
66 import android.os.BatteryManager;
67 import android.os.RemoteException;
68 import android.testing.AndroidTestingRunner;
69 import android.testing.TestableLooper;
70 
71 import androidx.test.filters.SmallTest;
72 
73 import com.android.keyguard.TrustGrantFlags;
74 import com.android.settingslib.fuelgauge.BatteryStatus;
75 import com.android.systemui.R;
76 import com.android.systemui.dock.DockManager;
77 import com.android.systemui.keyguard.KeyguardIndication;
78 import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
79 
80 import org.junit.Test;
81 import org.junit.runner.RunWith;
82 
83 import java.text.NumberFormat;
84 import java.util.Collections;
85 import java.util.HashSet;
86 import java.util.List;
87 import java.util.Set;
88 
89 @SmallTest
90 @RunWith(AndroidTestingRunner.class)
91 @TestableLooper.RunWithLooper
92 public class KeyguardIndicationControllerTest extends KeyguardIndicationControllerBaseTest {
93     @Test
createController_setIndicationAreaAgain_destroysPreviousRotateTextViewController()94     public void createController_setIndicationAreaAgain_destroysPreviousRotateTextViewController() {
95         // GIVEN a controller with a mocked rotate text view controlller
96         final KeyguardIndicationRotateTextViewController mockedRotateTextViewController =
97                 mock(KeyguardIndicationRotateTextViewController.class);
98         createController();
99         mController.mRotateTextViewController = mockedRotateTextViewController;
100 
101         // WHEN a new indication area is set
102         mController.setIndicationArea(mIndicationArea);
103 
104         // THEN the previous rotateTextViewController is destroyed
105         verify(mockedRotateTextViewController).destroy();
106     }
107 
108     @Test
createController_addsAlignmentListener()109     public void createController_addsAlignmentListener() {
110         createController();
111 
112         verify(mDockManager).addAlignmentStateListener(
113                 any(DockManager.AlignmentStateListener.class));
114     }
115 
116     @Test
onAlignmentStateChanged_showsSlowChargingIndication()117     public void onAlignmentStateChanged_showsSlowChargingIndication() {
118         mInstrumentation.runOnMainSync(() -> {
119             createController();
120             verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
121             mController.setVisible(true);
122 
123             mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR);
124         });
125         mInstrumentation.waitForIdleSync();
126         mTestableLooper.processAllMessages();
127 
128         verifyIndicationMessage(INDICATION_TYPE_ALIGNMENT,
129                 mContext.getResources().getString(R.string.dock_alignment_slow_charging));
130         assertThat(mKeyguardIndicationCaptor.getValue().getTextColor().getDefaultColor())
131                 .isEqualTo(mContext.getColor(R.color.misalignment_text_color));
132     }
133 
134     @Test
onAlignmentStateChanged_showsNotChargingIndication()135     public void onAlignmentStateChanged_showsNotChargingIndication() {
136         mInstrumentation.runOnMainSync(() -> {
137             createController();
138             verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
139             mController.setVisible(true);
140 
141             mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
142         });
143         mInstrumentation.waitForIdleSync();
144         mTestableLooper.processAllMessages();
145 
146         verifyIndicationMessage(INDICATION_TYPE_ALIGNMENT,
147                 mContext.getResources().getString(R.string.dock_alignment_not_charging));
148         assertThat(mKeyguardIndicationCaptor.getValue().getTextColor().getDefaultColor())
149                 .isEqualTo(mContext.getColor(R.color.misalignment_text_color));
150     }
151 
152     @Test
onAlignmentStateChanged_whileDozing_showsSlowChargingIndication()153     public void onAlignmentStateChanged_whileDozing_showsSlowChargingIndication() {
154         mInstrumentation.runOnMainSync(() -> {
155             createController();
156             verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
157             mController.setVisible(true);
158             mStatusBarStateListener.onDozingChanged(true);
159 
160             mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR);
161         });
162         mInstrumentation.waitForIdleSync();
163         mTestableLooper.processAllMessages();
164 
165         assertThat(mTextView.getText()).isEqualTo(
166                 mContext.getResources().getString(R.string.dock_alignment_slow_charging));
167         assertThat(mTextView.getCurrentTextColor()).isEqualTo(
168                 mContext.getColor(R.color.misalignment_text_color));
169     }
170 
171     @Test
onAlignmentStateChanged_whileDozing_showsNotChargingIndication()172     public void onAlignmentStateChanged_whileDozing_showsNotChargingIndication() {
173         mInstrumentation.runOnMainSync(() -> {
174             createController();
175             verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
176             mController.setVisible(true);
177             mStatusBarStateListener.onDozingChanged(true);
178 
179             mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
180         });
181         mInstrumentation.waitForIdleSync();
182         mTestableLooper.processAllMessages();
183 
184         assertThat(mTextView.getText()).isEqualTo(
185                 mContext.getResources().getString(R.string.dock_alignment_not_charging));
186         assertThat(mTextView.getCurrentTextColor()).isEqualTo(
187                 mContext.getColor(R.color.misalignment_text_color));
188     }
189 
190     @Test
disclosure_unmanaged()191     public void disclosure_unmanaged() {
192         createController();
193         mController.setVisible(true);
194         when(mKeyguardStateController.isShowing()).thenReturn(true);
195         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
196         when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(false);
197         reset(mRotateTextViewController);
198 
199         sendUpdateDisclosureBroadcast();
200         mExecutor.runAllReady();
201 
202         verifyHideIndication(INDICATION_TYPE_DISCLOSURE);
203     }
204 
205     @Test
disclosure_deviceOwner_noOrganizationName()206     public void disclosure_deviceOwner_noOrganizationName() {
207         createController();
208         when(mKeyguardStateController.isShowing()).thenReturn(true);
209         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
210         when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
211         sendUpdateDisclosureBroadcast();
212         mController.setVisible(true);
213         mExecutor.runAllReady();
214 
215         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureGeneric);
216     }
217 
218     @Test
disclosure_orgOwnedDeviceWithManagedProfile_noOrganizationName()219     public void disclosure_orgOwnedDeviceWithManagedProfile_noOrganizationName() {
220         createController();
221         mController.setVisible(true);
222         when(mKeyguardStateController.isShowing()).thenReturn(true);
223         when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(true);
224         when(mUserManager.getProfiles(anyInt())).thenReturn(Collections.singletonList(
225                 new UserInfo(10, /* name */ null, /* flags */ FLAG_MANAGED_PROFILE)));
226         when(mDevicePolicyManager.getOrganizationNameForUser(eq(10))).thenReturn(null);
227         sendUpdateDisclosureBroadcast();
228         mExecutor.runAllReady();
229 
230         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureGeneric);
231     }
232 
233     @Test
disclosure_deviceOwner_withOrganizationName()234     public void disclosure_deviceOwner_withOrganizationName() {
235         createController();
236         mController.setVisible(true);
237         when(mKeyguardStateController.isShowing()).thenReturn(true);
238         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
239         when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
240         sendUpdateDisclosureBroadcast();
241         mExecutor.runAllReady();
242 
243         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureWithOrganization);
244     }
245 
246     @Test
disclosure_orgOwnedDeviceWithManagedProfile_withOrganizationName()247     public void disclosure_orgOwnedDeviceWithManagedProfile_withOrganizationName() {
248         createController();
249         mController.setVisible(true);
250         when(mKeyguardStateController.isShowing()).thenReturn(true);
251         when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(true);
252         when(mUserManager.getProfiles(anyInt())).thenReturn(Collections.singletonList(
253                 new UserInfo(10, /* name */ null, FLAG_MANAGED_PROFILE)));
254         when(mDevicePolicyManager.getOrganizationNameForUser(eq(10))).thenReturn(ORGANIZATION_NAME);
255         sendUpdateDisclosureBroadcast();
256         mExecutor.runAllReady();
257 
258         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureWithOrganization);
259     }
260 
261     @Test
disclosure_updateOnTheFly()262     public void disclosure_updateOnTheFly() {
263         when(mKeyguardStateController.isShowing()).thenReturn(true);
264         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
265         createController();
266         mController.setVisible(true);
267 
268         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
269         when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
270         sendUpdateDisclosureBroadcast();
271         mExecutor.runAllReady();
272 
273         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureGeneric);
274         reset(mRotateTextViewController);
275 
276         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
277         when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
278         sendUpdateDisclosureBroadcast();
279         mExecutor.runAllReady();
280 
281         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mDisclosureWithOrganization);
282         reset(mRotateTextViewController);
283 
284         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
285         sendUpdateDisclosureBroadcast();
286         mExecutor.runAllReady();
287 
288         verifyHideIndication(INDICATION_TYPE_DISCLOSURE);
289     }
290 
291     @Test
disclosure_deviceOwner_financedDeviceWithOrganizationName()292     public void disclosure_deviceOwner_financedDeviceWithOrganizationName() {
293         createController();
294         mController.setVisible(true);
295         when(mKeyguardStateController.isShowing()).thenReturn(true);
296         when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
297         when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
298         when(mDevicePolicyManager.isFinancedDevice()).thenReturn(true);
299         // TODO(b/259908270): remove
300         when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
301                 .thenReturn(DEVICE_OWNER_TYPE_FINANCED);
302         sendUpdateDisclosureBroadcast();
303         mExecutor.runAllReady();
304         mController.setVisible(true);
305 
306         verifyIndicationMessage(INDICATION_TYPE_DISCLOSURE, mFinancedDisclosureWithOrganization);
307     }
308 
309     @Test
transientIndication_holdsWakeLock_whenDozing()310     public void transientIndication_holdsWakeLock_whenDozing() {
311         // GIVEN animations are enabled and text is visible
312         mTextView.setAnimationsEnabled(true);
313         createController();
314         mController.setVisible(true);
315 
316         // WHEN transient text is shown
317         mStatusBarStateListener.onDozingChanged(true);
318         mController.showTransientIndication(TEST_STRING_RES);
319 
320         // THEN wake lock is held while the animation is running
321         assertTrue("WakeLock expected: HELD, was: RELEASED", mWakeLock.isHeld());
322     }
323 
324     @Test
transientIndication_releasesWakeLock_whenDozing()325     public void transientIndication_releasesWakeLock_whenDozing() {
326         // GIVEN animations aren't enabled
327         mTextView.setAnimationsEnabled(false);
328         createController();
329         mController.setVisible(true);
330 
331         // WHEN we show the transient indication
332         mStatusBarStateListener.onDozingChanged(true);
333         mController.showTransientIndication(TEST_STRING_RES);
334 
335         // THEN wake lock is RELEASED, not held
336         assertFalse("WakeLock expected: RELEASED, was: HELD", mWakeLock.isHeld());
337     }
338 
339     @Test
transientIndication_visibleWhenDozing()340     public void transientIndication_visibleWhenDozing() {
341         createController();
342         mController.setVisible(true);
343 
344         mStatusBarStateListener.onDozingChanged(true);
345         mController.showTransientIndication(TEST_STRING_RES);
346 
347         assertThat(mTextView.getText()).isEqualTo(
348                 mContext.getResources().getString(TEST_STRING_RES));
349         assertThat(mTextView.getCurrentTextColor()).isEqualTo(Color.WHITE);
350         assertThat(mTextView.getAlpha()).isEqualTo(1f);
351     }
352 
353     @Test
transientIndication_visibleWhenDozing_unlessSwipeUp_fromHelp()354     public void transientIndication_visibleWhenDozing_unlessSwipeUp_fromHelp() {
355         createController();
356         String message = "A message";
357 
358         mController.setVisible(true);
359         mController.getKeyguardCallback().onBiometricHelp(
360                 BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message,
361                 BiometricSourceType.FACE);
362         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message);
363         reset(mRotateTextViewController);
364         mStatusBarStateListener.onDozingChanged(true);
365 
366         assertThat(mTextView.getText()).isNotEqualTo(message);
367     }
368 
369     @Test
transientIndication_visibleWhenWokenUp()370     public void transientIndication_visibleWhenWokenUp() {
371         createController();
372         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
373         final String message = "helpMsg";
374 
375         // GIVEN screen is off
376         when(mScreenLifecycle.getScreenState()).thenReturn(SCREEN_OFF);
377 
378         // WHEN fingeprint help message received
379         mController.setVisible(true);
380         mController.getKeyguardCallback().onBiometricHelp(BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
381                 message, BiometricSourceType.FINGERPRINT);
382 
383         // THEN message isn't shown right away
384         verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
385 
386         // WHEN the screen turns on
387         mScreenObserver.onScreenTurnedOn();
388         mTestableLooper.processAllMessages();
389 
390         // THEN the message is shown
391         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message);
392     }
393 
394     @Test
onBiometricHelp_coEx_faceFailure()395     public void onBiometricHelp_coEx_faceFailure() {
396         createController();
397 
398         // GIVEN unlocking with fingerprint is possible and allowed
399         fingerprintUnlockIsPossibleAndAllowed();
400 
401         String message = "A message";
402         mController.setVisible(true);
403 
404         // WHEN there's a face not recognized message
405         mController.getKeyguardCallback().onBiometricHelp(
406                 BIOMETRIC_HELP_FACE_NOT_RECOGNIZED,
407                 message,
408                 BiometricSourceType.FACE);
409 
410         // THEN show sequential messages such as: 'face not recognized' and
411         // 'try fingerprint instead'
412         verifyIndicationMessage(
413                 INDICATION_TYPE_BIOMETRIC_MESSAGE,
414                 mContext.getString(R.string.keyguard_face_failed));
415         verifyIndicationMessage(
416                 INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
417                 mContext.getString(R.string.keyguard_suggest_fingerprint));
418     }
419 
420     @Test
onBiometricHelp_coEx_faceUnavailable()421     public void onBiometricHelp_coEx_faceUnavailable() {
422         createController();
423 
424         // GIVEN unlocking with fingerprint is possible and allowed
425         fingerprintUnlockIsPossibleAndAllowed();
426 
427         String message = "A message";
428         mController.setVisible(true);
429 
430         // WHEN there's a face unavailable message
431         mController.getKeyguardCallback().onBiometricHelp(
432                 BIOMETRIC_HELP_FACE_NOT_AVAILABLE,
433                 message,
434                 BiometricSourceType.FACE);
435 
436         // THEN show sequential messages such as: 'face unlock unavailable' and
437         // 'try fingerprint instead'
438         verifyIndicationMessage(
439                 INDICATION_TYPE_BIOMETRIC_MESSAGE,
440                 message);
441         verifyIndicationMessage(
442                 INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
443                 mContext.getString(R.string.keyguard_suggest_fingerprint));
444     }
445 
446 
447     @Test
onBiometricHelp_coEx_faceUnavailable_fpNotAllowed()448     public void onBiometricHelp_coEx_faceUnavailable_fpNotAllowed() {
449         createController();
450 
451         // GIVEN unlocking with fingerprint is possible but not allowed
452         setupFingerprintUnlockPossible(true);
453         when(mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed())
454                 .thenReturn(false);
455 
456         String message = "A message";
457         mController.setVisible(true);
458 
459         // WHEN there's a face unavailable message
460         mController.getKeyguardCallback().onBiometricHelp(
461                 BIOMETRIC_HELP_FACE_NOT_AVAILABLE,
462                 message,
463                 BiometricSourceType.FACE);
464 
465         // THEN show sequential messages such as: 'face unlock unavailable' and
466         // 'try fingerprint instead'
467         verifyIndicationMessage(
468                 INDICATION_TYPE_BIOMETRIC_MESSAGE,
469                 message);
470         verifyIndicationMessage(
471                 INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
472                 mContext.getString(R.string.keyguard_unlock));
473     }
474 
475     @Test
onBiometricHelp_coEx_fpFailure_faceAlreadyUnlocked()476     public void onBiometricHelp_coEx_fpFailure_faceAlreadyUnlocked() {
477         createController();
478 
479         // GIVEN face has already unlocked the device
480         when(mKeyguardUpdateMonitor.getUserUnlockedWithFace(anyInt())).thenReturn(true);
481 
482         String message = "A message";
483         mController.setVisible(true);
484 
485         // WHEN there's a fingerprint not recognized message
486         mController.getKeyguardCallback().onBiometricHelp(
487                 BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
488                 message,
489                 BiometricSourceType.FINGERPRINT);
490 
491         // THEN show sequential messages such as: 'Unlocked by face' and
492         // 'Swipe up to open'
493         verifyIndicationMessage(
494                 INDICATION_TYPE_BIOMETRIC_MESSAGE,
495                 mContext.getString(R.string.keyguard_face_successful_unlock));
496         verifyIndicationMessage(
497                 INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
498                 mContext.getString(R.string.keyguard_unlock));
499     }
500 
501     @Test
onBiometricHelp_coEx_fpFailure_trustAgentAlreadyUnlocked()502     public void onBiometricHelp_coEx_fpFailure_trustAgentAlreadyUnlocked() {
503         createController();
504 
505         // GIVEN trust agent has already unlocked the device
506         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
507 
508         String message = "A message";
509         mController.setVisible(true);
510 
511         // WHEN there's a fingerprint not recognized message
512         mController.getKeyguardCallback().onBiometricHelp(
513                 BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
514                 message,
515                 BiometricSourceType.FINGERPRINT);
516 
517         // THEN show sequential messages such as: 'Kept unlocked by TrustAgent' and
518         // 'Swipe up to open'
519         verifyIndicationMessage(
520                 INDICATION_TYPE_BIOMETRIC_MESSAGE,
521                 mContext.getString(R.string.keyguard_indication_trust_unlocked));
522         verifyIndicationMessage(
523                 INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
524                 mContext.getString(R.string.keyguard_unlock));
525     }
526 
527     @Test
onBiometricHelp_coEx_fpFailure_trustAgentUnlocked_emptyTrustGrantedMessage()528     public void onBiometricHelp_coEx_fpFailure_trustAgentUnlocked_emptyTrustGrantedMessage() {
529         createController();
530 
531         // GIVEN trust agent has already unlocked the device & trust granted message is empty
532         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
533         mController.showTrustGrantedMessage(false, "");
534 
535         String message = "A message";
536         mController.setVisible(true);
537 
538         // WHEN there's a fingerprint not recognized message
539         mController.getKeyguardCallback().onBiometricHelp(
540                 BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED,
541                 message,
542                 BiometricSourceType.FINGERPRINT);
543 
544         // THEN show action to unlock (ie: 'Swipe up to open')
545         verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
546         verifyIndicationMessage(
547                 INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
548                 mContext.getString(R.string.keyguard_unlock));
549     }
550 
551     @Test
transientIndication_visibleWhenDozing_unlessSwipeUp_fromError()552     public void transientIndication_visibleWhenDozing_unlessSwipeUp_fromError() {
553         createController();
554         String message = mContext.getString(R.string.keyguard_unlock);
555 
556         mController.setVisible(true);
557         mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
558                 "A message", BiometricSourceType.FACE);
559 
560         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message);
561         mStatusBarStateListener.onDozingChanged(true);
562 
563         assertThat(mTextView.getText()).isNotEqualTo(message);
564     }
565 
566     @Test
transientIndication_visibleWhenDozing_ignoresFingerprintErrorMsg()567     public void transientIndication_visibleWhenDozing_ignoresFingerprintErrorMsg() {
568         createController();
569         mController.setVisible(true);
570         reset(mRotateTextViewController);
571 
572         // WHEN a fingerprint error user cancelled message is received
573         mController.getKeyguardCallback().onBiometricError(
574                 BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED, "foo",
575                 BiometricSourceType.FINGERPRINT);
576 
577         // THEN no message is shown
578         verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
579         verifyNoMessage(INDICATION_TYPE_TRANSIENT);
580     }
581 
582     @Test
transientIndication_swipeUpToRetry()583     public void transientIndication_swipeUpToRetry() {
584         createController();
585         String message = mContext.getString(R.string.keyguard_retry);
586         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
587         when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true);
588         when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(false);
589 
590         mController.setVisible(true);
591         mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
592                 "A message", BiometricSourceType.FACE);
593 
594         verify(mStatusBarKeyguardViewManager).setKeyguardMessage(eq(message), any());
595     }
596 
597     @Test
transientIndication_swipeUpToRetry_faceAuthenticated()598     public void transientIndication_swipeUpToRetry_faceAuthenticated() {
599         createController();
600         String message = mContext.getString(R.string.keyguard_retry);
601         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
602         when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true);
603         when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true);
604 
605         mController.setVisible(true);
606         mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
607                 "A message", BiometricSourceType.FACE);
608 
609         verify(mStatusBarKeyguardViewManager, never()).setKeyguardMessage(eq(message), any());
610     }
611 
612     @Test
faceErrorTimeout_whenFingerprintEnrolled_doesNotShowMessage()613     public void faceErrorTimeout_whenFingerprintEnrolled_doesNotShowMessage() {
614         createController();
615         fingerprintUnlockIsPossibleAndAllowed();
616         String message = "A message";
617 
618         mController.setVisible(true);
619         mController.getKeyguardCallback().onBiometricError(
620                 FACE_ERROR_TIMEOUT, message, BiometricSourceType.FACE);
621         verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
622     }
623 
624     @Test
sendFaceHelpMessages_fingerprintEnrolled()625     public void sendFaceHelpMessages_fingerprintEnrolled() {
626         createController();
627 
628         // GIVEN unlocking with fingerprint is possible and allowed
629         fingerprintUnlockIsPossibleAndAllowed();
630 
631         // WHEN help messages received that are allowed to show
632         final String helpString = "helpString";
633         final int[] msgIds = new int[]{
634                 BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED,
635                 BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED
636         };
637         Set<CharSequence> messages = new HashSet<>();
638         for (int msgId : msgIds) {
639             final String message = helpString + msgId;
640             messages.add(message);
641             mKeyguardUpdateMonitorCallback.onBiometricHelp(
642                     msgId, message, BiometricSourceType.FACE);
643         }
644 
645         // THEN FACE_ACQUIRED_MOUTH_COVERING_DETECTED and DARK_GLASSES help messages shown
646         verifyIndicationMessages(INDICATION_TYPE_BIOMETRIC_MESSAGE,
647                 messages);
648     }
649 
650     @Test
doNotSendMostFaceHelpMessages_fingerprintEnrolled()651     public void doNotSendMostFaceHelpMessages_fingerprintEnrolled() {
652         createController();
653 
654         // GIVEN unlocking with fingerprint is possible and allowed
655         fingerprintUnlockIsPossibleAndAllowed();
656 
657         // WHEN help messages received that aren't supposed to show
658         final String helpString = "helpString";
659         final int[] msgIds = new int[]{
660                 BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED,
661                 BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT,
662                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
663                 BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
664                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
665                 BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT
666         };
667         for (int msgId : msgIds) {
668             mKeyguardUpdateMonitorCallback.onBiometricHelp(
669                     msgId,  helpString + msgId, BiometricSourceType.FACE);
670         }
671 
672         // THEN no messages shown
673         verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
674     }
675 
676     @Test
sendAllFaceHelpMessages_fingerprintNotEnrolled()677     public void sendAllFaceHelpMessages_fingerprintNotEnrolled() {
678         createController();
679 
680         // GIVEN fingerprint NOT possible
681         fingerprintUnlockIsNotPossible();
682 
683         // WHEN help messages received
684         final Set<CharSequence> helpStrings = new HashSet<>();
685         final String helpString = "helpString";
686         final int[] msgIds = new int[]{
687                 BiometricFaceConstants.FACE_ACQUIRED_FACE_OBSCURED,
688                 BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED,
689                 BiometricFaceConstants.FACE_ACQUIRED_TOO_RIGHT,
690                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
691                 BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
692                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
693                 BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT
694         };
695         for (int msgId : msgIds) {
696             final String numberedHelpString = helpString + msgId;
697             mKeyguardUpdateMonitorCallback.onBiometricHelp(
698                     msgId,  numberedHelpString, BiometricSourceType.FACE);
699             helpStrings.add(numberedHelpString);
700         }
701 
702         // THEN message shown for each call
703         verifyIndicationMessages(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpStrings);
704     }
705 
706     @Test
sendTooDarkFaceHelpMessages_onTimeout_noFpEnrolled()707     public void sendTooDarkFaceHelpMessages_onTimeout_noFpEnrolled() {
708         createController();
709 
710         // GIVEN fingerprint not possible
711         fingerprintUnlockIsNotPossible();
712 
713         // WHEN help message received and deferred message is valid
714         final String helpString = "helpMsg";
715         when(mFaceHelpMessageDeferral.getDeferredMessage()).thenReturn(helpString);
716         when(mFaceHelpMessageDeferral.shouldDefer(FACE_ACQUIRED_TOO_DARK)).thenReturn(true);
717         mKeyguardUpdateMonitorCallback.onBiometricHelp(
718                 BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
719                 helpString,
720                 BiometricSourceType.FACE
721         );
722 
723         // THEN help message not shown yet
724         verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
725 
726         // WHEN face timeout error received
727         mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_TIMEOUT, "face timeout",
728                 BiometricSourceType.FACE);
729 
730         // THEN the low light message shows with suggestion to swipe up to unlock
731         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpString);
732         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
733                 mContext.getString(R.string.keyguard_unlock));
734     }
735 
736     @Test
sendTooDarkFaceHelpMessages_onTimeout_fingerprintEnrolled()737     public void sendTooDarkFaceHelpMessages_onTimeout_fingerprintEnrolled() {
738         createController();
739 
740         // GIVEN unlocking with fingerprint is possible and allowed
741         fingerprintUnlockIsPossibleAndAllowed();
742 
743         // WHEN help message received and deferredMessage is valid
744         final String helpString = "helpMsg";
745         when(mFaceHelpMessageDeferral.getDeferredMessage()).thenReturn(helpString);
746         when(mFaceHelpMessageDeferral.shouldDefer(FACE_ACQUIRED_TOO_DARK)).thenReturn(true);
747         mKeyguardUpdateMonitorCallback.onBiometricHelp(
748                 BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
749                 helpString,
750                 BiometricSourceType.FACE
751         );
752 
753         // THEN help message not shown yet
754         verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
755 
756         // WHEN face timeout error received
757         mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_TIMEOUT, "face timeout",
758                 BiometricSourceType.FACE);
759 
760         // THEN the low light message shows and suggests trying fingerprint
761         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpString);
762         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
763                 mContext.getString(R.string.keyguard_suggest_fingerprint));
764     }
765 
766     @Test
onRefreshBatteryInfo_computesChargingTime()767     public void onRefreshBatteryInfo_computesChargingTime() throws RemoteException {
768         createController();
769         BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_CHARGING,
770                 80 /* level */, BatteryManager.BATTERY_PLUGGED_WIRELESS, 100 /* health */,
771                 0 /* maxChargingWattage */, true /* present */);
772 
773         mController.getKeyguardCallback().onRefreshBatteryInfo(status);
774         verify(mIBatteryStats).computeChargeTimeRemaining();
775     }
776 
777     @Test
onRefreshBatteryInfo_computesChargingTime_onlyWhenCharging()778     public void onRefreshBatteryInfo_computesChargingTime_onlyWhenCharging()
779             throws RemoteException {
780         createController();
781         BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_CHARGING,
782                 80 /* level */, 0 /* plugged */, 100 /* health */,
783                 0 /* maxChargingWattage */, true /* present */);
784 
785         mController.getKeyguardCallback().onRefreshBatteryInfo(status);
786         verify(mIBatteryStats, never()).computeChargeTimeRemaining();
787     }
788 
789     /**
790      * Regression test.
791      * We should not make calls to the system_process when updating the doze state.
792      */
793     @Test
setDozing_noIBatteryCalls()794     public void setDozing_noIBatteryCalls() throws RemoteException {
795         createController();
796         mController.setVisible(true);
797         mStatusBarStateListener.onDozingChanged(true);
798         mStatusBarStateListener.onDozingChanged(false);
799         verify(mIBatteryStats, never()).computeChargeTimeRemaining();
800     }
801 
802     @Test
registersKeyguardStateCallback()803     public void registersKeyguardStateCallback() {
804         createController();
805         verify(mKeyguardStateController).addCallback(any());
806     }
807 
808     @Test
unlockMethodCache_listenerUpdatesPluggedIndication()809     public void unlockMethodCache_listenerUpdatesPluggedIndication() {
810         createController();
811         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
812         mController.setPowerPluggedIn(true);
813         mController.setVisible(true);
814 
815         verifyIndicationMessage(
816                 INDICATION_TYPE_TRUST,
817                 mContext.getString(R.string.keyguard_indication_trust_unlocked));
818     }
819 
820     @Test
onRefreshBatteryInfo_chargingWithLongLife_presentChargingLimited()821     public void onRefreshBatteryInfo_chargingWithLongLife_presentChargingLimited() {
822         createController();
823         BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_CHARGING,
824                 80 /* level */, BatteryManager.BATTERY_PLUGGED_AC,
825                 BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE, 0 /* maxChargingWattage */,
826                 true /* present */);
827 
828         mController.getKeyguardCallback().onRefreshBatteryInfo(status);
829         mController.setVisible(true);
830 
831         verifyIndicationMessage(
832                 INDICATION_TYPE_BATTERY,
833                 mContext.getString(
834                         R.string.keyguard_plugged_in_charging_limited,
835                         NumberFormat.getPercentInstance().format(80 / 100f)));
836     }
837 
838     @Test
onRefreshBatteryInfo_fullChargedWithLongLife_presentChargingLimited()839     public void onRefreshBatteryInfo_fullChargedWithLongLife_presentChargingLimited() {
840         createController();
841         BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_CHARGING,
842                 100 /* level */, BatteryManager.BATTERY_PLUGGED_AC,
843                 BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE, 0 /* maxChargingWattage */,
844                 true /* present */);
845 
846         mController.getKeyguardCallback().onRefreshBatteryInfo(status);
847         mController.setVisible(true);
848 
849         verifyIndicationMessage(
850                 INDICATION_TYPE_BATTERY,
851                 mContext.getString(
852                         R.string.keyguard_plugged_in_charging_limited,
853                         NumberFormat.getPercentInstance().format(100 / 100f)));
854     }
855 
856     @Test
onRefreshBatteryInfo_fullChargedWithoutLongLife_presentCharged()857     public void onRefreshBatteryInfo_fullChargedWithoutLongLife_presentCharged() {
858         createController();
859         BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_CHARGING,
860                 100 /* level */, BatteryManager.BATTERY_PLUGGED_AC,
861                 BatteryManager.CHARGING_POLICY_DEFAULT, 0 /* maxChargingWattage */,
862                 true /* present */);
863 
864         mController.getKeyguardCallback().onRefreshBatteryInfo(status);
865         mController.setVisible(true);
866 
867         verifyIndicationMessage(
868                 INDICATION_TYPE_BATTERY,
869                 mContext.getString(R.string.keyguard_charged));
870     }
871 
872     @Test
onRefreshBatteryInfo_dozing_dischargingWithLongLife_presentBatteryPercentage()873     public void onRefreshBatteryInfo_dozing_dischargingWithLongLife_presentBatteryPercentage() {
874         createController();
875         mController.setVisible(true);
876         BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_DISCHARGING,
877                 90 /* level */, 0 /* plugged */, BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE,
878                 0 /* maxChargingWattage */, true /* present */);
879 
880         mController.getKeyguardCallback().onRefreshBatteryInfo(status);
881         mStatusBarStateListener.onDozingChanged(true);
882 
883         String percentage = NumberFormat.getPercentInstance().format(90 / 100f);
884         assertThat(mTextView.getText()).isEqualTo(percentage);
885     }
886 
887     @Test
onRequireUnlockForNfc_showsRequireUnlockForNfcIndication()888     public void onRequireUnlockForNfc_showsRequireUnlockForNfcIndication() {
889         createController();
890         mController.setVisible(true);
891         String message = mContext.getString(R.string.require_unlock_for_nfc);
892         mController.getKeyguardCallback().onRequireUnlockForNfc();
893 
894         verifyTransientMessage(message);
895     }
896 
897     @Test
testEmptyOwnerInfoHidesIndicationArea()898     public void testEmptyOwnerInfoHidesIndicationArea() {
899         createController();
900 
901         // GIVEN the owner info is set to an empty string & keyguard is showing
902         when(mKeyguardStateController.isShowing()).thenReturn(true);
903         when(mLockPatternUtils.getDeviceOwnerInfo()).thenReturn("");
904 
905         // WHEN asked to update the indication area
906         mController.setVisible(true);
907         mExecutor.runAllReady();
908 
909         // THEN the owner info should be hidden
910         verifyHideIndication(INDICATION_TYPE_OWNER_INFO);
911     }
912 
913     @Test
testOnKeyguardShowingChanged_notShowing_resetsMessages()914     public void testOnKeyguardShowingChanged_notShowing_resetsMessages() {
915         createController();
916 
917         // GIVEN keyguard isn't showing
918         when(mKeyguardStateController.isShowing()).thenReturn(false);
919 
920         // WHEN keyguard showing changed called
921         mKeyguardStateControllerCallback.onKeyguardShowingChanged();
922 
923         // THEN messages are reset
924         verify(mRotateTextViewController).clearMessages();
925         assertThat(mTextView.getText()).isEqualTo("");
926     }
927 
928     @Test
testOnKeyguardShowingChanged_showing_updatesPersistentMessages()929     public void testOnKeyguardShowingChanged_showing_updatesPersistentMessages() {
930         createController();
931         mController.setVisible(true);
932         mExecutor.runAllReady();
933         reset(mRotateTextViewController);
934 
935         // GIVEN keyguard is showing and not dozing
936         when(mKeyguardStateController.isShowing()).thenReturn(true);
937         mController.setVisible(true);
938         mExecutor.runAllReady();
939         reset(mRotateTextViewController);
940 
941         // WHEN keyguard showing changed called
942         mKeyguardStateControllerCallback.onKeyguardShowingChanged();
943         mExecutor.runAllReady();
944 
945         // THEN persistent messages are updated (in this case, most messages are hidden since
946         // no info is provided) - verify that this happens
947         verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_DISCLOSURE);
948         verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_OWNER_INFO);
949         verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_BATTERY);
950         verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_TRUST);
951         verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_ALIGNMENT);
952         verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_LOGOUT);
953     }
954 
955     @Test
onTrustGrantedMessageDoesNotShowUntilTrustGranted()956     public void onTrustGrantedMessageDoesNotShowUntilTrustGranted() {
957         createController();
958         mController.setVisible(true);
959         reset(mRotateTextViewController);
960 
961         // GIVEN a trust granted message but trust isn't granted
962         final String trustGrantedMsg = "testing trust granted message";
963         mController.getKeyguardCallback().onTrustGrantedForCurrentUser(
964                 false, false, new TrustGrantFlags(0), trustGrantedMsg);
965 
966         verifyHideIndication(INDICATION_TYPE_TRUST);
967 
968         // WHEN trust is granted
969         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
970         mKeyguardUpdateMonitorCallback.onTrustChanged(getCurrentUser());
971 
972         // THEN verify the trust granted message shows
973         verifyIndicationMessage(
974                 INDICATION_TYPE_TRUST,
975                 trustGrantedMsg);
976     }
977 
978     @Test
onTrustGrantedMessageShowsOnTrustGranted()979     public void onTrustGrantedMessageShowsOnTrustGranted() {
980         createController();
981         mController.setVisible(true);
982 
983         // GIVEN trust is granted
984         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
985 
986         // WHEN the showTrustGranted method is called
987         final String trustGrantedMsg = "testing trust granted message";
988         mController.getKeyguardCallback().onTrustGrantedForCurrentUser(
989                 false, false, new TrustGrantFlags(0), trustGrantedMsg);
990 
991         // THEN verify the trust granted message shows
992         verifyIndicationMessage(
993                 INDICATION_TYPE_TRUST,
994                 trustGrantedMsg);
995     }
996 
997     @Test
onTrustGrantedMessage_nullMessage_showsDefaultMessage()998     public void onTrustGrantedMessage_nullMessage_showsDefaultMessage() {
999         createController();
1000         mController.setVisible(true);
1001 
1002         // GIVEN trust is granted
1003         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
1004 
1005         // WHEN the showTrustGranted method is called with a null message
1006         mController.getKeyguardCallback().onTrustGrantedForCurrentUser(
1007                 false, false, new TrustGrantFlags(0), null);
1008 
1009         // THEN verify the default trust granted message shows
1010         verifyIndicationMessage(
1011                 INDICATION_TYPE_TRUST,
1012                 getContext().getString(R.string.keyguard_indication_trust_unlocked));
1013     }
1014 
1015     @Test
onTrustGrantedMessage_emptyString_showsNoMessage()1016     public void onTrustGrantedMessage_emptyString_showsNoMessage() {
1017         createController();
1018         mController.setVisible(true);
1019 
1020         // GIVEN trust is granted
1021         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
1022 
1023         // WHEN the showTrustGranted method is called with an EMPTY string
1024         mController.getKeyguardCallback().onTrustGrantedForCurrentUser(
1025                 false, false, new TrustGrantFlags(0), "");
1026 
1027         // THEN verify NO trust message is shown
1028         verifyNoMessage(INDICATION_TYPE_TRUST);
1029     }
1030 
1031     @Test
coEx_faceSuccess_showsPressToOpen()1032     public void coEx_faceSuccess_showsPressToOpen() {
1033         // GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, no a11y enabled
1034         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
1035         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()))
1036                 .thenReturn(true);
1037         when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true);
1038         when(mAccessibilityManager.isEnabled()).thenReturn(false);
1039         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1040         createController();
1041         mController.setVisible(true);
1042 
1043         // WHEN face auth succeeds
1044         when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true);
1045         mController.getKeyguardCallback().onBiometricAuthenticated(0,
1046                 BiometricSourceType.FACE, false);
1047 
1048         // THEN 'face unlocked' then 'press unlock icon to open' message show
1049         String unlockedByFace = mContext.getString(R.string.keyguard_face_successful_unlock);
1050         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, unlockedByFace);
1051         String pressToOpen = mContext.getString(R.string.keyguard_unlock_press);
1052         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, pressToOpen);
1053     }
1054 
1055     @Test
coEx_faceSuccess_touchExplorationEnabled_showsFaceUnlockedSwipeToOpen()1056     public void coEx_faceSuccess_touchExplorationEnabled_showsFaceUnlockedSwipeToOpen() {
1057         // GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, a11y enabled
1058         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
1059         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()))
1060                 .thenReturn(true);
1061         when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true);
1062         when(mAccessibilityManager.isEnabled()).thenReturn(true);
1063         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
1064         createController();
1065         mController.setVisible(true);
1066 
1067         // WHEN face authenticated
1068         when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true);
1069         mController.getKeyguardCallback().onBiometricAuthenticated(0,
1070                 BiometricSourceType.FACE, false);
1071 
1072         // THEN show 'face unlocked' and 'swipe up to open' messages
1073         String unlockedByFace = mContext.getString(R.string.keyguard_face_successful_unlock);
1074         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, unlockedByFace);
1075         String swipeUpToOpen = mContext.getString(R.string.keyguard_unlock);
1076         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, swipeUpToOpen);
1077     }
1078 
1079     @Test
coEx_faceSuccess_a11yEnabled_showsFaceUnlockedSwipeToOpen()1080     public void coEx_faceSuccess_a11yEnabled_showsFaceUnlockedSwipeToOpen() {
1081         // GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, a11y is enabled
1082         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
1083         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()))
1084                 .thenReturn(true);
1085         when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true);
1086         when(mAccessibilityManager.isEnabled()).thenReturn(true);
1087         createController();
1088         mController.setVisible(true);
1089 
1090         // WHEN face auth is successful
1091         when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true);
1092         mController.getKeyguardCallback().onBiometricAuthenticated(0,
1093                 BiometricSourceType.FACE, false);
1094 
1095         // THEN show 'face unlocked' and 'swipe up to open' messages
1096         String unlockedByFace = mContext.getString(R.string.keyguard_face_successful_unlock);
1097         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, unlockedByFace);
1098         String swipeUpToOpen = mContext.getString(R.string.keyguard_unlock);
1099         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, swipeUpToOpen);
1100     }
1101 
1102     @Test
faceOnly_faceSuccess_showsFaceUnlockedSwipeToOpen()1103     public void faceOnly_faceSuccess_showsFaceUnlockedSwipeToOpen() {
1104         // GIVEN bouncer isn't showing, can skip bouncer, no udfps supported
1105         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
1106         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()))
1107                 .thenReturn(true);
1108         when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(false);
1109         createController();
1110         mController.setVisible(true);
1111 
1112         // WHEN face auth is successful
1113         when(mKeyguardUpdateMonitor.getIsFaceAuthenticated()).thenReturn(true);
1114         mController.getKeyguardCallback().onBiometricAuthenticated(0,
1115                 BiometricSourceType.FACE, false);
1116 
1117         // THEN show 'face unlocked' and 'swipe up to open' messages
1118         String unlockedByFace = mContext.getString(R.string.keyguard_face_successful_unlock);
1119         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, unlockedByFace);
1120         String swipeUpToOpen = mContext.getString(R.string.keyguard_unlock);
1121         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, swipeUpToOpen);
1122     }
1123 
1124     @Test
udfpsOnly_a11yEnabled_showsSwipeToOpen()1125     public void udfpsOnly_a11yEnabled_showsSwipeToOpen() {
1126         // GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, a11y is enabled
1127         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
1128         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()))
1129                 .thenReturn(true);
1130         when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true);
1131         when(mAccessibilityManager.isEnabled()).thenReturn(true);
1132         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
1133         createController();
1134         mController.setVisible(true);
1135 
1136         // WHEN showActionToUnlock
1137         mController.showActionToUnlock();
1138 
1139         // THEN show 'swipe up to open' message
1140         String swipeToOpen = mContext.getString(R.string.keyguard_unlock);
1141         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, swipeToOpen);
1142     }
1143 
1144     @Test
udfpsOnly_showsPressToOpen()1145     public void udfpsOnly_showsPressToOpen() {
1146         // GIVEN bouncer isn't showing, udfps is supported, a11y is NOT enabled, can skip bouncer
1147         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
1148         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()))
1149                 .thenReturn(true);
1150         when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true);
1151         when(mAccessibilityManager.isEnabled()).thenReturn(false);
1152         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
1153         createController();
1154         mController.setVisible(true);
1155 
1156         // WHEN showActionToUnlock
1157         mController.showActionToUnlock();
1158 
1159         // THEN show 'press unlock icon to open' message
1160         String pressToOpen = mContext.getString(R.string.keyguard_unlock_press);
1161         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, pressToOpen);
1162     }
1163 
1164     @Test
canSkipBouncer_noSecurity_showSwipeToUnlockHint()1165     public void canSkipBouncer_noSecurity_showSwipeToUnlockHint() {
1166         // GIVEN bouncer isn't showing, can skip bouncer, no security (udfps isn't supported,
1167         // face wasn't authenticated)
1168         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
1169         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()))
1170                 .thenReturn(true);
1171         when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(false);
1172         createController();
1173         mController.setVisible(true);
1174 
1175         // WHEN showActionToUnlock
1176         mController.showActionToUnlock();
1177 
1178         // THEN show 'swipe up to open' message
1179         String swipeToOpen = mContext.getString(R.string.keyguard_unlock);
1180         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, swipeToOpen);
1181     }
1182 
1183     @Test
cannotSkipBouncer_showSwipeToUnlockHint()1184     public void cannotSkipBouncer_showSwipeToUnlockHint() {
1185         // GIVEN bouncer isn't showing and cannot skip bouncer
1186         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
1187         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(getCurrentUser()))
1188                 .thenReturn(false);
1189         createController();
1190         mController.setVisible(true);
1191 
1192         // WHEN showActionToUnlock
1193         mController.showActionToUnlock();
1194 
1195         // THEN show 'swipe up to open' message
1196         String swipeToOpen = mContext.getString(R.string.keyguard_unlock);
1197         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, swipeToOpen);
1198     }
1199 
1200     @Test
faceOnAcquired_processFrame()1201     public void faceOnAcquired_processFrame() {
1202         createController();
1203 
1204         // WHEN face sends an acquired message
1205         final int acquireInfo = 1;
1206         mKeyguardUpdateMonitorCallback.onBiometricAcquired(BiometricSourceType.FACE, acquireInfo);
1207 
1208         // THEN face help message deferral should process the acquired frame
1209         verify(mFaceHelpMessageDeferral).processFrame(acquireInfo);
1210     }
1211 
1212     @Test
fingerprintOnAcquired_noProcessFrame()1213     public void fingerprintOnAcquired_noProcessFrame() {
1214         createController();
1215 
1216         // WHEN fingerprint sends an acquired message
1217         mKeyguardUpdateMonitorCallback.onBiometricAcquired(BiometricSourceType.FINGERPRINT, 1);
1218 
1219         // THEN face help message deferral should NOT process any acquired frames
1220         verify(mFaceHelpMessageDeferral, never()).processFrame(anyInt());
1221     }
1222 
1223     @Test
onBiometricHelp_fingerprint_faceHelpMessageDeferralDoesNothing()1224     public void onBiometricHelp_fingerprint_faceHelpMessageDeferralDoesNothing() {
1225         createController();
1226 
1227         // WHEN fingerprint sends an onBiometricHelp
1228         mKeyguardUpdateMonitorCallback.onBiometricHelp(
1229                 1,
1230                 "placeholder",
1231                 BiometricSourceType.FINGERPRINT);
1232 
1233         // THEN face help message deferral is NOT: reset, updated, or checked for shouldDefer
1234         verify(mFaceHelpMessageDeferral, never()).reset();
1235         verify(mFaceHelpMessageDeferral, never()).updateMessage(anyInt(), anyString());
1236         verify(mFaceHelpMessageDeferral, never()).shouldDefer(anyInt());
1237     }
1238 
1239     @Test
onBiometricFailed_resetFaceHelpMessageDeferral()1240     public void onBiometricFailed_resetFaceHelpMessageDeferral() {
1241         createController();
1242 
1243         // WHEN face sends an onBiometricHelp BIOMETRIC_HELP_FACE_NOT_RECOGNIZED
1244         mKeyguardUpdateMonitorCallback.onBiometricAuthFailed(BiometricSourceType.FACE);
1245 
1246         // THEN face help message deferral is reset
1247         verify(mFaceHelpMessageDeferral).reset();
1248     }
1249 
1250     @Test
onBiometricError_resetFaceHelpMessageDeferral()1251     public void onBiometricError_resetFaceHelpMessageDeferral() {
1252         createController();
1253 
1254         // WHEN face has an error
1255         mKeyguardUpdateMonitorCallback.onBiometricError(4, "string",
1256                 BiometricSourceType.FACE);
1257 
1258         // THEN face help message deferral is reset
1259         verify(mFaceHelpMessageDeferral).reset();
1260     }
1261 
1262     @Test
onBiometricHelp_faceAcquiredInfo_faceHelpMessageDeferral()1263     public void onBiometricHelp_faceAcquiredInfo_faceHelpMessageDeferral() {
1264         createController();
1265 
1266         // WHEN face sends an onBiometricHelp BIOMETRIC_HELP_FACE_NOT_RECOGNIZED
1267         final int msgId = 1;
1268         final String helpString = "test";
1269         mKeyguardUpdateMonitorCallback.onBiometricHelp(
1270                 msgId,
1271                 "test",
1272                 BiometricSourceType.FACE);
1273 
1274         // THEN face help message deferral is NOT reset and message IS updated
1275         verify(mFaceHelpMessageDeferral, never()).reset();
1276         verify(mFaceHelpMessageDeferral).updateMessage(msgId, helpString);
1277     }
1278 
1279 
1280     @Test
onBiometricError_faceLockedOutFirstTime_showsThePassedInMessage()1281     public void onBiometricError_faceLockedOutFirstTime_showsThePassedInMessage() {
1282         createController();
1283         onFaceLockoutError("first lockout");
1284 
1285         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE, "first lockout");
1286     }
1287 
1288     @Test
onBiometricError_faceLockedOutFirstTimeAndFpAllowed_showsTheFpFollowupMessage()1289     public void onBiometricError_faceLockedOutFirstTimeAndFpAllowed_showsTheFpFollowupMessage() {
1290         createController();
1291         fingerprintUnlockIsPossibleAndAllowed();
1292         onFaceLockoutError("first lockout");
1293 
1294         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
1295                 mContext.getString(R.string.keyguard_suggest_fingerprint));
1296     }
1297 
1298     @Test
onBiometricError_faceLockedOutFirstTimeAndFpNotAllowed_showsDefaultFollowup()1299     public void onBiometricError_faceLockedOutFirstTimeAndFpNotAllowed_showsDefaultFollowup() {
1300         createController();
1301         fingerprintUnlockIsNotPossible();
1302         onFaceLockoutError("first lockout");
1303 
1304         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
1305                 mContext.getString(R.string.keyguard_unlock));
1306     }
1307 
1308     @Test
onBiometricError_faceLockedOutSecondTimeInSession_showsUnavailableMessage()1309     public void onBiometricError_faceLockedOutSecondTimeInSession_showsUnavailableMessage() {
1310         createController();
1311         onFaceLockoutError("first lockout");
1312         clearInvocations(mRotateTextViewController);
1313 
1314         onFaceLockoutError("second lockout");
1315 
1316         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE,
1317                 mContext.getString(R.string.keyguard_face_unlock_unavailable));
1318     }
1319 
1320     @Test
onBiometricError_faceLockedOutSecondTimeOnBouncer_showsUnavailableMessage()1321     public void onBiometricError_faceLockedOutSecondTimeOnBouncer_showsUnavailableMessage() {
1322         createController();
1323         onFaceLockoutError("first lockout");
1324         clearInvocations(mRotateTextViewController);
1325         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
1326 
1327         onFaceLockoutError("second lockout");
1328 
1329         verify(mStatusBarKeyguardViewManager)
1330                 .setKeyguardMessage(
1331                         eq(mContext.getString(R.string.keyguard_face_unlock_unavailable)),
1332                         any());
1333     }
1334 
1335     @Test
onBiometricError_faceLockedOutSecondTimeButUdfpsActive_showsNoMessage()1336     public void onBiometricError_faceLockedOutSecondTimeButUdfpsActive_showsNoMessage() {
1337         createController();
1338         onFaceLockoutError("first lockout");
1339         clearInvocations(mRotateTextViewController);
1340 
1341         when(mAuthController.isUdfpsFingerDown()).thenReturn(true);
1342         onFaceLockoutError("second lockout");
1343 
1344         verifyNoMoreInteractions(mRotateTextViewController);
1345     }
1346 
1347     @Test
onBiometricError_faceLockedOutAgainAndFpAllowed_showsTheFpFollowupMessage()1348     public void onBiometricError_faceLockedOutAgainAndFpAllowed_showsTheFpFollowupMessage() {
1349         createController();
1350         fingerprintUnlockIsPossibleAndAllowed();
1351         onFaceLockoutError("first lockout");
1352         clearInvocations(mRotateTextViewController);
1353 
1354         onFaceLockoutError("second lockout");
1355 
1356         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
1357                 mContext.getString(R.string.keyguard_suggest_fingerprint));
1358     }
1359 
1360     @Test
onBiometricError_faceLockedOutAgainAndFpNotAllowed_showsDefaultFollowup()1361     public void onBiometricError_faceLockedOutAgainAndFpNotAllowed_showsDefaultFollowup() {
1362         createController();
1363         fingerprintUnlockIsNotPossible();
1364         onFaceLockoutError("first lockout");
1365         clearInvocations(mRotateTextViewController);
1366 
1367         onFaceLockoutError("second lockout");
1368 
1369         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
1370                 mContext.getString(R.string.keyguard_unlock));
1371     }
1372 
1373     @Test
onBiometricError_whenFaceLockoutReset_onLockOutError_showsPassedInMessage()1374     public void onBiometricError_whenFaceLockoutReset_onLockOutError_showsPassedInMessage() {
1375         createController();
1376         onFaceLockoutError("first lockout");
1377         clearInvocations(mRotateTextViewController);
1378         when(mKeyguardUpdateMonitor.isFaceLockedOut()).thenReturn(false);
1379         mKeyguardUpdateMonitorCallback.onLockedOutStateChanged(BiometricSourceType.FACE);
1380 
1381         onFaceLockoutError("second lockout");
1382 
1383         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE, "second lockout");
1384     }
1385 
1386     @Test
onFpLockoutStateChanged_whenFpIsLockedOut_showsPersistentMessage()1387     public void onFpLockoutStateChanged_whenFpIsLockedOut_showsPersistentMessage() {
1388         createController();
1389         mController.setVisible(true);
1390         when(mKeyguardUpdateMonitor.isFingerprintLockedOut()).thenReturn(true);
1391 
1392         mKeyguardUpdateMonitorCallback.onLockedOutStateChanged(BiometricSourceType.FINGERPRINT);
1393 
1394         verifyIndicationShown(INDICATION_TYPE_PERSISTENT_UNLOCK_MESSAGE,
1395                 mContext.getString(R.string.keyguard_unlock));
1396     }
1397 
1398     @Test
onFpLockoutStateChanged_whenFpIsNotLockedOut_showsPersistentMessage()1399     public void onFpLockoutStateChanged_whenFpIsNotLockedOut_showsPersistentMessage() {
1400         createController();
1401         mController.setVisible(true);
1402         clearInvocations(mRotateTextViewController);
1403         when(mKeyguardUpdateMonitor.isFingerprintLockedOut()).thenReturn(false);
1404 
1405         mKeyguardUpdateMonitorCallback.onLockedOutStateChanged(BiometricSourceType.FINGERPRINT);
1406 
1407         verifyHideIndication(INDICATION_TYPE_PERSISTENT_UNLOCK_MESSAGE);
1408     }
1409 
1410     @Test
onVisibilityChange_showsPersistentMessage_ifFpIsLockedOut()1411     public void onVisibilityChange_showsPersistentMessage_ifFpIsLockedOut() {
1412         createController();
1413         mController.setVisible(false);
1414         when(mKeyguardUpdateMonitor.isFingerprintLockedOut()).thenReturn(true);
1415         mKeyguardUpdateMonitorCallback.onLockedOutStateChanged(BiometricSourceType.FINGERPRINT);
1416         clearInvocations(mRotateTextViewController);
1417 
1418         mController.setVisible(true);
1419 
1420         verifyIndicationShown(INDICATION_TYPE_PERSISTENT_UNLOCK_MESSAGE,
1421                 mContext.getString(R.string.keyguard_unlock));
1422     }
1423 
1424     @Test
onBiometricError_whenFaceIsLocked_onMultipleLockOutErrors_showUnavailableMessage()1425     public void onBiometricError_whenFaceIsLocked_onMultipleLockOutErrors_showUnavailableMessage() {
1426         createController();
1427         onFaceLockoutError("first lockout");
1428         clearInvocations(mRotateTextViewController);
1429         when(mKeyguardUpdateMonitor.isFaceLockedOut()).thenReturn(true);
1430         mKeyguardUpdateMonitorCallback.onLockedOutStateChanged(BiometricSourceType.FACE);
1431 
1432         onFaceLockoutError("second lockout");
1433 
1434         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE,
1435                 mContext.getString(R.string.keyguard_face_unlock_unavailable));
1436     }
1437 
1438     @Test
onBiometricError_screenIsTurningOn_faceLockedOutFpIsNotAvailable_showsMessage()1439     public void onBiometricError_screenIsTurningOn_faceLockedOutFpIsNotAvailable_showsMessage() {
1440         createController();
1441         screenIsTurningOn();
1442         fingerprintUnlockIsNotPossible();
1443 
1444         onFaceLockoutError("lockout error");
1445         verifyNoMoreInteractions(mRotateTextViewController);
1446 
1447         mScreenObserver.onScreenTurnedOn();
1448 
1449         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE,
1450                 "lockout error");
1451         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
1452                 mContext.getString(R.string.keyguard_unlock));
1453     }
1454 
1455     @Test
onBiometricError_screenIsTurningOn_faceLockedOutFpIsAvailable_showsMessage()1456     public void onBiometricError_screenIsTurningOn_faceLockedOutFpIsAvailable_showsMessage() {
1457         createController();
1458         screenIsTurningOn();
1459         fingerprintUnlockIsPossibleAndAllowed();
1460 
1461         onFaceLockoutError("lockout error");
1462         verifyNoMoreInteractions(mRotateTextViewController);
1463 
1464         mScreenObserver.onScreenTurnedOn();
1465 
1466         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE,
1467                 "lockout error");
1468         verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
1469                 mContext.getString(R.string.keyguard_suggest_fingerprint));
1470     }
1471 
screenIsTurningOn()1472     private void screenIsTurningOn() {
1473         when(mScreenLifecycle.getScreenState()).thenReturn(SCREEN_TURNING_ON);
1474     }
1475 
sendUpdateDisclosureBroadcast()1476     private void sendUpdateDisclosureBroadcast() {
1477         mBroadcastReceiver.onReceive(mContext, new Intent());
1478     }
1479 
verifyIndicationMessages(int type, Set<CharSequence> messages)1480     private void verifyIndicationMessages(int type, Set<CharSequence> messages) {
1481         verify(mRotateTextViewController, times(messages.size())).updateIndication(eq(type),
1482                 mKeyguardIndicationCaptor.capture(), anyBoolean());
1483         List<KeyguardIndication> kis = mKeyguardIndicationCaptor.getAllValues();
1484 
1485         for (KeyguardIndication ki : kis) {
1486             final CharSequence msg = ki.getMessage();
1487             assertTrue(messages.contains(msg)); // check message is shown
1488             messages.remove(msg);
1489         }
1490         assertThat(messages.size()).isEqualTo(0); // check that all messages accounted for (removed)
1491     }
1492 
verifyIndicationMessage(int type, String message)1493     private void verifyIndicationMessage(int type, String message) {
1494         verify(mRotateTextViewController).updateIndication(eq(type),
1495                 mKeyguardIndicationCaptor.capture(), anyBoolean());
1496         assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
1497                 .isEqualTo(message);
1498     }
1499 
verifyHideIndication(int type)1500     private void verifyHideIndication(int type) {
1501         if (type == INDICATION_TYPE_TRANSIENT) {
1502             verify(mRotateTextViewController).hideTransient();
1503             verify(mRotateTextViewController, never()).showTransient(anyString());
1504         } else {
1505             verify(mRotateTextViewController).hideIndication(type);
1506             verify(mRotateTextViewController, never()).updateIndication(eq(type),
1507                     anyObject(), anyBoolean());
1508         }
1509     }
1510 
verifyTransientMessage(String message)1511     private void verifyTransientMessage(String message) {
1512         verify(mRotateTextViewController).showTransient(eq(message));
1513     }
1514 
verifyNoMessage(int type)1515     private void verifyNoMessage(int type) {
1516         if (type == INDICATION_TYPE_TRANSIENT) {
1517             verify(mRotateTextViewController, never()).showTransient(anyString());
1518         } else {
1519             verify(mRotateTextViewController, never()).updateIndication(eq(type),
1520                     anyObject(), anyBoolean());
1521         }
1522     }
1523 
verifyIndicationShown(int indicationType, String message)1524     private void verifyIndicationShown(int indicationType, String message) {
1525         verify(mRotateTextViewController)
1526                 .updateIndication(eq(indicationType),
1527                         mKeyguardIndicationCaptor.capture(),
1528                         eq(true));
1529         assertThat(mKeyguardIndicationCaptor.getValue().getMessage().toString())
1530                 .isEqualTo(message);
1531     }
1532 
fingerprintUnlockIsNotPossible()1533     private void fingerprintUnlockIsNotPossible() {
1534         setupFingerprintUnlockPossible(false);
1535     }
1536 
fingerprintUnlockIsPossibleAndAllowed()1537     private void fingerprintUnlockIsPossibleAndAllowed() {
1538         setupFingerprintUnlockPossible(true);
1539         when(mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed()).thenReturn(true);
1540     }
1541 
setupFingerprintUnlockPossible(boolean possible)1542     private void setupFingerprintUnlockPossible(boolean possible) {
1543         when(mKeyguardUpdateMonitor
1544                 .getCachedIsUnlockWithFingerprintPossible(getCurrentUser()))
1545                 .thenReturn(possible);
1546     }
1547 
getCurrentUser()1548     private int getCurrentUser() {
1549         return mCurrentUserId;
1550     }
1551 
onFaceLockoutError(String errMsg)1552     private void onFaceLockoutError(String errMsg) {
1553         mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_LOCKOUT_PERMANENT,
1554                 errMsg,
1555                 BiometricSourceType.FACE);
1556     }
1557 }
1558