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