1 /*
2  * Copyright (C) 2019 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.policy;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.anyInt;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.when;
26 
27 import android.hardware.biometrics.BiometricSourceType;
28 import android.testing.AndroidTestingRunner;
29 import android.testing.TestableLooper;
30 
31 import androidx.test.filters.SmallTest;
32 
33 import com.android.internal.widget.LockPatternUtils;
34 import com.android.keyguard.KeyguardUpdateMonitor;
35 import com.android.keyguard.KeyguardUpdateMonitorCallback;
36 import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
37 import com.android.systemui.SysuiTestCase;
38 import com.android.systemui.dump.DumpManager;
39 import com.android.systemui.flags.FeatureFlags;
40 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
41 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
42 
43 import dagger.Lazy;
44 
45 import org.junit.Before;
46 import org.junit.Test;
47 import org.junit.runner.RunWith;
48 import org.mockito.ArgumentCaptor;
49 import org.mockito.Captor;
50 import org.mockito.Mock;
51 import org.mockito.MockitoAnnotations;
52 
53 import java.util.Random;
54 
55 @SmallTest
56 @TestableLooper.RunWithLooper
57 @RunWith(AndroidTestingRunner.class)
58 public class KeyguardStateControllerTest extends SysuiTestCase {
59 
60     @Mock
61     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
62     @Mock
63     private LockPatternUtils mLockPatternUtils;
64     private KeyguardStateController mKeyguardStateController;
65     @Mock
66     private DumpManager mDumpManager;
67     @Mock
68     private Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
69     @Mock
70     private SelectedUserInteractor mSelectedUserInteractor;
71     @Mock
72     private KeyguardUpdateMonitorLogger mLogger;
73     @Mock
74     private FeatureFlags mFeatureFlags;
75 
76     @Captor
77     private ArgumentCaptor<KeyguardUpdateMonitorCallback> mUpdateCallbackCaptor;
78 
79     @Before
setup()80     public void setup() {
81         MockitoAnnotations.initMocks(this);
82         mKeyguardStateController = new KeyguardStateControllerImpl(
83                 mContext,
84                 mKeyguardUpdateMonitor,
85                 mLockPatternUtils,
86                 mKeyguardUnlockAnimationControllerLazy,
87                 mLogger,
88                 mDumpManager,
89                 mFeatureFlags,
90                 mSelectedUserInteractor);
91     }
92 
93     @Test
testAddCallback_registersListener()94     public void testAddCallback_registersListener() {
95         verify(mKeyguardUpdateMonitor).registerCallback(any());
96     }
97 
98     @Test
testFaceAuthEnrolleddChanged_calledWhenFaceEnrollmentStateChanges()99     public void testFaceAuthEnrolleddChanged_calledWhenFaceEnrollmentStateChanges() {
100         KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class);
101 
102         when(mKeyguardUpdateMonitor.isFaceEnabledAndEnrolled()).thenReturn(false);
103         verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture());
104         mKeyguardStateController.addCallback(callback);
105         assertThat(mKeyguardStateController.isFaceEnrolledAndEnabled()).isFalse();
106 
107         when(mKeyguardUpdateMonitor.isFaceEnabledAndEnrolled()).thenReturn(true);
108         mUpdateCallbackCaptor.getValue().onBiometricEnrollmentStateChanged(
109                 BiometricSourceType.FACE);
110 
111         assertThat(mKeyguardStateController.isFaceEnrolledAndEnabled()).isTrue();
112         verify(callback).onFaceEnrolledChanged();
113     }
114 
115     @Test
testIsShowing()116     public void testIsShowing() {
117         assertThat(mKeyguardStateController.isShowing()).isFalse();
118         mKeyguardStateController.notifyKeyguardState(true /* showing */, false /* occluded */);
119         assertThat(mKeyguardStateController.isShowing()).isTrue();
120     }
121 
122     @Test
testIsMethodSecure()123     public void testIsMethodSecure() {
124         assertThat(mKeyguardStateController.isMethodSecure()).isFalse();
125 
126         when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
127         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
128         assertThat(mKeyguardStateController.isMethodSecure()).isTrue();
129     }
130 
131     @Test
testIsOccluded()132     public void testIsOccluded() {
133         assertThat(mKeyguardStateController.isOccluded()).isFalse();
134         mKeyguardStateController.notifyKeyguardState(false /* showing */, true /* occluded */);
135         assertThat(mKeyguardStateController.isOccluded()).isTrue();
136     }
137 
138     @Test
testCanSkipLockScreen()139     public void testCanSkipLockScreen() {
140         // Can skip because LockPatternUtils#isSecure is false
141         assertThat(mKeyguardStateController.canDismissLockScreen()).isTrue();
142 
143         // Cannot skip after there's a password/pin/pattern
144         when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
145         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
146         assertThat(mKeyguardStateController.canDismissLockScreen()).isFalse();
147 
148         // Unless user is authenticated
149         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(anyInt())).thenReturn(true);
150         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
151         assertThat(mKeyguardStateController.canDismissLockScreen()).isTrue();
152     }
153 
154     @Test
testCanSkipLockScreen_updateCalledOnFacesCleared()155     public void testCanSkipLockScreen_updateCalledOnFacesCleared() {
156         verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture());
157 
158         // Cannot skip after there's a password/pin/pattern
159         when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
160         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
161         assertThat(mKeyguardStateController.canDismissLockScreen()).isFalse();
162 
163         // Unless user is authenticated
164         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(anyInt())).thenReturn(true);
165         mUpdateCallbackCaptor.getValue().onFacesCleared();
166         assertThat(mKeyguardStateController.canDismissLockScreen()).isTrue();
167     }
168 
169     @Test
testCanSkipLockScreen_updateCalledOnFingerprintssCleared()170     public void testCanSkipLockScreen_updateCalledOnFingerprintssCleared() {
171         verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture());
172 
173         // Cannot skip after there's a password/pin/pattern
174         when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
175         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
176         assertThat(mKeyguardStateController.canDismissLockScreen()).isFalse();
177 
178         // Unless user is authenticated
179         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(anyInt())).thenReturn(true);
180         mUpdateCallbackCaptor.getValue().onFingerprintsCleared();
181         assertThat(mKeyguardStateController.canDismissLockScreen()).isTrue();
182     }
183 
184     @Test
testIsUnlocked()185     public void testIsUnlocked() {
186         // Is unlocked whenever the keyguard is not showing
187         assertThat(mKeyguardStateController.isShowing()).isFalse();
188         assertThat(mKeyguardStateController.isUnlocked()).isTrue();
189 
190         // Unlocked if showing, but insecure
191         mKeyguardStateController.notifyKeyguardState(true /* showing */, false /* occluded */);
192         assertThat(mKeyguardStateController.isUnlocked()).isTrue();
193 
194         // Locked if showing, and requires password
195         when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
196         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
197         assertThat(mKeyguardStateController.isUnlocked()).isFalse();
198 
199         // But unlocked after #getUserCanSkipBouncer allows it
200         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(anyInt())).thenReturn(true);
201         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
202         assertThat(mKeyguardStateController.isUnlocked()).isTrue();
203     }
204 
205     @Test
testIsTrusted()206     public void testIsTrusted() {
207         assertThat(mKeyguardStateController.isTrusted()).isFalse();
208 
209         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
210         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
211 
212         assertThat(mKeyguardStateController.isTrusted()).isTrue();
213     }
214 
215     @Test
testCallbacksAreInvoked()216     public void testCallbacksAreInvoked() {
217         KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class);
218         mKeyguardStateController.addCallback(callback);
219 
220         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
221         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
222 
223         verify(callback).onUnlockedChanged();
224     }
225 
226     @Test
testKeyguardDismissAmountCallbackInvoked()227     public void testKeyguardDismissAmountCallbackInvoked() {
228         KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class);
229         mKeyguardStateController.addCallback(callback);
230 
231         mKeyguardStateController.notifyKeyguardDismissAmountChanged(100f, false);
232 
233         verify(callback).onKeyguardDismissAmountChanged();
234     }
235 
236     @Test
testOnEnabledTrustAgentsChangedCallback()237     public void testOnEnabledTrustAgentsChangedCallback() {
238         final Random random = new Random();
239 
240         verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture());
241         final KeyguardStateController.Callback stateCallback =
242                 mock(KeyguardStateController.Callback.class);
243         mKeyguardStateController.addCallback(stateCallback);
244 
245         when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
246         mUpdateCallbackCaptor.getValue().onEnabledTrustAgentsChanged(random.nextInt());
247         verify(stateCallback).onUnlockedChanged();
248     }
249 }
250