• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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