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