1 /*
2  * Copyright (C) 2006 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.ActivityTaskManager.INVALID_STACK_ID;
20 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
21 import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
22 import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
24 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
25 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
26 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
27 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
28 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
29 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
30 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
31 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
32 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
33 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
34 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
35 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
36 import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
37 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
38 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
39 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
40 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
41 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
42 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
43 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
44 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
45 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
46 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
47 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
48 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
49 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
50 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
51 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
52 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
53 import static android.view.Display.DEFAULT_DISPLAY;
54 
55 import static com.android.server.EventLogTags.WM_TASK_CREATED;
56 import static com.android.server.am.TaskRecordProto.ACTIVITIES;
57 import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
58 import static com.android.server.am.TaskRecordProto.BOUNDS;
59 import static com.android.server.am.TaskRecordProto.CONFIGURATION_CONTAINER;
60 import static com.android.server.am.TaskRecordProto.FULLSCREEN;
61 import static com.android.server.am.TaskRecordProto.ID;
62 import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
63 import static com.android.server.am.TaskRecordProto.MIN_HEIGHT;
64 import static com.android.server.am.TaskRecordProto.MIN_WIDTH;
65 import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY;
66 import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
67 import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
68 import static com.android.server.am.TaskRecordProto.STACK_ID;
69 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
70 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
71 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP;
72 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
73 import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
74 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
75 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
76 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
77 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
78 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
79 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
80 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
81 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
82 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
83 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
84 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
85 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
86 import static com.android.server.wm.WindowContainer.POSITION_TOP;
87 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
88 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
89 
90 import static java.lang.Integer.MAX_VALUE;
91 
92 import android.annotation.IntDef;
93 import android.annotation.NonNull;
94 import android.annotation.Nullable;
95 import android.app.Activity;
96 import android.app.ActivityManager;
97 import android.app.ActivityManager.TaskDescription;
98 import android.app.ActivityManager.TaskSnapshot;
99 import android.app.ActivityOptions;
100 import android.app.ActivityTaskManager;
101 import android.app.AppGlobals;
102 import android.app.TaskInfo;
103 import android.app.WindowConfiguration;
104 import android.content.ComponentName;
105 import android.content.Intent;
106 import android.content.pm.ActivityInfo;
107 import android.content.pm.ApplicationInfo;
108 import android.content.pm.IPackageManager;
109 import android.content.pm.PackageManager;
110 import android.content.res.Configuration;
111 import android.graphics.Rect;
112 import android.os.Debug;
113 import android.os.RemoteException;
114 import android.os.SystemClock;
115 import android.os.Trace;
116 import android.os.UserHandle;
117 import android.provider.Settings;
118 import android.service.voice.IVoiceInteractionSession;
119 import android.util.DisplayMetrics;
120 import android.util.EventLog;
121 import android.util.Slog;
122 import android.util.proto.ProtoOutputStream;
123 import android.view.Display;
124 import android.view.DisplayInfo;
125 
126 import com.android.internal.annotations.VisibleForTesting;
127 import com.android.internal.app.IVoiceInteractor;
128 import com.android.internal.util.XmlUtils;
129 import com.android.server.wm.ActivityStack.ActivityState;
130 
131 import org.xmlpull.v1.XmlPullParser;
132 import org.xmlpull.v1.XmlPullParserException;
133 import org.xmlpull.v1.XmlSerializer;
134 
135 import java.io.IOException;
136 import java.io.PrintWriter;
137 import java.lang.annotation.Retention;
138 import java.lang.annotation.RetentionPolicy;
139 import java.util.ArrayList;
140 import java.util.Objects;
141 
142 class TaskRecord extends ConfigurationContainer {
143     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_ATM;
144     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
145     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
146     private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
147     private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
148 
149     private static final String ATTR_TASKID = "task_id";
150     private static final String TAG_INTENT = "intent";
151     private static final String TAG_AFFINITYINTENT = "affinity_intent";
152     private static final String ATTR_REALACTIVITY = "real_activity";
153     private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
154     private static final String ATTR_ORIGACTIVITY = "orig_activity";
155     private static final String TAG_ACTIVITY = "activity";
156     private static final String ATTR_AFFINITY = "affinity";
157     private static final String ATTR_ROOT_AFFINITY = "root_affinity";
158     private static final String ATTR_ROOTHASRESET = "root_has_reset";
159     private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
160     private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
161     private static final String ATTR_USERID = "user_id";
162     private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
163     private static final String ATTR_EFFECTIVE_UID = "effective_uid";
164     @Deprecated
165     private static final String ATTR_TASKTYPE = "task_type";
166     private static final String ATTR_LASTDESCRIPTION = "last_description";
167     private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
168     private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
169     private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
170     private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
171     private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
172     private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
173     private static final String ATTR_CALLING_UID = "calling_uid";
174     private static final String ATTR_CALLING_PACKAGE = "calling_package";
175     private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
176     private static final String ATTR_RESIZE_MODE = "resize_mode";
177     private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
178     private static final String ATTR_MIN_WIDTH = "min_width";
179     private static final String ATTR_MIN_HEIGHT = "min_height";
180     private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
181 
182     // Current version of the task record we persist. Used to check if we need to run any upgrade
183     // code.
184     private static final int PERSIST_TASK_VERSION = 1;
185 
186     private static final int INVALID_MIN_SIZE = -1;
187 
188     /**
189      * The modes to control how the stack is moved to the front when calling
190      * {@link TaskRecord#reparent}.
191      */
192     @Retention(RetentionPolicy.SOURCE)
193     @IntDef({
194             REPARENT_MOVE_STACK_TO_FRONT,
195             REPARENT_KEEP_STACK_AT_FRONT,
196             REPARENT_LEAVE_STACK_IN_PLACE
197     })
198     @interface ReparentMoveStackMode {}
199     // Moves the stack to the front if it was not at the front
200     static final int REPARENT_MOVE_STACK_TO_FRONT = 0;
201     // Only moves the stack to the front if it was focused or front most already
202     static final int REPARENT_KEEP_STACK_AT_FRONT = 1;
203     // Do not move the stack as a part of reparenting
204     static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
205 
206     /**
207      * The factory used to create {@link TaskRecord}. This allows OEM subclass {@link TaskRecord}.
208      */
209     private static TaskRecordFactory sTaskRecordFactory;
210 
211     final int taskId;       // Unique identifier for this task.
212     String affinity;        // The affinity name for this task, or null; may change identity.
213     String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
214     final IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
215     final IVoiceInteractor voiceInteractor;         // Associated interactor to provide to app
216     Intent intent;          // The original intent that started the task. Note that this value can
217                             // be null.
218     Intent affinityIntent;  // Intent of affinity-moved activity that started this task.
219     int effectiveUid;       // The current effective uid of the identity of this task.
220     ComponentName origActivity; // The non-alias activity component of the intent.
221     ComponentName realActivity; // The actual activity component that started the task.
222     boolean realActivitySuspended; // True if the actual activity component that started the
223                                    // task is suspended.
224     boolean inRecents;      // Actually in the recents list?
225     long lastActiveTime;    // Last time this task was active in the current device session,
226                             // including sleep. This time is initialized to the elapsed time when
227                             // restored from disk.
228     boolean isAvailable;    // Is the activity available to be launched?
229     boolean rootWasReset;   // True if the intent at the root of the task had
230                             // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
231     boolean autoRemoveRecents;  // If true, we should automatically remove the task from
232                                 // recents when activity finishes
233     boolean askedCompatMode;// Have asked the user about compat mode for this task.
234     boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
235 
236     String stringName;      // caching of toString() result.
237     int userId;             // user for which this task was created
238     boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
239                                 // was changed.
240 
241     int numFullscreen;      // Number of fullscreen activities.
242 
243     int mResizeMode;        // The resize mode of this task and its activities.
244                             // Based on the {@link ActivityInfo#resizeMode} of the root activity.
245     private boolean mSupportsPictureInPicture;  // Whether or not this task and its activities
246             // support PiP. Based on the {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag
247             // of the root activity.
248     /** Can't be put in lockTask mode. */
249     final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
250     /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
251     final static int LOCK_TASK_AUTH_PINNABLE = 1;
252     /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
253     final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
254     /** Can enter lockTask without user approval. Can start over existing lockTask task. */
255     final static int LOCK_TASK_AUTH_WHITELISTED = 3;
256     /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
257      * lockTask task. */
258     final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
259     int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
260 
261     int mLockTaskUid = -1;  // The uid of the application that called startLockTask().
262 
263     // This represents the last resolved activity values for this task
264     // NOTE: This value needs to be persisted with each task
265     TaskDescription lastTaskDescription = new TaskDescription();
266 
267     /** List of all activities in the task arranged in history order */
268     final ArrayList<ActivityRecord> mActivities;
269 
270     /** Current stack. Setter must always be used to update the value. */
271     private ActivityStack mStack;
272 
273     /** The process that had previously hosted the root activity of this task.
274      * Used to know that we should try harder to keep this process around, in case the
275      * user wants to return to it. */
276     private WindowProcessController mRootProcess;
277 
278     /** Takes on same value as first root activity */
279     boolean isPersistable = false;
280     int maxRecents;
281 
282     /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
283      * determining the order when restoring. Sign indicates whether last task movement was to front
284      * (positive) or back (negative). Absolute value indicates time. */
285     long mLastTimeMoved = System.currentTimeMillis();
286 
287     /** If original intent did not allow relinquishing task identity, save that information */
288     private boolean mNeverRelinquishIdentity = true;
289 
290     // Used in the unique case where we are clearing the task in order to reuse it. In that case we
291     // do not want to delete the stack when the task goes empty.
292     private boolean mReuseTask = false;
293 
294     CharSequence lastDescription; // Last description captured for this item.
295 
296     int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
297     int mAffiliatedTaskColor; // color of the parent task affiliation.
298     TaskRecord mPrevAffiliate; // previous task in affiliated chain.
299     int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
300     TaskRecord mNextAffiliate; // next task in affiliated chain.
301     int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
302 
303     // For relaunching the task from recents as though it was launched by the original launcher.
304     int mCallingUid;
305     String mCallingPackage;
306 
307     final ActivityTaskManagerService mService;
308 
309     private final Rect mTmpStableBounds = new Rect();
310     private final Rect mTmpNonDecorBounds = new Rect();
311     private final Rect mTmpBounds = new Rect();
312     private final Rect mTmpInsets = new Rect();
313 
314     // Last non-fullscreen bounds the task was launched in or resized to.
315     // The information is persisted and used to determine the appropriate stack to launch the
316     // task into on restore.
317     Rect mLastNonFullscreenBounds = null;
318     // Minimal width and height of this task when it's resizeable. -1 means it should use the
319     // default minimal width/height.
320     int mMinWidth;
321     int mMinHeight;
322 
323     // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
324     // This number will be assigned when we evaluate OOM scores for all visible tasks.
325     int mLayerRank = -1;
326 
327     // When non-empty, this represents the bounds this task will be drawn at. This gets set during
328     // transient operations such as split-divider dragging and animations.
329     // TODO(b/119687367): This member is temporary.
330     final Rect mDisplayedBounds = new Rect();
331 
332     /** Helper object used for updating override configuration. */
333     private Configuration mTmpConfig = new Configuration();
334 
335     // TODO: remove after unification
336     Task mTask;
337 
338     /** Used by fillTaskInfo */
339     final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
340 
341     /**
342      * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
343      * ActivityInfo, Intent, TaskDescription)} instead.
344      */
TaskRecord(ActivityTaskManagerService service, int _taskId, ActivityInfo info, Intent _intent, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor)345     TaskRecord(ActivityTaskManagerService service, int _taskId, ActivityInfo info, Intent _intent,
346             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
347         mService = service;
348         userId = UserHandle.getUserId(info.applicationInfo.uid);
349         taskId = _taskId;
350         lastActiveTime = SystemClock.elapsedRealtime();
351         mAffiliatedTaskId = _taskId;
352         voiceSession = _voiceSession;
353         voiceInteractor = _voiceInteractor;
354         isAvailable = true;
355         mActivities = new ArrayList<>();
356         mCallingUid = info.applicationInfo.uid;
357         mCallingPackage = info.packageName;
358         setIntent(_intent, info);
359         setMinDimensions(info);
360         touchActiveTime();
361         mService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
362     }
363 
364     /**
365      * Don't use constructor directly.
366      * Use {@link #create(ActivityTaskManagerService, int, ActivityInfo,
367      * Intent, IVoiceInteractionSession, IVoiceInteractor)} instead.
368      */
TaskRecord(ActivityTaskManagerService service, int _taskId, ActivityInfo info, Intent _intent, TaskDescription _taskDescription)369     TaskRecord(ActivityTaskManagerService service, int _taskId, ActivityInfo info, Intent _intent,
370             TaskDescription _taskDescription) {
371         mService = service;
372         userId = UserHandle.getUserId(info.applicationInfo.uid);
373         taskId = _taskId;
374         lastActiveTime = SystemClock.elapsedRealtime();
375         mAffiliatedTaskId = _taskId;
376         voiceSession = null;
377         voiceInteractor = null;
378         isAvailable = true;
379         mActivities = new ArrayList<>();
380         mCallingUid = info.applicationInfo.uid;
381         mCallingPackage = info.packageName;
382         setIntent(_intent, info);
383         setMinDimensions(info);
384 
385         isPersistable = true;
386         // Clamp to [1, max].
387         maxRecents = Math.min(Math.max(info.maxRecents, 1),
388                 ActivityTaskManager.getMaxAppRecentsLimitStatic());
389 
390         lastTaskDescription = _taskDescription;
391         touchActiveTime();
392         mService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
393     }
394 
395     /**
396      * Don't use constructor directly. This is only used by XML parser.
397      */
TaskRecord(ActivityTaskManagerService service, int _taskId, Intent _intent, Intent _affinityIntent, String _affinity, String _rootAffinity, ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight)398     TaskRecord(ActivityTaskManagerService service, int _taskId, Intent _intent,
399             Intent _affinityIntent, String _affinity, String _rootAffinity,
400             ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
401             boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
402             int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities,
403             long lastTimeMoved, boolean neverRelinquishIdentity,
404             TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
405             int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
406             int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
407             boolean userSetupComplete, int minWidth, int minHeight) {
408         mService = service;
409         taskId = _taskId;
410         intent = _intent;
411         affinityIntent = _affinityIntent;
412         affinity = _affinity;
413         rootAffinity = _rootAffinity;
414         voiceSession = null;
415         voiceInteractor = null;
416         realActivity = _realActivity;
417         realActivitySuspended = _realActivitySuspended;
418         origActivity = _origActivity;
419         rootWasReset = _rootWasReset;
420         isAvailable = true;
421         autoRemoveRecents = _autoRemoveRecents;
422         askedCompatMode = _askedCompatMode;
423         userId = _userId;
424         mUserSetupComplete = userSetupComplete;
425         effectiveUid = _effectiveUid;
426         lastActiveTime = SystemClock.elapsedRealtime();
427         lastDescription = _lastDescription;
428         mActivities = activities;
429         mLastTimeMoved = lastTimeMoved;
430         mNeverRelinquishIdentity = neverRelinquishIdentity;
431         lastTaskDescription = _lastTaskDescription;
432         mAffiliatedTaskId = taskAffiliation;
433         mAffiliatedTaskColor = taskAffiliationColor;
434         mPrevAffiliateTaskId = prevTaskId;
435         mNextAffiliateTaskId = nextTaskId;
436         mCallingUid = callingUid;
437         mCallingPackage = callingPackage;
438         mResizeMode = resizeMode;
439         mSupportsPictureInPicture = supportsPictureInPicture;
440         mMinWidth = minWidth;
441         mMinHeight = minHeight;
442         mService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
443     }
444 
getTask()445     Task getTask() {
446         return mTask;
447     }
448 
createTask(boolean onTop, boolean showForAllUsers)449     void createTask(boolean onTop, boolean showForAllUsers) {
450         if (mTask != null) {
451             throw new IllegalArgumentException("mTask=" + mTask
452                     + " already created for task=" + this);
453         }
454 
455         final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
456         final TaskStack stack = getStack().getTaskStack();
457 
458         if (stack == null) {
459             throw new IllegalArgumentException("TaskRecord: invalid stack=" + mStack);
460         }
461         EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
462         mTask = new Task(taskId, stack, userId, mService.mWindowManager, mResizeMode,
463                 mSupportsPictureInPicture, lastTaskDescription, this);
464         final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
465 
466         if (!mDisplayedBounds.isEmpty()) {
467             mTask.setOverrideDisplayedBounds(mDisplayedBounds);
468         }
469         // We only want to move the parents to the parents if we are creating this task at the
470         // top of its stack.
471         stack.addTask(mTask, position, showForAllUsers, onTop /* moveParents */);
472     }
473 
setTask(Task task)474     void setTask(Task task) {
475         mTask = task;
476     }
477 
cleanUpResourcesForDestroy()478     void cleanUpResourcesForDestroy() {
479         if (!mActivities.isEmpty()) {
480             return;
481         }
482 
483         // This task is going away, so save the last state if necessary.
484         saveLaunchingStateIfNeeded();
485 
486         // TODO: VI what about activity?
487         final boolean isVoiceSession = voiceSession != null;
488         if (isVoiceSession) {
489             try {
490                 voiceSession.taskFinished(intent, taskId);
491             } catch (RemoteException e) {
492             }
493         }
494         if (autoRemoveFromRecents() || isVoiceSession) {
495             // Task creator asked to remove this when done, or this task was a voice
496             // interaction, so it should not remain on the recent tasks list.
497             mService.mStackSupervisor.mRecentTasks.remove(this);
498         }
499 
500         removeWindowContainer();
501     }
502 
503     @VisibleForTesting
removeWindowContainer()504     void removeWindowContainer() {
505         mService.getLockTaskController().clearLockedTask(this);
506         if (mTask == null) {
507             if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: could not find taskId=" + taskId);
508             return;
509         }
510         mTask.removeIfPossible();
511         mTask = null;
512         if (!getWindowConfiguration().persistTaskBounds()) {
513             // Reset current bounds for task whose bounds shouldn't be persisted so it uses
514             // default configuration the next time it launches.
515             updateOverrideConfiguration(null);
516         }
517         mService.getTaskChangeNotificationController().notifyTaskRemoved(taskId);
518     }
519 
onSnapshotChanged(TaskSnapshot snapshot)520     public void onSnapshotChanged(TaskSnapshot snapshot) {
521         mService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(taskId, snapshot);
522     }
523 
setResizeMode(int resizeMode)524     void setResizeMode(int resizeMode) {
525         if (mResizeMode == resizeMode) {
526             return;
527         }
528         mResizeMode = resizeMode;
529         mTask.setResizeable(resizeMode);
530         mService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
531         mService.mRootActivityContainer.resumeFocusedStacksTopActivities();
532     }
533 
setTaskDockedResizing(boolean resizing)534     void setTaskDockedResizing(boolean resizing) {
535         if (mTask == null) {
536             Slog.w(TAG_WM, "setTaskDockedResizing: taskId " + taskId + " not found.");
537             return;
538         }
539         mTask.setTaskDockedResizing(resizing);
540     }
541 
542     // TODO: Consolidate this with the resize() method below.
requestResize(Rect bounds, int resizeMode)543     public void requestResize(Rect bounds, int resizeMode) {
544         mService.resizeTask(taskId, bounds, resizeMode);
545     }
546 
resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume)547     boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
548         mService.mWindowManager.deferSurfaceLayout();
549 
550         try {
551             if (!isResizeable()) {
552                 Slog.w(TAG, "resizeTask: task " + this + " not resizeable.");
553                 return true;
554             }
555 
556             // If this is a forced resize, let it go through even if the bounds is not changing,
557             // as we might need a relayout due to surface size change (to/from fullscreen).
558             final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
559             if (equivalentRequestedOverrideBounds(bounds) && !forced) {
560                 // Nothing to do here...
561                 return true;
562             }
563 
564             if (mTask == null) {
565                 // Task doesn't exist in window manager yet (e.g. was restored from recents).
566                 // All we can do for now is update the bounds so it can be used when the task is
567                 // added to window manager.
568                 updateOverrideConfiguration(bounds);
569                 if (!inFreeformWindowingMode()) {
570                     // re-restore the task so it can have the proper stack association.
571                     mService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
572                 }
573                 return true;
574             }
575 
576             if (!canResizeToBounds(bounds)) {
577                 throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
578                         + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
579             }
580 
581             // Do not move the task to another stack here.
582             // This method assumes that the task is already placed in the right stack.
583             // we do not mess with that decision and we only do the resize!
584 
585             Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + taskId);
586 
587             final boolean updatedConfig = updateOverrideConfiguration(bounds);
588             // This variable holds information whether the configuration didn't change in a significant
589 
590             // way and the activity was kept the way it was. If it's false, it means the activity
591             // had
592             // to be relaunched due to configuration change.
593             boolean kept = true;
594             if (updatedConfig) {
595                 final ActivityRecord r = topRunningActivityLocked();
596                 if (r != null && !deferResume) {
597                     kept = r.ensureActivityConfiguration(0 /* globalChanges */,
598                             preserveWindow);
599                     // Preserve other windows for resizing because if resizing happens when there
600                     // is a dialog activity in the front, the activity that still shows some
601                     // content to the user will become black and cause flickers. Note in most cases
602                     // this won't cause tons of irrelevant windows being preserved because only
603                     // activities in this task may experience a bounds change. Configs for other
604                     // activities stay the same.
605                     mService.mRootActivityContainer.ensureActivitiesVisible(r, 0, preserveWindow);
606                     if (!kept) {
607                         mService.mRootActivityContainer.resumeFocusedStacksTopActivities();
608                     }
609                 }
610             }
611             mTask.resize(kept, forced);
612 
613             saveLaunchingStateIfNeeded();
614 
615             Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
616             return kept;
617         } finally {
618             mService.mWindowManager.continueSurfaceLayout();
619         }
620     }
621 
622     // TODO: Investigate combining with the resize() method above.
resizeWindowContainer()623     void resizeWindowContainer() {
624         mTask.resize(false /* relayout */, false /* forced */);
625     }
626 
getWindowContainerBounds(Rect bounds)627     void getWindowContainerBounds(Rect bounds) {
628         if (mTask != null) {
629             mTask.getBounds(bounds);
630         } else {
631             bounds.setEmpty();
632         }
633     }
634 
635     /**
636      * Convenience method to reparent a task to the top or bottom position of the stack.
637      */
reparent(ActivityStack preferredStack, boolean toTop, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, String reason)638     boolean reparent(ActivityStack preferredStack, boolean toTop,
639             @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
640             String reason) {
641         return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume,
642                 true /* schedulePictureInPictureModeChange */, reason);
643     }
644 
645     /**
646      * Convenience method to reparent a task to the top or bottom position of the stack, with
647      * an option to skip scheduling the picture-in-picture mode change.
648      */
reparent(ActivityStack preferredStack, boolean toTop, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason)649     boolean reparent(ActivityStack preferredStack, boolean toTop,
650             @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
651             boolean schedulePictureInPictureModeChange, String reason) {
652         return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate,
653                 deferResume, schedulePictureInPictureModeChange, reason);
654     }
655 
656     /** Convenience method to reparent a task to a specific position of the stack. */
reparent(ActivityStack preferredStack, int position, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, String reason)657     boolean reparent(ActivityStack preferredStack, int position,
658             @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
659             String reason) {
660         return reparent(preferredStack, position, moveStackMode, animate, deferResume,
661                 true /* schedulePictureInPictureModeChange */, reason);
662     }
663 
664     /**
665      * Reparents the task into a preferred stack, creating it if necessary.
666      *
667      * @param preferredStack the target stack to move this task
668      * @param position the position to place this task in the new stack
669      * @param animate whether or not we should wait for the new window created as a part of the
670      *            reparenting to be drawn and animated in
671      * @param moveStackMode whether or not to move the stack to the front always, only if it was
672      *            previously focused & in front, or never
673      * @param deferResume whether or not to update the visibility of other tasks and stacks that may
674      *            have changed as a result of this reparenting
675      * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
676      *            change. Callers may set this to false if they are explicitly scheduling PiP mode
677      *            changes themselves, like during the PiP animation
678      * @param reason the caller of this reparenting
679      * @return whether the task was reparented
680      */
681     // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
682     // re-parenting the task. Can only be done when we are no longer using static stack Ids.
reparent(ActivityStack preferredStack, int position, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason)683     boolean reparent(ActivityStack preferredStack, int position,
684             @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
685             boolean schedulePictureInPictureModeChange, String reason) {
686         final ActivityStackSupervisor supervisor = mService.mStackSupervisor;
687         final RootActivityContainer root = mService.mRootActivityContainer;
688         final WindowManagerService windowManager = mService.mWindowManager;
689         final ActivityStack sourceStack = getStack();
690         final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack,
691                 position == MAX_VALUE);
692         if (toStack == sourceStack) {
693             return false;
694         }
695         if (!canBeLaunchedOnDisplay(toStack.mDisplayId)) {
696             return false;
697         }
698 
699         final boolean toTopOfStack = position == MAX_VALUE;
700         if (toTopOfStack && toStack.getResumedActivity() != null
701                 && toStack.topRunningActivityLocked() != null) {
702             // Pause the resumed activity on the target stack while re-parenting task on top of it.
703             toStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
704                     null /* resuming */, false /* pauseImmediately */);
705         }
706 
707         final int toStackWindowingMode = toStack.getWindowingMode();
708         final ActivityRecord topActivity = getTopActivity();
709 
710         final boolean mightReplaceWindow = topActivity != null
711                 && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode);
712         if (mightReplaceWindow) {
713             // We are about to relaunch the activity because its configuration changed due to
714             // being maximized, i.e. size change. The activity will first remove the old window
715             // and then add a new one. This call will tell window manager about this, so it can
716             // preserve the old window until the new one is drawn. This prevents having a gap
717             // between the removal and addition, in which no window is visible. We also want the
718             // entrance of the new window to be properly animated.
719             // Note here we always set the replacing window first, as the flags might be needed
720             // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
721             windowManager.setWillReplaceWindow(topActivity.appToken, animate);
722         }
723 
724         windowManager.deferSurfaceLayout();
725         boolean kept = true;
726         try {
727             final ActivityRecord r = topRunningActivityLocked();
728             final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack)
729                     && (topRunningActivityLocked() == r);
730             final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r;
731             final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
732 
733             // In some cases the focused stack isn't the front stack. E.g. pinned stack.
734             // Whenever we are moving the top activity from the front stack we want to make sure to
735             // move the stack to the front.
736             final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay()
737                     && (sourceStack.topRunningActivityLocked() == r);
738 
739             // Adjust the position for the new parent stack as needed.
740             position = toStack.getAdjustedPositionForTask(this, position, null /* starting */);
741 
742             // Must reparent first in window manager to avoid a situation where AM can delete the
743             // we are coming from in WM before we reparent because it became empty.
744             mTask.reparent(toStack.getTaskStack(), position,
745                     moveStackMode == REPARENT_MOVE_STACK_TO_FRONT);
746 
747             final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
748                     || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
749             // Move the task
750             sourceStack.removeTask(this, reason, moveStackToFront
751                     ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING);
752             toStack.addTask(this, position, false /* schedulePictureInPictureModeChange */, reason);
753 
754             if (schedulePictureInPictureModeChange) {
755                 // Notify of picture-in-picture mode changes
756                 supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
757             }
758 
759             // TODO: Ensure that this is actually necessary here
760             // Notify the voice session if required
761             if (voiceSession != null) {
762                 try {
763                     voiceSession.taskStarted(intent, taskId);
764                 } catch (RemoteException e) {
765                 }
766             }
767 
768             // If the task had focus before (or we're requested to move focus), move focus to the
769             // new stack by moving the stack to the front.
770             if (r != null) {
771                 toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed,
772                         wasPaused, reason);
773             }
774             if (!animate) {
775                 mService.mStackSupervisor.mNoAnimActivities.add(topActivity);
776             }
777 
778             // We might trigger a configuration change. Save the current task bounds for freezing.
779             // TODO: Should this call be moved inside the resize method in WM?
780             toStack.prepareFreezingTaskBounds();
781 
782             // Make sure the task has the appropriate bounds/size for the stack it is in.
783             final boolean toStackSplitScreenPrimary =
784                     toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
785             final Rect configBounds = getRequestedOverrideBounds();
786             if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN
787                     || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
788                     && !Objects.equals(configBounds, toStack.getRequestedOverrideBounds())) {
789                 kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
790                         !mightReplaceWindow, deferResume);
791             } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
792                 Rect bounds = getLaunchBounds();
793                 if (bounds == null) {
794                     mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
795                     bounds = configBounds;
796                 }
797                 kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
798             } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) {
799                 if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
800                     // Move recents to front so it is not behind home stack when going into docked
801                     // mode
802                     mService.mStackSupervisor.moveRecentsStackToFront(reason);
803                 }
804                 kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
805                         !mightReplaceWindow, deferResume);
806             }
807         } finally {
808             windowManager.continueSurfaceLayout();
809         }
810 
811         if (mightReplaceWindow) {
812             // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
813             // window), we need to clear the replace window settings. Otherwise, we schedule a
814             // timeout to remove the old window if the replacing window is not coming in time.
815             windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
816         }
817 
818         if (!deferResume) {
819             // The task might have already been running and its visibility needs to be synchronized
820             // with the visibility of the stack / windows.
821             root.ensureActivitiesVisible(null, 0, !mightReplaceWindow);
822             root.resumeFocusedStacksTopActivities();
823         }
824 
825         // TODO: Handle incorrect request to move before the actual move, not after.
826         supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
827                 DEFAULT_DISPLAY, toStack);
828 
829         return (preferredStack == toStack);
830     }
831 
832     /**
833      * @return True if the windows of tasks being moved to the target stack from the source stack
834      * should be replaced, meaning that window manager will keep the old window around until the new
835      * is ready.
836      */
replaceWindowsOnTaskMove( int sourceWindowingMode, int targetWindowingMode)837     private static boolean replaceWindowsOnTaskMove(
838             int sourceWindowingMode, int targetWindowingMode) {
839         return sourceWindowingMode == WINDOWING_MODE_FREEFORM
840                 || targetWindowingMode == WINDOWING_MODE_FREEFORM;
841     }
842 
cancelWindowTransition()843     void cancelWindowTransition() {
844         if (mTask == null) {
845             Slog.w(TAG_WM, "cancelWindowTransition: taskId " + taskId + " not found.");
846             return;
847         }
848         mTask.cancelTaskWindowTransition();
849     }
850 
851     /**
852      * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
853      */
getSnapshot(boolean reducedResolution, boolean restoreFromDisk)854     TaskSnapshot getSnapshot(boolean reducedResolution, boolean restoreFromDisk) {
855 
856         // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
857         // synchronized between AM and WM.
858         return mService.mWindowManager.getTaskSnapshot(taskId, userId, reducedResolution,
859                 restoreFromDisk);
860     }
861 
touchActiveTime()862     void touchActiveTime() {
863         lastActiveTime = SystemClock.elapsedRealtime();
864     }
865 
getInactiveDuration()866     long getInactiveDuration() {
867         return SystemClock.elapsedRealtime() - lastActiveTime;
868     }
869 
870     /** Sets the original intent, and the calling uid and package. */
setIntent(ActivityRecord r)871     void setIntent(ActivityRecord r) {
872         mCallingUid = r.launchedFromUid;
873         mCallingPackage = r.launchedFromPackage;
874         setIntent(r.intent, r.info);
875         setLockTaskAuth(r);
876     }
877 
878     /** Sets the original intent, _without_ updating the calling uid or package. */
setIntent(Intent _intent, ActivityInfo info)879     private void setIntent(Intent _intent, ActivityInfo info) {
880         if (intent == null) {
881             mNeverRelinquishIdentity =
882                     (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
883         } else if (mNeverRelinquishIdentity) {
884             return;
885         }
886 
887         affinity = info.taskAffinity;
888         if (intent == null) {
889             // If this task already has an intent associated with it, don't set the root
890             // affinity -- we don't want it changing after initially set, but the initially
891             // set value may be null.
892             rootAffinity = affinity;
893         }
894         effectiveUid = info.applicationInfo.uid;
895         stringName = null;
896 
897         if (info.targetActivity == null) {
898             if (_intent != null) {
899                 // If this Intent has a selector, we want to clear it for the
900                 // recent task since it is not relevant if the user later wants
901                 // to re-launch the app.
902                 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
903                     _intent = new Intent(_intent);
904                     _intent.setSelector(null);
905                     _intent.setSourceBounds(null);
906                 }
907             }
908             if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
909             intent = _intent;
910             realActivity = _intent != null ? _intent.getComponent() : null;
911             origActivity = null;
912         } else {
913             ComponentName targetComponent = new ComponentName(
914                     info.packageName, info.targetActivity);
915             if (_intent != null) {
916                 Intent targetIntent = new Intent(_intent);
917                 targetIntent.setSelector(null);
918                 targetIntent.setSourceBounds(null);
919                 if (DEBUG_TASKS) Slog.v(TAG_TASKS,
920                         "Setting Intent of " + this + " to target " + targetIntent);
921                 intent = targetIntent;
922                 realActivity = targetComponent;
923                 origActivity = _intent.getComponent();
924             } else {
925                 intent = null;
926                 realActivity = targetComponent;
927                 origActivity = new ComponentName(info.packageName, info.name);
928             }
929         }
930 
931         final int intentFlags = intent == null ? 0 : intent.getFlags();
932         if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
933             // Once we are set to an Intent with this flag, we count this
934             // task as having a true root activity.
935             rootWasReset = true;
936         }
937         userId = UserHandle.getUserId(info.applicationInfo.uid);
938         mUserSetupComplete = Settings.Secure.getIntForUser(mService.mContext.getContentResolver(),
939                 USER_SETUP_COMPLETE, 0, userId) != 0;
940         if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
941             // If the activity itself has requested auto-remove, then just always do it.
942             autoRemoveRecents = true;
943         } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
944                 == FLAG_ACTIVITY_NEW_DOCUMENT) {
945             // If the caller has not asked for the document to be retained, then we may
946             // want to turn on auto-remove, depending on whether the target has set its
947             // own document launch mode.
948             if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
949                 autoRemoveRecents = false;
950             } else {
951                 autoRemoveRecents = true;
952             }
953         } else {
954             autoRemoveRecents = false;
955         }
956         mResizeMode = info.resizeMode;
957         mSupportsPictureInPicture = info.supportsPictureInPicture();
958     }
959 
960     /** Sets the original minimal width and height. */
setMinDimensions(ActivityInfo info)961     private void setMinDimensions(ActivityInfo info) {
962         if (info != null && info.windowLayout != null) {
963             mMinWidth = info.windowLayout.minWidth;
964             mMinHeight = info.windowLayout.minHeight;
965         } else {
966             mMinWidth = INVALID_MIN_SIZE;
967             mMinHeight = INVALID_MIN_SIZE;
968         }
969     }
970 
971     /**
972      * Return true if the input activity has the same intent filter as the intent this task
973      * record is based on (normally the root activity intent).
974      */
isSameIntentFilter(ActivityRecord r)975     boolean isSameIntentFilter(ActivityRecord r) {
976         final Intent intent = new Intent(r.intent);
977         // Make sure the component are the same if the input activity has the same real activity
978         // as the one in the task because either one of them could be the alias activity.
979         if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) {
980             intent.setComponent(this.intent.getComponent());
981         }
982         return intent.filterEquals(this.intent);
983     }
984 
returnsToHomeStack()985     boolean returnsToHomeStack() {
986         final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME;
987         return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags;
988     }
989 
setPrevAffiliate(TaskRecord prevAffiliate)990     void setPrevAffiliate(TaskRecord prevAffiliate) {
991         mPrevAffiliate = prevAffiliate;
992         mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.taskId;
993     }
994 
setNextAffiliate(TaskRecord nextAffiliate)995     void setNextAffiliate(TaskRecord nextAffiliate) {
996         mNextAffiliate = nextAffiliate;
997         mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId;
998     }
999 
getStack()1000     <T extends ActivityStack> T getStack() {
1001         return (T) mStack;
1002     }
1003 
1004     /**
1005      * Must be used for setting parent stack because it performs configuration updates.
1006      * Must be called after adding task as a child to the stack.
1007      */
setStack(ActivityStack stack)1008     void setStack(ActivityStack stack) {
1009         if (stack != null && !stack.isInStackLocked(this)) {
1010             throw new IllegalStateException("Task must be added as a Stack child first.");
1011         }
1012         final ActivityStack oldStack = mStack;
1013         mStack = stack;
1014 
1015         // If the new {@link TaskRecord} is from a different {@link ActivityStack}, remove this
1016         // {@link ActivityRecord} from its current {@link ActivityStack}.
1017 
1018         if (oldStack != mStack) {
1019             for (int i = getChildCount() - 1; i >= 0; --i) {
1020                 final ActivityRecord activity = getChildAt(i);
1021 
1022                 if (oldStack != null) {
1023                     oldStack.onActivityRemovedFromStack(activity);
1024                 }
1025 
1026                 if (mStack != null) {
1027                     stack.onActivityAddedToStack(activity);
1028                 }
1029             }
1030         }
1031 
1032         onParentChanged();
1033     }
1034 
1035     /**
1036      * @return Id of current stack, {@link INVALID_STACK_ID} if no stack is set.
1037      */
getStackId()1038     int getStackId() {
1039         return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
1040     }
1041 
1042     @Override
getChildCount()1043     protected int getChildCount() {
1044         return mActivities.size();
1045     }
1046 
1047     @Override
getChildAt(int index)1048     protected ActivityRecord getChildAt(int index) {
1049         return mActivities.get(index);
1050     }
1051 
1052     @Override
getParent()1053     protected ConfigurationContainer getParent() {
1054         return mStack;
1055     }
1056 
1057     @Override
onParentChanged()1058     protected void onParentChanged() {
1059         super.onParentChanged();
1060         mService.mRootActivityContainer.updateUIDsPresentOnDisplay();
1061     }
1062 
1063     // Close up recents linked list.
closeRecentsChain()1064     private void closeRecentsChain() {
1065         if (mPrevAffiliate != null) {
1066             mPrevAffiliate.setNextAffiliate(mNextAffiliate);
1067         }
1068         if (mNextAffiliate != null) {
1069             mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
1070         }
1071         setPrevAffiliate(null);
1072         setNextAffiliate(null);
1073     }
1074 
removedFromRecents()1075     void removedFromRecents() {
1076         closeRecentsChain();
1077         if (inRecents) {
1078             inRecents = false;
1079             mService.notifyTaskPersisterLocked(this, false);
1080         }
1081 
1082         clearRootProcess();
1083 
1084         // TODO: Use window container controller once tasks are better synced between AM and WM
1085         mService.mWindowManager.notifyTaskRemovedFromRecents(taskId, userId);
1086     }
1087 
setTaskToAffiliateWith(TaskRecord taskToAffiliateWith)1088     void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
1089         closeRecentsChain();
1090         mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
1091         mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
1092         // Find the end
1093         while (taskToAffiliateWith.mNextAffiliate != null) {
1094             final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate;
1095             if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
1096                 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
1097                         + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
1098                 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
1099                     nextRecents.setPrevAffiliate(null);
1100                 }
1101                 taskToAffiliateWith.setNextAffiliate(null);
1102                 break;
1103             }
1104             taskToAffiliateWith = nextRecents;
1105         }
1106         taskToAffiliateWith.setNextAffiliate(this);
1107         setPrevAffiliate(taskToAffiliateWith);
1108         setNextAffiliate(null);
1109     }
1110 
1111     /** Returns the intent for the root activity for this task */
getBaseIntent()1112     Intent getBaseIntent() {
1113         return intent != null ? intent : affinityIntent;
1114     }
1115 
1116     /** Returns the first non-finishing activity from the root. */
getRootActivity()1117     ActivityRecord getRootActivity() {
1118         for (int i = 0; i < mActivities.size(); i++) {
1119             final ActivityRecord r = mActivities.get(i);
1120             if (r.finishing) {
1121                 continue;
1122             }
1123             return r;
1124         }
1125         return null;
1126     }
1127 
getTopActivity()1128     ActivityRecord getTopActivity() {
1129         return getTopActivity(true /* includeOverlays */);
1130     }
1131 
getTopActivity(boolean includeOverlays)1132     ActivityRecord getTopActivity(boolean includeOverlays) {
1133         for (int i = mActivities.size() - 1; i >= 0; --i) {
1134             final ActivityRecord r = mActivities.get(i);
1135             if (r.finishing || (!includeOverlays && r.mTaskOverlay)) {
1136                 continue;
1137             }
1138             return r;
1139         }
1140         return null;
1141     }
1142 
topRunningActivityLocked()1143     ActivityRecord topRunningActivityLocked() {
1144         if (mStack != null) {
1145             for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
1146                 ActivityRecord r = mActivities.get(activityNdx);
1147                 if (!r.finishing && r.okToShowLocked()) {
1148                     return r;
1149                 }
1150             }
1151         }
1152         return null;
1153     }
1154 
isVisible()1155     boolean isVisible() {
1156         for (int i = mActivities.size() - 1; i >= 0; --i) {
1157             final ActivityRecord r = mActivities.get(i);
1158             if (r.visible) {
1159                 return true;
1160             }
1161         }
1162         return false;
1163     }
1164 
1165     /**
1166      * Return true if any activities in this task belongs to input uid.
1167      */
containsAppUid(int uid)1168     boolean containsAppUid(int uid) {
1169         for (int i = mActivities.size() - 1; i >= 0; --i) {
1170             final ActivityRecord r = mActivities.get(i);
1171             if (r.getUid() == uid) {
1172                 return true;
1173             }
1174         }
1175         return false;
1176     }
1177 
getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities)1178     void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
1179         if (mStack != null) {
1180             for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
1181                 ActivityRecord r = mActivities.get(activityNdx);
1182                 if (!r.finishing && r.okToShowLocked() && r.visibleIgnoringKeyguard) {
1183                     outActivities.add(r);
1184                 }
1185             }
1186         }
1187     }
1188 
topRunningActivityWithStartingWindowLocked()1189     ActivityRecord topRunningActivityWithStartingWindowLocked() {
1190         if (mStack != null) {
1191             for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
1192                 ActivityRecord r = mActivities.get(activityNdx);
1193                 if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
1194                         || r.finishing || !r.okToShowLocked()) {
1195                     continue;
1196                 }
1197                 return r;
1198             }
1199         }
1200         return null;
1201     }
1202 
1203     /**
1204      * Return the number of running activities, and the number of non-finishing/initializing
1205      * activities in the provided {@param reportOut} respectively.
1206      */
getNumRunningActivities(TaskActivitiesReport reportOut)1207     void getNumRunningActivities(TaskActivitiesReport reportOut) {
1208         reportOut.reset();
1209         for (int i = mActivities.size() - 1; i >= 0; --i) {
1210             final ActivityRecord r = mActivities.get(i);
1211             if (r.finishing) {
1212                 continue;
1213             }
1214 
1215             reportOut.base = r;
1216 
1217             // Increment the total number of non-finishing activities
1218             reportOut.numActivities++;
1219 
1220             if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) {
1221                 reportOut.top = r;
1222                 // Reset the number of running activities until we hit the first non-initializing
1223                 // activity
1224                 reportOut.numRunning = 0;
1225             }
1226             if (r.attachedToProcess()) {
1227                 // Increment the number of actually running activities
1228                 reportOut.numRunning++;
1229             }
1230         }
1231     }
1232 
okToShowLocked()1233     boolean okToShowLocked() {
1234         // NOTE: If {@link TaskRecord#topRunningActivity} return is not null then it is
1235         // okay to show the activity when locked.
1236         return mService.mStackSupervisor.isCurrentProfileLocked(userId)
1237                 || topRunningActivityLocked() != null;
1238     }
1239 
1240     /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
setFrontOfTask()1241     final void setFrontOfTask() {
1242         boolean foundFront = false;
1243         final int numActivities = mActivities.size();
1244         for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
1245             final ActivityRecord r = mActivities.get(activityNdx);
1246             if (foundFront || r.finishing) {
1247                 r.frontOfTask = false;
1248             } else {
1249                 r.frontOfTask = true;
1250                 // Set frontOfTask false for every following activity.
1251                 foundFront = true;
1252             }
1253         }
1254         if (!foundFront && numActivities > 0) {
1255             // All activities of this task are finishing. As we ought to have a frontOfTask
1256             // activity, make the bottom activity front.
1257             mActivities.get(0).frontOfTask = true;
1258         }
1259     }
1260 
1261     /**
1262      * Reorder the history stack so that the passed activity is brought to the front.
1263      */
moveActivityToFrontLocked(ActivityRecord newTop)1264     final void moveActivityToFrontLocked(ActivityRecord newTop) {
1265         if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE,
1266                 "Removing and adding activity " + newTop
1267                 + " to stack at top callers=" + Debug.getCallers(4));
1268 
1269         mActivities.remove(newTop);
1270         mActivities.add(newTop);
1271 
1272         // Make sure window manager is aware of the position change.
1273         mTask.positionChildAtTop(newTop.mAppWindowToken);
1274         updateEffectiveIntent();
1275 
1276         setFrontOfTask();
1277     }
1278 
addActivityToTop(ActivityRecord r)1279     void addActivityToTop(ActivityRecord r) {
1280         addActivityAtIndex(mActivities.size(), r);
1281     }
1282 
1283     @Override
1284     /*@WindowConfiguration.ActivityType*/
getActivityType()1285     public int getActivityType() {
1286         final int applicationType = super.getActivityType();
1287         if (applicationType != ACTIVITY_TYPE_UNDEFINED || mActivities.isEmpty()) {
1288             return applicationType;
1289         }
1290         return mActivities.get(0).getActivityType();
1291     }
1292 
1293     /**
1294      * Adds an activity {@param r} at the given {@param index}. The activity {@param r} must either
1295      * be in the current task or unparented to any task.
1296      */
addActivityAtIndex(int index, ActivityRecord r)1297     void addActivityAtIndex(int index, ActivityRecord r) {
1298         TaskRecord task = r.getTaskRecord();
1299         if (task != null && task != this) {
1300             throw new IllegalArgumentException("Can not add r=" + " to task=" + this
1301                     + " current parent=" + task);
1302         }
1303 
1304         r.setTask(this);
1305 
1306         // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
1307         if (!mActivities.remove(r) && r.fullscreen) {
1308             // Was not previously in list.
1309             numFullscreen++;
1310         }
1311         // Only set this based on the first activity
1312         if (mActivities.isEmpty()) {
1313             if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
1314                 // Normally non-standard activity type for the activity record will be set when the
1315                 // object is created, however we delay setting the standard application type until
1316                 // this point so that the task can set the type for additional activities added in
1317                 // the else condition below.
1318                 r.setActivityType(ACTIVITY_TYPE_STANDARD);
1319             }
1320             setActivityType(r.getActivityType());
1321             isPersistable = r.isPersistable();
1322             mCallingUid = r.launchedFromUid;
1323             mCallingPackage = r.launchedFromPackage;
1324             // Clamp to [1, max].
1325             maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
1326                     ActivityTaskManager.getMaxAppRecentsLimitStatic());
1327         } else {
1328             // Otherwise make all added activities match this one.
1329             r.setActivityType(getActivityType());
1330         }
1331 
1332         final int size = mActivities.size();
1333 
1334         if (index == size && size > 0) {
1335             final ActivityRecord top = mActivities.get(size - 1);
1336             if (top.mTaskOverlay) {
1337                 // Place below the task overlay activity since the overlay activity should always
1338                 // be on top.
1339                 index--;
1340             }
1341         }
1342 
1343         index = Math.min(size, index);
1344         mActivities.add(index, r);
1345 
1346         updateEffectiveIntent();
1347         if (r.isPersistable()) {
1348             mService.notifyTaskPersisterLocked(this, false);
1349         }
1350 
1351         if (r.mAppWindowToken != null) {
1352             // Only attempt to move in WM if the child has a controller. It is possible we haven't
1353             // created controller for the activity we are starting yet.
1354             mTask.positionChildAt(r.mAppWindowToken, index);
1355         }
1356 
1357         // Make sure the list of display UID whitelists is updated
1358         // now that this record is in a new task.
1359         mService.mRootActivityContainer.updateUIDsPresentOnDisplay();
1360     }
1361 
1362     /**
1363      * Removes the specified activity from this task.
1364      * @param r The {@link ActivityRecord} to remove.
1365      * @return true if this was the last activity in the task.
1366      */
removeActivity(ActivityRecord r)1367     boolean removeActivity(ActivityRecord r) {
1368         return removeActivity(r, false /* reparenting */);
1369     }
1370 
removeActivity(ActivityRecord r, boolean reparenting)1371     boolean removeActivity(ActivityRecord r, boolean reparenting) {
1372         if (r.getTaskRecord() != this) {
1373             throw new IllegalArgumentException(
1374                     "Activity=" + r + " does not belong to task=" + this);
1375         }
1376 
1377         r.setTask(null /* task */, reparenting /* reparenting */);
1378 
1379         if (mActivities.remove(r) && r.fullscreen) {
1380             // Was previously in list.
1381             numFullscreen--;
1382         }
1383         if (r.isPersistable()) {
1384             mService.notifyTaskPersisterLocked(this, false);
1385         }
1386 
1387         if (inPinnedWindowingMode()) {
1388             // We normally notify listeners of task stack changes on pause, however pinned stack
1389             // activities are normally in the paused state so no notification will be sent there
1390             // before the activity is removed. We send it here so instead.
1391             mService.getTaskChangeNotificationController().notifyTaskStackChanged();
1392         }
1393 
1394         if (mActivities.isEmpty()) {
1395             return !mReuseTask;
1396         }
1397         updateEffectiveIntent();
1398         return false;
1399     }
1400 
1401     /**
1402      * @return whether or not there are ONLY task overlay activities in the stack.
1403      *         If {@param excludeFinishing} is set, then ignore finishing activities in the check.
1404      *         If there are no task overlay activities, this call returns false.
1405      */
onlyHasTaskOverlayActivities(boolean excludeFinishing)1406     boolean onlyHasTaskOverlayActivities(boolean excludeFinishing) {
1407         int count = 0;
1408         for (int i = mActivities.size() - 1; i >= 0; i--) {
1409             final ActivityRecord r = mActivities.get(i);
1410             if (excludeFinishing && r.finishing) {
1411                 continue;
1412             }
1413             if (!r.mTaskOverlay) {
1414                 return false;
1415             }
1416             count++;
1417         }
1418         return count > 0;
1419     }
1420 
autoRemoveFromRecents()1421     boolean autoRemoveFromRecents() {
1422         // We will automatically remove the task either if it has explicitly asked for
1423         // this, or it is empty and has never contained an activity that got shown to
1424         // the user.
1425         return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible);
1426     }
1427 
1428     /**
1429      * Completely remove all activities associated with an existing
1430      * task starting at a specified index.
1431      */
performClearTaskAtIndexLocked(int activityNdx, boolean pauseImmediately, String reason)1432     final void performClearTaskAtIndexLocked(int activityNdx, boolean pauseImmediately,
1433             String reason) {
1434         int numActivities = mActivities.size();
1435         for ( ; activityNdx < numActivities; ++activityNdx) {
1436             final ActivityRecord r = mActivities.get(activityNdx);
1437             if (r.finishing) {
1438                 continue;
1439             }
1440             if (mStack == null) {
1441                 // Task was restored from persistent storage.
1442                 r.takeFromHistory();
1443                 mActivities.remove(activityNdx);
1444                 --activityNdx;
1445                 --numActivities;
1446             } else if (mStack.finishActivityLocked(r, Activity.RESULT_CANCELED, null,
1447                     reason, false, pauseImmediately)) {
1448                 --activityNdx;
1449                 --numActivities;
1450             }
1451         }
1452     }
1453 
1454     /**
1455      * Completely remove all activities associated with an existing task.
1456      */
performClearTaskLocked()1457     void performClearTaskLocked() {
1458         mReuseTask = true;
1459         performClearTaskAtIndexLocked(0, !PAUSE_IMMEDIATELY, "clear-task-all");
1460         mReuseTask = false;
1461     }
1462 
performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags)1463     ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
1464         mReuseTask = true;
1465         final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
1466         mReuseTask = false;
1467         return result;
1468     }
1469 
1470     /**
1471      * Perform clear operation as requested by
1472      * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
1473      * stack to the given task, then look for
1474      * an instance of that activity in the stack and, if found, finish all
1475      * activities on top of it and return the instance.
1476      *
1477      * @param newR Description of the new activity being started.
1478      * @return Returns the old activity that should be continued to be used,
1479      * or null if none was found.
1480      */
performClearTaskLocked(ActivityRecord newR, int launchFlags)1481     final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
1482         int numActivities = mActivities.size();
1483         for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
1484             ActivityRecord r = mActivities.get(activityNdx);
1485             if (r.finishing) {
1486                 continue;
1487             }
1488             if (r.mActivityComponent.equals(newR.mActivityComponent)) {
1489                 // Here it is!  Now finish everything in front...
1490                 final ActivityRecord ret = r;
1491 
1492                 for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
1493                     r = mActivities.get(activityNdx);
1494                     if (r.finishing) {
1495                         continue;
1496                     }
1497                     ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
1498                     if (opts != null) {
1499                         ret.updateOptionsLocked(opts);
1500                     }
1501                     if (mStack != null && mStack.finishActivityLocked(
1502                             r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
1503                         --activityNdx;
1504                         --numActivities;
1505                     }
1506                 }
1507 
1508                 // Finally, if this is a normal launch mode (that is, not
1509                 // expecting onNewIntent()), then we will finish the current
1510                 // instance of the activity so a new fresh one can be started.
1511                 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
1512                         && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
1513                         && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
1514                     if (!ret.finishing) {
1515                         if (mStack != null) {
1516                             mStack.finishActivityLocked(
1517                                     ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
1518                         }
1519                         return null;
1520                     }
1521                 }
1522 
1523                 return ret;
1524             }
1525         }
1526 
1527         return null;
1528     }
1529 
removeTaskActivitiesLocked(boolean pauseImmediately, String reason)1530     void removeTaskActivitiesLocked(boolean pauseImmediately, String reason) {
1531         // Just remove the entire task.
1532         performClearTaskAtIndexLocked(0, pauseImmediately, reason);
1533     }
1534 
lockTaskAuthToString()1535     String lockTaskAuthToString() {
1536         switch (mLockTaskAuth) {
1537             case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
1538             case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
1539             case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
1540             case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
1541             case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
1542             default: return "unknown=" + mLockTaskAuth;
1543         }
1544     }
1545 
setLockTaskAuth()1546     void setLockTaskAuth() {
1547         setLockTaskAuth(getRootActivity());
1548     }
1549 
setLockTaskAuth(@ullable ActivityRecord r)1550     private void setLockTaskAuth(@Nullable ActivityRecord r) {
1551         if (r == null) {
1552             mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
1553             return;
1554         }
1555 
1556         final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
1557         final LockTaskController lockTaskController = mService.getLockTaskController();
1558         switch (r.lockTaskLaunchMode) {
1559             case LOCK_TASK_LAUNCH_MODE_DEFAULT:
1560                 mLockTaskAuth = lockTaskController.isPackageWhitelisted(userId, pkg)
1561                         ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
1562                 break;
1563 
1564             case LOCK_TASK_LAUNCH_MODE_NEVER:
1565                 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
1566                 break;
1567 
1568             case LOCK_TASK_LAUNCH_MODE_ALWAYS:
1569                 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
1570                 break;
1571 
1572             case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
1573                 mLockTaskAuth = lockTaskController.isPackageWhitelisted(userId, pkg)
1574                         ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
1575                 break;
1576         }
1577         if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
1578                 " mLockTaskAuth=" + lockTaskAuthToString());
1579     }
1580 
isResizeable(boolean checkSupportsPip)1581     private boolean isResizeable(boolean checkSupportsPip) {
1582         return (mService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
1583                 || (checkSupportsPip && mSupportsPictureInPicture));
1584     }
1585 
isResizeable()1586     boolean isResizeable() {
1587         return isResizeable(true /* checkSupportsPip */);
1588     }
1589 
1590     @Override
supportsSplitScreenWindowingMode()1591     public boolean supportsSplitScreenWindowingMode() {
1592         // A task can not be docked even if it is considered resizeable because it only supports
1593         // picture-in-picture mode but has a non-resizeable resizeMode
1594         return super.supportsSplitScreenWindowingMode()
1595                 && mService.mSupportsSplitScreenMultiWindow
1596                 && (mService.mForceResizableActivities
1597                         || (isResizeable(false /* checkSupportsPip */)
1598                                 && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
1599     }
1600 
1601     /**
1602      * Check whether this task can be launched on the specified display.
1603      *
1604      * @param displayId Target display id.
1605      * @return {@code true} if either it is the default display or this activity can be put on a
1606      *         secondary display.
1607      */
canBeLaunchedOnDisplay(int displayId)1608     boolean canBeLaunchedOnDisplay(int displayId) {
1609         return mService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
1610                 -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
1611     }
1612 
1613     /**
1614      * Check that a given bounds matches the application requested orientation.
1615      *
1616      * @param bounds The bounds to be tested.
1617      * @return True if the requested bounds are okay for a resizing request.
1618      */
canResizeToBounds(Rect bounds)1619     private boolean canResizeToBounds(Rect bounds) {
1620         if (bounds == null || !inFreeformWindowingMode()) {
1621             // Note: If not on the freeform workspace, we ignore the bounds.
1622             return true;
1623         }
1624         final boolean landscape = bounds.width() > bounds.height();
1625         final Rect configBounds = getRequestedOverrideBounds();
1626         if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
1627             return configBounds.isEmpty()
1628                     || landscape == (configBounds.width() > configBounds.height());
1629         }
1630         return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
1631                 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
1632     }
1633 
1634     /**
1635      * @return {@code true} if the task is being cleared for the purposes of being reused.
1636      */
isClearingToReuseTask()1637     boolean isClearingToReuseTask() {
1638         return mReuseTask;
1639     }
1640 
1641     /**
1642      * Find the activity in the history stack within the given task.  Returns
1643      * the index within the history at which it's found, or < 0 if not found.
1644      */
findActivityInHistoryLocked(ActivityRecord r)1645     final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
1646         final ComponentName realActivity = r.mActivityComponent;
1647         for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
1648             ActivityRecord candidate = mActivities.get(activityNdx);
1649             if (candidate.finishing) {
1650                 continue;
1651             }
1652             if (candidate.mActivityComponent.equals(realActivity)) {
1653                 return candidate;
1654             }
1655         }
1656         return null;
1657     }
1658 
1659     /** Updates the last task description values. */
updateTaskDescription()1660     void updateTaskDescription() {
1661         // Traverse upwards looking for any break between main task activities and
1662         // utility activities.
1663         int activityNdx;
1664         final int numActivities = mActivities.size();
1665         final boolean relinquish = numActivities != 0 &&
1666                 (mActivities.get(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0;
1667         for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
1668                 ++activityNdx) {
1669             final ActivityRecord r = mActivities.get(activityNdx);
1670             if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1671                 // This will be the top activity for determining taskDescription. Pre-inc to
1672                 // overcome initial decrement below.
1673                 ++activityNdx;
1674                 break;
1675             }
1676             if (r.intent != null &&
1677                     (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
1678                 break;
1679             }
1680         }
1681         if (activityNdx > 0) {
1682             // Traverse downwards starting below break looking for set label, icon.
1683             // Note that if there are activities in the task but none of them set the
1684             // recent activity values, then we do not fall back to the last set
1685             // values in the TaskRecord.
1686             String label = null;
1687             String iconFilename = null;
1688             int iconResource = -1;
1689             int colorPrimary = 0;
1690             int colorBackground = 0;
1691             int statusBarColor = 0;
1692             int navigationBarColor = 0;
1693             boolean statusBarContrastWhenTransparent = false;
1694             boolean navigationBarContrastWhenTransparent = false;
1695             boolean topActivity = true;
1696             for (--activityNdx; activityNdx >= 0; --activityNdx) {
1697                 final ActivityRecord r = mActivities.get(activityNdx);
1698                 if (r.mTaskOverlay) {
1699                     continue;
1700                 }
1701                 if (r.taskDescription != null) {
1702                     if (label == null) {
1703                         label = r.taskDescription.getLabel();
1704                     }
1705                     if (iconResource == -1) {
1706                         iconResource = r.taskDescription.getIconResource();
1707                     }
1708                     if (iconFilename == null) {
1709                         iconFilename = r.taskDescription.getIconFilename();
1710                     }
1711                     if (colorPrimary == 0) {
1712                         colorPrimary = r.taskDescription.getPrimaryColor();
1713                     }
1714                     if (topActivity) {
1715                         colorBackground = r.taskDescription.getBackgroundColor();
1716                         statusBarColor = r.taskDescription.getStatusBarColor();
1717                         navigationBarColor = r.taskDescription.getNavigationBarColor();
1718                         statusBarContrastWhenTransparent =
1719                                 r.taskDescription.getEnsureStatusBarContrastWhenTransparent();
1720                         navigationBarContrastWhenTransparent =
1721                                 r.taskDescription.getEnsureNavigationBarContrastWhenTransparent();
1722                     }
1723                 }
1724                 topActivity = false;
1725             }
1726             lastTaskDescription = new TaskDescription(label, null, iconResource, iconFilename,
1727                     colorPrimary, colorBackground, statusBarColor, navigationBarColor,
1728                     statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent);
1729             if (mTask != null) {
1730                 mTask.setTaskDescription(lastTaskDescription);
1731             }
1732             // Update the task affiliation color if we are the parent of the group
1733             if (taskId == mAffiliatedTaskId) {
1734                 mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
1735             }
1736         }
1737     }
1738 
findEffectiveRootIndex()1739     int findEffectiveRootIndex() {
1740         int effectiveNdx = 0;
1741         final int topActivityNdx = mActivities.size() - 1;
1742         for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
1743             final ActivityRecord r = mActivities.get(activityNdx);
1744             if (r.finishing) {
1745                 continue;
1746             }
1747             effectiveNdx = activityNdx;
1748             if ((r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1749                 break;
1750             }
1751         }
1752         return effectiveNdx;
1753     }
1754 
updateEffectiveIntent()1755     void updateEffectiveIntent() {
1756         final int effectiveRootIndex = findEffectiveRootIndex();
1757         final ActivityRecord r = mActivities.get(effectiveRootIndex);
1758         setIntent(r);
1759 
1760         // Update the task description when the activities change
1761         updateTaskDescription();
1762     }
1763 
adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds)1764     void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
1765         if (bounds == null) {
1766             return;
1767         }
1768         int minWidth = mMinWidth;
1769         int minHeight = mMinHeight;
1770         // If the task has no requested minimal size, we'd like to enforce a minimal size
1771         // so that the user can not render the task too small to manipulate. We don't need
1772         // to do this for the pinned stack as the bounds are controlled by the system.
1773         if (!inPinnedWindowingMode() && mStack != null) {
1774             final int defaultMinSizeDp =
1775                     mService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
1776             final ActivityDisplay display =
1777                     mService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
1778             final float density =
1779                     (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
1780             final int defaultMinSize = (int) (defaultMinSizeDp * density);
1781 
1782             if (minWidth == INVALID_MIN_SIZE) {
1783                 minWidth = defaultMinSize;
1784             }
1785             if (minHeight == INVALID_MIN_SIZE) {
1786                 minHeight = defaultMinSize;
1787             }
1788         }
1789         final boolean adjustWidth = minWidth > bounds.width();
1790         final boolean adjustHeight = minHeight > bounds.height();
1791         if (!(adjustWidth || adjustHeight)) {
1792             return;
1793         }
1794 
1795         if (adjustWidth) {
1796             if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
1797                 bounds.left = bounds.right - minWidth;
1798             } else {
1799                 // Either left bounds match, or neither match, or the previous bounds were
1800                 // fullscreen and we default to keeping left.
1801                 bounds.right = bounds.left + minWidth;
1802             }
1803         }
1804         if (adjustHeight) {
1805             if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
1806                 bounds.top = bounds.bottom - minHeight;
1807             } else {
1808                 // Either top bounds match, or neither match, or the previous bounds were
1809                 // fullscreen and we default to keeping top.
1810                 bounds.bottom = bounds.top + minHeight;
1811             }
1812         }
1813     }
1814 
1815     /**
1816      * Update task's override configuration based on the bounds.
1817      * @param bounds The bounds of the task.
1818      * @return True if the override configuration was updated.
1819      */
updateOverrideConfiguration(Rect bounds)1820     boolean updateOverrideConfiguration(Rect bounds) {
1821         return updateOverrideConfiguration(bounds, null /* insetBounds */);
1822     }
1823 
setLastNonFullscreenBounds(Rect bounds)1824     void setLastNonFullscreenBounds(Rect bounds) {
1825         if (mLastNonFullscreenBounds == null) {
1826             mLastNonFullscreenBounds = new Rect(bounds);
1827         } else {
1828             mLastNonFullscreenBounds.set(bounds);
1829         }
1830     }
1831 
1832     /**
1833      * Update task's override configuration based on the bounds.
1834      * @param bounds The bounds of the task.
1835      * @param insetBounds The bounds used to calculate the system insets, which is used here to
1836      *                    subtract the navigation bar/status bar size from the screen size reported
1837      *                    to the application. See {@link IActivityTaskManager#resizeDockedStack}.
1838      * @return True if the override configuration was updated.
1839      */
updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds)1840     boolean updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) {
1841         final boolean hasSetDisplayedBounds = (insetBounds != null && !insetBounds.isEmpty());
1842         if (hasSetDisplayedBounds) {
1843             setDisplayedBounds(bounds);
1844         } else {
1845             setDisplayedBounds(null);
1846         }
1847         // "steady" bounds do not include any temporary offsets from animation or interaction.
1848         Rect steadyBounds = hasSetDisplayedBounds ? insetBounds : bounds;
1849         if (equivalentRequestedOverrideBounds(steadyBounds)) {
1850             return false;
1851         }
1852 
1853         mTmpConfig.setTo(getResolvedOverrideConfiguration());
1854         setBounds(steadyBounds);
1855         return !mTmpConfig.equals(getResolvedOverrideConfiguration());
1856     }
1857 
1858     /**
1859      * This should be called when an child activity changes state. This should only
1860      * be called from
1861      * {@link ActivityRecord#setState(ActivityState, String)} .
1862      * @param record The {@link ActivityRecord} whose state has changed.
1863      * @param state The new state.
1864      * @param reason The reason for the change.
1865      */
onActivityStateChanged(ActivityRecord record, ActivityState state, String reason)1866     void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
1867         final ActivityStack parent = getStack();
1868 
1869         if (parent != null) {
1870             parent.onActivityStateChanged(record, state, reason);
1871         }
1872     }
1873 
1874     @Override
onConfigurationChanged(Configuration newParentConfig)1875     public void onConfigurationChanged(Configuration newParentConfig) {
1876         // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
1877         // restore the last recorded non-fullscreen bounds.
1878         final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
1879         final boolean nextPersistTaskBounds =
1880                 getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds()
1881                 || newParentConfig.windowConfiguration.persistTaskBounds();
1882         if (!prevPersistTaskBounds && nextPersistTaskBounds
1883                 && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
1884             // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
1885             getRequestedOverrideConfiguration().windowConfiguration
1886                     .setBounds(mLastNonFullscreenBounds);
1887         }
1888 
1889         final boolean wasInMultiWindowMode = inMultiWindowMode();
1890         super.onConfigurationChanged(newParentConfig);
1891         if (wasInMultiWindowMode != inMultiWindowMode()) {
1892             mService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
1893         }
1894 
1895         // If the configuration supports persistent bounds (eg. Freeform), keep track of the
1896         // current (non-fullscreen) bounds for persistence.
1897         if (getWindowConfiguration().persistTaskBounds()) {
1898             final Rect currentBounds = getRequestedOverrideBounds();
1899             if (!currentBounds.isEmpty()) {
1900                 setLastNonFullscreenBounds(currentBounds);
1901             }
1902         }
1903         // TODO: Should also take care of Pip mode changes here.
1904 
1905         saveLaunchingStateIfNeeded();
1906     }
1907 
1908     /**
1909      * Saves launching state if necessary so that we can launch the activity to its latest state.
1910      * It only saves state if this task has been shown to user and it's in fullscreen or freeform
1911      * mode.
1912      */
saveLaunchingStateIfNeeded()1913     void saveLaunchingStateIfNeeded() {
1914         if (!hasBeenVisible) {
1915             // Not ever visible to user.
1916             return;
1917         }
1918 
1919         final int windowingMode = getWindowingMode();
1920         if (windowingMode != WindowConfiguration.WINDOWING_MODE_FULLSCREEN
1921                 && windowingMode != WindowConfiguration.WINDOWING_MODE_FREEFORM) {
1922             return;
1923         }
1924 
1925         // Saves the new state so that we can launch the activity at the same location.
1926         mService.mStackSupervisor.mLaunchParamsPersister.saveTask(this);
1927     }
1928 
1929     /**
1930      * Adjust bounds to stay within stack bounds.
1931      *
1932      * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
1933      * that keep them unchanged, but be contained within the stack bounds.
1934      *
1935      * @param bounds Bounds to be adjusted.
1936      * @param stackBounds Bounds within which the other bounds should remain.
1937      * @param overlapPxX The amount of px required to be visible in the X dimension.
1938      * @param overlapPxY The amount of px required to be visible in the Y dimension.
1939      */
fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX, int overlapPxY)1940     private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX,
1941             int overlapPxY) {
1942         if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) {
1943             return;
1944         }
1945 
1946         // For each side of the parent (eg. left), check if the opposing side of the window (eg.
1947         // right) is at least overlap pixels away. If less, offset the window by that difference.
1948         int horizontalDiff = 0;
1949         // If window is smaller than overlap, use it's smallest dimension instead
1950         int overlapLR = Math.min(overlapPxX, bounds.width());
1951         if (bounds.right < (stackBounds.left + overlapLR)) {
1952             horizontalDiff = overlapLR - (bounds.right - stackBounds.left);
1953         } else if (bounds.left > (stackBounds.right - overlapLR)) {
1954             horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left));
1955         }
1956         int verticalDiff = 0;
1957         int overlapTB = Math.min(overlapPxY, bounds.width());
1958         if (bounds.bottom < (stackBounds.top + overlapTB)) {
1959             verticalDiff = overlapTB - (bounds.bottom - stackBounds.top);
1960         } else if (bounds.top > (stackBounds.bottom - overlapTB)) {
1961             verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top));
1962         }
1963         bounds.offset(horizontalDiff, verticalDiff);
1964     }
1965 
1966     /**
1967      * Displayed bounds are used to set where the task is drawn at any given time. This is
1968      * separate from its actual bounds so that the app doesn't see any meaningful configuration
1969      * changes during transitionary periods.
1970      */
setDisplayedBounds(Rect bounds)1971     void setDisplayedBounds(Rect bounds) {
1972         if (bounds == null) {
1973             mDisplayedBounds.setEmpty();
1974         } else {
1975             mDisplayedBounds.set(bounds);
1976         }
1977         if (mTask != null) {
1978             mTask.setOverrideDisplayedBounds(
1979                     mDisplayedBounds.isEmpty() ? null : mDisplayedBounds);
1980         }
1981     }
1982 
1983     /**
1984      * Gets the current overridden displayed bounds. These will be empty if the task is not
1985      * currently overriding where it is displayed.
1986      */
getDisplayedBounds()1987     Rect getDisplayedBounds() {
1988         return mDisplayedBounds;
1989     }
1990 
1991     /**
1992      * @return {@code true} if this has overridden displayed bounds.
1993      */
hasDisplayedBounds()1994     boolean hasDisplayedBounds() {
1995         return !mDisplayedBounds.isEmpty();
1996     }
1997 
1998     /**
1999      * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
2000      * intersectBounds on a side, then the respective side will not be intersected.
2001      *
2002      * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
2003      * inset on that side is no-longer applicable. This scenario happens when a task's minimal
2004      * bounds are larger than the provided parent/display bounds.
2005      *
2006      * @param inOutBounds the bounds to intersect.
2007      * @param intersectBounds the bounds to intersect with.
2008      * @param intersectInsets insets to apply to intersectBounds before intersecting.
2009      */
intersectWithInsetsIfFits( Rect inOutBounds, Rect intersectBounds, Rect intersectInsets)2010     static void intersectWithInsetsIfFits(
2011             Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
2012         if (inOutBounds.right <= intersectBounds.right) {
2013             inOutBounds.right =
2014                     Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
2015         }
2016         if (inOutBounds.bottom <= intersectBounds.bottom) {
2017             inOutBounds.bottom =
2018                     Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
2019         }
2020         if (inOutBounds.left >= intersectBounds.left) {
2021             inOutBounds.left =
2022                     Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
2023         }
2024         if (inOutBounds.top >= intersectBounds.top) {
2025             inOutBounds.top =
2026                     Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
2027         }
2028     }
2029 
2030     /**
2031      * Gets bounds with non-decor and stable insets applied respectively.
2032      *
2033      * If bounds overhangs the display, those edges will not get insets. See
2034      * {@link #intersectWithInsetsIfFits}
2035      *
2036      * @param outNonDecorBounds where to place bounds with non-decor insets applied.
2037      * @param outStableBounds where to place bounds with stable insets applied.
2038      * @param bounds the bounds to inset.
2039      */
calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, DisplayInfo displayInfo)2040     private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
2041             DisplayInfo displayInfo) {
2042         outNonDecorBounds.set(bounds);
2043         outStableBounds.set(bounds);
2044         if (getStack() == null || getStack().getDisplay() == null) {
2045             return;
2046         }
2047         DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy();
2048         if (policy == null) {
2049             return;
2050         }
2051         mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
2052 
2053         policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
2054                 displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
2055         intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
2056 
2057         policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
2058         intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
2059     }
2060 
2061     /**
2062      * Asks docked-divider controller for the smallestwidthdp given bounds.
2063      * @param bounds bounds to calculate smallestwidthdp for.
2064      */
getSmallestScreenWidthDpForDockedBounds(Rect bounds)2065     private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) {
2066         DisplayContent dc = mStack.getDisplay().mDisplayContent;
2067         if (dc != null) {
2068             return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds);
2069         }
2070         return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
2071     }
2072 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig)2073     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2074             @NonNull Configuration parentConfig) {
2075         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
2076     }
2077 
2078     /**
2079      * Calculates configuration values used by the client to get resources. This should be run
2080      * using app-facing bounds (bounds unmodified by animations or transient interactions).
2081      *
2082      * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
2083      * configuring an "inherit-bounds" window which means that all configuration settings would
2084      * just be inherited from the parent configuration.
2085      **/
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2086     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2087             @NonNull Configuration parentConfig,
2088             @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
2089         int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
2090         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
2091             windowingMode = parentConfig.windowConfiguration.getWindowingMode();
2092         }
2093 
2094         float density = inOutConfig.densityDpi;
2095         if (density == Configuration.DENSITY_DPI_UNDEFINED) {
2096             density = parentConfig.densityDpi;
2097         }
2098         density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
2099 
2100         final Rect bounds = inOutConfig.windowConfiguration.getBounds();
2101         Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
2102         if (outAppBounds == null || outAppBounds.isEmpty()) {
2103             inOutConfig.windowConfiguration.setAppBounds(bounds);
2104             outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
2105         }
2106         // Non-null compatibility insets means the activity prefers to keep its original size, so
2107         // the out bounds doesn't need to be restricted by the parent.
2108         final boolean insideParentBounds = compatInsets == null;
2109         if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
2110             final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
2111             if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
2112                 outAppBounds.intersect(parentAppBounds);
2113             }
2114         }
2115 
2116         if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
2117                 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2118             if (insideParentBounds && mStack != null) {
2119                 final DisplayInfo di = new DisplayInfo();
2120                 mStack.getDisplay().mDisplay.getDisplayInfo(di);
2121 
2122                 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
2123                 // area, i.e. the screen area without the system bars.
2124                 // The non decor inset are areas that could never be removed in Honeycomb. See
2125                 // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
2126                 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, bounds, di);
2127             } else {
2128                 // Apply the given non-decor and stable insets to calculate the corresponding bounds
2129                 // for screen size of configuration.
2130                 final int rotation = parentConfig.windowConfiguration.getRotation();
2131                 if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
2132                     mTmpNonDecorBounds.set(bounds);
2133                     mTmpStableBounds.set(bounds);
2134                     compatInsets.getDisplayBoundsByRotation(mTmpBounds, rotation);
2135                     intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
2136                             compatInsets.mNonDecorInsets[rotation]);
2137                     intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
2138                             compatInsets.mStableInsets[rotation]);
2139                     outAppBounds.set(mTmpNonDecorBounds);
2140                 } else {
2141                     // Set to app bounds because it excludes decor insets.
2142                     mTmpNonDecorBounds.set(outAppBounds);
2143                     mTmpStableBounds.set(outAppBounds);
2144                 }
2145             }
2146 
2147             if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
2148                 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
2149                 inOutConfig.screenWidthDp = insideParentBounds
2150                         ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
2151                         : overrideScreenWidthDp;
2152             }
2153             if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2154                 final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
2155                 inOutConfig.screenHeightDp = insideParentBounds
2156                         ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
2157                         : overrideScreenHeightDp;
2158             }
2159 
2160             if (inOutConfig.smallestScreenWidthDp
2161                     == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
2162                 if (WindowConfiguration.isFloating(windowingMode)) {
2163                     // For floating tasks, calculate the smallest width from the bounds of the task
2164                     inOutConfig.smallestScreenWidthDp = (int) (
2165                             Math.min(bounds.width(), bounds.height()) / density);
2166                 } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
2167                     // Iterating across all screen orientations, and return the minimum of the task
2168                     // width taking into account that the bounds might change because the snap
2169                     // algorithm snaps to a different value
2170                     inOutConfig.smallestScreenWidthDp =
2171                             getSmallestScreenWidthDpForDockedBounds(bounds);
2172                 }
2173                 // otherwise, it will just inherit
2174             }
2175         }
2176 
2177         if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
2178             inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
2179                     ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
2180         }
2181         if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
2182             // For calculating screen layout, we need to use the non-decor inset screen area for the
2183             // calculation for compatibility reasons, i.e. screen area without system bars that
2184             // could never go away in Honeycomb.
2185             final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
2186             final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
2187             // We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start
2188             // override calculation with partial default.
2189             // Reducing the screen layout starting from its parent config.
2190             final int sl = parentConfig.screenLayout
2191                     & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
2192             final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
2193             final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
2194             inOutConfig.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
2195         }
2196     }
2197 
2198     @Override
resolveOverrideConfiguration(Configuration newParentConfig)2199     void resolveOverrideConfiguration(Configuration newParentConfig) {
2200         mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
2201         super.resolveOverrideConfiguration(newParentConfig);
2202         int windowingMode =
2203                 getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
2204         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
2205             windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
2206         }
2207         Rect outOverrideBounds =
2208                 getResolvedOverrideConfiguration().windowConfiguration.getBounds();
2209 
2210         if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
2211             computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
2212                     newParentConfig.windowConfiguration.getBounds(),
2213                     newParentConfig.orientation);
2214         }
2215 
2216         if (outOverrideBounds.isEmpty()) {
2217             // If the task fills the parent, just inherit all the other configs from parent.
2218             return;
2219         }
2220 
2221         adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
2222         if (windowingMode == WINDOWING_MODE_FREEFORM) {
2223             // by policy, make sure the window remains within parent somewhere
2224             final float density =
2225                     ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
2226             final Rect parentBounds =
2227                     new Rect(newParentConfig.windowConfiguration.getBounds());
2228             final ActivityDisplay display = mStack.getDisplay();
2229             if (display != null && display.mDisplayContent != null) {
2230                 // If a freeform window moves below system bar, there is no way to move it again
2231                 // by touch. Because its caption is covered by system bar. So we exclude them
2232                 // from stack bounds. and then caption will be shown inside stable area.
2233                 final Rect stableBounds = new Rect();
2234                 display.mDisplayContent.getStableRect(stableBounds);
2235                 parentBounds.intersect(stableBounds);
2236             }
2237 
2238             fitWithinBounds(outOverrideBounds, parentBounds,
2239                     (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
2240                     (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
2241 
2242             // Prevent to overlap caption with stable insets.
2243             final int offsetTop = parentBounds.top - outOverrideBounds.top;
2244             if (offsetTop > 0) {
2245                 outOverrideBounds.offset(0, offsetTop);
2246             }
2247         }
2248         computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
2249     }
2250 
2251     /** @see WindowContainer#handlesOrientationChangeFromDescendant */
handlesOrientationChangeFromDescendant()2252     boolean handlesOrientationChangeFromDescendant() {
2253         return mTask != null && mTask.getParent() != null
2254                 && mTask.getParent().handlesOrientationChangeFromDescendant();
2255     }
2256 
2257     /**
2258      * Compute bounds (letterbox or pillarbox) for {@link #WINDOWING_MODE_FULLSCREEN} when the
2259      * parent doesn't handle the orientation change and the requested orientation is different from
2260      * the parent.
2261      */
computeFullscreenBounds(@onNull Rect outBounds, @Nullable ActivityRecord refActivity, @NonNull Rect parentBounds, int parentOrientation)2262     void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
2263             @NonNull Rect parentBounds, int parentOrientation) {
2264         // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
2265         outBounds.setEmpty();
2266         if (handlesOrientationChangeFromDescendant()) {
2267             return;
2268         }
2269         if (refActivity == null) {
2270             // Use the top activity as the reference of orientation. Don't include overlays because
2271             // it is usually not the actual content or just temporarily shown.
2272             // E.g. ForcedResizableInfoActivity.
2273             refActivity = getTopActivity(false /* includeOverlays */);
2274         }
2275 
2276         // If the task or the reference activity requires a different orientation (either by
2277         // override or activityInfo), make it fit the available bounds by scaling down its bounds.
2278         final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
2279         final int forcedOrientation =
2280                 (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
2281                         ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
2282         if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
2283             return;
2284         }
2285 
2286         final int parentWidth = parentBounds.width();
2287         final int parentHeight = parentBounds.height();
2288         final float aspect = ((float) parentHeight) / parentWidth;
2289         if (forcedOrientation == ORIENTATION_LANDSCAPE) {
2290             final int height = (int) (parentWidth / aspect);
2291             final int top = parentBounds.centerY() - height / 2;
2292             outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
2293         } else {
2294             final int width = (int) (parentHeight * aspect);
2295             final int left = parentBounds.centerX() - width / 2;
2296             outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
2297         }
2298     }
2299 
updateOverrideConfigurationFromLaunchBounds()2300     Rect updateOverrideConfigurationFromLaunchBounds() {
2301         final Rect bounds = getLaunchBounds();
2302         updateOverrideConfiguration(bounds);
2303         if (bounds != null && !bounds.isEmpty()) {
2304             // TODO: Review if we actually want to do this - we are setting the launch bounds
2305             // directly here.
2306             bounds.set(getRequestedOverrideBounds());
2307         }
2308         return bounds;
2309     }
2310 
2311     /** Updates the task's bounds and override configuration to match what is expected for the
2312      * input stack. */
updateOverrideConfigurationForStack(ActivityStack inStack)2313     void updateOverrideConfigurationForStack(ActivityStack inStack) {
2314         if (mStack != null && mStack == inStack) {
2315             return;
2316         }
2317 
2318         if (inStack.inFreeformWindowingMode()) {
2319             if (!isResizeable()) {
2320                 throw new IllegalArgumentException("Can not position non-resizeable task="
2321                         + this + " in stack=" + inStack);
2322             }
2323             if (!matchParentBounds()) {
2324                 return;
2325             }
2326             if (mLastNonFullscreenBounds != null) {
2327                 updateOverrideConfiguration(mLastNonFullscreenBounds);
2328             } else {
2329                 mService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
2330             }
2331         } else {
2332             updateOverrideConfiguration(inStack.getRequestedOverrideBounds());
2333         }
2334     }
2335 
2336     /** Returns the bounds that should be used to launch this task. */
getLaunchBounds()2337     Rect getLaunchBounds() {
2338         if (mStack == null) {
2339             return null;
2340         }
2341 
2342         final int windowingMode = getWindowingMode();
2343         if (!isActivityTypeStandardOrUndefined()
2344                 || windowingMode == WINDOWING_MODE_FULLSCREEN
2345                 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
2346             return isResizeable() ? mStack.getRequestedOverrideBounds() : null;
2347         } else if (!getWindowConfiguration().persistTaskBounds()) {
2348             return mStack.getRequestedOverrideBounds();
2349         }
2350         return mLastNonFullscreenBounds;
2351     }
2352 
addStartingWindowsForVisibleActivities(boolean taskSwitch)2353     void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
2354         for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
2355             final ActivityRecord r = mActivities.get(activityNdx);
2356             if (r.visible) {
2357                 r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch);
2358             }
2359         }
2360     }
2361 
setRootProcess(WindowProcessController proc)2362     void setRootProcess(WindowProcessController proc) {
2363         clearRootProcess();
2364         if (intent != null &&
2365                 (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
2366             mRootProcess = proc;
2367             mRootProcess.addRecentTask(this);
2368         }
2369     }
2370 
clearRootProcess()2371     void clearRootProcess() {
2372         if (mRootProcess != null) {
2373             mRootProcess.removeRecentTask(this);
2374             mRootProcess = null;
2375         }
2376     }
2377 
clearAllPendingOptions()2378     void clearAllPendingOptions() {
2379         for (int i = getChildCount() - 1; i >= 0; i--) {
2380             getChildAt(i).clearOptionsLocked(false /* withAbort */);
2381         }
2382     }
2383 
2384     /**
2385      * Fills in a {@link TaskInfo} with information from this task.
2386      * @param info the {@link TaskInfo} to fill in
2387      */
fillTaskInfo(TaskInfo info)2388     void fillTaskInfo(TaskInfo info) {
2389         getNumRunningActivities(mReuseActivitiesReport);
2390         info.userId = userId;
2391         info.stackId = getStackId();
2392         info.taskId = taskId;
2393         info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
2394         info.isRunning = getTopActivity() != null;
2395         info.baseIntent = new Intent(getBaseIntent());
2396         info.baseActivity = mReuseActivitiesReport.base != null
2397                 ? mReuseActivitiesReport.base.intent.getComponent()
2398                 : null;
2399         info.topActivity = mReuseActivitiesReport.top != null
2400                 ? mReuseActivitiesReport.top.mActivityComponent
2401                 : null;
2402         info.origActivity = origActivity;
2403         info.realActivity = realActivity;
2404         info.numActivities = mReuseActivitiesReport.numActivities;
2405         info.lastActiveTime = lastActiveTime;
2406         info.taskDescription = new ActivityManager.TaskDescription(lastTaskDescription);
2407         info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
2408         info.resizeMode = mResizeMode;
2409         info.configuration.setTo(getConfiguration());
2410     }
2411 
2412     /**
2413      * Returns a  {@link TaskInfo} with information from this task.
2414      */
getTaskInfo()2415     ActivityManager.RunningTaskInfo getTaskInfo() {
2416         ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
2417         fillTaskInfo(info);
2418         return info;
2419     }
2420 
dump(PrintWriter pw, String prefix)2421     void dump(PrintWriter pw, String prefix) {
2422         pw.print(prefix); pw.print("userId="); pw.print(userId);
2423                 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
2424                 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
2425                 pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
2426                 pw.print(" mCallingPackage="); pw.println(mCallingPackage);
2427         if (affinity != null || rootAffinity != null) {
2428             pw.print(prefix); pw.print("affinity="); pw.print(affinity);
2429             if (affinity == null || !affinity.equals(rootAffinity)) {
2430                 pw.print(" root="); pw.println(rootAffinity);
2431             } else {
2432                 pw.println();
2433             }
2434         }
2435         if (voiceSession != null || voiceInteractor != null) {
2436             pw.print(prefix); pw.print("VOICE: session=0x");
2437             pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
2438             pw.print(" interactor=0x");
2439             pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
2440         }
2441         if (intent != null) {
2442             StringBuilder sb = new StringBuilder(128);
2443             sb.append(prefix); sb.append("intent={");
2444             intent.toShortString(sb, false, true, false, true);
2445             sb.append('}');
2446             pw.println(sb.toString());
2447         }
2448         if (affinityIntent != null) {
2449             StringBuilder sb = new StringBuilder(128);
2450             sb.append(prefix); sb.append("affinityIntent={");
2451             affinityIntent.toShortString(sb, false, true, false, true);
2452             sb.append('}');
2453             pw.println(sb.toString());
2454         }
2455         if (origActivity != null) {
2456             pw.print(prefix); pw.print("origActivity=");
2457             pw.println(origActivity.flattenToShortString());
2458         }
2459         if (realActivity != null) {
2460             pw.print(prefix); pw.print("mActivityComponent=");
2461             pw.println(realActivity.flattenToShortString());
2462         }
2463         if (autoRemoveRecents || isPersistable || !isActivityTypeStandard() || numFullscreen != 0) {
2464             pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
2465                     pw.print(" isPersistable="); pw.print(isPersistable);
2466                     pw.print(" numFullscreen="); pw.print(numFullscreen);
2467                     pw.print(" activityType="); pw.println(getActivityType());
2468         }
2469         if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
2470                 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
2471             pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
2472                     pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
2473                     pw.print(" mReuseTask="); pw.print(mReuseTask);
2474                     pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
2475         }
2476         if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID
2477                 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
2478                 || mNextAffiliate != null) {
2479             pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
2480                     pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
2481                     pw.print(" (");
2482                     if (mPrevAffiliate == null) {
2483                         pw.print("null");
2484                     } else {
2485                         pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
2486                     }
2487                     pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
2488                     pw.print(" (");
2489                     if (mNextAffiliate == null) {
2490                         pw.print("null");
2491                     } else {
2492                         pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
2493                     }
2494                     pw.println(")");
2495         }
2496         pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
2497         if (!askedCompatMode || !inRecents || !isAvailable) {
2498             pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
2499                     pw.print(" inRecents="); pw.print(inRecents);
2500                     pw.print(" isAvailable="); pw.println(isAvailable);
2501         }
2502         if (lastDescription != null) {
2503             pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
2504         }
2505         if (mRootProcess != null) {
2506             pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
2507         }
2508         pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
2509         pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
2510                 pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
2511                 pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
2512                 pw.print(" isResizeable=" + isResizeable());
2513                 pw.print(" lastActiveTime=" + lastActiveTime);
2514                 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
2515     }
2516 
2517     @Override
toString()2518     public String toString() {
2519         StringBuilder sb = new StringBuilder(128);
2520         if (stringName != null) {
2521             sb.append(stringName);
2522             sb.append(" U=");
2523             sb.append(userId);
2524             sb.append(" StackId=");
2525             sb.append(getStackId());
2526             sb.append(" sz=");
2527             sb.append(mActivities.size());
2528             sb.append('}');
2529             return sb.toString();
2530         }
2531         sb.append("TaskRecord{");
2532         sb.append(Integer.toHexString(System.identityHashCode(this)));
2533         sb.append(" #");
2534         sb.append(taskId);
2535         if (affinity != null) {
2536             sb.append(" A=");
2537             sb.append(affinity);
2538         } else if (intent != null) {
2539             sb.append(" I=");
2540             sb.append(intent.getComponent().flattenToShortString());
2541         } else if (affinityIntent != null && affinityIntent.getComponent() != null) {
2542             sb.append(" aI=");
2543             sb.append(affinityIntent.getComponent().flattenToShortString());
2544         } else {
2545             sb.append(" ??");
2546         }
2547         stringName = sb.toString();
2548         return toString();
2549     }
2550 
writeToProto(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)2551     public void writeToProto(ProtoOutputStream proto, long fieldId,
2552             @WindowTraceLogLevel int logLevel) {
2553         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
2554             return;
2555         }
2556 
2557         final long token = proto.start(fieldId);
2558         super.writeToProto(proto, CONFIGURATION_CONTAINER, logLevel);
2559         proto.write(ID, taskId);
2560         for (int i = mActivities.size() - 1; i >= 0; i--) {
2561             ActivityRecord activity = mActivities.get(i);
2562             activity.writeToProto(proto, ACTIVITIES);
2563         }
2564         proto.write(STACK_ID, mStack.mStackId);
2565         if (mLastNonFullscreenBounds != null) {
2566             mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
2567         }
2568         if (realActivity != null) {
2569             proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
2570         }
2571         if (origActivity != null) {
2572             proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
2573         }
2574         proto.write(ACTIVITY_TYPE, getActivityType());
2575         proto.write(RESIZE_MODE, mResizeMode);
2576         // TODO: Remove, no longer needed with windowingMode.
2577         proto.write(FULLSCREEN, matchParentBounds());
2578 
2579         if (!matchParentBounds()) {
2580             final Rect bounds = getRequestedOverrideBounds();
2581             bounds.writeToProto(proto, BOUNDS);
2582         }
2583         proto.write(MIN_WIDTH, mMinWidth);
2584         proto.write(MIN_HEIGHT, mMinHeight);
2585         proto.end(token);
2586     }
2587 
2588     /**
2589      * See {@link #getNumRunningActivities(TaskActivitiesReport)}.
2590      */
2591     static class TaskActivitiesReport {
2592         int numRunning;
2593         int numActivities;
2594         ActivityRecord top;
2595         ActivityRecord base;
2596 
reset()2597         void reset() {
2598             numRunning = numActivities = 0;
2599             top = base = null;
2600         }
2601     }
2602 
2603     /**
2604      * Saves this {@link TaskRecord} to XML using given serializer.
2605      */
saveToXml(XmlSerializer out)2606     void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
2607         if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
2608 
2609         out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
2610         if (realActivity != null) {
2611             out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
2612         }
2613         out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
2614         if (origActivity != null) {
2615             out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
2616         }
2617         // Write affinity, and root affinity if it is different from affinity.
2618         // We use the special string "@" for a null root affinity, so we can identify
2619         // later whether we were given a root affinity or should just make it the
2620         // same as the affinity.
2621         if (affinity != null) {
2622             out.attribute(null, ATTR_AFFINITY, affinity);
2623             if (!affinity.equals(rootAffinity)) {
2624                 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
2625             }
2626         } else if (rootAffinity != null) {
2627             out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
2628         }
2629         out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
2630         out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
2631         out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
2632         out.attribute(null, ATTR_USERID, String.valueOf(userId));
2633         out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
2634         out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
2635         out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
2636         out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
2637         if (lastDescription != null) {
2638             out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
2639         }
2640         if (lastTaskDescription != null) {
2641             lastTaskDescription.saveToXml(out);
2642         }
2643         out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
2644         out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
2645         out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
2646         out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
2647         out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
2648         out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
2649         out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
2650         out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
2651                 String.valueOf(mSupportsPictureInPicture));
2652         if (mLastNonFullscreenBounds != null) {
2653             out.attribute(
2654                     null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
2655         }
2656         out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
2657         out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
2658         out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
2659 
2660         if (affinityIntent != null) {
2661             out.startTag(null, TAG_AFFINITYINTENT);
2662             affinityIntent.saveToXml(out);
2663             out.endTag(null, TAG_AFFINITYINTENT);
2664         }
2665 
2666         if (intent != null) {
2667             out.startTag(null, TAG_INTENT);
2668             intent.saveToXml(out);
2669             out.endTag(null, TAG_INTENT);
2670         }
2671 
2672         final ArrayList<ActivityRecord> activities = mActivities;
2673         final int numActivities = activities.size();
2674         for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
2675             final ActivityRecord r = activities.get(activityNdx);
2676             if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
2677                     ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
2678                             | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) &&
2679                             activityNdx > 0) {
2680                 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
2681                 break;
2682             }
2683             out.startTag(null, TAG_ACTIVITY);
2684             r.saveToXml(out);
2685             out.endTag(null, TAG_ACTIVITY);
2686         }
2687     }
2688 
2689     @VisibleForTesting
getTaskRecordFactory()2690     static TaskRecordFactory getTaskRecordFactory() {
2691         if (sTaskRecordFactory == null) {
2692             setTaskRecordFactory(new TaskRecordFactory());
2693         }
2694         return sTaskRecordFactory;
2695     }
2696 
setTaskRecordFactory(TaskRecordFactory factory)2697     static void setTaskRecordFactory(TaskRecordFactory factory) {
2698         sTaskRecordFactory = factory;
2699     }
2700 
create(ActivityTaskManagerService service, int taskId, ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor)2701     static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
2702             Intent intent, IVoiceInteractionSession voiceSession,
2703             IVoiceInteractor voiceInteractor) {
2704         return getTaskRecordFactory().create(
2705                 service, taskId, info, intent, voiceSession, voiceInteractor);
2706     }
2707 
create(ActivityTaskManagerService service, int taskId, ActivityInfo info, Intent intent, TaskDescription taskDescription)2708     static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
2709             Intent intent, TaskDescription taskDescription) {
2710         return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription);
2711     }
2712 
restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)2713     static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
2714             throws IOException, XmlPullParserException {
2715         return getTaskRecordFactory().restoreFromXml(in, stackSupervisor);
2716     }
2717 
2718     /**
2719      * A factory class used to create {@link TaskRecord} or its subclass if any. This can be
2720      * specified when system boots by setting it with
2721      * {@link #setTaskRecordFactory(TaskRecordFactory)}.
2722      */
2723     static class TaskRecordFactory {
2724 
create(ActivityTaskManagerService service, int taskId, ActivityInfo info, Intent intent, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor)2725         TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
2726                 Intent intent, IVoiceInteractionSession voiceSession,
2727                 IVoiceInteractor voiceInteractor) {
2728             return new TaskRecord(
2729                     service, taskId, info, intent, voiceSession, voiceInteractor);
2730         }
2731 
create(ActivityTaskManagerService service, int taskId, ActivityInfo info, Intent intent, TaskDescription taskDescription)2732         TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
2733                 Intent intent, TaskDescription taskDescription) {
2734             return new TaskRecord(service, taskId, info, intent, taskDescription);
2735         }
2736 
2737         /**
2738          * Should only be used when we're restoring {@link TaskRecord} from storage.
2739          */
create(ActivityTaskManagerService service, int taskId, Intent intent, Intent affinityIntent, String affinity, String rootAffinity, ComponentName realActivity, ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents, boolean askedCompatMode, int userId, int effectiveUid, String lastDescription, ArrayList<ActivityRecord> activities, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight)2740         TaskRecord create(ActivityTaskManagerService service, int taskId, Intent intent,
2741                 Intent affinityIntent, String affinity, String rootAffinity,
2742                 ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
2743                 boolean autoRemoveRecents, boolean askedCompatMode, int userId,
2744                 int effectiveUid, String lastDescription, ArrayList<ActivityRecord> activities,
2745                 long lastTimeMoved, boolean neverRelinquishIdentity,
2746                 TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
2747                 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
2748                 int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
2749                 boolean userSetupComplete, int minWidth, int minHeight) {
2750             return new TaskRecord(service, taskId, intent, affinityIntent, affinity,
2751                     rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
2752                     askedCompatMode, userId, effectiveUid, lastDescription, activities,
2753                     lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
2754                     prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
2755                     resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
2756                     minWidth, minHeight);
2757         }
2758 
restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)2759         TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
2760                 throws IOException, XmlPullParserException {
2761             Intent intent = null;
2762             Intent affinityIntent = null;
2763             ArrayList<ActivityRecord> activities = new ArrayList<>();
2764             ComponentName realActivity = null;
2765             boolean realActivitySuspended = false;
2766             ComponentName origActivity = null;
2767             String affinity = null;
2768             String rootAffinity = null;
2769             boolean hasRootAffinity = false;
2770             boolean rootHasReset = false;
2771             boolean autoRemoveRecents = false;
2772             boolean askedCompatMode = false;
2773             int taskType = 0;
2774             int userId = 0;
2775             boolean userSetupComplete = true;
2776             int effectiveUid = -1;
2777             String lastDescription = null;
2778             long lastTimeOnTop = 0;
2779             boolean neverRelinquishIdentity = true;
2780             int taskId = INVALID_TASK_ID;
2781             final int outerDepth = in.getDepth();
2782             TaskDescription taskDescription = new TaskDescription();
2783             int taskAffiliation = INVALID_TASK_ID;
2784             int taskAffiliationColor = 0;
2785             int prevTaskId = INVALID_TASK_ID;
2786             int nextTaskId = INVALID_TASK_ID;
2787             int callingUid = -1;
2788             String callingPackage = "";
2789             int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
2790             boolean supportsPictureInPicture = false;
2791             Rect lastNonFullscreenBounds = null;
2792             int minWidth = INVALID_MIN_SIZE;
2793             int minHeight = INVALID_MIN_SIZE;
2794             int persistTaskVersion = 0;
2795 
2796             for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
2797                 final String attrName = in.getAttributeName(attrNdx);
2798                 final String attrValue = in.getAttributeValue(attrNdx);
2799                 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
2800                         attrName + " value=" + attrValue);
2801                 switch (attrName) {
2802                     case ATTR_TASKID:
2803                         if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
2804                         break;
2805                     case ATTR_REALACTIVITY:
2806                         realActivity = ComponentName.unflattenFromString(attrValue);
2807                         break;
2808                     case ATTR_REALACTIVITY_SUSPENDED:
2809                         realActivitySuspended = Boolean.valueOf(attrValue);
2810                         break;
2811                     case ATTR_ORIGACTIVITY:
2812                         origActivity = ComponentName.unflattenFromString(attrValue);
2813                         break;
2814                     case ATTR_AFFINITY:
2815                         affinity = attrValue;
2816                         break;
2817                     case ATTR_ROOT_AFFINITY:
2818                         rootAffinity = attrValue;
2819                         hasRootAffinity = true;
2820                         break;
2821                     case ATTR_ROOTHASRESET:
2822                         rootHasReset = Boolean.parseBoolean(attrValue);
2823                         break;
2824                     case ATTR_AUTOREMOVERECENTS:
2825                         autoRemoveRecents = Boolean.parseBoolean(attrValue);
2826                         break;
2827                     case ATTR_ASKEDCOMPATMODE:
2828                         askedCompatMode = Boolean.parseBoolean(attrValue);
2829                         break;
2830                     case ATTR_USERID:
2831                         userId = Integer.parseInt(attrValue);
2832                         break;
2833                     case ATTR_USER_SETUP_COMPLETE:
2834                         userSetupComplete = Boolean.parseBoolean(attrValue);
2835                         break;
2836                     case ATTR_EFFECTIVE_UID:
2837                         effectiveUid = Integer.parseInt(attrValue);
2838                         break;
2839                     case ATTR_TASKTYPE:
2840                         taskType = Integer.parseInt(attrValue);
2841                         break;
2842                     case ATTR_LASTDESCRIPTION:
2843                         lastDescription = attrValue;
2844                         break;
2845                     case ATTR_LASTTIMEMOVED:
2846                         lastTimeOnTop = Long.parseLong(attrValue);
2847                         break;
2848                     case ATTR_NEVERRELINQUISH:
2849                         neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
2850                         break;
2851                     case ATTR_TASK_AFFILIATION:
2852                         taskAffiliation = Integer.parseInt(attrValue);
2853                         break;
2854                     case ATTR_PREV_AFFILIATION:
2855                         prevTaskId = Integer.parseInt(attrValue);
2856                         break;
2857                     case ATTR_NEXT_AFFILIATION:
2858                         nextTaskId = Integer.parseInt(attrValue);
2859                         break;
2860                     case ATTR_TASK_AFFILIATION_COLOR:
2861                         taskAffiliationColor = Integer.parseInt(attrValue);
2862                         break;
2863                     case ATTR_CALLING_UID:
2864                         callingUid = Integer.parseInt(attrValue);
2865                         break;
2866                     case ATTR_CALLING_PACKAGE:
2867                         callingPackage = attrValue;
2868                         break;
2869                     case ATTR_RESIZE_MODE:
2870                         resizeMode = Integer.parseInt(attrValue);
2871                         break;
2872                     case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
2873                         supportsPictureInPicture = Boolean.parseBoolean(attrValue);
2874                         break;
2875                     case ATTR_NON_FULLSCREEN_BOUNDS:
2876                         lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
2877                         break;
2878                     case ATTR_MIN_WIDTH:
2879                         minWidth = Integer.parseInt(attrValue);
2880                         break;
2881                     case ATTR_MIN_HEIGHT:
2882                         minHeight = Integer.parseInt(attrValue);
2883                         break;
2884                     case ATTR_PERSIST_TASK_VERSION:
2885                         persistTaskVersion = Integer.parseInt(attrValue);
2886                         break;
2887                     default:
2888                         if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
2889                             taskDescription.restoreFromXml(attrName, attrValue);
2890                         } else {
2891                             Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
2892                         }
2893                 }
2894             }
2895 
2896             int event;
2897             while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
2898                     (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
2899                 if (event == XmlPullParser.START_TAG) {
2900                     final String name = in.getName();
2901                     if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
2902                             "TaskRecord: START_TAG name=" + name);
2903                     if (TAG_AFFINITYINTENT.equals(name)) {
2904                         affinityIntent = Intent.restoreFromXml(in);
2905                     } else if (TAG_INTENT.equals(name)) {
2906                         intent = Intent.restoreFromXml(in);
2907                     } else if (TAG_ACTIVITY.equals(name)) {
2908                         ActivityRecord activity =
2909                                 ActivityRecord.restoreFromXml(in, stackSupervisor);
2910                         if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
2911                                 activity);
2912                         if (activity != null) {
2913                             activities.add(activity);
2914                         }
2915                     } else {
2916                         handleUnknownTag(name, in);
2917                     }
2918                 }
2919             }
2920             if (!hasRootAffinity) {
2921                 rootAffinity = affinity;
2922             } else if ("@".equals(rootAffinity)) {
2923                 rootAffinity = null;
2924             }
2925             if (effectiveUid <= 0) {
2926                 Intent checkIntent = intent != null ? intent : affinityIntent;
2927                 effectiveUid = 0;
2928                 if (checkIntent != null) {
2929                     IPackageManager pm = AppGlobals.getPackageManager();
2930                     try {
2931                         ApplicationInfo ai = pm.getApplicationInfo(
2932                                 checkIntent.getComponent().getPackageName(),
2933                                 PackageManager.MATCH_UNINSTALLED_PACKAGES
2934                                         | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
2935                         if (ai != null) {
2936                             effectiveUid = ai.uid;
2937                         }
2938                     } catch (RemoteException e) {
2939                     }
2940                 }
2941                 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
2942                         + ": effectiveUid=" + effectiveUid);
2943             }
2944 
2945             if (persistTaskVersion < 1) {
2946                 // We need to convert the resize mode of home activities saved before version one if
2947                 // they are marked as RESIZE_MODE_RESIZEABLE to
2948                 // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
2949                 // before version 1 and the system didn't resize home activities before then.
2950                 if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
2951                     resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
2952                 }
2953             } else {
2954                 // This activity has previously marked itself explicitly as both resizeable and
2955                 // supporting picture-in-picture.  Since there is no longer a requirement for
2956                 // picture-in-picture activities to be resizeable, we can mark this simply as
2957                 // resizeable and supporting picture-in-picture separately.
2958                 if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
2959                     resizeMode = RESIZE_MODE_RESIZEABLE;
2960                     supportsPictureInPicture = true;
2961                 }
2962             }
2963 
2964             final TaskRecord task = create(stackSupervisor.mService,
2965                     taskId, intent, affinityIntent,
2966                     affinity, rootAffinity, realActivity, origActivity, rootHasReset,
2967                     autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
2968                     activities, lastTimeOnTop, neverRelinquishIdentity, taskDescription,
2969                     taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
2970                     callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
2971                     userSetupComplete, minWidth, minHeight);
2972             task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
2973             task.setBounds(lastNonFullscreenBounds);
2974 
2975             for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
2976                 activities.get(activityNdx).setTask(task);
2977             }
2978 
2979             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
2980             return task;
2981         }
2982 
handleUnknownTag(String name, XmlPullParser in)2983         void handleUnknownTag(String name, XmlPullParser in)
2984                 throws IOException, XmlPullParserException {
2985             Slog.e(TAG, "restoreTask: Unexpected name=" + name);
2986             XmlUtils.skipCurrentTag(in);
2987         }
2988     }
2989 }
2990