1 /*
2  * Copyright 2017, 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.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
23 import static android.content.Context.DEVICE_POLICY_SERVICE;
24 import static android.content.Context.STATUS_BAR_SERVICE;
25 import static android.content.Intent.ACTION_CALL_EMERGENCY;
26 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
27 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
28 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
29 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
30 import static android.os.UserHandle.USER_ALL;
31 import static android.os.UserHandle.USER_CURRENT;
32 import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT;
33 
34 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
35 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
36 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
37 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
38 
39 import android.annotation.NonNull;
40 import android.annotation.Nullable;
41 import android.app.Activity;
42 import android.app.ActivityManager;
43 import android.app.StatusBarManager;
44 import android.app.admin.DevicePolicyManager;
45 import android.app.admin.IDevicePolicyManager;
46 import android.content.ComponentName;
47 import android.content.Context;
48 import android.content.Intent;
49 import android.os.Binder;
50 import android.os.Debug;
51 import android.os.Handler;
52 import android.os.IBinder;
53 import android.os.RemoteException;
54 import android.os.ServiceManager;
55 import android.os.UserHandle;
56 import android.provider.Settings;
57 import android.telecom.TelecomManager;
58 import android.util.Pair;
59 import android.util.Slog;
60 import android.util.SparseArray;
61 import android.util.SparseIntArray;
62 
63 import com.android.internal.annotations.VisibleForTesting;
64 import com.android.internal.policy.IKeyguardDismissCallback;
65 import com.android.internal.protolog.common.ProtoLog;
66 import com.android.internal.statusbar.IStatusBarService;
67 import com.android.internal.widget.LockPatternUtils;
68 import com.android.server.LocalServices;
69 import com.android.server.am.ActivityManagerService;
70 import com.android.server.statusbar.StatusBarManagerInternal;
71 
72 import java.io.PrintWriter;
73 import java.util.ArrayList;
74 import java.util.Arrays;
75 
76 /**
77  * Helper class that deals with all things related to task locking. This includes the screen pinning
78  * mode that can be launched via System UI as well as the fully locked mode that can be achieved
79  * on fully managed devices.
80  *
81  * Note: All methods in this class should only be called with the ActivityTaskManagerService lock
82  * held.
83  *
84  * @see Activity#startLockTask()
85  * @see Activity#stopLockTask()
86  */
87 public class LockTaskController {
88     private static final String TAG = TAG_WITH_CLASS_NAME ? "LockTaskController" : TAG_ATM;
89     private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
90 
91     @VisibleForTesting
92     static final int STATUS_BAR_MASK_LOCKED = StatusBarManager.DISABLE_MASK
93             & (~StatusBarManager.DISABLE_EXPAND)
94             & (~StatusBarManager.DISABLE_NOTIFICATION_TICKER)
95             & (~StatusBarManager.DISABLE_SYSTEM_INFO)
96             & (~StatusBarManager.DISABLE_BACK);
97     @VisibleForTesting
98     static final int STATUS_BAR_MASK_PINNED = StatusBarManager.DISABLE_MASK
99             & (~StatusBarManager.DISABLE_BACK)
100             & (~StatusBarManager.DISABLE_HOME)
101             & (~StatusBarManager.DISABLE_RECENT);
102 
103     private static final SparseArray<Pair<Integer, Integer>> STATUS_BAR_FLAG_MAP_LOCKED;
104     static {
105         STATUS_BAR_FLAG_MAP_LOCKED = new SparseArray<>();
106 
STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO, new Pair<>(StatusBarManager.DISABLE_CLOCK, StatusBarManager.DISABLE2_SYSTEM_ICONS))107         STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO,
108                 new Pair<>(StatusBarManager.DISABLE_CLOCK, StatusBarManager.DISABLE2_SYSTEM_ICONS));
109 
STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS, new Pair<>(StatusBarManager.DISABLE_NOTIFICATION_ICONS | StatusBarManager.DISABLE_NOTIFICATION_ALERTS, StatusBarManager.DISABLE2_NOTIFICATION_SHADE))110         STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS,
111                 new Pair<>(StatusBarManager.DISABLE_NOTIFICATION_ICONS
112                         | StatusBarManager.DISABLE_NOTIFICATION_ALERTS,
113                         StatusBarManager.DISABLE2_NOTIFICATION_SHADE));
114 
STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_HOME, new Pair<>(StatusBarManager.DISABLE_HOME, StatusBarManager.DISABLE2_NONE))115         STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_HOME,
116                 new Pair<>(StatusBarManager.DISABLE_HOME, StatusBarManager.DISABLE2_NONE));
117 
STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW, new Pair<>(StatusBarManager.DISABLE_RECENT, StatusBarManager.DISABLE2_NONE))118         STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW,
119                 new Pair<>(StatusBarManager.DISABLE_RECENT, StatusBarManager.DISABLE2_NONE));
120 
STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS, new Pair<>(StatusBarManager.DISABLE_NONE, StatusBarManager.DISABLE2_GLOBAL_ACTIONS))121         STATUS_BAR_FLAG_MAP_LOCKED.append(DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
122                 new Pair<>(StatusBarManager.DISABLE_NONE,
123                         StatusBarManager.DISABLE2_GLOBAL_ACTIONS));
124     }
125 
126     /** Tag used for disabling of keyguard */
127     private static final String LOCK_TASK_TAG = "Lock-to-App";
128 
129     /** Can't be put in lockTask mode. */
130     static final int LOCK_TASK_AUTH_DONT_LOCK = 0;
131     /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
132     static final int LOCK_TASK_AUTH_PINNABLE = 1;
133     /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
134     static final int LOCK_TASK_AUTH_LAUNCHABLE = 2;
135     /** Can enter lockTask without user approval. Can start over existing lockTask task. */
136     static final int LOCK_TASK_AUTH_ALLOWLISTED = 3;
137     /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
138      * lockTask task. */
139     static final int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
140 
141     private final IBinder mToken = new LockTaskToken();
142     private final ActivityTaskSupervisor mSupervisor;
143     private final Context mContext;
144     private final TaskChangeNotificationController mTaskChangeNotificationController;
145 
146     // The following system services cannot be final, because they do not exist when this class
147     // is instantiated during device boot
148     @VisibleForTesting
149     IStatusBarService mStatusBarService;
150     @VisibleForTesting
151     IDevicePolicyManager mDevicePolicyManager;
152     @VisibleForTesting
153     WindowManagerService mWindowManager;
154     @VisibleForTesting
155     LockPatternUtils mLockPatternUtils;
156     @VisibleForTesting
157     TelecomManager mTelecomManager;
158 
159     /**
160      * The chain of tasks in LockTask mode, in the order of when they first entered LockTask mode.
161      *
162      * The first task in the list, which started the current LockTask session, is called the root
163      * task. It coincides with the Home task in a typical multi-app kiosk deployment. When there are
164      * more than one locked tasks, the root task can't be finished. Nor can it be moved to the back
165      * of the stack by {@link Task#moveTaskToBack(Task)};
166      *
167      * Calling {@link Activity#stopLockTask()} on the root task will finish all tasks but itself in
168      * this list, and the device will exit LockTask mode.
169      *
170      * The list is empty if LockTask is inactive.
171      */
172     private final ArrayList<Task> mLockTaskModeTasks = new ArrayList<>();
173 
174     /**
175      * Packages that are allowed to be launched into the lock task mode for each user.
176      */
177     private final SparseArray<String[]> mLockTaskPackages = new SparseArray<>();
178 
179     /**
180      * Features that are allowed by DPC to show during LockTask mode.
181      */
182     private final SparseIntArray mLockTaskFeatures = new SparseIntArray();
183 
184     /**
185      * Store the current lock task mode. Possible values:
186      * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
187      * {@link ActivityManager#LOCK_TASK_MODE_PINNED}
188      */
189     private volatile int mLockTaskModeState = LOCK_TASK_MODE_NONE;
190 
191     /**
192      * This is ActivityTaskSupervisor's Handler.
193      */
194     private final Handler mHandler;
195 
196     /**
197      * Stores the user for which we're trying to dismiss the keyguard and then subsequently
198      * disable it.
199      *
200      * Tracking this ensures we don't mistakenly disable the keyguard if we've stopped trying to
201      * between the dismiss request and when it succeeds.
202      *
203      * Must only be accessed from the Handler thread.
204      */
205     private int mPendingDisableFromDismiss = UserHandle.USER_NULL;
206 
LockTaskController(Context context, ActivityTaskSupervisor supervisor, Handler handler, TaskChangeNotificationController taskChangeNotificationController)207     LockTaskController(Context context, ActivityTaskSupervisor supervisor,
208             Handler handler, TaskChangeNotificationController taskChangeNotificationController) {
209         mContext = context;
210         mSupervisor = supervisor;
211         mHandler = handler;
212         mTaskChangeNotificationController = taskChangeNotificationController;
213     }
214 
215     /**
216      * Set the window manager instance used in this class. This is necessary, because the window
217      * manager does not exist during instantiation of this class.
218      */
setWindowManager(WindowManagerService windowManager)219     void setWindowManager(WindowManagerService windowManager) {
220         mWindowManager = windowManager;
221     }
222 
223     /**
224      * @return the current lock task state. This can be any of
225      * {@link ActivityManager#LOCK_TASK_MODE_NONE}, {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
226      * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
227      */
getLockTaskModeState()228     int getLockTaskModeState() {
229         return mLockTaskModeState;
230     }
231 
232     /**
233      * @return whether the given task is locked at the moment. Locked tasks cannot be moved to the
234      * back of the stack.
235      */
236     @VisibleForTesting
isTaskLocked(Task task)237     boolean isTaskLocked(Task task) {
238         return mLockTaskModeTasks.contains(task);
239     }
240 
241     /**
242      * @return {@code true} whether this task first started the current LockTask session.
243      */
isRootTask(Task task)244     private boolean isRootTask(Task task) {
245         return mLockTaskModeTasks.indexOf(task) == 0;
246     }
247 
248     /**
249      * @return whether the given activity is blocked from finishing, because it is the only activity
250      * of the last locked task and finishing it would mean that lock task mode is ended illegally.
251      */
activityBlockedFromFinish(ActivityRecord activity)252     boolean activityBlockedFromFinish(ActivityRecord activity) {
253         final Task task = activity.getTask();
254         if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV || !isRootTask(task)) {
255             return false;
256         }
257 
258         final ActivityRecord taskTop = task.getTopNonFinishingActivity();
259         final ActivityRecord taskRoot = task.getRootActivity();
260         // If task has more than one Activity, verify if there's only adjacent TaskFragments that
261         // should be finish together in the Task.
262         if (activity != taskRoot || activity != taskTop) {
263             final TaskFragment taskFragment = activity.getTaskFragment();
264             final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
265             if (taskFragment.asTask() != null
266                     || !taskFragment.isDelayLastActivityRemoval()
267                     || adjacentTaskFragment == null) {
268                 // Don't block activity from finishing if the TaskFragment don't have any adjacent
269                 // TaskFragment, or it won't finish together with its adjacent TaskFragment.
270                 return false;
271             }
272 
273             final boolean hasOtherActivityInTaskFragment =
274                     taskFragment.getActivity(a -> !a.finishing && a != activity) != null;
275             if (hasOtherActivityInTaskFragment) {
276                 // Don't block activity from finishing if there's other Activity in the same
277                 // TaskFragment.
278                 return false;
279             }
280 
281             final boolean hasOtherActivityInTask = task.getActivity(a -> !a.finishing
282                     && a != activity && a.getTaskFragment() != adjacentTaskFragment) != null;
283             if (hasOtherActivityInTask) {
284                 // Do not block activity from finishing if there are another running activities
285                 // after the current and adjacent TaskFragments are removed. Note that we don't
286                 // check activities in adjacent TaskFragment because it will be finished together
287                 // with TaskFragment regardless of numbers of activities.
288                 return false;
289             }
290         }
291 
292         Slog.i(TAG, "Not finishing task in lock task mode");
293         showLockTaskToast();
294         return true;
295     }
296 
297     /**
298      * @return whether the given task can be moved to the back of the stack with
299      * {@link Task#moveTaskToBack(Task)}
300      * @see #mLockTaskModeTasks
301      */
canMoveTaskToBack(Task task)302     boolean canMoveTaskToBack(Task task) {
303         if (isRootTask(task)) {
304             showLockTaskToast();
305             return false;
306         }
307         return true;
308     }
309 
310     /**
311      * @return whether the requested task auth is allowed to be locked.
312      */
isTaskAuthAllowlisted(int lockTaskAuth)313     static boolean isTaskAuthAllowlisted(int lockTaskAuth) {
314         switch(lockTaskAuth) {
315             case LOCK_TASK_AUTH_ALLOWLISTED:
316             case LOCK_TASK_AUTH_LAUNCHABLE:
317             case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
318                 return true;
319             case LOCK_TASK_AUTH_PINNABLE:
320             case LOCK_TASK_AUTH_DONT_LOCK:
321             default:
322                 return false;
323         }
324     }
325 
326     /**
327      * @return whether the requested task is disallowed to be launched.
328      */
isLockTaskModeViolation(Task task)329     boolean isLockTaskModeViolation(Task task) {
330         return isLockTaskModeViolation(task, false);
331     }
332 
333     /**
334      * @param isNewClearTask whether the task would be cleared as part of the operation.
335      * @return whether the requested task is disallowed to be launched.
336      */
isLockTaskModeViolation(Task task, boolean isNewClearTask)337     boolean isLockTaskModeViolation(Task task, boolean isNewClearTask) {
338         // TODO: Double check what's going on here. If the task is already in lock task mode, it's
339         // likely allowlisted, so will return false below.
340         if (isTaskLocked(task) && !isNewClearTask) {
341             // If the task is already at the top and won't be cleared, then allow the operation
342         } else if (isLockTaskModeViolationInternal(task, task.mUserId, task.intent,
343                 task.mLockTaskAuth)) {
344             showLockTaskToast();
345             return true;
346         }
347         return false;
348     }
349 
350     /**
351      * @param activity an activity that is going to be started in a new task as the root activity.
352      * @return whether the given activity is allowed to be launched.
353      */
isNewTaskLockTaskModeViolation(ActivityRecord activity)354     boolean isNewTaskLockTaskModeViolation(ActivityRecord activity) {
355         // Use the belong task (if any) to perform the lock task checks
356         if (activity.getTask() != null) {
357             return isLockTaskModeViolation(activity.getTask());
358         }
359 
360         int auth = getLockTaskAuth(activity, null /* task */);
361         if (isLockTaskModeViolationInternal(activity, activity.mUserId, activity.intent, auth)) {
362             showLockTaskToast();
363             return true;
364         }
365         return false;
366     }
367 
368     /**
369      * @return the root task of the lock task.
370      */
getRootTask()371     Task getRootTask() {
372         if (mLockTaskModeTasks.isEmpty()) {
373             return null;
374         }
375         return mLockTaskModeTasks.get(0);
376     }
377 
isLockTaskModeViolationInternal(WindowContainer wc, int userId, Intent intent, int taskAuth)378     private boolean isLockTaskModeViolationInternal(WindowContainer wc, int userId,
379             Intent intent, int taskAuth) {
380         // Allow recents activity if enabled by policy
381         if (wc.isActivityTypeRecents() && isRecentsAllowed(userId)) {
382             return false;
383         }
384 
385         // Allow emergency calling when the device is protected by a locked keyguard
386         if (isKeyguardAllowed(userId) && isEmergencyCallIntent(intent)) {
387             return false;
388         }
389 
390         // Allow the dream to start during lock task mode
391         if (wc.isActivityTypeDream()) {
392             return false;
393         }
394 
395         return !(isTaskAuthAllowlisted(taskAuth) || mLockTaskModeTasks.isEmpty());
396     }
397 
isRecentsAllowed(int userId)398     private boolean isRecentsAllowed(int userId) {
399         return (getLockTaskFeaturesForUser(userId)
400                 & DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW) != 0;
401     }
402 
isKeyguardAllowed(int userId)403     private boolean isKeyguardAllowed(int userId) {
404         return (getLockTaskFeaturesForUser(userId)
405                 & DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD) != 0;
406     }
407 
isBlockingInTaskEnabled(int userId)408     private boolean isBlockingInTaskEnabled(int userId) {
409         return (getLockTaskFeaturesForUser(userId)
410                 & DevicePolicyManager.LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK) != 0;
411     }
412 
isActivityAllowed(int userId, String packageName, int lockTaskLaunchMode)413     boolean isActivityAllowed(int userId, String packageName, int lockTaskLaunchMode) {
414         if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED || !isBlockingInTaskEnabled(userId)) {
415             return true;
416         }
417         switch (lockTaskLaunchMode) {
418             case LOCK_TASK_LAUNCH_MODE_ALWAYS:
419                 return true;
420             case LOCK_TASK_LAUNCH_MODE_NEVER:
421                 return false;
422             default:
423         }
424         return isPackageAllowlisted(userId, packageName);
425     }
426 
isEmergencyCallIntent(Intent intent)427     private boolean isEmergencyCallIntent(Intent intent) {
428         if (intent == null) {
429             return false;
430         }
431 
432         // 1. The emergency keypad activity launched on top of the keyguard
433         if (EMERGENCY_DIALER_COMPONENT.equals(intent.getComponent())) {
434             return true;
435         }
436 
437         // 2. The intent sent by the keypad, which is handled by Telephony
438         if (ACTION_CALL_EMERGENCY.equals(intent.getAction())) {
439             return true;
440         }
441 
442         // 3. Telephony then starts the default package for making the call
443         final TelecomManager tm = getTelecomManager();
444         final String dialerPackage = tm != null ? tm.getSystemDialerPackage() : null;
445         if (dialerPackage != null && dialerPackage.equals(intent.getComponent().getPackageName())) {
446             return true;
447         }
448 
449         return false;
450     }
451 
452     /**
453      * Stop the current lock task mode.
454      *
455      * This is called by {@link ActivityManagerService} and performs various checks before actually
456      * finishing the locked task.
457      *
458      * @param task the task that requested the end of lock task mode ({@code null} for quitting app
459      *             pinning mode)
460      * @param isSystemCaller indicates whether this request comes from the system via
461      *                       {@link ActivityTaskManagerService#stopSystemLockTaskMode()}. If
462      *                       {@code true}, it means the user intends to stop pinned mode through UI;
463      *                       otherwise, it's called by an app and we need to stop locked or pinned
464      *                       mode, subject to checks.
465      * @param callingUid the caller that requested the end of lock task mode.
466      * @throws IllegalArgumentException if the calling task is invalid (e.g., {@code null} or not in
467      *                                  foreground)
468      * @throws SecurityException if the caller is not authorized to stop the lock task mode, i.e. if
469      *                           they differ from the one that launched lock task mode.
470      */
stopLockTaskMode(@ullable Task task, boolean isSystemCaller, int callingUid)471     void stopLockTaskMode(@Nullable Task task, boolean isSystemCaller, int callingUid) {
472         if (mLockTaskModeState == LOCK_TASK_MODE_NONE) {
473             return;
474         }
475 
476         if (isSystemCaller) {
477             if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
478                 clearLockedTasks("stopAppPinning");
479             } else {
480                 Slog.e(TAG_LOCKTASK, "Attempted to stop LockTask with isSystemCaller=true");
481                 showLockTaskToast();
482             }
483 
484         } else {
485             // Ensure calling activity is not null
486             if (task == null) {
487                 throw new IllegalArgumentException("can't stop LockTask for null task");
488             }
489 
490             // Ensure the same caller for startLockTaskMode and stopLockTaskMode.
491             // It is possible lockTaskMode was started by the system process because
492             // android:lockTaskMode is set to a locking value in the application manifest
493             // instead of the app calling startLockTaskMode. In this case
494             // {@link Task.mLockTaskUid} will be 0, so we compare the callingUid to the
495             // {@link Task.effectiveUid} instead. Also caller with
496             // {@link MANAGE_ACTIVITY_TASKS} can stop any lock task.
497             if (callingUid != task.mLockTaskUid
498                     && (task.mLockTaskUid != 0 || callingUid != task.effectiveUid)) {
499                 throw new SecurityException("Invalid uid, expected " + task.mLockTaskUid
500                         + " callingUid=" + callingUid + " effectiveUid=" + task.effectiveUid);
501             }
502 
503             // We don't care if it's pinned or locked mode; this will stop it anyways.
504             clearLockedTask(task);
505         }
506     }
507 
508     /**
509      * Clear all locked tasks and request the end of LockTask mode.
510      *
511      * This method is called by UserController when starting a new foreground user, and,
512      * unlike {@link #stopLockTaskMode(Task, boolean, int)}, it doesn't perform the checks.
513      */
clearLockedTasks(String reason)514     void clearLockedTasks(String reason) {
515         ProtoLog.i(WM_DEBUG_LOCKTASK, "clearLockedTasks: %s", reason);
516         if (!mLockTaskModeTasks.isEmpty()) {
517             clearLockedTask(mLockTaskModeTasks.get(0));
518         }
519     }
520 
521     /**
522      * Clear one locked task from LockTask mode.
523      *
524      * If the requested task is the root task (see {@link #mLockTaskModeTasks}), then all locked
525      * tasks are cleared. Otherwise, only the requested task is cleared. LockTask mode is stopped
526      * when the last locked task is cleared.
527      *
528      * @param task the task to be cleared from LockTask mode.
529      */
clearLockedTask(final Task task)530     void clearLockedTask(final Task task) {
531         if (task == null || mLockTaskModeTasks.isEmpty()) return;
532 
533         if (task == mLockTaskModeTasks.get(0)) {
534             // We're removing the root task while there are other locked tasks. Therefore we should
535             // clear all locked tasks in reverse order.
536             for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx > 0; --taskNdx) {
537                 clearLockedTask(mLockTaskModeTasks.get(taskNdx));
538             }
539         }
540 
541         removeLockedTask(task);
542         if (mLockTaskModeTasks.isEmpty()) {
543             return;
544         }
545         task.performClearTaskLocked();
546         mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities();
547     }
548 
549     /**
550      * Remove the given task from the locked task list. If this was the last task in the list,
551      * lock task mode is stopped.
552      */
removeLockedTask(final Task task)553     private void removeLockedTask(final Task task) {
554         if (!mLockTaskModeTasks.remove(task)) {
555             return;
556         }
557         ProtoLog.d(WM_DEBUG_LOCKTASK, "removeLockedTask: removed %s", task);
558         if (mLockTaskModeTasks.isEmpty()) {
559             ProtoLog.d(WM_DEBUG_LOCKTASK, "removeLockedTask: task=%s last task, "
560                     + "reverting locktask mode. Callers=%s", task, Debug.getCallers(3));
561             mHandler.post(() -> performStopLockTask(task.mUserId));
562         }
563     }
564 
565     // This method should only be called on the handler thread
performStopLockTask(int userId)566     private void performStopLockTask(int userId) {
567         // Update the internal mLockTaskModeState early to avoid the scenario that SysUI queries
568         // mLockTaskModeState (from setStatusBarState) and gets staled state.
569         // TODO: revisit this approach.
570         // The race condition raised above can be addressed by moving this function out of handler
571         // thread, which makes it guarded by ATMS#mGlobalLock as ATMS#getLockTaskModeState.
572         final int oldLockTaskModeState = mLockTaskModeState;
573         mLockTaskModeState = LOCK_TASK_MODE_NONE;
574         mTaskChangeNotificationController.notifyLockTaskModeChanged(mLockTaskModeState);
575         // When lock task ends, we enable the status bars.
576         try {
577             setStatusBarState(mLockTaskModeState, userId);
578             setKeyguardState(mLockTaskModeState, userId);
579             if (oldLockTaskModeState == LOCK_TASK_MODE_PINNED) {
580                 lockKeyguardIfNeeded(userId);
581             }
582             if (getDevicePolicyManager() != null) {
583                 getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId);
584             }
585             if (oldLockTaskModeState == LOCK_TASK_MODE_PINNED) {
586                 getStatusBarService().showPinningEnterExitToast(false /* entering */);
587             }
588             mWindowManager.onLockTaskStateChanged(mLockTaskModeState);
589         } catch (RemoteException ex) {
590             throw new RuntimeException(ex);
591         }
592     }
593 
594     /**
595      * Show the lock task violation toast. Currently we only show toast for screen pinning mode, and
596      * no-op if the device is in locked mode.
597      */
showLockTaskToast()598     void showLockTaskToast() {
599         if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) {
600             try {
601                 getStatusBarService().showPinningEscapeToast();
602             } catch (RemoteException e) {
603                 Slog.e(TAG, "Failed to send pinning escape toast", e);
604             }
605         }
606     }
607 
608     // Starting lock task
609 
610     /**
611      * Method to start lock task mode on a given task.
612      *
613      * @param task the task that should be locked.
614      * @param isSystemCaller indicates whether this request was initiated by the system via
615      *                       {@link ActivityTaskManagerService#startSystemLockTaskMode(int)}. If
616      *                       {@code true}, this intends to start pinned mode; otherwise, we look
617      *                       at the calling task's mLockTaskAuth to decide which mode to start.
618      * @param callingUid the caller that requested the launch of lock task mode.
619      */
startLockTaskMode(@onNull Task task, boolean isSystemCaller, int callingUid)620     void startLockTaskMode(@NonNull Task task, boolean isSystemCaller, int callingUid) {
621         if (!isSystemCaller) {
622             task.mLockTaskUid = callingUid;
623             if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
624                 // startLockTask() called by app, but app is not part of lock task allowlist. Show
625                 // app pinning request. We will come back here with isSystemCaller true.
626                 ProtoLog.w(WM_DEBUG_LOCKTASK, "Mode default, asking user");
627                 StatusBarManagerInternal statusBarManager = LocalServices.getService(
628                         StatusBarManagerInternal.class);
629                 if (statusBarManager != null) {
630                     statusBarManager.showScreenPinningRequest(task.mTaskId);
631                 }
632                 return;
633             }
634         }
635 
636         // System can only initiate screen pinning, not full lock task mode
637         ProtoLog.w(WM_DEBUG_LOCKTASK, "%s", isSystemCaller ? "Locking pinned" : "Locking fully");
638         setLockTaskMode(task, isSystemCaller ? LOCK_TASK_MODE_PINNED : LOCK_TASK_MODE_LOCKED,
639                 "startLockTask", true);
640     }
641 
642     /**
643      * Start lock task mode on the given task.
644      * @param lockTaskModeState whether fully locked or pinned mode.
645      * @param andResume whether the task should be brought to foreground as part of the operation.
646      */
setLockTaskMode(@onNull Task task, int lockTaskModeState, String reason, boolean andResume)647     private void setLockTaskMode(@NonNull Task task, int lockTaskModeState,
648                                  String reason, boolean andResume) {
649         // Should have already been checked, but do it again.
650         if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
651             ProtoLog.w(WM_DEBUG_LOCKTASK,
652                     "setLockTaskMode: Can't lock due to auth");
653             return;
654         }
655         if (isLockTaskModeViolation(task)) {
656             Slog.e(TAG_LOCKTASK, "setLockTaskMode: Attempt to start an unauthorized lock task.");
657             return;
658         }
659 
660         final Intent taskIntent = task.intent;
661         if (mLockTaskModeTasks.isEmpty() && taskIntent != null) {
662             mSupervisor.mRecentTasks.onLockTaskModeStateChanged(lockTaskModeState, task.mUserId);
663             // Start lock task on the handler thread
664             mHandler.post(() -> performStartLockTask(
665                     taskIntent.getComponent().getPackageName(),
666                     task.mUserId,
667                     lockTaskModeState));
668         }
669         ProtoLog.w(WM_DEBUG_LOCKTASK, "setLockTaskMode: Locking to %s Callers=%s",
670                 task, Debug.getCallers(4));
671 
672         if (!mLockTaskModeTasks.contains(task)) {
673             mLockTaskModeTasks.add(task);
674         }
675 
676         if (task.mLockTaskUid == -1) {
677             task.mLockTaskUid = task.effectiveUid;
678         }
679 
680         if (andResume) {
681             mSupervisor.findTaskToMoveToFront(task, 0, null, reason,
682                     lockTaskModeState != LOCK_TASK_MODE_NONE);
683             mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities();
684             final Task rootTask = task.getRootTask();
685             if (rootTask != null) {
686                 rootTask.mDisplayContent.executeAppTransition();
687             }
688         } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
689             mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
690                     mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea(),
691                     task.getRootTask(), true /* forceNonResizable */);
692         }
693     }
694 
695     // This method should only be called on the handler thread
performStartLockTask(String packageName, int userId, int lockTaskModeState)696     private void performStartLockTask(String packageName, int userId, int lockTaskModeState) {
697         // When lock task starts, we disable the status bars.
698         try {
699             if (lockTaskModeState == LOCK_TASK_MODE_PINNED) {
700                 getStatusBarService().showPinningEnterExitToast(true /* entering */);
701             }
702             mWindowManager.onLockTaskStateChanged(lockTaskModeState);
703             mLockTaskModeState = lockTaskModeState;
704             mTaskChangeNotificationController.notifyLockTaskModeChanged(mLockTaskModeState);
705             setStatusBarState(lockTaskModeState, userId);
706             setKeyguardState(lockTaskModeState, userId);
707             if (getDevicePolicyManager() != null) {
708                 getDevicePolicyManager().notifyLockTaskModeChanged(true, packageName, userId);
709             }
710         } catch (RemoteException ex) {
711             throw new RuntimeException(ex);
712         }
713     }
714 
715     /**
716      * Update packages that are allowed to be launched in lock task mode.
717      * @param userId Which user this allowlist is associated with
718      * @param packages The allowlist of packages allowed in lock task mode
719      * @see #mLockTaskPackages
720      */
updateLockTaskPackages(int userId, String[] packages)721     void updateLockTaskPackages(int userId, String[] packages) {
722         mLockTaskPackages.put(userId, packages);
723 
724         boolean taskChanged = false;
725         for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
726             final Task lockedTask = mLockTaskModeTasks.get(taskNdx);
727             final boolean wasAllowlisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
728                     || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED;
729             lockedTask.setLockTaskAuth();
730             final boolean isAllowlisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
731                     || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED;
732 
733             if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED
734                     || lockedTask.mUserId != userId
735                     || !wasAllowlisted || isAllowlisted) {
736                 continue;
737             }
738 
739             // Terminate locked tasks that have recently lost allowlist authorization.
740             ProtoLog.d(WM_DEBUG_LOCKTASK, "onLockTaskPackagesUpdated: removing %s"
741                     + " mLockTaskAuth()=%s", lockedTask, lockedTask.lockTaskAuthToString());
742             removeLockedTask(lockedTask);
743             lockedTask.performClearTaskLocked();
744             taskChanged = true;
745         }
746 
747         mSupervisor.mRootWindowContainer.forAllTasks(Task::setLockTaskAuth);
748 
749         final ActivityRecord r = mSupervisor.mRootWindowContainer.topRunningActivity();
750         final Task task = (r != null) ? r.getTask() : null;
751         if (mLockTaskModeTasks.isEmpty() && task!= null
752                 && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
753             // This task must have just been authorized.
754             ProtoLog.d(WM_DEBUG_LOCKTASK, "onLockTaskPackagesUpdated: starting new "
755                     + "locktask task=%s", task);
756             setLockTaskMode(task, LOCK_TASK_MODE_LOCKED, "package updated", false);
757             taskChanged = true;
758         }
759 
760         if (taskChanged) {
761             mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities();
762         }
763     }
764 
getLockTaskAuth(@ullable ActivityRecord rootActivity, @Nullable Task task)765     int getLockTaskAuth(@Nullable ActivityRecord rootActivity, @Nullable Task task) {
766         if (rootActivity == null && task == null) {
767             return LOCK_TASK_AUTH_DONT_LOCK;
768         }
769         if (rootActivity == null) {
770             return LOCK_TASK_AUTH_PINNABLE;
771         }
772 
773         final String pkg = (task == null || task.realActivity == null) ? rootActivity.packageName
774                 : task.realActivity.getPackageName();
775         final int userId = task != null ? task.mUserId : rootActivity.mUserId;
776         int lockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
777         switch (rootActivity.lockTaskLaunchMode) {
778             case LOCK_TASK_LAUNCH_MODE_DEFAULT:
779                 lockTaskAuth = isPackageAllowlisted(userId, pkg)
780                         ? LOCK_TASK_AUTH_ALLOWLISTED : LOCK_TASK_AUTH_PINNABLE;
781                 break;
782 
783             case LOCK_TASK_LAUNCH_MODE_NEVER:
784                 lockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
785                 break;
786 
787             case LOCK_TASK_LAUNCH_MODE_ALWAYS:
788                 lockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
789                 break;
790 
791             case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
792                 lockTaskAuth = isPackageAllowlisted(userId, pkg)
793                         ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
794                 break;
795         }
796         return lockTaskAuth;
797     }
798 
isPackageAllowlisted(int userId, String pkg)799     boolean isPackageAllowlisted(int userId, String pkg) {
800         if (pkg == null) {
801             return false;
802         }
803         String[] allowlist;
804         allowlist = mLockTaskPackages.get(userId);
805         if (allowlist == null) {
806             return false;
807         }
808         for (String allowlistedPkg : allowlist) {
809             if (pkg.equals(allowlistedPkg)) {
810                 return true;
811             }
812         }
813         return false;
814     }
815 
816     /**
817      * Update the UI features that are enabled for LockTask mode.
818      * @param userId Which user these feature flags are associated with
819      * @param flags Bitfield of feature flags
820      * @see DevicePolicyManager#setLockTaskFeatures(ComponentName, int)
821      */
updateLockTaskFeatures(int userId, int flags)822     void updateLockTaskFeatures(int userId, int flags) {
823         int oldFlags = getLockTaskFeaturesForUser(userId);
824         if (flags == oldFlags) {
825             return;
826         }
827 
828         mLockTaskFeatures.put(userId, flags);
829         if (!mLockTaskModeTasks.isEmpty() && userId == mLockTaskModeTasks.get(0).mUserId) {
830             mHandler.post(() -> {
831                 if (mLockTaskModeState == LOCK_TASK_MODE_LOCKED) {
832                     setStatusBarState(mLockTaskModeState, userId);
833                     setKeyguardState(mLockTaskModeState, userId);
834                 }
835             });
836         }
837     }
838 
839     /**
840      * Helper method for configuring the status bar disabled state.
841      * Should only be called on the handler thread to avoid race.
842      */
setStatusBarState(int lockTaskModeState, int userId)843     private void setStatusBarState(int lockTaskModeState, int userId) {
844         IStatusBarService statusBar = getStatusBarService();
845         if (statusBar == null) {
846             Slog.e(TAG, "Can't find StatusBarService");
847             return;
848         }
849 
850         // Default state, when lockTaskModeState == LOCK_TASK_MODE_NONE
851         int flags1 = StatusBarManager.DISABLE_NONE;
852         int flags2 = StatusBarManager.DISABLE2_NONE;
853 
854         if (lockTaskModeState == LOCK_TASK_MODE_PINNED) {
855             flags1 = STATUS_BAR_MASK_PINNED;
856 
857         } else if (lockTaskModeState == LOCK_TASK_MODE_LOCKED) {
858             int lockTaskFeatures = getLockTaskFeaturesForUser(userId);
859             Pair<Integer, Integer> statusBarFlags = getStatusBarDisableFlags(lockTaskFeatures);
860             flags1 = statusBarFlags.first;
861             flags2 = statusBarFlags.second;
862         }
863 
864         try {
865             statusBar.disable(flags1, mToken, mContext.getPackageName());
866             statusBar.disable2(flags2, mToken, mContext.getPackageName());
867         } catch (RemoteException e) {
868             Slog.e(TAG, "Failed to set status bar flags", e);
869         }
870     }
871 
872     /**
873      * Helper method for configuring the keyguard disabled state.
874      * Should only be called on the handler thread to avoid race.
875      */
setKeyguardState(int lockTaskModeState, int userId)876     private void setKeyguardState(int lockTaskModeState, int userId) {
877         mPendingDisableFromDismiss = UserHandle.USER_NULL;
878         if (lockTaskModeState == LOCK_TASK_MODE_NONE) {
879             mWindowManager.reenableKeyguard(mToken, userId);
880 
881         } else if (lockTaskModeState == LOCK_TASK_MODE_LOCKED) {
882             if (isKeyguardAllowed(userId)) {
883                 mWindowManager.reenableKeyguard(mToken, userId);
884             } else {
885                 // If keyguard is not secure and it is locked, dismiss the keyguard before
886                 // disabling it, which avoids the platform to think the keyguard is still on.
887                 if (mWindowManager.isKeyguardLocked() && !mWindowManager.isKeyguardSecure(userId)) {
888                     mPendingDisableFromDismiss = userId;
889                     mWindowManager.dismissKeyguard(new IKeyguardDismissCallback.Stub() {
890                         @Override
891                         public void onDismissError() throws RemoteException {
892                             Slog.i(TAG, "setKeyguardState: failed to dismiss keyguard");
893                         }
894 
895                         @Override
896                         public void onDismissSucceeded() throws RemoteException {
897                             mHandler.post(
898                                     () -> {
899                                         if (mPendingDisableFromDismiss == userId) {
900                                             mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG,
901                                                     userId);
902                                             mPendingDisableFromDismiss = UserHandle.USER_NULL;
903                                         }
904                                     });
905                         }
906 
907                         @Override
908                         public void onDismissCancelled() throws RemoteException {
909                             Slog.i(TAG, "setKeyguardState: dismiss cancelled");
910                         }
911                     }, null);
912                 } else {
913                     mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG, userId);
914                 }
915             }
916 
917         } else { // lockTaskModeState == LOCK_TASK_MODE_PINNED
918             mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG, userId);
919         }
920     }
921 
922     /**
923      * Helper method for locking the device immediately. This may be necessary when the device
924      * leaves the pinned mode.
925      */
lockKeyguardIfNeeded(int userId)926     private void lockKeyguardIfNeeded(int userId) {
927         if (shouldLockKeyguard(userId)) {
928             mWindowManager.lockNow(null);
929             mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
930             getLockPatternUtils().requireCredentialEntry(USER_ALL);
931         }
932     }
933 
shouldLockKeyguard(int userId)934     private boolean shouldLockKeyguard(int userId) {
935         // This functionality should be kept consistent with
936         // com.android.settings.security.ScreenPinningSettings (see b/127605586)
937         try {
938             return Settings.Secure.getIntForUser(
939                     mContext.getContentResolver(),
940                     Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, USER_CURRENT) != 0;
941         } catch (Settings.SettingNotFoundException e) {
942             // Log to SafetyNet for b/127605586
943             android.util.EventLog.writeEvent(0x534e4554, "127605586", -1, "");
944             return getLockPatternUtils().isSecure(userId);
945         }
946     }
947 
948     /**
949      * Translates from LockTask feature flags to StatusBarManager disable and disable2 flags.
950      * @param lockTaskFlags Bitfield of flags as per
951      *                      {@link DevicePolicyManager#setLockTaskFeatures(ComponentName, int)}
952      * @return A {@link Pair} of {@link StatusBarManager#disable(int)} and
953      *         {@link StatusBarManager#disable2(int)} flags
954      */
955     @VisibleForTesting
getStatusBarDisableFlags(int lockTaskFlags)956     Pair<Integer, Integer> getStatusBarDisableFlags(int lockTaskFlags) {
957         // Everything is disabled by default
958         int flags1 = StatusBarManager.DISABLE_MASK;
959         int flags2 = StatusBarManager.DISABLE2_MASK;
960         for (int i = STATUS_BAR_FLAG_MAP_LOCKED.size() - 1; i >= 0; i--) {
961             Pair<Integer, Integer> statusBarFlags = STATUS_BAR_FLAG_MAP_LOCKED.valueAt(i);
962             if ((STATUS_BAR_FLAG_MAP_LOCKED.keyAt(i) & lockTaskFlags) != 0) {
963                 flags1 &= ~statusBarFlags.first;
964                 flags2 &= ~statusBarFlags.second;
965             }
966         }
967         // Some flags are not used for LockTask purposes, so we mask them
968         flags1 &= STATUS_BAR_MASK_LOCKED;
969         return new Pair<>(flags1, flags2);
970     }
971 
972     /**
973      * @param packageName The package to check
974      * @return Whether the package is the base of any locked task
975      */
isBaseOfLockedTask(String packageName)976     boolean isBaseOfLockedTask(String packageName) {
977         for (int i = 0; i < mLockTaskModeTasks.size(); i++) {
978             final Intent bi = mLockTaskModeTasks.get(i).getBaseIntent();
979             if (bi != null && packageName.equals(bi.getComponent()
980                     .getPackageName())) {
981                 return true;
982             }
983         }
984         return false;
985     }
986 
987     /**
988      * Gets the cached value of LockTask feature flags for a specific user.
989      */
getLockTaskFeaturesForUser(int userId)990     private int getLockTaskFeaturesForUser(int userId) {
991         return mLockTaskFeatures.get(userId, DevicePolicyManager.LOCK_TASK_FEATURE_NONE);
992     }
993 
994     // Should only be called on the handler thread
995     @Nullable
getStatusBarService()996     private IStatusBarService getStatusBarService() {
997         if (mStatusBarService == null) {
998             mStatusBarService = IStatusBarService.Stub.asInterface(
999                     ServiceManager.checkService(STATUS_BAR_SERVICE));
1000             if (mStatusBarService == null) {
1001                 Slog.w("StatusBarManager", "warning: no STATUS_BAR_SERVICE");
1002             }
1003         }
1004         return mStatusBarService;
1005     }
1006 
1007     // Should only be called on the handler thread
1008     @Nullable
getDevicePolicyManager()1009     private IDevicePolicyManager getDevicePolicyManager() {
1010         if (mDevicePolicyManager == null) {
1011             mDevicePolicyManager = IDevicePolicyManager.Stub.asInterface(
1012                     ServiceManager.checkService(DEVICE_POLICY_SERVICE));
1013             if (mDevicePolicyManager == null) {
1014                 Slog.w(TAG, "warning: no DEVICE_POLICY_SERVICE");
1015             }
1016         }
1017         return mDevicePolicyManager;
1018     }
1019 
1020     @NonNull
getLockPatternUtils()1021     private LockPatternUtils getLockPatternUtils() {
1022         if (mLockPatternUtils == null) {
1023             // We don't preserve the LPU object to save memory
1024             return new LockPatternUtils(mContext);
1025         }
1026         return mLockPatternUtils;
1027     }
1028 
1029     @Nullable
getTelecomManager()1030     private TelecomManager getTelecomManager() {
1031         if (mTelecomManager == null) {
1032             // We don't preserve the TelecomManager object to save memory
1033             return mContext.getSystemService(TelecomManager.class);
1034         }
1035         return mTelecomManager;
1036     }
1037 
dump(PrintWriter pw, String prefix)1038     public void dump(PrintWriter pw, String prefix) {
1039         pw.println(prefix + "LockTaskController:");
1040         prefix = prefix + "  ";
1041         pw.println(prefix + "mLockTaskModeState=" + lockTaskModeToString());
1042         pw.println(prefix + "mLockTaskModeTasks=");
1043         for (int i = 0; i < mLockTaskModeTasks.size(); ++i) {
1044             pw.println(prefix + "  #" + i + " " + mLockTaskModeTasks.get(i));
1045         }
1046         pw.println(prefix + "mLockTaskPackages (userId:packages)=");
1047         for (int i = 0; i < mLockTaskPackages.size(); ++i) {
1048             pw.println(prefix + "  u" + mLockTaskPackages.keyAt(i)
1049                     + ":" + Arrays.toString(mLockTaskPackages.valueAt(i)));
1050         }
1051         pw.println();
1052     }
1053 
lockTaskModeToString()1054     private String lockTaskModeToString() {
1055         switch (mLockTaskModeState) {
1056             case LOCK_TASK_MODE_LOCKED:
1057                 return "LOCKED";
1058             case LOCK_TASK_MODE_PINNED:
1059                 return "PINNED";
1060             case LOCK_TASK_MODE_NONE:
1061                 return "NONE";
1062             default: return "unknown=" + mLockTaskModeState;
1063         }
1064     }
1065 
1066     /** Marker class for the token used to disable keyguard. */
1067     static class LockTaskToken extends Binder {
LockTaskToken()1068         private LockTaskToken() {
1069         }
1070     }
1071 }
1072