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