1 /* 2 * Copyright (C) 2018 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.server.wm; 18 19 import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; 20 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; 21 import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; 22 import static android.app.StatusBarManager.DISABLE2_MASK; 23 import static android.app.StatusBarManager.DISABLE2_NONE; 24 import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE; 25 import static android.app.StatusBarManager.DISABLE_HOME; 26 import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ALERTS; 27 import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS; 28 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK; 29 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME; 30 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD; 31 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NONE; 32 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS; 33 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; 34 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; 35 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; 36 import static android.os.Process.SYSTEM_UID; 37 import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; 38 39 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 40 41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; 42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; 43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; 44 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 45 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; 46 import static com.android.dx.mockito.inline.extended.ExtendedMockito.isNull; 47 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 48 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; 49 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; 50 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; 51 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 52 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; 53 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED; 54 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_DONT_LOCK; 55 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE; 56 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; 57 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_PINNABLE; 58 import static com.android.server.wm.LockTaskController.STATUS_BAR_MASK_LOCKED; 59 import static com.android.server.wm.LockTaskController.STATUS_BAR_MASK_PINNED; 60 61 import static org.junit.Assert.assertEquals; 62 import static org.junit.Assert.assertFalse; 63 import static org.junit.Assert.assertTrue; 64 65 import android.app.StatusBarManager; 66 import android.app.admin.DevicePolicyManager; 67 import android.app.admin.IDevicePolicyManager; 68 import android.content.ComponentName; 69 import android.content.Context; 70 import android.content.Intent; 71 import android.os.Handler; 72 import android.os.IBinder; 73 import android.os.Looper; 74 import android.os.Message; 75 import android.os.UserHandle; 76 import android.platform.test.annotations.Presubmit; 77 import android.provider.Settings; 78 import android.telecom.TelecomManager; 79 import android.testing.DexmakerShareClassLoaderRule; 80 import android.util.Pair; 81 82 import androidx.test.filters.SmallTest; 83 84 import com.android.internal.statusbar.IStatusBarService; 85 import com.android.internal.telephony.CellBroadcastUtils; 86 import com.android.internal.widget.LockPatternUtils; 87 import com.android.server.LocalServices; 88 import com.android.server.statusbar.StatusBarManagerInternal; 89 90 import org.junit.After; 91 import org.junit.Before; 92 import org.junit.Rule; 93 import org.junit.Test; 94 import org.mockito.Mock; 95 import org.mockito.MockitoAnnotations; 96 import org.mockito.verification.VerificationMode; 97 98 /** 99 * Unit tests for {@link LockTaskController}. 100 * 101 * Build/Install/Run: 102 * atest WmTests:LockTaskControllerTest 103 */ 104 @SmallTest 105 @Presubmit 106 public class LockTaskControllerTest { 107 private static final String TEST_PACKAGE_NAME = "com.test.package"; 108 private static final String TEST_PACKAGE_NAME_2 = "com.test.package2"; 109 private static final String TEST_CLASS_NAME = ".TestClass"; 110 private static final int TEST_USER_ID = 123; 111 private static final int TEST_UID = 10467; 112 113 @Rule 114 public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = 115 new DexmakerShareClassLoaderRule(); 116 117 @Mock private ActivityTaskSupervisor mSupervisor; 118 @Mock private RootWindowContainer mRootWindowContainer; 119 @Mock private IDevicePolicyManager mDevicePolicyManager; 120 @Mock private IStatusBarService mStatusBarService; 121 @Mock private WindowManagerService mWindowManager; 122 @Mock private LockPatternUtils mLockPatternUtils; 123 @Mock private StatusBarManagerInternal mStatusBarManagerInternal; 124 @Mock private TelecomManager mTelecomManager; 125 @Mock private RecentTasks mRecentTasks; 126 @Mock private TaskChangeNotificationController mTaskChangeNotificationController; 127 128 private LockTaskController mLockTaskController; 129 private Context mContext; 130 private String mPackageName; 131 private String mLockToAppSetting; 132 133 @Before setUp()134 public void setUp() throws Exception { 135 MockitoAnnotations.initMocks(this); 136 137 mContext = getInstrumentation().getTargetContext(); 138 mPackageName = mContext.getPackageName(); 139 mLockToAppSetting = Settings.Secure.getString(mContext.getContentResolver(), 140 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED); 141 142 if (Looper.myLooper() == null) { 143 Looper.prepare(); 144 } 145 146 mSupervisor.mRecentTasks = mRecentTasks; 147 mSupervisor.mRootWindowContainer = mRootWindowContainer; 148 149 mLockTaskController = new LockTaskController(mContext, mSupervisor, 150 new ImmediatelyExecuteHandler(), mTaskChangeNotificationController); 151 mLockTaskController.setWindowManager(mWindowManager); 152 mLockTaskController.mStatusBarService = mStatusBarService; 153 mLockTaskController.mDevicePolicyManager = mDevicePolicyManager; 154 mLockTaskController.mTelecomManager = mTelecomManager; 155 mLockTaskController.mLockPatternUtils = mLockPatternUtils; 156 157 LocalServices.removeServiceForTest(StatusBarManagerInternal.class); 158 LocalServices.addService(StatusBarManagerInternal.class, mStatusBarManagerInternal); 159 } 160 161 @After tearDown()162 public void tearDown() throws Exception { 163 mLockTaskController.setWindowManager(null); 164 Settings.Secure.putString(mContext.getContentResolver(), 165 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, mLockToAppSetting); 166 } 167 168 @Test testPreconditions()169 public void testPreconditions() { 170 // GIVEN nothing has happened 171 172 // THEN current lock task mode should be NONE 173 assertEquals(LOCK_TASK_MODE_NONE, mLockTaskController.getLockTaskModeState()); 174 } 175 176 @Test testStartLockTaskMode_once()177 public void testStartLockTaskMode_once() throws Exception { 178 // GIVEN a task record with allowlisted auth 179 Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 180 181 // WHEN calling setLockTaskMode for LOCKED mode without resuming 182 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 183 184 // THEN the lock task mode state should be LOCKED 185 assertEquals(LOCK_TASK_MODE_LOCKED, mLockTaskController.getLockTaskModeState()); 186 // THEN the task should be locked 187 assertTrue(mLockTaskController.isTaskLocked(tr)); 188 189 // THEN lock task mode should be started 190 verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK); 191 } 192 193 @Test testStartLockTaskMode_twice()194 public void testStartLockTaskMode_twice() throws Exception { 195 // GIVEN two task records with allowlisted auth 196 Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 197 Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 198 199 // WHEN calling setLockTaskMode for LOCKED mode on both tasks 200 mLockTaskController.startLockTaskMode(tr1, false, TEST_UID); 201 mLockTaskController.startLockTaskMode(tr2, false, TEST_UID); 202 203 // THEN the lock task mode state should be LOCKED 204 assertEquals(LOCK_TASK_MODE_LOCKED, mLockTaskController.getLockTaskModeState()); 205 // THEN neither of the tasks should be able to move to back of stack 206 assertTrue(mLockTaskController.isTaskLocked(tr1)); 207 assertTrue(mLockTaskController.isTaskLocked(tr2)); 208 209 // THEN lock task mode should be started 210 verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK); 211 } 212 213 @Test testStartLockTaskMode_pinningRequest()214 public void testStartLockTaskMode_pinningRequest() { 215 // GIVEN a task record that is not allowlisted, i.e. with pinned auth 216 Task tr = getTask(LOCK_TASK_AUTH_PINNABLE); 217 218 // WHEN calling startLockTaskMode 219 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 220 221 // THEN a pinning request should be shown 222 verify(mStatusBarManagerInternal).showScreenPinningRequest(anyInt()); 223 } 224 225 @Test testStartLockTaskMode_pinnedBySystem()226 public void testStartLockTaskMode_pinnedBySystem() throws Exception { 227 // GIVEN a task record with pinned auth 228 Task tr = getTask(LOCK_TASK_AUTH_PINNABLE); 229 230 // WHEN the system calls startLockTaskMode 231 mLockTaskController.startLockTaskMode(tr, true, SYSTEM_UID); 232 233 // THEN the lock task mode state should be PINNED 234 assertEquals(LOCK_TASK_MODE_PINNED, mLockTaskController.getLockTaskModeState()); 235 // THEN the task should be locked 236 assertTrue(mLockTaskController.isTaskLocked(tr)); 237 238 // THEN lock task mode should be started 239 verifyLockTaskStarted(STATUS_BAR_MASK_PINNED, DISABLE2_NONE); 240 // THEN screen pinning toast should be shown 241 verify(mStatusBarService).showPinningEnterExitToast(eq(true /* entering */)); 242 } 243 244 @Test testLockTaskViolation()245 public void testLockTaskViolation() { 246 // GIVEN one task record with allowlisted auth that is in lock task mode 247 Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 248 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 249 250 // THEN it's not a lock task violation to try and launch this task without clearing 251 assertFalse(mLockTaskController.isLockTaskModeViolation(tr, false)); 252 253 // THEN it's a lock task violation to launch another task that is not allowlisted 254 assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(LOCK_TASK_AUTH_PINNABLE))); 255 // THEN it's a lock task violation to launch another task that is disallowed from lock task 256 assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(LOCK_TASK_AUTH_DONT_LOCK))); 257 258 // THEN it's no a lock task violation to launch another task that is allowlisted 259 assertFalse(mLockTaskController.isLockTaskModeViolation(getTask( 260 LOCK_TASK_AUTH_ALLOWLISTED))); 261 assertFalse(mLockTaskController.isLockTaskModeViolation(getTask( 262 LOCK_TASK_AUTH_LAUNCHABLE))); 263 // THEN it's not a lock task violation to launch another task that is priv launchable 264 assertFalse(mLockTaskController.isLockTaskModeViolation(getTask( 265 LOCK_TASK_AUTH_LAUNCHABLE_PRIV))); 266 } 267 268 @Test testLockTaskViolation_emergencyCall()269 public void testLockTaskViolation_emergencyCall() { 270 // GIVEN one task record with allowlisted auth that is in lock task mode 271 Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 272 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 273 274 // GIVEN tasks necessary for emergency calling 275 Task keypad = getTask(new Intent().setComponent(EMERGENCY_DIALER_COMPONENT), 276 LOCK_TASK_AUTH_PINNABLE); 277 Task callAction = getTask(new Intent(Intent.ACTION_CALL_EMERGENCY), 278 LOCK_TASK_AUTH_PINNABLE); 279 Task dialer = getTask("com.example.dialer", LOCK_TASK_AUTH_PINNABLE); 280 when(mTelecomManager.getSystemDialerPackage()) 281 .thenReturn(dialer.intent.getComponent().getPackageName()); 282 283 // GIVEN keyguard is allowed for lock task mode 284 mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_KEYGUARD); 285 286 // THEN the above tasks should all be allowed 287 assertFalse(mLockTaskController.isLockTaskModeViolation(keypad)); 288 assertFalse(mLockTaskController.isLockTaskModeViolation(callAction)); 289 assertFalse(mLockTaskController.isLockTaskModeViolation(dialer)); 290 291 // GIVEN keyguard is disallowed for lock task mode (default) 292 mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_NONE); 293 294 // THEN the above tasks should all be blocked 295 assertTrue(mLockTaskController.isLockTaskModeViolation(keypad)); 296 assertTrue(mLockTaskController.isLockTaskModeViolation(callAction)); 297 assertTrue(mLockTaskController.isLockTaskModeViolation(dialer)); 298 } 299 300 @Test testLockTaskViolation_wirelessEmergencyAlerts()301 public void testLockTaskViolation_wirelessEmergencyAlerts() { 302 // GIVEN one task record with allowlisted auth that is in lock task mode 303 Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 304 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 305 306 // GIVEN cellbroadcast task necessary for emergency warning alerts 307 Task cellbroadcastreceiver = getTask( 308 new Intent().setComponent( 309 CellBroadcastUtils.getDefaultCellBroadcastAlertDialogComponent(mContext)), 310 LOCK_TASK_AUTH_PINNABLE); 311 312 // THEN the cellbroadcast task should all be allowed 313 assertFalse(mLockTaskController.isLockTaskModeViolation(cellbroadcastreceiver)); 314 } 315 316 @Test testStopLockTaskMode()317 public void testStopLockTaskMode() throws Exception { 318 // GIVEN one task record with allowlisted auth that is in lock task mode 319 Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 320 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 321 322 // WHEN the same caller calls stopLockTaskMode 323 mLockTaskController.stopLockTaskMode(tr, false, TEST_UID); 324 325 // THEN the lock task mode should be NONE 326 assertEquals(LOCK_TASK_MODE_NONE, mLockTaskController.getLockTaskModeState()); 327 // THEN the task should no longer be locked 328 assertFalse(mLockTaskController.isTaskLocked(tr)); 329 // THEN lock task mode should have been finished 330 verifyLockTaskStopped(times(1)); 331 } 332 333 @Test(expected = SecurityException.class) testStopLockTaskMode_differentCaller()334 public void testStopLockTaskMode_differentCaller() { 335 // GIVEN one task record with allowlisted auth that is in lock task mode 336 Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 337 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 338 339 // WHEN a different caller calls stopLockTaskMode 340 mLockTaskController.stopLockTaskMode(tr, false, TEST_UID + 1); 341 342 // THEN security exception should be thrown, because different caller tried to unlock 343 } 344 345 @Test testStopLockTaskMode_systemCaller()346 public void testStopLockTaskMode_systemCaller() { 347 // GIVEN one task record with allowlisted auth that is in lock task mode 348 Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 349 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 350 351 // WHEN system calls stopLockTaskMode 352 mLockTaskController.stopLockTaskMode(tr, true, SYSTEM_UID); 353 354 // THEN lock task mode should still be active 355 assertEquals(LOCK_TASK_MODE_LOCKED, mLockTaskController.getLockTaskModeState()); 356 } 357 358 @Test testStopLockTaskMode_twoTasks()359 public void testStopLockTaskMode_twoTasks() throws Exception { 360 // GIVEN two task records with allowlisted auth that is in lock task mode 361 Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 362 Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 363 mLockTaskController.startLockTaskMode(tr1, false, TEST_UID); 364 mLockTaskController.startLockTaskMode(tr2, false, TEST_UID); 365 366 // WHEN calling stopLockTaskMode 367 mLockTaskController.stopLockTaskMode(tr2, false, TEST_UID); 368 369 // THEN the lock task mode should still be active 370 assertEquals(LOCK_TASK_MODE_LOCKED, mLockTaskController.getLockTaskModeState()); 371 // THEN the first task should still be locked 372 assertTrue(mLockTaskController.isTaskLocked(tr1)); 373 // THEN the top task should no longer be locked 374 assertFalse(mLockTaskController.isTaskLocked(tr2)); 375 // THEN lock task mode should not have been finished 376 verifyLockTaskStopped(never()); 377 } 378 379 @Test testStopLockTaskMode_rootTask()380 public void testStopLockTaskMode_rootTask() throws Exception { 381 // GIVEN two task records with allowlisted auth that is in lock task mode 382 Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 383 Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 384 mLockTaskController.startLockTaskMode(tr1, false, TEST_UID); 385 mLockTaskController.startLockTaskMode(tr2, false, TEST_UID); 386 387 // WHEN calling stopLockTaskMode on the root task 388 mLockTaskController.stopLockTaskMode(tr1, false, TEST_UID); 389 390 // THEN the lock task mode should be inactive 391 assertEquals(LOCK_TASK_MODE_NONE, mLockTaskController.getLockTaskModeState()); 392 // THEN the first task should no longer be locked 393 assertFalse(mLockTaskController.isTaskLocked(tr1)); 394 // THEN the top task should no longer be locked 395 assertFalse(mLockTaskController.isTaskLocked(tr2)); 396 // THEN lock task mode should be finished 397 verifyLockTaskStopped(times(1)); 398 } 399 400 @Test testStopLockTaskMode_pinned()401 public void testStopLockTaskMode_pinned() throws Exception { 402 // GIVEN one task records that is in pinned mode 403 Task tr = getTask(LOCK_TASK_AUTH_PINNABLE); 404 mLockTaskController.startLockTaskMode(tr, true, SYSTEM_UID); 405 // GIVEN that the keyguard is required to show after unlocking 406 Settings.Secure.putInt(mContext.getContentResolver(), 407 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 1); 408 409 // reset invocation counter 410 reset(mStatusBarService); 411 412 // WHEN calling stopLockTask 413 mLockTaskController.stopLockTaskMode(null, true, SYSTEM_UID); 414 415 // THEN the lock task mode should no longer be active 416 assertEquals(LOCK_TASK_MODE_NONE, mLockTaskController.getLockTaskModeState()); 417 // THEN the task should no longer be locked 418 assertFalse(mLockTaskController.isTaskLocked(tr)); 419 // THEN lock task mode should have been finished 420 verifyLockTaskStopped(times(1)); 421 // THEN the keyguard should be shown 422 verify(mLockPatternUtils).requireCredentialEntry(eq(UserHandle.USER_ALL)); 423 // THEN screen pinning toast should be shown 424 verify(mStatusBarService).showPinningEnterExitToast(eq(false /* entering */)); 425 } 426 427 @Test testClearLockedTasks()428 public void testClearLockedTasks() throws Exception { 429 // GIVEN two task records with allowlisted auth that is in lock task mode 430 Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 431 Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 432 mLockTaskController.startLockTaskMode(tr1, false, TEST_UID); 433 mLockTaskController.startLockTaskMode(tr2, false, TEST_UID); 434 435 // WHEN calling clearLockedTasks on the root task 436 mLockTaskController.clearLockedTasks("testClearLockedTasks"); 437 438 // THEN the lock task mode should be inactive 439 assertEquals(LOCK_TASK_MODE_NONE, mLockTaskController.getLockTaskModeState()); 440 // THEN the first task should no longer be locked 441 assertFalse(mLockTaskController.isTaskLocked(tr1)); 442 // THEN the top task should no longer be locked 443 assertFalse(mLockTaskController.isTaskLocked(tr2)); 444 // THEN lock task mode should be finished 445 verifyLockTaskStopped(times(1)); 446 } 447 448 @Test testClearLockedTasks_noLockSetting_noPassword_deviceIsUnlocked()449 public void testClearLockedTasks_noLockSetting_noPassword_deviceIsUnlocked() throws Exception { 450 // GIVEN There is no setting set for LOCK_TO_APP_EXIT_LOCKED 451 Settings.Secure.clearProviderForTest(); 452 453 // AND no password is set 454 when(mLockPatternUtils.getKeyguardStoredPasswordQuality(anyInt())) 455 .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); 456 457 // AND there is a task record 458 Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 459 mLockTaskController.startLockTaskMode(tr1, true, TEST_UID); 460 461 // WHEN calling clearLockedTasks on the root task 462 mLockTaskController.clearLockedTasks("testClearLockedTasks"); 463 464 // THEN the device should not be locked 465 verify(mWindowManager, never()).lockNow(any()); 466 } 467 468 @Test testClearLockedTasks_noLockSetting_password_deviceIsLocked()469 public void testClearLockedTasks_noLockSetting_password_deviceIsLocked() throws Exception { 470 // GIVEN There is no setting set for LOCK_TO_APP_EXIT_LOCKED 471 Settings.Secure.clearProviderForTest(); 472 473 // AND a password is set 474 when(mLockPatternUtils.isSecure(TEST_USER_ID)) 475 .thenReturn(true); 476 477 // AND there is a task record 478 Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 479 mLockTaskController.startLockTaskMode(tr1, true, TEST_UID); 480 481 // WHEN calling clearLockedTasks on the root task 482 mLockTaskController.clearLockedTasks("testClearLockedTasks"); 483 484 // THEN the device should be locked 485 verify(mWindowManager, times(1)).lockNow(any()); 486 } 487 488 @Test testClearLockedTasks_lockSettingTrue_deviceIsLocked()489 public void testClearLockedTasks_lockSettingTrue_deviceIsLocked() throws Exception { 490 // GIVEN LOCK_TO_APP_EXIT_LOCKED is set to 1 491 Settings.Secure.putIntForUser(mContext.getContentResolver(), 492 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 1, mContext.getUserId()); 493 494 // AND there is a task record 495 Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 496 mLockTaskController.startLockTaskMode(tr1, true, TEST_UID); 497 498 // WHEN calling clearLockedTasks on the root task 499 mLockTaskController.clearLockedTasks("testClearLockedTasks"); 500 501 // THEN the device should be locked 502 verify(mWindowManager, times(1)).lockNow(any()); 503 } 504 505 @Test testClearLockedTasks_lockSettingFalse_doesNotRequirePassword()506 public void testClearLockedTasks_lockSettingFalse_doesNotRequirePassword() throws Exception { 507 // GIVEN LOCK_TO_APP_EXIT_LOCKED is set to 1 508 Settings.Secure.putIntForUser(mContext.getContentResolver(), 509 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 0, mContext.getUserId()); 510 511 // AND there is a task record 512 Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 513 mLockTaskController.startLockTaskMode(tr1, true, TEST_UID); 514 515 // WHEN calling clearLockedTasks on the root task 516 mLockTaskController.clearLockedTasks("testClearLockedTasks"); 517 518 // THEN the device should be unlocked 519 verify(mWindowManager, never()).lockNow(any()); 520 } 521 522 @Test testUpdateLockTaskPackages()523 public void testUpdateLockTaskPackages() { 524 String[] allowlist1 = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2}; 525 String[] allowlist2 = {TEST_PACKAGE_NAME}; 526 527 // No package is allowlisted initially 528 for (String pkg : allowlist1) { 529 assertFalse("Package shouldn't be allowlisted: " + pkg, 530 mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg)); 531 assertFalse("Package shouldn't be allowlisted for user 0: " + pkg, 532 mLockTaskController.isPackageAllowlisted(0, pkg)); 533 } 534 535 // Apply allowlist 536 mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist1); 537 538 // Assert the allowlist is applied to the correct user 539 for (String pkg : allowlist1) { 540 assertTrue("Package should be allowlisted: " + pkg, 541 mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg)); 542 assertFalse("Package shouldn't be allowlisted for user 0: " + pkg, 543 mLockTaskController.isPackageAllowlisted(0, pkg)); 544 } 545 546 // Update allowlist 547 mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist2); 548 549 // Assert the new allowlist is applied 550 assertTrue("Package should remain allowlisted: " + TEST_PACKAGE_NAME, 551 mLockTaskController.isPackageAllowlisted(TEST_USER_ID, TEST_PACKAGE_NAME)); 552 assertFalse("Package should no longer be allowlisted: " + TEST_PACKAGE_NAME_2, 553 mLockTaskController.isPackageAllowlisted(TEST_USER_ID, TEST_PACKAGE_NAME_2)); 554 } 555 556 @Test testUpdateLockTaskPackages_taskRemoved()557 public void testUpdateLockTaskPackages_taskRemoved() throws Exception { 558 // GIVEN two tasks which are allowlisted initially 559 Task tr1 = getTaskForUpdate(TEST_PACKAGE_NAME, true); 560 Task tr2 = getTaskForUpdate(TEST_PACKAGE_NAME_2, false); 561 String[] allowlist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2}; 562 mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist); 563 564 // GIVEN the tasks are launched into LockTask mode 565 mLockTaskController.startLockTaskMode(tr1, false, TEST_UID); 566 mLockTaskController.startLockTaskMode(tr2, false, TEST_UID); 567 assertEquals(LOCK_TASK_MODE_LOCKED, mLockTaskController.getLockTaskModeState()); 568 assertTrue(mLockTaskController.isTaskLocked(tr1)); 569 assertTrue(mLockTaskController.isTaskLocked(tr2)); 570 verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK); 571 572 // WHEN removing one package from allowlist 573 allowlist = new String[] {TEST_PACKAGE_NAME}; 574 mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist); 575 576 // THEN the task running that package should be stopped 577 verify(tr2).performClearTaskForReuse(false /* excludingTaskOverlay*/); 578 assertFalse(mLockTaskController.isTaskLocked(tr2)); 579 // THEN the other task should remain locked 580 assertEquals(LOCK_TASK_MODE_LOCKED, mLockTaskController.getLockTaskModeState()); 581 assertTrue(mLockTaskController.isTaskLocked(tr1)); 582 verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK); 583 584 // WHEN removing the last package from allowlist 585 allowlist = new String[] {}; 586 mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist); 587 588 // THEN the last task should be cleared, and the system should quit LockTask mode 589 verify(tr1).performClearTaskForReuse(false /* excludingTaskOverlay*/); 590 assertFalse(mLockTaskController.isTaskLocked(tr1)); 591 assertEquals(LOCK_TASK_MODE_NONE, mLockTaskController.getLockTaskModeState()); 592 verifyLockTaskStopped(times(1)); 593 } 594 595 @Test testUpdateLockTaskFeatures()596 public void testUpdateLockTaskFeatures() throws Exception { 597 // GIVEN a locked task 598 Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 599 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 600 601 // THEN lock task mode should be started with default status bar masks 602 verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK); 603 604 // reset invocation counter 605 reset(mStatusBarService); 606 607 // WHEN home button is enabled for lock task mode 608 mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_HOME); 609 610 // THEN status bar should be updated to reflect this change 611 int expectedFlags = STATUS_BAR_MASK_LOCKED 612 & ~DISABLE_HOME; 613 int expectedFlags2 = DISABLE2_MASK; 614 verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class), 615 eq(mPackageName)); 616 verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class), 617 eq(mPackageName)); 618 619 // reset invocation counter 620 reset(mStatusBarService); 621 622 // WHEN notifications are enabled for lock task mode 623 mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_NOTIFICATIONS); 624 625 // THEN status bar should be updated to reflect this change 626 expectedFlags = STATUS_BAR_MASK_LOCKED 627 & ~DISABLE_NOTIFICATION_ICONS 628 & ~DISABLE_NOTIFICATION_ALERTS; 629 expectedFlags2 = DISABLE2_MASK 630 & ~DISABLE2_NOTIFICATION_SHADE; 631 verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class), 632 eq(mPackageName)); 633 verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class), 634 eq(mPackageName)); 635 } 636 637 @Test testUpdateLockTaskFeatures_differentUser()638 public void testUpdateLockTaskFeatures_differentUser() throws Exception { 639 // GIVEN a locked task 640 Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 641 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 642 643 // THEN lock task mode should be started with default status bar masks 644 verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK); 645 646 // reset invocation counter 647 reset(mStatusBarService); 648 649 // WHEN home button is enabled for lock task mode for another user 650 mLockTaskController.updateLockTaskFeatures(TEST_USER_ID + 1, LOCK_TASK_FEATURE_HOME); 651 652 // THEN status bar shouldn't change 653 verify(mStatusBarService, never()).disable(anyInt(), any(IBinder.class), 654 eq(mPackageName)); 655 verify(mStatusBarService, never()).disable2(anyInt(), any(IBinder.class), 656 eq(mPackageName)); 657 } 658 659 @Test testUpdateLockTaskFeatures_keyguard()660 public void testUpdateLockTaskFeatures_keyguard() { 661 // GIVEN a locked task 662 Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 663 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 664 665 // THEN keyguard should be disabled 666 verify(mWindowManager).disableKeyguard(any(IBinder.class), anyString(), eq(TEST_USER_ID)); 667 668 // WHEN keyguard is enabled for lock task mode 669 mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_KEYGUARD); 670 671 // THEN keyguard should be enabled 672 verify(mWindowManager).reenableKeyguard(any(IBinder.class), eq(TEST_USER_ID)); 673 674 // WHEN keyguard is disabled again for lock task mode 675 mLockTaskController.updateLockTaskFeatures(TEST_USER_ID, LOCK_TASK_FEATURE_NONE); 676 677 // THEN keyguard should be disabled 678 verify(mWindowManager, times(2)).disableKeyguard(any(IBinder.class), anyString(), 679 eq(TEST_USER_ID)); 680 } 681 682 @Test testGetStatusBarDisableFlags()683 public void testGetStatusBarDisableFlags() { 684 // Note that we don't enumerate all StatusBarManager flags, but only choose a subset to test 685 686 // WHEN nothing is enabled 687 Pair<Integer, Integer> flags = mLockTaskController.getStatusBarDisableFlags( 688 LOCK_TASK_FEATURE_NONE); 689 // THEN unsupported feature flags should still be untouched 690 assertTrue((~STATUS_BAR_MASK_LOCKED & flags.first) == 0); 691 // THEN everything else should be disabled 692 assertTrue((StatusBarManager.DISABLE_CLOCK & flags.first) != 0); 693 assertTrue((StatusBarManager.DISABLE2_QUICK_SETTINGS & flags.second) != 0); 694 695 // WHEN only home button is enabled 696 flags = mLockTaskController.getStatusBarDisableFlags( 697 LOCK_TASK_FEATURE_HOME); 698 // THEN unsupported feature flags should still be untouched 699 assertTrue((~STATUS_BAR_MASK_LOCKED & flags.first) == 0); 700 // THEN home button should indeed be enabled 701 assertTrue((StatusBarManager.DISABLE_HOME & flags.first) == 0); 702 // THEN other feature flags should remain disabled 703 assertTrue((StatusBarManager.DISABLE2_NOTIFICATION_SHADE & flags.second) != 0); 704 705 // WHEN only global actions menu and notifications are enabled 706 flags = mLockTaskController.getStatusBarDisableFlags( 707 DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS 708 | DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS); 709 // THEN unsupported feature flags should still be untouched 710 assertTrue((~STATUS_BAR_MASK_LOCKED & flags.first) == 0); 711 // THEN notifications should be enabled 712 assertTrue((StatusBarManager.DISABLE_NOTIFICATION_ICONS & flags.first) == 0); 713 assertTrue((StatusBarManager.DISABLE_NOTIFICATION_ALERTS & flags.first) == 0); 714 assertTrue((StatusBarManager.DISABLE2_NOTIFICATION_SHADE & flags.second) == 0); 715 // THEN global actions should be enabled 716 assertTrue((StatusBarManager.DISABLE2_GLOBAL_ACTIONS & flags.second) == 0); 717 // THEN quick settings should still be disabled 718 assertTrue((StatusBarManager.DISABLE2_QUICK_SETTINGS & flags.second) != 0); 719 } 720 721 @Test testIsActivityAllowed()722 public void testIsActivityAllowed() { 723 // WHEN lock task mode is not enabled 724 assertTrue(mLockTaskController.isActivityAllowed( 725 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT)); 726 727 // Start lock task mode 728 Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED); 729 mLockTaskController.startLockTaskMode(tr, false, TEST_UID); 730 731 // WHEN LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK is not enabled 732 assertTrue(mLockTaskController.isActivityAllowed( 733 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT)); 734 735 // Enable LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK feature 736 mLockTaskController.updateLockTaskFeatures( 737 TEST_USER_ID, LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK); 738 739 // package with LOCK_TASK_LAUNCH_MODE_ALWAYS should always be allowed 740 assertTrue(mLockTaskController.isActivityAllowed( 741 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_ALWAYS)); 742 743 // unallowlisted package should not be allowed 744 assertFalse(mLockTaskController.isActivityAllowed( 745 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT)); 746 747 // update the allowlist 748 String[] allowlist = new String[] { TEST_PACKAGE_NAME }; 749 mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist); 750 751 // allowlisted package should be allowed 752 assertTrue(mLockTaskController.isActivityAllowed( 753 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT)); 754 755 // package with LOCK_TASK_LAUNCH_MODE_NEVER should never be allowed 756 assertFalse(mLockTaskController.isActivityAllowed( 757 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_NEVER)); 758 } 759 getTask(int lockTaskAuth)760 private Task getTask(int lockTaskAuth) { 761 return getTask(TEST_PACKAGE_NAME, lockTaskAuth); 762 } 763 getTask(String pkg, int lockTaskAuth)764 private Task getTask(String pkg, int lockTaskAuth) { 765 final Intent intent = new Intent() 766 .setComponent(ComponentName.createRelative(pkg, TEST_CLASS_NAME)); 767 return getTask(intent, lockTaskAuth); 768 } 769 getTask(Intent intent, int lockTaskAuth)770 private Task getTask(Intent intent, int lockTaskAuth) { 771 Task tr = mock(Task.class); 772 tr.mLockTaskAuth = lockTaskAuth; 773 tr.intent = intent; 774 tr.mUserId = TEST_USER_ID; 775 return tr; 776 } 777 778 /** 779 * @param isAppAware {@code true} if the app has marked if allowlisted in its manifest 780 */ getTaskForUpdate(String pkg, boolean isAppAware)781 private Task getTaskForUpdate(String pkg, boolean isAppAware) { 782 final int authIfAllowlisted = 783 isAppAware ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_ALLOWLISTED; 784 Task tr = getTask(pkg, authIfAllowlisted); 785 doAnswer((invocation) -> { 786 boolean isAllowlisted = 787 mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg); 788 tr.mLockTaskAuth = isAllowlisted ? authIfAllowlisted : LOCK_TASK_AUTH_PINNABLE; 789 return null; 790 }).when(tr).setLockTaskAuth(); 791 return tr; 792 } 793 verifyLockTaskStarted(int statusBarMask, int statusBarMask2)794 private void verifyLockTaskStarted(int statusBarMask, int statusBarMask2) throws Exception { 795 // THEN the keyguard should have been disabled 796 verify(mWindowManager).disableKeyguard(any(IBinder.class), anyString(), eq(TEST_USER_ID)); 797 // THEN the status bar should have been disabled 798 verify(mStatusBarService).disable(eq(statusBarMask), any(IBinder.class), 799 eq(mPackageName)); 800 verify(mStatusBarService).disable2(eq(statusBarMask2), any(IBinder.class), 801 eq(mPackageName)); 802 // THEN recents should have been notified 803 verify(mRecentTasks).onLockTaskModeStateChanged(anyInt(), eq(TEST_USER_ID)); 804 // THEN the DO/PO should be informed about the operation 805 verify(mDevicePolicyManager).notifyLockTaskModeChanged(eq(true), eq(TEST_PACKAGE_NAME), 806 eq(TEST_USER_ID)); 807 } 808 verifyLockTaskStopped(VerificationMode mode)809 private void verifyLockTaskStopped(VerificationMode mode) throws Exception { 810 // THEN the keyguard should have been disabled 811 verify(mWindowManager, mode).reenableKeyguard(any(IBinder.class), eq(TEST_USER_ID)); 812 // THEN the status bar should have been disabled 813 verify(mStatusBarService, mode).disable(eq(StatusBarManager.DISABLE_NONE), 814 any(IBinder.class), eq(mPackageName)); 815 verify(mStatusBarService, mode).disable2(eq(StatusBarManager.DISABLE2_NONE), 816 any(IBinder.class), eq(mPackageName)); 817 // THEN the DO/PO should be informed about the operation 818 verify(mDevicePolicyManager, mode).notifyLockTaskModeChanged(eq(false), isNull(), 819 eq(TEST_USER_ID)); 820 } 821 822 /** 823 * Special handler implementation that executes any message / runnable posted immediately on the 824 * thread that it's posted on rather than enqueuing them on its looper. 825 */ 826 private static class ImmediatelyExecuteHandler extends Handler { 827 @Override sendMessageAtTime(Message msg, long uptimeMillis)828 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 829 if (msg.getCallback() != null) { 830 msg.getCallback().run(); 831 } 832 return true; 833 } 834 } 835 } 836