1 /*
2  * Copyright (C) 2022 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.log;
18 
19 import static android.app.StatusBarManager.ALL_SESSIONS;
20 import static android.app.StatusBarManager.SESSION_BIOMETRIC_PROMPT;
21 import static android.app.StatusBarManager.SESSION_KEYGUARD;
22 
23 import static junit.framework.Assert.assertNotNull;
24 import static junit.framework.Assert.assertNull;
25 
26 import static org.junit.Assert.assertNotEquals;
27 import static org.mockito.ArgumentMatchers.any;
28 import static org.mockito.ArgumentMatchers.eq;
29 import static org.mockito.Mockito.never;
30 import static org.mockito.Mockito.times;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 
34 import android.os.RemoteException;
35 import android.testing.AndroidTestingRunner;
36 import android.testing.TestableLooper;
37 
38 import androidx.test.filters.SmallTest;
39 
40 import com.android.internal.logging.InstanceId;
41 import com.android.internal.logging.UiEventLogger;
42 import com.android.internal.statusbar.IStatusBarService;
43 import com.android.keyguard.KeyguardUpdateMonitor;
44 import com.android.keyguard.KeyguardUpdateMonitorCallback;
45 import com.android.systemui.SysuiTestCase;
46 import com.android.systemui.biometrics.AuthController;
47 import com.android.systemui.statusbar.policy.KeyguardStateController;
48 
49 import org.junit.Before;
50 import org.junit.Test;
51 import org.junit.runner.RunWith;
52 import org.mockito.ArgumentCaptor;
53 import org.mockito.Captor;
54 import org.mockito.Mock;
55 import org.mockito.MockitoAnnotations;
56 
57 @RunWith(AndroidTestingRunner.class)
58 @TestableLooper.RunWithLooper
59 @SmallTest
60 public class SessionTrackerTest extends SysuiTestCase {
61     @Mock
62     private IStatusBarService mStatusBarService;
63     @Mock
64     private AuthController mAuthController;
65     @Mock
66     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
67     @Mock
68     private KeyguardStateController mKeyguardStateController;
69     @Mock
70     private UiEventLogger mUiEventLogger;
71 
72     @Captor
73     ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
74     KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
75 
76     @Captor
77     ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateCallbackCaptor;
78     KeyguardStateController.Callback mKeyguardStateCallback;
79 
80     @Captor
81     ArgumentCaptor<AuthController.Callback> mAuthControllerCallbackCaptor;
82     AuthController.Callback mAuthControllerCallback;
83 
84     private SessionTracker mSessionTracker;
85 
86     @Before
setup()87     public void setup() throws RemoteException {
88         MockitoAnnotations.initMocks(this);
89 
90         mSessionTracker = new SessionTracker(
91                 mStatusBarService,
92                 mAuthController,
93                 mKeyguardUpdateMonitor,
94                 mKeyguardStateController,
95                 mUiEventLogger
96         );
97     }
98 
99     @Test
testOnStartShowingKeyguard()100     public void testOnStartShowingKeyguard() throws RemoteException {
101         // GIVEN the keyguard is showing before start
102         when(mKeyguardStateController.isShowing()).thenReturn(true);
103 
104         // WHEN started
105         mSessionTracker.start();
106 
107         // THEN keyguard session has a session id
108         assertNotNull(mSessionTracker.getSessionId(SESSION_KEYGUARD));
109 
110         // THEN send event to status bar service
111         verify(mStatusBarService).onSessionStarted(eq(SESSION_KEYGUARD), any(InstanceId.class));
112     }
113 
114     @Test
testNoSessions()115     public void testNoSessions() throws RemoteException {
116         // GIVEN no sessions
117         when(mKeyguardStateController.isShowing()).thenReturn(false);
118 
119         // WHEN started
120         mSessionTracker.start();
121 
122         // THEN all sessions are null
123         for (int sessionType : ALL_SESSIONS) {
124             assertNull(mSessionTracker.getSessionId(sessionType));
125         }
126     }
127 
128     @Test
testBiometricPromptShowing()129     public void testBiometricPromptShowing() throws RemoteException {
130         // GIVEN session tracker started w/o any sessions
131         mSessionTracker.start();
132         captureAuthControllerCallback();
133 
134         // WHEN auth controller shows the biometric prompt
135         mAuthControllerCallback.onBiometricPromptShown();
136 
137         // THEN the biometric prompt session has a session id
138         assertNotNull(mSessionTracker.getSessionId(SESSION_BIOMETRIC_PROMPT));
139 
140         // THEN session started event gets sent to status bar service
141         verify(mStatusBarService).onSessionStarted(
142                 eq(SESSION_BIOMETRIC_PROMPT), any(InstanceId.class));
143     }
144 
145     @Test
testBiometricPromptDismissed()146     public void testBiometricPromptDismissed() throws RemoteException {
147         // GIVEN session tracker started w/o any sessions
148         mSessionTracker.start();
149         captureAuthControllerCallback();
150 
151         // WHEN auth controller shows the biometric prompt and then hides it
152         mAuthControllerCallback.onBiometricPromptShown();
153         mAuthControllerCallback.onBiometricPromptDismissed();
154 
155         // THEN the biometric prompt session no longer has a session id
156         assertNull(mSessionTracker.getSessionId(SESSION_BIOMETRIC_PROMPT));
157 
158         // THEN session end event gets sent to status bar service
159         verify(mStatusBarService).onSessionEnded(
160                 eq(SESSION_BIOMETRIC_PROMPT), any(InstanceId.class));
161     }
162 
163     @Test
testKeyguardSessionOnDeviceStartsSleeping()164     public void testKeyguardSessionOnDeviceStartsSleeping() throws RemoteException {
165         // GIVEN session tracker started w/o any sessions
166         mSessionTracker.start();
167         captureKeyguardUpdateMonitorCallback();
168 
169         // WHEN device starts going to sleep
170         mKeyguardUpdateMonitorCallback.onStartedGoingToSleep(0);
171 
172         // THEN the keyguard session has a session id
173         assertNotNull(mSessionTracker.getSessionId(SESSION_KEYGUARD));
174 
175         // THEN session start event gets sent to status bar service
176         verify(mStatusBarService).onSessionStarted(
177                 eq(SESSION_KEYGUARD), any(InstanceId.class));
178     }
179 
180     @Test
testKeyguardSessionOnDeviceStartsSleepingTwiceInARow_startsNewKeyguardSession()181     public void testKeyguardSessionOnDeviceStartsSleepingTwiceInARow_startsNewKeyguardSession()
182             throws RemoteException {
183         // GIVEN session tracker started w/o any sessions
184         mSessionTracker.start();
185         captureKeyguardUpdateMonitorCallback();
186 
187         // WHEN device starts going to sleep
188         mKeyguardUpdateMonitorCallback.onStartedGoingToSleep(0);
189 
190         // THEN the keyguard session has a session id
191         final InstanceId firstSessionId = mSessionTracker.getSessionId(SESSION_KEYGUARD);
192         assertNotNull(firstSessionId);
193 
194         // WHEN device starts going to sleep a second time
195         mKeyguardUpdateMonitorCallback.onStartedGoingToSleep(0);
196 
197         // THEN there's a new keyguard session with a unique session id
198         final InstanceId secondSessionId = mSessionTracker.getSessionId(SESSION_KEYGUARD);
199         assertNotNull(secondSessionId);
200         assertNotEquals(firstSessionId, secondSessionId);
201 
202         // THEN session start event gets sent to status bar service twice (once per going to
203         // sleep signal)
204         verify(mStatusBarService, times(2)).onSessionStarted(
205                 eq(SESSION_KEYGUARD), any(InstanceId.class));
206     }
207 
208     @Test
testKeyguardSessionOnKeyguardShowingChange()209     public void testKeyguardSessionOnKeyguardShowingChange() throws RemoteException {
210         // GIVEN session tracker started w/o any sessions
211         mSessionTracker.start();
212         captureKeyguardStateControllerCallback();
213 
214         // WHEN keyguard becomes visible (ie: from lockdown)
215         when(mKeyguardStateController.isShowing()).thenReturn(true);
216         mKeyguardStateCallback.onKeyguardShowingChanged();
217 
218         // THEN the keyguard session has a session id
219         assertNotNull(mSessionTracker.getSessionId(SESSION_KEYGUARD));
220 
221         // THEN session start event gets sent to status bar service
222         verify(mStatusBarService).onSessionStarted(
223                 eq(SESSION_KEYGUARD), any(InstanceId.class));
224     }
225 
226     @Test
testKeyguardSessionOnKeyguardNotShowing()227     public void testKeyguardSessionOnKeyguardNotShowing() throws RemoteException {
228         // GIVEN session tracker started w/o any sessions
229         mSessionTracker.start();
230         captureKeyguardStateControllerCallback();
231 
232         // WHEN keyguard was showing and now it's not
233         when(mKeyguardStateController.isShowing()).thenReturn(true);
234         mKeyguardStateCallback.onKeyguardShowingChanged();
235         when(mKeyguardStateController.isShowing()).thenReturn(false);
236         mKeyguardStateCallback.onKeyguardShowingChanged();
237 
238         // THEN the keyguard session no longer has a session id
239         assertNull(mSessionTracker.getSessionId(SESSION_KEYGUARD));
240 
241         // THEN session end event gets sent to status bar service
242         verify(mStatusBarService).onSessionEnded(
243                 eq(SESSION_KEYGUARD), any(InstanceId.class));
244     }
245 
246     @Test
uiEventLoggedOnEndSessionWhenDeviceStartsSleeping()247     public void uiEventLoggedOnEndSessionWhenDeviceStartsSleeping() throws RemoteException {
248         // GIVEN session tracker start
249         mSessionTracker.start();
250         captureKeyguardUpdateMonitorCallback();
251         captureKeyguardStateControllerCallback();
252 
253         // GIVEN keyguard becomes visible (ie: from lockdown), so there's a valid keyguard
254         // session running
255         when(mKeyguardStateController.isShowing()).thenReturn(true);
256         mKeyguardStateCallback.onKeyguardShowingChanged();
257 
258         // WHEN device starts going to sleep
259         mKeyguardUpdateMonitorCallback.onStartedGoingToSleep(0);
260 
261         // THEN UI event is logged
262         verify(mUiEventLogger).log(
263                 eq(SessionTracker.SessionUiEvent.KEYGUARD_SESSION_END_GOING_TO_SLEEP),
264                 any(InstanceId.class));
265     }
266 
267     @Test
noUiEventLoggedOnEndSessionWhenDeviceStartsSleepingWithoutStartSession()268     public void noUiEventLoggedOnEndSessionWhenDeviceStartsSleepingWithoutStartSession()
269             throws RemoteException {
270         // GIVEN session tracker start without any valid sessions
271         mSessionTracker.start();
272         captureKeyguardUpdateMonitorCallback();
273 
274         // WHEN device starts going to sleep when there was no started sessions
275         mKeyguardUpdateMonitorCallback.onStartedGoingToSleep(0);
276 
277         // THEN UI event is never logged
278         verify(mUiEventLogger, never()).log(
279                 eq(SessionTracker.SessionUiEvent.KEYGUARD_SESSION_END_GOING_TO_SLEEP),
280                 any(InstanceId.class));
281     }
282 
283     @Test
uiEventLoggedOnEndSessionWhenKeyguardGoingAway()284     public void uiEventLoggedOnEndSessionWhenKeyguardGoingAway() throws RemoteException {
285         // GIVEN session tracker started w/o any sessions
286         mSessionTracker.start();
287         captureKeyguardUpdateMonitorCallback();
288         captureKeyguardStateControllerCallback();
289 
290         // WHEN keyguard was showing and now it's not
291         when(mKeyguardStateController.isShowing()).thenReturn(true);
292         mKeyguardStateCallback.onKeyguardShowingChanged();
293         when(mKeyguardStateController.isShowing()).thenReturn(false);
294         mKeyguardStateCallback.onKeyguardShowingChanged();
295 
296         // THEN UI event is logged
297         verify(mUiEventLogger).log(
298                 eq(SessionTracker.SessionUiEvent.KEYGUARD_SESSION_END_KEYGUARD_GOING_AWAY),
299                 any(InstanceId.class));
300     }
301 
captureKeyguardUpdateMonitorCallback()302     void captureKeyguardUpdateMonitorCallback() {
303         verify(mKeyguardUpdateMonitor).registerCallback(
304                 mKeyguardUpdateMonitorCallbackCaptor.capture());
305         mKeyguardUpdateMonitorCallback = mKeyguardUpdateMonitorCallbackCaptor.getValue();
306     }
307 
captureKeyguardStateControllerCallback()308     void captureKeyguardStateControllerCallback() {
309         verify(mKeyguardStateController).addCallback(
310                 mKeyguardStateCallbackCaptor.capture());
311         mKeyguardStateCallback = mKeyguardStateCallbackCaptor.getValue();
312     }
313 
captureAuthControllerCallback()314     void captureAuthControllerCallback() {
315         verify(mAuthController).addCallback(
316                 mAuthControllerCallbackCaptor.capture());
317         mAuthControllerCallback = mAuthControllerCallbackCaptor.getValue();
318     }
319 }
320