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 
42 import dagger.Lazy;
43 
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.mockito.ArgumentCaptor;
48 import org.mockito.Captor;
49 import org.mockito.Mock;
50 import org.mockito.MockitoAnnotations;
51 
52 import java.util.Random;
53 
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 KeyguardUpdateMonitorLogger mLogger;
71     @Mock
72     private FeatureFlags mFeatureFlags;
73 
74     @Captor
75     private ArgumentCaptor<KeyguardUpdateMonitorCallback> mUpdateCallbackCaptor;
76 
77     @Before
setup()78     public void setup() {
79         MockitoAnnotations.initMocks(this);
80         mKeyguardStateController = new KeyguardStateControllerImpl(
81                 mContext,
82                 mKeyguardUpdateMonitor,
83                 mLockPatternUtils,
84                 mKeyguardUnlockAnimationControllerLazy,
85                 mLogger,
86                 mDumpManager,
87                 mFeatureFlags);
88     }
89 
90     @Test
testAddCallback_registersListener()91     public void testAddCallback_registersListener() {
92         verify(mKeyguardUpdateMonitor).registerCallback(any());
93     }
94 
95     @Test
testFaceAuthEnabledChanged_calledWhenFaceEnrollmentStateChanges()96     public void testFaceAuthEnabledChanged_calledWhenFaceEnrollmentStateChanges() {
97         KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class);
98 
99         when(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(anyInt())).thenReturn(false);
100         verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture());
101         mKeyguardStateController.addCallback(callback);
102         assertThat(mKeyguardStateController.isFaceAuthEnabled()).isFalse();
103 
104         when(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(anyInt())).thenReturn(true);
105         mUpdateCallbackCaptor.getValue().onBiometricEnrollmentStateChanged(
106                 BiometricSourceType.FACE);
107 
108         assertThat(mKeyguardStateController.isFaceAuthEnabled()).isTrue();
109         verify(callback).onFaceAuthEnabledChanged();
110     }
111 
112     @Test
testIsShowing()113     public void testIsShowing() {
114         assertThat(mKeyguardStateController.isShowing()).isFalse();
115         mKeyguardStateController.notifyKeyguardState(true /* showing */, false /* occluded */);
116         assertThat(mKeyguardStateController.isShowing()).isTrue();
117     }
118 
119     @Test
testIsMethodSecure()120     public void testIsMethodSecure() {
121         assertThat(mKeyguardStateController.isMethodSecure()).isFalse();
122 
123         when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
124         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
125         assertThat(mKeyguardStateController.isMethodSecure()).isTrue();
126     }
127 
128     @Test
testIsOccluded()129     public void testIsOccluded() {
130         assertThat(mKeyguardStateController.isOccluded()).isFalse();
131         mKeyguardStateController.notifyKeyguardState(false /* showing */, true /* occluded */);
132         assertThat(mKeyguardStateController.isOccluded()).isTrue();
133     }
134 
135     @Test
testCanSkipLockScreen()136     public void testCanSkipLockScreen() {
137         // Can skip because LockPatternUtils#isSecure is false
138         assertThat(mKeyguardStateController.canDismissLockScreen()).isTrue();
139 
140         // Cannot skip after there's a password/pin/pattern
141         when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
142         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
143         assertThat(mKeyguardStateController.canDismissLockScreen()).isFalse();
144 
145         // Unless user is authenticated
146         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(anyInt())).thenReturn(true);
147         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
148         assertThat(mKeyguardStateController.canDismissLockScreen()).isTrue();
149     }
150 
151     @Test
testIsUnlocked()152     public void testIsUnlocked() {
153         // Is unlocked whenever the keyguard is not showing
154         assertThat(mKeyguardStateController.isShowing()).isFalse();
155         assertThat(mKeyguardStateController.isUnlocked()).isTrue();
156 
157         // Unlocked if showing, but insecure
158         mKeyguardStateController.notifyKeyguardState(true /* showing */, false /* occluded */);
159         assertThat(mKeyguardStateController.isUnlocked()).isTrue();
160 
161         // Locked if showing, and requires password
162         when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
163         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
164         assertThat(mKeyguardStateController.isUnlocked()).isFalse();
165 
166         // But unlocked after #getUserCanSkipBouncer allows it
167         when(mKeyguardUpdateMonitor.getUserCanSkipBouncer(anyInt())).thenReturn(true);
168         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
169         assertThat(mKeyguardStateController.isUnlocked()).isTrue();
170     }
171 
172     @Test
testIsTrusted()173     public void testIsTrusted() {
174         assertThat(mKeyguardStateController.isTrusted()).isFalse();
175 
176         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
177         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
178 
179         assertThat(mKeyguardStateController.isTrusted()).isTrue();
180     }
181 
182     @Test
testCallbacksAreInvoked()183     public void testCallbacksAreInvoked() {
184         KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class);
185         mKeyguardStateController.addCallback(callback);
186 
187         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
188         ((KeyguardStateControllerImpl) mKeyguardStateController).update(false /* alwaysUpdate */);
189 
190         verify(callback).onUnlockedChanged();
191     }
192 
193     @Test
testKeyguardDismissAmountCallbackInvoked()194     public void testKeyguardDismissAmountCallbackInvoked() {
195         KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class);
196         mKeyguardStateController.addCallback(callback);
197 
198         mKeyguardStateController.notifyKeyguardDismissAmountChanged(100f, false);
199 
200         verify(callback).onKeyguardDismissAmountChanged();
201     }
202 
203     @Test
testOnEnabledTrustAgentsChangedCallback()204     public void testOnEnabledTrustAgentsChangedCallback() {
205         final Random random = new Random();
206 
207         verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture());
208         final KeyguardStateController.Callback stateCallback =
209                 mock(KeyguardStateController.Callback.class);
210         mKeyguardStateController.addCallback(stateCallback);
211 
212         when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
213         mUpdateCallbackCaptor.getValue().onEnabledTrustAgentsChanged(random.nextInt());
214         verify(stateCallback).onUnlockedChanged();
215     }
216 }
217