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