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
17package com.android.server.am;
18
19import android.annotation.IntDef;
20import android.annotation.Nullable;
21import android.app.Activity;
22import android.app.ActivityManager;
23import android.app.ActivityManager.StackId;
24import android.app.ActivityManager.TaskDescription;
25import android.app.ActivityManager.TaskSnapshot;
26import android.app.ActivityManager.TaskThumbnail;
27import android.app.ActivityManager.TaskThumbnailInfo;
28import android.app.ActivityOptions;
29import android.app.AppGlobals;
30import android.app.IActivityManager;
31import android.content.ComponentName;
32import android.content.Intent;
33import android.content.pm.ActivityInfo;
34import android.content.pm.ApplicationInfo;
35import android.content.pm.IPackageManager;
36import android.content.pm.PackageManager;
37import android.content.res.Configuration;
38import android.graphics.Bitmap;
39import android.graphics.Point;
40import android.graphics.Rect;
41import android.os.Debug;
42import android.os.ParcelFileDescriptor;
43import android.os.RemoteException;
44import android.os.Trace;
45import android.os.UserHandle;
46import android.provider.Settings;
47import android.service.voice.IVoiceInteractionSession;
48import android.util.DisplayMetrics;
49import android.util.Slog;
50
51import com.android.internal.annotations.VisibleForTesting;
52import com.android.internal.app.IVoiceInteractor;
53import com.android.internal.util.XmlUtils;
54
55import com.android.server.wm.AppWindowContainerController;
56import com.android.server.wm.StackWindowController;
57import com.android.server.wm.TaskWindowContainerController;
58import com.android.server.wm.TaskWindowContainerListener;
59import com.android.server.wm.WindowManagerService;
60
61import org.xmlpull.v1.XmlPullParser;
62import org.xmlpull.v1.XmlPullParserException;
63import org.xmlpull.v1.XmlSerializer;
64
65import java.io.File;
66import java.io.IOException;
67import java.io.PrintWriter;
68import java.lang.annotation.Retention;
69import java.lang.annotation.RetentionPolicy;
70import java.util.ArrayList;
71import java.util.Objects;
72
73import static android.app.ActivityManager.RESIZE_MODE_FORCED;
74import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
75import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
76import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
77import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
78import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
79import static android.app.ActivityManager.StackId.HOME_STACK_ID;
80import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
81import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
82import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
83import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
84import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
85import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
86import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
87import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
88import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
89import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
90import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
91import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
92import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
93import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
94import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
95import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
96import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
97import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
98import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
99import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
100import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
101import static android.view.Display.DEFAULT_DISPLAY;
102
103import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
104import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
105import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
106import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
107import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
108import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
109import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
110import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
111import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
112import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
113import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
114import static com.android.server.am.ActivityRecord.ASSISTANT_ACTIVITY_TYPE;
115import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
116import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
117import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
118import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
119import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP;
120import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
121import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
122
123import static java.lang.Integer.MAX_VALUE;
124
125final class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {
126    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
127    private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
128    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
129    private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
130    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
131
132    private static final String ATTR_TASKID = "task_id";
133    private static final String TAG_INTENT = "intent";
134    private static final String TAG_AFFINITYINTENT = "affinity_intent";
135    private static final String ATTR_REALACTIVITY = "real_activity";
136    private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
137    private static final String ATTR_ORIGACTIVITY = "orig_activity";
138    private static final String TAG_ACTIVITY = "activity";
139    private static final String ATTR_AFFINITY = "affinity";
140    private static final String ATTR_ROOT_AFFINITY = "root_affinity";
141    private static final String ATTR_ROOTHASRESET = "root_has_reset";
142    private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
143    private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
144    private static final String ATTR_USERID = "user_id";
145    private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
146    private static final String ATTR_EFFECTIVE_UID = "effective_uid";
147    private static final String ATTR_TASKTYPE = "task_type";
148    private static final String ATTR_FIRSTACTIVETIME = "first_active_time";
149    private static final String ATTR_LASTACTIVETIME = "last_active_time";
150    private static final String ATTR_LASTDESCRIPTION = "last_description";
151    private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
152    private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
153    private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
154    private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
155    private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
156    private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
157    private static final String ATTR_CALLING_UID = "calling_uid";
158    private static final String ATTR_CALLING_PACKAGE = "calling_package";
159    private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
160    private static final String ATTR_RESIZE_MODE = "resize_mode";
161    private static final String ATTR_PRIVILEGED = "privileged";
162    private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
163    private static final String ATTR_MIN_WIDTH = "min_width";
164    private static final String ATTR_MIN_HEIGHT = "min_height";
165    private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
166
167    // Current version of the task record we persist. Used to check if we need to run any upgrade
168    // code.
169    private static final int PERSIST_TASK_VERSION = 1;
170    private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
171
172    static final int INVALID_TASK_ID = -1;
173    private static final int INVALID_MIN_SIZE = -1;
174
175    /**
176     * The modes to control how the stack is moved to the front when calling
177     * {@link TaskRecord#reparent}.
178     */
179    @Retention(RetentionPolicy.SOURCE)
180    @IntDef({
181            REPARENT_MOVE_STACK_TO_FRONT,
182            REPARENT_KEEP_STACK_AT_FRONT,
183            REPARENT_LEAVE_STACK_IN_PLACE
184    })
185    public @interface ReparentMoveStackMode {}
186    // Moves the stack to the front if it was not at the front
187    public static final int REPARENT_MOVE_STACK_TO_FRONT = 0;
188    // Only moves the stack to the front if it was focused or front most already
189    public static final int REPARENT_KEEP_STACK_AT_FRONT = 1;
190    // Do not move the stack as a part of reparenting
191    public static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
192
193    final int taskId;       // Unique identifier for this task.
194    String affinity;        // The affinity name for this task, or null; may change identity.
195    String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
196    final IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
197    final IVoiceInteractor voiceInteractor;         // Associated interactor to provide to app
198    Intent intent;          // The original intent that started the task.
199    Intent affinityIntent;  // Intent of affinity-moved activity that started this task.
200    int effectiveUid;       // The current effective uid of the identity of this task.
201    ComponentName origActivity; // The non-alias activity component of the intent.
202    ComponentName realActivity; // The actual activity component that started the task.
203    boolean realActivitySuspended; // True if the actual activity component that started the
204                                   // task is suspended.
205    long firstActiveTime;   // First time this task was active.
206    long lastActiveTime;    // Last time this task was active, including sleep.
207    boolean inRecents;      // Actually in the recents list?
208    boolean isAvailable;    // Is the activity available to be launched?
209    boolean rootWasReset;   // True if the intent at the root of the task had
210                            // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
211    boolean autoRemoveRecents;  // If true, we should automatically remove the task from
212                                // recents when activity finishes
213    boolean askedCompatMode;// Have asked the user about compat mode for this task.
214    boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
215
216    String stringName;      // caching of toString() result.
217    int userId;             // user for which this task was created
218    boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
219                                // was changed.
220
221    int numFullscreen;      // Number of fullscreen activities.
222
223    int mResizeMode;        // The resize mode of this task and its activities.
224                            // Based on the {@link ActivityInfo#resizeMode} of the root activity.
225    private boolean mSupportsPictureInPicture;  // Whether or not this task and its activities
226            // support PiP. Based on the {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag
227            // of the root activity.
228    boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize
229                                     // changes on a temporary basis.
230    private int mLockTaskMode;  // Which tasklock mode to launch this task in. One of
231                                // ActivityManager.LOCK_TASK_LAUNCH_MODE_*
232    private boolean mPrivileged;    // The root activity application of this task holds
233                                    // privileged permissions.
234
235    /** Can't be put in lockTask mode. */
236    final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
237    /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
238    final static int LOCK_TASK_AUTH_PINNABLE = 1;
239    /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
240    final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
241    /** Can enter lockTask without user approval. Can start over existing lockTask task. */
242    final static int LOCK_TASK_AUTH_WHITELISTED = 3;
243    /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
244     * lockTask task. */
245    final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
246    int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
247
248    int mLockTaskUid = -1;  // The uid of the application that called startLockTask().
249
250    // This represents the last resolved activity values for this task
251    // NOTE: This value needs to be persisted with each task
252    TaskDescription lastTaskDescription = new TaskDescription();
253
254    /** List of all activities in the task arranged in history order */
255    final ArrayList<ActivityRecord> mActivities;
256
257    /** Current stack. Setter must always be used to update the value. */
258    private ActivityStack mStack;
259
260    /** Takes on same set of values as ActivityRecord.mActivityType */
261    int taskType;
262
263    /** Takes on same value as first root activity */
264    boolean isPersistable = false;
265    int maxRecents;
266
267    /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
268     * determining the order when restoring. Sign indicates whether last task movement was to front
269     * (positive) or back (negative). Absolute value indicates time. */
270    long mLastTimeMoved = System.currentTimeMillis();
271
272    /** Indication of what to run next when task exits. Use ActivityRecord types.
273     * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
274     * task stack. */
275    private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
276
277    /** If original intent did not allow relinquishing task identity, save that information */
278    private boolean mNeverRelinquishIdentity = true;
279
280    // Used in the unique case where we are clearing the task in order to reuse it. In that case we
281    // do not want to delete the stack when the task goes empty.
282    private boolean mReuseTask = false;
283
284    private Bitmap mLastThumbnail; // Last thumbnail captured for this item.
285    private final File mLastThumbnailFile; // File containing last thumbnail.
286    private final String mFilename;
287    private TaskThumbnailInfo mLastThumbnailInfo;
288    CharSequence lastDescription; // Last description captured for this item.
289
290    int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
291    int mAffiliatedTaskColor; // color of the parent task affiliation.
292    TaskRecord mPrevAffiliate; // previous task in affiliated chain.
293    int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
294    TaskRecord mNextAffiliate; // next task in affiliated chain.
295    int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
296
297    // For relaunching the task from recents as though it was launched by the original launcher.
298    int mCallingUid;
299    String mCallingPackage;
300
301    final ActivityManagerService mService;
302
303    // Whether or not this task covers the entire screen; by default tasks are fullscreen.
304    boolean mFullscreen = true;
305
306    // Bounds of the Task. null for fullscreen tasks.
307    Rect mBounds = null;
308    private final Rect mTmpStableBounds = new Rect();
309    private final Rect mTmpNonDecorBounds = new Rect();
310    private final Rect mTmpRect = new Rect();
311
312    // Last non-fullscreen bounds the task was launched in or resized to.
313    // The information is persisted and used to determine the appropriate stack to launch the
314    // task into on restore.
315    Rect mLastNonFullscreenBounds = null;
316    // Minimal width and height of this task when it's resizeable. -1 means it should use the
317    // default minimal width/height.
318    int mMinWidth;
319    int mMinHeight;
320
321    // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
322    // This number will be assigned when we evaluate OOM scores for all visible tasks.
323    int mLayerRank = -1;
324
325    /** Helper object used for updating override configuration. */
326    private Configuration mTmpConfig = new Configuration();
327
328    private TaskWindowContainerController mWindowContainerController;
329
330    TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
331            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, int type) {
332        mService = service;
333        mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
334                TaskPersister.IMAGE_EXTENSION;
335        userId = UserHandle.getUserId(info.applicationInfo.uid);
336        mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename);
337        mLastThumbnailInfo = new TaskThumbnailInfo();
338        taskId = _taskId;
339        mAffiliatedTaskId = _taskId;
340        voiceSession = _voiceSession;
341        voiceInteractor = _voiceInteractor;
342        isAvailable = true;
343        mActivities = new ArrayList<>();
344        mCallingUid = info.applicationInfo.uid;
345        mCallingPackage = info.packageName;
346        taskType = type;
347        setIntent(_intent, info);
348        setMinDimensions(info);
349        touchActiveTime();
350        mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity);
351    }
352
353    TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
354            TaskDescription _taskDescription, TaskThumbnailInfo thumbnailInfo) {
355        mService = service;
356        mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
357                TaskPersister.IMAGE_EXTENSION;
358        userId = UserHandle.getUserId(info.applicationInfo.uid);
359        mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename);
360        mLastThumbnailInfo = thumbnailInfo;
361        taskId = _taskId;
362        mAffiliatedTaskId = _taskId;
363        voiceSession = null;
364        voiceInteractor = null;
365        isAvailable = true;
366        mActivities = new ArrayList<>();
367        mCallingUid = info.applicationInfo.uid;
368        mCallingPackage = info.packageName;
369        setIntent(_intent, info);
370        setMinDimensions(info);
371
372        isPersistable = true;
373        // Clamp to [1, max].
374        maxRecents = Math.min(Math.max(info.maxRecents, 1),
375                ActivityManager.getMaxAppRecentsLimitStatic());
376
377        taskType = APPLICATION_ACTIVITY_TYPE;
378        mTaskToReturnTo = HOME_ACTIVITY_TYPE;
379        lastTaskDescription = _taskDescription;
380        touchActiveTime();
381        mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity);
382    }
383
384    private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
385            Intent _affinityIntent, String _affinity, String _rootAffinity,
386            ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
387            boolean _autoRemoveRecents, boolean _askedCompatMode, int _taskType, int _userId,
388            int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities,
389            long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
390            boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
391            TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId,
392            int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
393            int resizeMode, boolean supportsPictureInPicture, boolean privileged,
394            boolean _realActivitySuspended, boolean userSetupComplete, int minWidth,
395            int minHeight) {
396        mService = service;
397        mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
398                TaskPersister.IMAGE_EXTENSION;
399        mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(_userId), mFilename);
400        mLastThumbnailInfo = lastThumbnailInfo;
401        taskId = _taskId;
402        intent = _intent;
403        affinityIntent = _affinityIntent;
404        affinity = _affinity;
405        rootAffinity = _rootAffinity;
406        voiceSession = null;
407        voiceInteractor = null;
408        realActivity = _realActivity;
409        realActivitySuspended = _realActivitySuspended;
410        origActivity = _origActivity;
411        rootWasReset = _rootWasReset;
412        isAvailable = true;
413        autoRemoveRecents = _autoRemoveRecents;
414        askedCompatMode = _askedCompatMode;
415        taskType = _taskType;
416        mTaskToReturnTo = HOME_ACTIVITY_TYPE;
417        userId = _userId;
418        mUserSetupComplete = userSetupComplete;
419        effectiveUid = _effectiveUid;
420        firstActiveTime = _firstActiveTime;
421        lastActiveTime = _lastActiveTime;
422        lastDescription = _lastDescription;
423        mActivities = activities;
424        mLastTimeMoved = lastTimeMoved;
425        mNeverRelinquishIdentity = neverRelinquishIdentity;
426        lastTaskDescription = _lastTaskDescription;
427        mAffiliatedTaskId = taskAffiliation;
428        mAffiliatedTaskColor = taskAffiliationColor;
429        mPrevAffiliateTaskId = prevTaskId;
430        mNextAffiliateTaskId = nextTaskId;
431        mCallingUid = callingUid;
432        mCallingPackage = callingPackage;
433        mResizeMode = resizeMode;
434        mSupportsPictureInPicture = supportsPictureInPicture;
435        mPrivileged = privileged;
436        mMinWidth = minWidth;
437        mMinHeight = minHeight;
438        mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity);
439    }
440
441    TaskWindowContainerController getWindowContainerController() {
442        return mWindowContainerController;
443    }
444
445    void createWindowContainer(boolean onTop, boolean showForAllUsers) {
446        if (mWindowContainerController != null) {
447            throw new IllegalArgumentException("Window container=" + mWindowContainerController
448                    + " already created for task=" + this);
449        }
450
451        final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
452        final Configuration overrideConfig = getOverrideConfiguration();
453        setWindowContainerController(new TaskWindowContainerController(taskId, this,
454                getStack().getWindowContainerController(), userId, bounds, overrideConfig,
455                mResizeMode, mSupportsPictureInPicture, isHomeTask(), onTop, showForAllUsers,
456                lastTaskDescription));
457    }
458
459    /**
460     * Should only be invoked from {@link #createWindowContainer(boolean, boolean)}.
461     */
462    @VisibleForTesting
463    protected void setWindowContainerController(TaskWindowContainerController controller) {
464        if (mWindowContainerController != null) {
465            throw new IllegalArgumentException("Window container=" + mWindowContainerController
466                    + " already created for task=" + this);
467        }
468
469        mWindowContainerController = controller;
470    }
471
472    void removeWindowContainer() {
473        mService.mStackSupervisor.removeLockedTaskLocked(this);
474        mWindowContainerController.removeContainer();
475        if (!StackId.persistTaskBounds(getStackId())) {
476            // Reset current bounds for task whose bounds shouldn't be persisted so it uses
477            // default configuration the next time it launches.
478            updateOverrideConfiguration(null);
479        }
480        mService.mTaskChangeNotificationController.notifyTaskRemoved(taskId);
481        mWindowContainerController = null;
482    }
483
484    @Override
485    public void onSnapshotChanged(TaskSnapshot snapshot) {
486        mService.mTaskChangeNotificationController.notifyTaskSnapshotChanged(taskId, snapshot);
487    }
488
489    void setResizeMode(int resizeMode) {
490        if (mResizeMode == resizeMode) {
491            return;
492        }
493        mResizeMode = resizeMode;
494        mWindowContainerController.setResizeable(resizeMode);
495        mService.mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
496        mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
497    }
498
499    void setTaskDockedResizing(boolean resizing) {
500        mWindowContainerController.setTaskDockedResizing(resizing);
501    }
502
503    // TODO: Consolidate this with the resize() method below.
504    @Override
505    public void requestResize(Rect bounds, int resizeMode) {
506        mService.resizeTask(taskId, bounds, resizeMode);
507    }
508
509    boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
510        if (!isResizeable()) {
511            Slog.w(TAG, "resizeTask: task " + this + " not resizeable.");
512            return true;
513        }
514
515        // If this is a forced resize, let it go through even if the bounds is not changing,
516        // as we might need a relayout due to surface size change (to/from fullscreen).
517        final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
518        if (Objects.equals(mBounds, bounds) && !forced) {
519            // Nothing to do here...
520            return true;
521        }
522        bounds = validateBounds(bounds);
523
524        if (mWindowContainerController == null) {
525            // Task doesn't exist in window manager yet (e.g. was restored from recents).
526            // All we can do for now is update the bounds so it can be used when the task is
527            // added to window manager.
528            updateOverrideConfiguration(bounds);
529            if (getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
530                // re-restore the task so it can have the proper stack association.
531                mService.mStackSupervisor.restoreRecentTaskLocked(this,
532                        FREEFORM_WORKSPACE_STACK_ID);
533            }
534            return true;
535        }
536
537        if (!canResizeToBounds(bounds)) {
538            throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
539                    + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
540        }
541
542        // Do not move the task to another stack here.
543        // This method assumes that the task is already placed in the right stack.
544        // we do not mess with that decision and we only do the resize!
545
546        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + taskId);
547
548        final boolean updatedConfig = updateOverrideConfiguration(bounds);
549        // This variable holds information whether the configuration didn't change in a significant
550        // way and the activity was kept the way it was. If it's false, it means the activity had
551        // to be relaunched due to configuration change.
552        boolean kept = true;
553        if (updatedConfig) {
554            final ActivityRecord r = topRunningActivityLocked();
555            if (r != null && !deferResume) {
556                kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindow);
557                mService.mStackSupervisor.ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
558                if (!kept) {
559                    mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
560                }
561            }
562        }
563        mWindowContainerController.resize(mBounds, getOverrideConfiguration(), kept, forced);
564
565        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
566        return kept;
567    }
568
569    // TODO: Investigate combining with the resize() method above.
570    void resizeWindowContainer() {
571        mWindowContainerController.resize(mBounds, getOverrideConfiguration(), false /* relayout */,
572                false /* forced */);
573    }
574
575    void getWindowContainerBounds(Rect bounds) {
576        mWindowContainerController.getBounds(bounds);
577    }
578
579    /**
580     * Convenience method to reparent a task to the top or bottom position of the stack.
581     */
582    boolean reparent(int preferredStackId, boolean toTop, @ReparentMoveStackMode int moveStackMode,
583            boolean animate, boolean deferResume, String reason) {
584        return reparent(preferredStackId, toTop ? MAX_VALUE : 0, moveStackMode, animate,
585                deferResume, true /* schedulePictureInPictureModeChange */, reason);
586    }
587
588    /**
589     * Convenience method to reparent a task to the top or bottom position of the stack, with
590     * an option to skip scheduling the picture-in-picture mode change.
591     */
592    boolean reparent(int preferredStackId, boolean toTop, @ReparentMoveStackMode int moveStackMode,
593            boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange,
594            String reason) {
595        return reparent(preferredStackId, toTop ? MAX_VALUE : 0, moveStackMode, animate,
596                deferResume, schedulePictureInPictureModeChange, reason);
597    }
598
599    /**
600     * Convenience method to reparent a task to a specific position of the stack.
601     */
602    boolean reparent(int preferredStackId, int position, @ReparentMoveStackMode int moveStackMode,
603            boolean animate, boolean deferResume, String reason) {
604        return reparent(preferredStackId, position, moveStackMode, animate, deferResume,
605                true /* schedulePictureInPictureModeChange */, reason);
606    }
607
608    /**
609     * Reparents the task into a preferred stack, creating it if necessary.
610     *
611     * @param preferredStackId the stack id of the target stack to move this task
612     * @param position the position to place this task in the new stack
613     * @param animate whether or not we should wait for the new window created as a part of the
614     *            reparenting to be drawn and animated in
615     * @param moveStackMode whether or not to move the stack to the front always, only if it was
616     *            previously focused & in front, or never
617     * @param deferResume whether or not to update the visibility of other tasks and stacks that may
618     *            have changed as a result of this reparenting
619     * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
620     *            change. Callers may set this to false if they are explicitly scheduling PiP mode
621     *            changes themselves, like during the PiP animation
622     * @param reason the caller of this reparenting
623     * @return whether the task was reparented
624     */
625    boolean reparent(int preferredStackId, int position, @ReparentMoveStackMode int moveStackMode,
626            boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange,
627            String reason) {
628        final ActivityStackSupervisor supervisor = mService.mStackSupervisor;
629        final WindowManagerService windowManager = mService.mWindowManager;
630        final ActivityStack sourceStack = getStack();
631        final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStackId,
632                position == MAX_VALUE);
633        if (toStack == sourceStack) {
634            return false;
635        }
636
637        final int sourceStackId = getStackId();
638        final int stackId = toStack.getStackId();
639        final ActivityRecord topActivity = getTopActivity();
640
641        final boolean mightReplaceWindow = StackId.replaceWindowsOnTaskMove(sourceStackId, stackId)
642                && topActivity != null;
643        if (mightReplaceWindow) {
644            // We are about to relaunch the activity because its configuration changed due to
645            // being maximized, i.e. size change. The activity will first remove the old window
646            // and then add a new one. This call will tell window manager about this, so it can
647            // preserve the old window until the new one is drawn. This prevents having a gap
648            // between the removal and addition, in which no window is visible. We also want the
649            // entrance of the new window to be properly animated.
650            // Note here we always set the replacing window first, as the flags might be needed
651            // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
652            windowManager.setWillReplaceWindow(topActivity.appToken, animate);
653        }
654
655        windowManager.deferSurfaceLayout();
656        boolean kept = true;
657        try {
658            final ActivityRecord r = topRunningActivityLocked();
659            final boolean wasFocused = r != null && supervisor.isFocusedStack(sourceStack)
660                    && (topRunningActivityLocked() == r);
661            final boolean wasResumed = r != null && sourceStack.mResumedActivity == r;
662            final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
663
664            // In some cases the focused stack isn't the front stack. E.g. pinned stack.
665            // Whenever we are moving the top activity from the front stack we want to make sure to
666            // move the stack to the front.
667            final boolean wasFront = r != null && supervisor.isFrontStackOnDisplay(sourceStack)
668                    && (sourceStack.topRunningActivityLocked() == r);
669
670            // Adjust the position for the new parent stack as needed.
671            position = toStack.getAdjustedPositionForTask(this, position, null /* starting */);
672
673            // Must reparent first in window manager to avoid a situation where AM can delete the
674            // we are coming from in WM before we reparent because it became empty.
675            mWindowContainerController.reparent(toStack.getWindowContainerController(), position,
676                    moveStackMode == REPARENT_MOVE_STACK_TO_FRONT);
677
678            final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
679                    || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
680            // Move the task
681            sourceStack.removeTask(this, reason, moveStackToFront
682                    ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING);
683            toStack.addTask(this, position, false /* schedulePictureInPictureModeChange */, reason);
684
685            if (schedulePictureInPictureModeChange) {
686                // Notify of picture-in-picture mode changes
687                supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
688            }
689
690            // TODO: Ensure that this is actually necessary here
691            // Notify the voice session if required
692            if (voiceSession != null) {
693                try {
694                    voiceSession.taskStarted(intent, taskId);
695                } catch (RemoteException e) {
696                }
697            }
698
699            // If the task had focus before (or we're requested to move focus), move focus to the
700            // new stack by moving the stack to the front.
701            if (r != null) {
702                toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed,
703                        wasPaused, reason);
704            }
705            if (!animate) {
706                toStack.mNoAnimActivities.add(topActivity);
707            }
708
709            // We might trigger a configuration change. Save the current task bounds for freezing.
710            // TODO: Should this call be moved inside the resize method in WM?
711            toStack.prepareFreezingTaskBounds();
712
713            // Make sure the task has the appropriate bounds/size for the stack it is in.
714            if (stackId == FULLSCREEN_WORKSPACE_STACK_ID
715                    && !Objects.equals(mBounds, toStack.mBounds)) {
716                kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow,
717                        deferResume);
718            } else if (stackId == FREEFORM_WORKSPACE_STACK_ID) {
719                Rect bounds = getLaunchBounds();
720                if (bounds == null) {
721                    toStack.layoutTaskInStack(this, null);
722                    bounds = mBounds;
723                }
724                kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
725            } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
726                if (stackId == DOCKED_STACK_ID && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
727                    // Move recents to front so it is not behind home stack when going into docked
728                    // mode
729                    mService.mStackSupervisor.moveRecentsStackToFront(reason);
730                }
731                kept = resize(toStack.mBounds, RESIZE_MODE_SYSTEM, !mightReplaceWindow,
732                        deferResume);
733            }
734        } finally {
735            windowManager.continueSurfaceLayout();
736        }
737
738        if (mightReplaceWindow) {
739            // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
740            // window), we need to clear the replace window settings. Otherwise, we schedule a
741            // timeout to remove the old window if the replacing window is not coming in time.
742            windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
743        }
744
745        if (!deferResume) {
746            // The task might have already been running and its visibility needs to be synchronized
747            // with the visibility of the stack / windows.
748            supervisor.ensureActivitiesVisibleLocked(null, 0, !mightReplaceWindow);
749            supervisor.resumeFocusedStackTopActivityLocked();
750        }
751
752        // TODO: Handle incorrect request to move before the actual move, not after.
753        supervisor.handleNonResizableTaskIfNeeded(this, preferredStackId, DEFAULT_DISPLAY, stackId);
754
755        boolean successful = (preferredStackId == stackId);
756        if (successful && stackId == DOCKED_STACK_ID) {
757            // If task moved to docked stack - show recents if needed.
758            mService.mWindowManager.showRecentApps(false /* fromHome */);
759        }
760        return successful;
761    }
762
763    void cancelWindowTransition() {
764        mWindowContainerController.cancelWindowTransition();
765    }
766
767    void cancelThumbnailTransition() {
768        mWindowContainerController.cancelThumbnailTransition();
769    }
770
771    /**
772     * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
773     */
774    TaskSnapshot getSnapshot(boolean reducedResolution) {
775
776        // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
777        // synchronized between AM and WM.
778        return mService.mWindowManager.getTaskSnapshot(taskId, userId, reducedResolution);
779    }
780
781    void touchActiveTime() {
782        lastActiveTime = System.currentTimeMillis();
783        if (firstActiveTime == 0) {
784            firstActiveTime = lastActiveTime;
785        }
786    }
787
788    long getInactiveDuration() {
789        return System.currentTimeMillis() - lastActiveTime;
790    }
791
792    /** Sets the original intent, and the calling uid and package. */
793    void setIntent(ActivityRecord r) {
794        mCallingUid = r.launchedFromUid;
795        mCallingPackage = r.launchedFromPackage;
796        setIntent(r.intent, r.info);
797    }
798
799    /** Sets the original intent, _without_ updating the calling uid or package. */
800    private void setIntent(Intent _intent, ActivityInfo info) {
801        if (intent == null) {
802            mNeverRelinquishIdentity =
803                    (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
804        } else if (mNeverRelinquishIdentity) {
805            return;
806        }
807
808        affinity = info.taskAffinity;
809        if (intent == null) {
810            // If this task already has an intent associated with it, don't set the root
811            // affinity -- we don't want it changing after initially set, but the initially
812            // set value may be null.
813            rootAffinity = affinity;
814        }
815        effectiveUid = info.applicationInfo.uid;
816        stringName = null;
817
818        if (info.targetActivity == null) {
819            if (_intent != null) {
820                // If this Intent has a selector, we want to clear it for the
821                // recent task since it is not relevant if the user later wants
822                // to re-launch the app.
823                if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
824                    _intent = new Intent(_intent);
825                    _intent.setSelector(null);
826                    _intent.setSourceBounds(null);
827                }
828            }
829            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
830            intent = _intent;
831            realActivity = _intent != null ? _intent.getComponent() : null;
832            origActivity = null;
833        } else {
834            ComponentName targetComponent = new ComponentName(
835                    info.packageName, info.targetActivity);
836            if (_intent != null) {
837                Intent targetIntent = new Intent(_intent);
838                targetIntent.setComponent(targetComponent);
839                targetIntent.setSelector(null);
840                targetIntent.setSourceBounds(null);
841                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
842                        "Setting Intent of " + this + " to target " + targetIntent);
843                intent = targetIntent;
844                realActivity = targetComponent;
845                origActivity = _intent.getComponent();
846            } else {
847                intent = null;
848                realActivity = targetComponent;
849                origActivity = new ComponentName(info.packageName, info.name);
850            }
851        }
852
853        final int intentFlags = intent == null ? 0 : intent.getFlags();
854        if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
855            // Once we are set to an Intent with this flag, we count this
856            // task as having a true root activity.
857            rootWasReset = true;
858        }
859        userId = UserHandle.getUserId(info.applicationInfo.uid);
860        mUserSetupComplete = Settings.Secure.getIntForUser(mService.mContext.getContentResolver(),
861                USER_SETUP_COMPLETE, 0, userId) != 0;
862        if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
863            // If the activity itself has requested auto-remove, then just always do it.
864            autoRemoveRecents = true;
865        } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
866                == FLAG_ACTIVITY_NEW_DOCUMENT) {
867            // If the caller has not asked for the document to be retained, then we may
868            // want to turn on auto-remove, depending on whether the target has set its
869            // own document launch mode.
870            if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
871                autoRemoveRecents = false;
872            } else {
873                autoRemoveRecents = true;
874            }
875        } else {
876            autoRemoveRecents = false;
877        }
878        mResizeMode = info.resizeMode;
879        mSupportsPictureInPicture = info.supportsPictureInPicture();
880        mLockTaskMode = info.lockTaskLaunchMode;
881        mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
882        setLockTaskAuth();
883    }
884
885    /** Sets the original minimal width and height. */
886    private void setMinDimensions(ActivityInfo info) {
887        if (info != null && info.windowLayout != null) {
888            mMinWidth = info.windowLayout.minWidth;
889            mMinHeight = info.windowLayout.minHeight;
890        } else {
891            mMinWidth = INVALID_MIN_SIZE;
892            mMinHeight = INVALID_MIN_SIZE;
893        }
894    }
895
896    /**
897     * Return true if the input activity has the same intent filter as the intent this task
898     * record is based on (normally the root activity intent).
899     */
900    boolean isSameIntentFilter(ActivityRecord r) {
901        final Intent intent = new Intent(r.intent);
902        // Correct the activity intent for aliasing. The task record intent will always be based on
903        // the real activity that will be launched not the alias, so we need to use an intent with
904        // the component name pointing to the real activity not the alias in the activity record.
905        intent.setComponent(r.realActivity);
906        return this.intent.filterEquals(intent);
907    }
908
909    void setTaskToReturnTo(int taskToReturnTo) {
910        mTaskToReturnTo = (taskToReturnTo == RECENTS_ACTIVITY_TYPE)
911                ? HOME_ACTIVITY_TYPE : taskToReturnTo;
912    }
913
914    void setTaskToReturnTo(ActivityRecord source) {
915        if (source.isRecentsActivity()) {
916            setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
917        } else if (source.isAssistantActivity()) {
918            setTaskToReturnTo(ASSISTANT_ACTIVITY_TYPE);
919        }
920    }
921
922    int getTaskToReturnTo() {
923        return mTaskToReturnTo;
924    }
925
926    void setPrevAffiliate(TaskRecord prevAffiliate) {
927        mPrevAffiliate = prevAffiliate;
928        mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.taskId;
929    }
930
931    void setNextAffiliate(TaskRecord nextAffiliate) {
932        mNextAffiliate = nextAffiliate;
933        mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId;
934    }
935
936    ActivityStack getStack() {
937        return mStack;
938    }
939
940    /**
941     * Must be used for setting parent stack because it performs configuration updates.
942     * Must be called after adding task as a child to the stack.
943     */
944    void setStack(ActivityStack stack) {
945        if (stack != null && !stack.isInStackLocked(this)) {
946            throw new IllegalStateException("Task must be added as a Stack child first.");
947        }
948        mStack = stack;
949        onParentChanged();
950    }
951
952    /**
953     * @return Id of current stack, {@link INVALID_STACK_ID} if no stack is set.
954     */
955    int getStackId() {
956        return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
957    }
958
959    @Override
960    protected int getChildCount() {
961        return mActivities.size();
962    }
963
964    @Override
965    protected ConfigurationContainer getChildAt(int index) {
966        return mActivities.get(index);
967    }
968
969    @Override
970    protected ConfigurationContainer getParent() {
971        return mStack;
972    }
973
974    @Override
975    void onParentChanged() {
976        super.onParentChanged();
977        mService.mStackSupervisor.updateUIDsPresentOnDisplay();
978    }
979
980    // Close up recents linked list.
981    private void closeRecentsChain() {
982        if (mPrevAffiliate != null) {
983            mPrevAffiliate.setNextAffiliate(mNextAffiliate);
984        }
985        if (mNextAffiliate != null) {
986            mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
987        }
988        setPrevAffiliate(null);
989        setNextAffiliate(null);
990    }
991
992    void removedFromRecents() {
993        disposeThumbnail();
994        closeRecentsChain();
995        if (inRecents) {
996            inRecents = false;
997            mService.notifyTaskPersisterLocked(this, false);
998        }
999
1000        // TODO: Use window container controller once tasks are better synced between AM and WM
1001        mService.mWindowManager.notifyTaskRemovedFromRecents(taskId, userId);
1002    }
1003
1004    void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
1005        closeRecentsChain();
1006        mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
1007        mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
1008        // Find the end
1009        while (taskToAffiliateWith.mNextAffiliate != null) {
1010            final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate;
1011            if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
1012                Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
1013                        + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
1014                if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
1015                    nextRecents.setPrevAffiliate(null);
1016                }
1017                taskToAffiliateWith.setNextAffiliate(null);
1018                break;
1019            }
1020            taskToAffiliateWith = nextRecents;
1021        }
1022        taskToAffiliateWith.setNextAffiliate(this);
1023        setPrevAffiliate(taskToAffiliateWith);
1024        setNextAffiliate(null);
1025    }
1026
1027    /**
1028     * Sets the last thumbnail with the current task bounds and the system orientation.
1029     * @return whether the thumbnail was set
1030     */
1031    boolean setLastThumbnailLocked(Bitmap thumbnail) {
1032        int taskWidth = 0;
1033        int taskHeight = 0;
1034        if (mBounds != null) {
1035            // Non-fullscreen tasks
1036            taskWidth = mBounds.width();
1037            taskHeight = mBounds.height();
1038        } else if (mStack != null) {
1039            // Fullscreen tasks
1040            final Point displaySize = new Point();
1041            mStack.getDisplaySize(displaySize);
1042            taskWidth = displaySize.x;
1043            taskHeight = displaySize.y;
1044        } else {
1045            Slog.e(TAG, "setLastThumbnailLocked() called on Task without stack");
1046        }
1047        // We need to provide the current orientation of the display on which this task resides,
1048        // not the orientation of the task.
1049        final int orientation = getStack().getDisplay().getConfiguration().orientation;
1050        return setLastThumbnailLocked(thumbnail, taskWidth, taskHeight, orientation);
1051    }
1052
1053    /**
1054     * Sets the last thumbnail with the current task bounds.
1055     * @return whether the thumbnail was set
1056     */
1057    private boolean setLastThumbnailLocked(Bitmap thumbnail, int taskWidth, int taskHeight,
1058            int screenOrientation) {
1059        if (mLastThumbnail != thumbnail) {
1060            mLastThumbnail = thumbnail;
1061            mLastThumbnailInfo.taskWidth = taskWidth;
1062            mLastThumbnailInfo.taskHeight = taskHeight;
1063            mLastThumbnailInfo.screenOrientation = screenOrientation;
1064            if (thumbnail == null) {
1065                if (mLastThumbnailFile != null) {
1066                    mLastThumbnailFile.delete();
1067                }
1068            } else {
1069                mService.mRecentTasks.saveImage(thumbnail, mLastThumbnailFile.getAbsolutePath());
1070            }
1071            return true;
1072        }
1073        return false;
1074    }
1075
1076    void getLastThumbnail(TaskThumbnail thumbs) {
1077        thumbs.mainThumbnail = mLastThumbnail;
1078        thumbs.thumbnailInfo = mLastThumbnailInfo;
1079        thumbs.thumbnailFileDescriptor = null;
1080        if (mLastThumbnail == null) {
1081            thumbs.mainThumbnail = mService.mRecentTasks.getImageFromWriteQueue(
1082                    mLastThumbnailFile.getAbsolutePath());
1083        }
1084        // Only load the thumbnail file if we don't have a thumbnail
1085        if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) {
1086            try {
1087                thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,
1088                        ParcelFileDescriptor.MODE_READ_ONLY);
1089            } catch (IOException e) {
1090            }
1091        }
1092    }
1093
1094    /**
1095     * Removes in-memory thumbnail data when the max number of in-memory task thumbnails is reached.
1096     */
1097    void freeLastThumbnail() {
1098        mLastThumbnail = null;
1099    }
1100
1101    /**
1102     * Removes all associated thumbnail data when a task is removed or pruned from recents.
1103     */
1104    void disposeThumbnail() {
1105        mLastThumbnailInfo.reset();
1106        mLastThumbnail = null;
1107        lastDescription = null;
1108    }
1109
1110    /** Returns the intent for the root activity for this task */
1111    Intent getBaseIntent() {
1112        return intent != null ? intent : affinityIntent;
1113    }
1114
1115    /** Returns the first non-finishing activity from the root. */
1116    ActivityRecord getRootActivity() {
1117        for (int i = 0; i < mActivities.size(); i++) {
1118            final ActivityRecord r = mActivities.get(i);
1119            if (r.finishing) {
1120                continue;
1121            }
1122            return r;
1123        }
1124        return null;
1125    }
1126
1127    ActivityRecord getTopActivity() {
1128        return getTopActivity(true /* includeOverlays */);
1129    }
1130
1131    ActivityRecord getTopActivity(boolean includeOverlays) {
1132        for (int i = mActivities.size() - 1; i >= 0; --i) {
1133            final ActivityRecord r = mActivities.get(i);
1134            if (r.finishing || (!includeOverlays && r.mTaskOverlay)) {
1135                continue;
1136            }
1137            return r;
1138        }
1139        return null;
1140    }
1141
1142    ActivityRecord topRunningActivityLocked() {
1143        if (mStack != null) {
1144            for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
1145                ActivityRecord r = mActivities.get(activityNdx);
1146                if (!r.finishing && r.okToShowLocked()) {
1147                    return r;
1148                }
1149            }
1150        }
1151        return null;
1152    }
1153
1154    boolean isVisible() {
1155        for (int i = mActivities.size() - 1; i >= 0; --i) {
1156            final ActivityRecord r = mActivities.get(i);
1157            if (r.visible) {
1158                return true;
1159            }
1160        }
1161        return false;
1162    }
1163
1164    void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
1165        if (mStack != null) {
1166            for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
1167                ActivityRecord r = mActivities.get(activityNdx);
1168                if (!r.finishing && r.okToShowLocked() && r.visibleIgnoringKeyguard) {
1169                    outActivities.add(r);
1170                }
1171            }
1172        }
1173    }
1174
1175    ActivityRecord topRunningActivityWithStartingWindowLocked() {
1176        if (mStack != null) {
1177            for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
1178                ActivityRecord r = mActivities.get(activityNdx);
1179                if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
1180                        || r.finishing || !r.okToShowLocked()) {
1181                    continue;
1182                }
1183                return r;
1184            }
1185        }
1186        return null;
1187    }
1188
1189    boolean okToShowLocked() {
1190        // NOTE: If {@link TaskRecord#topRunningActivityLocked} return is not null then it is
1191        // okay to show the activity when locked.
1192        return mService.mStackSupervisor.isCurrentProfileLocked(userId)
1193                || topRunningActivityLocked() != null;
1194    }
1195
1196    /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
1197    final void setFrontOfTask() {
1198        boolean foundFront = false;
1199        final int numActivities = mActivities.size();
1200        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
1201            final ActivityRecord r = mActivities.get(activityNdx);
1202            if (foundFront || r.finishing) {
1203                r.frontOfTask = false;
1204            } else {
1205                r.frontOfTask = true;
1206                // Set frontOfTask false for every following activity.
1207                foundFront = true;
1208            }
1209        }
1210        if (!foundFront && numActivities > 0) {
1211            // All activities of this task are finishing. As we ought to have a frontOfTask
1212            // activity, make the bottom activity front.
1213            mActivities.get(0).frontOfTask = true;
1214        }
1215    }
1216
1217    /**
1218     * Reorder the history stack so that the passed activity is brought to the front.
1219     */
1220    final void moveActivityToFrontLocked(ActivityRecord newTop) {
1221        if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE,
1222                "Removing and adding activity " + newTop
1223                + " to stack at top callers=" + Debug.getCallers(4));
1224
1225        mActivities.remove(newTop);
1226        mActivities.add(newTop);
1227        updateEffectiveIntent();
1228
1229        setFrontOfTask();
1230    }
1231
1232    void addActivityAtBottom(ActivityRecord r) {
1233        addActivityAtIndex(0, r);
1234    }
1235
1236    void addActivityToTop(ActivityRecord r) {
1237        addActivityAtIndex(mActivities.size(), r);
1238    }
1239
1240    /**
1241     * Adds an activity {@param r} at the given {@param index}. The activity {@param r} must either
1242     * be in the current task or unparented to any task.
1243     */
1244    void addActivityAtIndex(int index, ActivityRecord r) {
1245        TaskRecord task = r.getTask();
1246        if (task != null && task != this) {
1247            throw new IllegalArgumentException("Can not add r=" + " to task=" + this
1248                    + " current parent=" + task);
1249        }
1250
1251        r.setTask(this);
1252
1253        // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
1254        if (!mActivities.remove(r) && r.fullscreen) {
1255            // Was not previously in list.
1256            numFullscreen++;
1257        }
1258        // Only set this based on the first activity
1259        if (mActivities.isEmpty()) {
1260            taskType = r.mActivityType;
1261            isPersistable = r.isPersistable();
1262            mCallingUid = r.launchedFromUid;
1263            mCallingPackage = r.launchedFromPackage;
1264            // Clamp to [1, max].
1265            maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
1266                    ActivityManager.getMaxAppRecentsLimitStatic());
1267        } else {
1268            // Otherwise make all added activities match this one.
1269            r.mActivityType = taskType;
1270        }
1271
1272        final int size = mActivities.size();
1273
1274        if (index == size && size > 0) {
1275            final ActivityRecord top = mActivities.get(size - 1);
1276            if (top.mTaskOverlay) {
1277                // Place below the task overlay activity since the overlay activity should always
1278                // be on top.
1279                index--;
1280            }
1281        }
1282
1283        index = Math.min(size, index);
1284        mActivities.add(index, r);
1285        updateEffectiveIntent();
1286        if (r.isPersistable()) {
1287            mService.notifyTaskPersisterLocked(this, false);
1288        }
1289
1290        // Sync. with window manager
1291        updateOverrideConfigurationFromLaunchBounds();
1292        final AppWindowContainerController appController = r.getWindowContainerController();
1293        if (appController != null) {
1294            // Only attempt to move in WM if the child has a controller. It is possible we haven't
1295            // created controller for the activity we are starting yet.
1296            mWindowContainerController.positionChildAt(appController, index);
1297        }
1298
1299        // Make sure the list of display UID whitelists is updated
1300        // now that this record is in a new task.
1301        mService.mStackSupervisor.updateUIDsPresentOnDisplay();
1302    }
1303
1304    /**
1305     * Removes the specified activity from this task.
1306     * @param r The {@link ActivityRecord} to remove.
1307     * @return true if this was the last activity in the task.
1308     */
1309    boolean removeActivity(ActivityRecord r) {
1310        return removeActivity(r, false /*reparenting*/);
1311    }
1312
1313    boolean removeActivity(ActivityRecord r, boolean reparenting) {
1314        if (r.getTask() != this) {
1315            throw new IllegalArgumentException(
1316                    "Activity=" + r + " does not belong to task=" + this);
1317        }
1318
1319        r.setTask(null /*task*/, reparenting);
1320
1321        if (mActivities.remove(r) && r.fullscreen) {
1322            // Was previously in list.
1323            numFullscreen--;
1324        }
1325        if (r.isPersistable()) {
1326            mService.notifyTaskPersisterLocked(this, false);
1327        }
1328
1329        if (getStackId() == PINNED_STACK_ID) {
1330            // We normally notify listeners of task stack changes on pause, however pinned stack
1331            // activities are normally in the paused state so no notification will be sent there
1332            // before the activity is removed. We send it here so instead.
1333            mService.mTaskChangeNotificationController.notifyTaskStackChanged();
1334        }
1335
1336        if (mActivities.isEmpty()) {
1337            return !mReuseTask;
1338        }
1339        updateEffectiveIntent();
1340        return false;
1341    }
1342
1343    /**
1344     * @return whether or not there are ONLY task overlay activities in the stack.
1345     *         If {@param excludeFinishing} is set, then ignore finishing activities in the check.
1346     *         If there are no task overlay activities, this call returns false.
1347     */
1348    boolean onlyHasTaskOverlayActivities(boolean excludeFinishing) {
1349        int count = 0;
1350        for (int i = mActivities.size() - 1; i >= 0; i--) {
1351            final ActivityRecord r = mActivities.get(i);
1352            if (excludeFinishing && r.finishing) {
1353                continue;
1354            }
1355            if (!r.mTaskOverlay) {
1356                return false;
1357            }
1358            count++;
1359        }
1360        return count > 0;
1361    }
1362
1363    boolean autoRemoveFromRecents() {
1364        // We will automatically remove the task either if it has explicitly asked for
1365        // this, or it is empty and has never contained an activity that got shown to
1366        // the user.
1367        return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible);
1368    }
1369
1370    /**
1371     * Completely remove all activities associated with an existing
1372     * task starting at a specified index.
1373     */
1374    final void performClearTaskAtIndexLocked(int activityNdx, boolean pauseImmediately) {
1375        int numActivities = mActivities.size();
1376        for ( ; activityNdx < numActivities; ++activityNdx) {
1377            final ActivityRecord r = mActivities.get(activityNdx);
1378            if (r.finishing) {
1379                continue;
1380            }
1381            if (mStack == null) {
1382                // Task was restored from persistent storage.
1383                r.takeFromHistory();
1384                mActivities.remove(activityNdx);
1385                --activityNdx;
1386                --numActivities;
1387            } else if (mStack.finishActivityLocked(r, Activity.RESULT_CANCELED, null,
1388                    "clear-task-index", false, pauseImmediately)) {
1389                --activityNdx;
1390                --numActivities;
1391            }
1392        }
1393    }
1394
1395    /**
1396     * Completely remove all activities associated with an existing task.
1397     */
1398    final void performClearTaskLocked() {
1399        mReuseTask = true;
1400        performClearTaskAtIndexLocked(0, !PAUSE_IMMEDIATELY);
1401        mReuseTask = false;
1402    }
1403
1404    ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
1405        mReuseTask = true;
1406        final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
1407        mReuseTask = false;
1408        return result;
1409    }
1410
1411    /**
1412     * Perform clear operation as requested by
1413     * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
1414     * stack to the given task, then look for
1415     * an instance of that activity in the stack and, if found, finish all
1416     * activities on top of it and return the instance.
1417     *
1418     * @param newR Description of the new activity being started.
1419     * @return Returns the old activity that should be continued to be used,
1420     * or null if none was found.
1421     */
1422    final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
1423        int numActivities = mActivities.size();
1424        for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
1425            ActivityRecord r = mActivities.get(activityNdx);
1426            if (r.finishing) {
1427                continue;
1428            }
1429            if (r.realActivity.equals(newR.realActivity)) {
1430                // Here it is!  Now finish everything in front...
1431                final ActivityRecord ret = r;
1432
1433                for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
1434                    r = mActivities.get(activityNdx);
1435                    if (r.finishing) {
1436                        continue;
1437                    }
1438                    ActivityOptions opts = r.takeOptionsLocked();
1439                    if (opts != null) {
1440                        ret.updateOptionsLocked(opts);
1441                    }
1442                    if (mStack != null && mStack.finishActivityLocked(
1443                            r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
1444                        --activityNdx;
1445                        --numActivities;
1446                    }
1447                }
1448
1449                // Finally, if this is a normal launch mode (that is, not
1450                // expecting onNewIntent()), then we will finish the current
1451                // instance of the activity so a new fresh one can be started.
1452                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
1453                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
1454                        && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
1455                    if (!ret.finishing) {
1456                        if (mStack != null) {
1457                            mStack.finishActivityLocked(
1458                                    ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
1459                        }
1460                        return null;
1461                    }
1462                }
1463
1464                return ret;
1465            }
1466        }
1467
1468        return null;
1469    }
1470
1471    TaskThumbnail getTaskThumbnailLocked() {
1472        if (mStack != null) {
1473            final ActivityRecord resumedActivity = mStack.mResumedActivity;
1474            if (resumedActivity != null && resumedActivity.getTask() == this) {
1475                final Bitmap thumbnail = resumedActivity.screenshotActivityLocked();
1476                setLastThumbnailLocked(thumbnail);
1477            }
1478        }
1479        final TaskThumbnail taskThumbnail = new TaskThumbnail();
1480        getLastThumbnail(taskThumbnail);
1481        return taskThumbnail;
1482    }
1483
1484    void removeTaskActivitiesLocked(boolean pauseImmediately) {
1485        // Just remove the entire task.
1486        performClearTaskAtIndexLocked(0, pauseImmediately);
1487    }
1488
1489    String lockTaskAuthToString() {
1490        switch (mLockTaskAuth) {
1491            case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
1492            case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
1493            case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
1494            case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
1495            case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
1496            default: return "unknown=" + mLockTaskAuth;
1497        }
1498    }
1499
1500    void setLockTaskAuth() {
1501        if (!mPrivileged &&
1502                (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS ||
1503                        mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
1504            // Non-priv apps are not allowed to use always or never, fall back to default
1505            mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
1506        }
1507        switch (mLockTaskMode) {
1508            case LOCK_TASK_LAUNCH_MODE_DEFAULT:
1509                mLockTaskAuth = isLockTaskWhitelistedLocked() ?
1510                    LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
1511                break;
1512
1513            case LOCK_TASK_LAUNCH_MODE_NEVER:
1514                mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
1515                break;
1516
1517            case LOCK_TASK_LAUNCH_MODE_ALWAYS:
1518                mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
1519                break;
1520
1521            case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
1522                mLockTaskAuth = isLockTaskWhitelistedLocked() ?
1523                        LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
1524                break;
1525        }
1526        if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
1527                " mLockTaskAuth=" + lockTaskAuthToString());
1528    }
1529
1530    boolean isLockTaskWhitelistedLocked() {
1531        String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
1532        if (pkg == null) {
1533            return false;
1534        }
1535        String[] packages = mService.mLockTaskPackages.get(userId);
1536        if (packages == null) {
1537            return false;
1538        }
1539        for (int i = packages.length - 1; i >= 0; --i) {
1540            if (pkg.equals(packages[i])) {
1541                return true;
1542            }
1543        }
1544        return false;
1545    }
1546
1547    boolean isHomeTask() {
1548        return taskType == HOME_ACTIVITY_TYPE;
1549    }
1550
1551    boolean isRecentsTask() {
1552        return taskType == RECENTS_ACTIVITY_TYPE;
1553    }
1554
1555    boolean isAssistantTask() {
1556        return taskType == ASSISTANT_ACTIVITY_TYPE;
1557    }
1558
1559    boolean isApplicationTask() {
1560        return taskType == APPLICATION_ACTIVITY_TYPE;
1561    }
1562
1563    boolean isOverHomeStack() {
1564        return mTaskToReturnTo == HOME_ACTIVITY_TYPE;
1565    }
1566
1567    boolean isOverAssistantStack() {
1568        return mTaskToReturnTo == ASSISTANT_ACTIVITY_TYPE;
1569    }
1570
1571    private boolean isResizeable(boolean checkSupportsPip) {
1572        return (mService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
1573                || (checkSupportsPip && mSupportsPictureInPicture)) && !mTemporarilyUnresizable;
1574    }
1575
1576    boolean isResizeable() {
1577        return isResizeable(true /* checkSupportsPip */);
1578    }
1579
1580    boolean supportsSplitScreen() {
1581        // A task can not be docked even if it is considered resizeable because it only supports
1582        // picture-in-picture mode but has a non-resizeable resizeMode
1583        return mService.mSupportsSplitScreenMultiWindow
1584                && (mService.mForceResizableActivities
1585                        || (isResizeable(false /* checkSupportsPip */)
1586                                && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
1587    }
1588
1589    /**
1590     * Check whether this task can be launched on the specified display.
1591     * @param displayId Target display id.
1592     * @return {@code true} if either it is the default display or this activity is resizeable and
1593     *         can be put a secondary screen.
1594     */
1595    boolean canBeLaunchedOnDisplay(int displayId) {
1596        return mService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
1597                isResizeable(false /* checkSupportsPip */), -1 /* don't check PID */,
1598                -1 /* don't check UID */, null /* activityInfo */);
1599    }
1600
1601    /**
1602     * Check that a given bounds matches the application requested orientation.
1603     *
1604     * @param bounds The bounds to be tested.
1605     * @return True if the requested bounds are okay for a resizing request.
1606     */
1607    private boolean canResizeToBounds(Rect bounds) {
1608        if (bounds == null || getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
1609            // Note: If not on the freeform workspace, we ignore the bounds.
1610            return true;
1611        }
1612        final boolean landscape = bounds.width() > bounds.height();
1613        if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
1614            return mBounds == null || landscape == (mBounds.width() > mBounds.height());
1615        }
1616        return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
1617                && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
1618    }
1619
1620    /**
1621     * @return {@code true} if the task is being cleared for the purposes of being reused.
1622     */
1623    boolean isClearingToReuseTask() {
1624        return mReuseTask;
1625    }
1626
1627    /**
1628     * Find the activity in the history stack within the given task.  Returns
1629     * the index within the history at which it's found, or < 0 if not found.
1630     */
1631    final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
1632        final ComponentName realActivity = r.realActivity;
1633        for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
1634            ActivityRecord candidate = mActivities.get(activityNdx);
1635            if (candidate.finishing) {
1636                continue;
1637            }
1638            if (candidate.realActivity.equals(realActivity)) {
1639                return candidate;
1640            }
1641        }
1642        return null;
1643    }
1644
1645    /** Updates the last task description values. */
1646    void updateTaskDescription() {
1647        // Traverse upwards looking for any break between main task activities and
1648        // utility activities.
1649        int activityNdx;
1650        final int numActivities = mActivities.size();
1651        final boolean relinquish = numActivities != 0 &&
1652                (mActivities.get(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0;
1653        for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
1654                ++activityNdx) {
1655            final ActivityRecord r = mActivities.get(activityNdx);
1656            if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1657                // This will be the top activity for determining taskDescription. Pre-inc to
1658                // overcome initial decrement below.
1659                ++activityNdx;
1660                break;
1661            }
1662            if (r.intent != null &&
1663                    (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
1664                break;
1665            }
1666        }
1667        if (activityNdx > 0) {
1668            // Traverse downwards starting below break looking for set label, icon.
1669            // Note that if there are activities in the task but none of them set the
1670            // recent activity values, then we do not fall back to the last set
1671            // values in the TaskRecord.
1672            String label = null;
1673            String iconFilename = null;
1674            int colorPrimary = 0;
1675            int colorBackground = 0;
1676            int statusBarColor = 0;
1677            int navigationBarColor = 0;
1678            boolean topActivity = true;
1679            for (--activityNdx; activityNdx >= 0; --activityNdx) {
1680                final ActivityRecord r = mActivities.get(activityNdx);
1681                if (r.taskDescription != null) {
1682                    if (label == null) {
1683                        label = r.taskDescription.getLabel();
1684                    }
1685                    if (iconFilename == null) {
1686                        iconFilename = r.taskDescription.getIconFilename();
1687                    }
1688                    if (colorPrimary == 0) {
1689                        colorPrimary = r.taskDescription.getPrimaryColor();
1690                    }
1691                    if (topActivity) {
1692                        colorBackground = r.taskDescription.getBackgroundColor();
1693                        statusBarColor = r.taskDescription.getStatusBarColor();
1694                        navigationBarColor = r.taskDescription.getNavigationBarColor();
1695                    }
1696                }
1697                topActivity = false;
1698            }
1699            lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary,
1700                    colorBackground, statusBarColor, navigationBarColor);
1701            if (mWindowContainerController != null) {
1702                mWindowContainerController.setTaskDescription(lastTaskDescription);
1703            }
1704            // Update the task affiliation color if we are the parent of the group
1705            if (taskId == mAffiliatedTaskId) {
1706                mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
1707            }
1708        }
1709    }
1710
1711    int findEffectiveRootIndex() {
1712        int effectiveNdx = 0;
1713        final int topActivityNdx = mActivities.size() - 1;
1714        for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
1715            final ActivityRecord r = mActivities.get(activityNdx);
1716            if (r.finishing) {
1717                continue;
1718            }
1719            effectiveNdx = activityNdx;
1720            if ((r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
1721                break;
1722            }
1723        }
1724        return effectiveNdx;
1725    }
1726
1727    void updateEffectiveIntent() {
1728        final int effectiveRootIndex = findEffectiveRootIndex();
1729        final ActivityRecord r = mActivities.get(effectiveRootIndex);
1730        setIntent(r);
1731    }
1732
1733    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
1734        if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
1735
1736        out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
1737        if (realActivity != null) {
1738            out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
1739        }
1740        out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
1741        if (origActivity != null) {
1742            out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
1743        }
1744        // Write affinity, and root affinity if it is different from affinity.
1745        // We use the special string "@" for a null root affinity, so we can identify
1746        // later whether we were given a root affinity or should just make it the
1747        // same as the affinity.
1748        if (affinity != null) {
1749            out.attribute(null, ATTR_AFFINITY, affinity);
1750            if (!affinity.equals(rootAffinity)) {
1751                out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
1752            }
1753        } else if (rootAffinity != null) {
1754            out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
1755        }
1756        out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
1757        out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
1758        out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
1759        out.attribute(null, ATTR_USERID, String.valueOf(userId));
1760        out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
1761        out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
1762        out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
1763        out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime));
1764        out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime));
1765        out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
1766        out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
1767        if (lastDescription != null) {
1768            out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
1769        }
1770        if (lastTaskDescription != null) {
1771            lastTaskDescription.saveToXml(out);
1772        }
1773        mLastThumbnailInfo.saveToXml(out);
1774        out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
1775        out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
1776        out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
1777        out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
1778        out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
1779        out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
1780        out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
1781        out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
1782                String.valueOf(mSupportsPictureInPicture));
1783        out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged));
1784        if (mLastNonFullscreenBounds != null) {
1785            out.attribute(
1786                    null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
1787        }
1788        out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
1789        out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
1790        out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
1791
1792        if (affinityIntent != null) {
1793            out.startTag(null, TAG_AFFINITYINTENT);
1794            affinityIntent.saveToXml(out);
1795            out.endTag(null, TAG_AFFINITYINTENT);
1796        }
1797
1798        out.startTag(null, TAG_INTENT);
1799        intent.saveToXml(out);
1800        out.endTag(null, TAG_INTENT);
1801
1802        final ArrayList<ActivityRecord> activities = mActivities;
1803        final int numActivities = activities.size();
1804        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
1805            final ActivityRecord r = activities.get(activityNdx);
1806            if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
1807                    ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
1808                            | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) &&
1809                            activityNdx > 0) {
1810                // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
1811                break;
1812            }
1813            out.startTag(null, TAG_ACTIVITY);
1814            r.saveToXml(out);
1815            out.endTag(null, TAG_ACTIVITY);
1816        }
1817    }
1818
1819    static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
1820            throws IOException, XmlPullParserException {
1821        Intent intent = null;
1822        Intent affinityIntent = null;
1823        ArrayList<ActivityRecord> activities = new ArrayList<>();
1824        ComponentName realActivity = null;
1825        boolean realActivitySuspended = false;
1826        ComponentName origActivity = null;
1827        String affinity = null;
1828        String rootAffinity = null;
1829        boolean hasRootAffinity = false;
1830        boolean rootHasReset = false;
1831        boolean autoRemoveRecents = false;
1832        boolean askedCompatMode = false;
1833        int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
1834        int userId = 0;
1835        boolean userSetupComplete = true;
1836        int effectiveUid = -1;
1837        String lastDescription = null;
1838        long firstActiveTime = -1;
1839        long lastActiveTime = -1;
1840        long lastTimeOnTop = 0;
1841        boolean neverRelinquishIdentity = true;
1842        int taskId = INVALID_TASK_ID;
1843        final int outerDepth = in.getDepth();
1844        TaskDescription taskDescription = new TaskDescription();
1845        TaskThumbnailInfo thumbnailInfo = new TaskThumbnailInfo();
1846        int taskAffiliation = INVALID_TASK_ID;
1847        int taskAffiliationColor = 0;
1848        int prevTaskId = INVALID_TASK_ID;
1849        int nextTaskId = INVALID_TASK_ID;
1850        int callingUid = -1;
1851        String callingPackage = "";
1852        int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
1853        boolean supportsPictureInPicture = false;
1854        boolean privileged = false;
1855        Rect bounds = null;
1856        int minWidth = INVALID_MIN_SIZE;
1857        int minHeight = INVALID_MIN_SIZE;
1858        int persistTaskVersion = 0;
1859
1860        for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
1861            final String attrName = in.getAttributeName(attrNdx);
1862            final String attrValue = in.getAttributeValue(attrNdx);
1863            if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
1864                    attrName + " value=" + attrValue);
1865            if (ATTR_TASKID.equals(attrName)) {
1866                if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
1867            } else if (ATTR_REALACTIVITY.equals(attrName)) {
1868                realActivity = ComponentName.unflattenFromString(attrValue);
1869            } else if (ATTR_REALACTIVITY_SUSPENDED.equals(attrName)) {
1870                realActivitySuspended = Boolean.valueOf(attrValue);
1871            } else if (ATTR_ORIGACTIVITY.equals(attrName)) {
1872                origActivity = ComponentName.unflattenFromString(attrValue);
1873            } else if (ATTR_AFFINITY.equals(attrName)) {
1874                affinity = attrValue;
1875            } else if (ATTR_ROOT_AFFINITY.equals(attrName)) {
1876                rootAffinity = attrValue;
1877                hasRootAffinity = true;
1878            } else if (ATTR_ROOTHASRESET.equals(attrName)) {
1879                rootHasReset = Boolean.parseBoolean(attrValue);
1880            } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) {
1881                autoRemoveRecents = Boolean.parseBoolean(attrValue);
1882            } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) {
1883                askedCompatMode = Boolean.parseBoolean(attrValue);
1884            } else if (ATTR_USERID.equals(attrName)) {
1885                userId = Integer.parseInt(attrValue);
1886            } else if (ATTR_USER_SETUP_COMPLETE.equals(attrName)) {
1887                userSetupComplete = Boolean.parseBoolean(attrValue);
1888            } else if (ATTR_EFFECTIVE_UID.equals(attrName)) {
1889                effectiveUid = Integer.parseInt(attrValue);
1890            } else if (ATTR_TASKTYPE.equals(attrName)) {
1891                taskType = Integer.parseInt(attrValue);
1892            } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) {
1893                firstActiveTime = Long.parseLong(attrValue);
1894            } else if (ATTR_LASTACTIVETIME.equals(attrName)) {
1895                lastActiveTime = Long.parseLong(attrValue);
1896            } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
1897                lastDescription = attrValue;
1898            } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
1899                lastTimeOnTop = Long.parseLong(attrValue);
1900            } else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
1901                neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
1902            } else if (attrName.startsWith(TaskThumbnailInfo.ATTR_TASK_THUMBNAILINFO_PREFIX)) {
1903                thumbnailInfo.restoreFromXml(attrName, attrValue);
1904            } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
1905                taskDescription.restoreFromXml(attrName, attrValue);
1906            } else if (ATTR_TASK_AFFILIATION.equals(attrName)) {
1907                taskAffiliation = Integer.parseInt(attrValue);
1908            } else if (ATTR_PREV_AFFILIATION.equals(attrName)) {
1909                prevTaskId = Integer.parseInt(attrValue);
1910            } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) {
1911                nextTaskId = Integer.parseInt(attrValue);
1912            } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) {
1913                taskAffiliationColor = Integer.parseInt(attrValue);
1914            } else if (ATTR_CALLING_UID.equals(attrName)) {
1915                callingUid = Integer.parseInt(attrValue);
1916            } else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
1917                callingPackage = attrValue;
1918            } else if (ATTR_RESIZE_MODE.equals(attrName)) {
1919                resizeMode = Integer.parseInt(attrValue);
1920            } else if (ATTR_SUPPORTS_PICTURE_IN_PICTURE.equals(attrName)) {
1921                supportsPictureInPicture = Boolean.parseBoolean(attrValue);
1922            } else if (ATTR_PRIVILEGED.equals(attrName)) {
1923                privileged = Boolean.parseBoolean(attrValue);
1924            } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
1925                bounds = Rect.unflattenFromString(attrValue);
1926            } else if (ATTR_MIN_WIDTH.equals(attrName)) {
1927                minWidth = Integer.parseInt(attrValue);
1928            } else if (ATTR_MIN_HEIGHT.equals(attrName)) {
1929                minHeight = Integer.parseInt(attrValue);
1930            } else if (ATTR_PERSIST_TASK_VERSION.equals(attrName)) {
1931                persistTaskVersion = Integer.parseInt(attrValue);
1932            } else {
1933                Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
1934            }
1935        }
1936
1937        int event;
1938        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
1939                (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
1940            if (event == XmlPullParser.START_TAG) {
1941                final String name = in.getName();
1942                if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
1943                        name);
1944                if (TAG_AFFINITYINTENT.equals(name)) {
1945                    affinityIntent = Intent.restoreFromXml(in);
1946                } else if (TAG_INTENT.equals(name)) {
1947                    intent = Intent.restoreFromXml(in);
1948                } else if (TAG_ACTIVITY.equals(name)) {
1949                    ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor);
1950                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
1951                            activity);
1952                    if (activity != null) {
1953                        activities.add(activity);
1954                    }
1955                } else {
1956                    Slog.e(TAG, "restoreTask: Unexpected name=" + name);
1957                    XmlUtils.skipCurrentTag(in);
1958                }
1959            }
1960        }
1961        if (!hasRootAffinity) {
1962            rootAffinity = affinity;
1963        } else if ("@".equals(rootAffinity)) {
1964            rootAffinity = null;
1965        }
1966        if (effectiveUid <= 0) {
1967            Intent checkIntent = intent != null ? intent : affinityIntent;
1968            effectiveUid = 0;
1969            if (checkIntent != null) {
1970                IPackageManager pm = AppGlobals.getPackageManager();
1971                try {
1972                    ApplicationInfo ai = pm.getApplicationInfo(
1973                            checkIntent.getComponent().getPackageName(),
1974                            PackageManager.MATCH_UNINSTALLED_PACKAGES
1975                                    | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
1976                    if (ai != null) {
1977                        effectiveUid = ai.uid;
1978                    }
1979                } catch (RemoteException e) {
1980                }
1981            }
1982            Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
1983                    + ": effectiveUid=" + effectiveUid);
1984        }
1985
1986        if (persistTaskVersion < 1) {
1987            // We need to convert the resize mode of home activities saved before version one if
1988            // they are marked as RESIZE_MODE_RESIZEABLE to RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION
1989            // since we didn't have that differentiation before version 1 and the system didn't
1990            // resize home activities before then.
1991            if (taskType == HOME_ACTIVITY_TYPE && resizeMode == RESIZE_MODE_RESIZEABLE) {
1992                resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
1993            }
1994        } else {
1995            // This activity has previously marked itself explicitly as both resizeable and
1996            // supporting picture-in-picture.  Since there is no longer a requirement for
1997            // picture-in-picture activities to be resizeable, we can mark this simply as
1998            // resizeable and supporting picture-in-picture separately.
1999            if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
2000                resizeMode = RESIZE_MODE_RESIZEABLE;
2001                supportsPictureInPicture = true;
2002            }
2003        }
2004
2005        final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
2006                affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
2007                autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
2008                activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
2009                taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId,
2010                taskAffiliationColor, callingUid, callingPackage, resizeMode,
2011                supportsPictureInPicture, privileged, realActivitySuspended, userSetupComplete,
2012                minWidth, minHeight);
2013        task.updateOverrideConfiguration(bounds);
2014
2015        for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
2016            activities.get(activityNdx).setTask(task);
2017        }
2018
2019        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
2020        return task;
2021    }
2022
2023    private void adjustForMinimalTaskDimensions(Rect bounds) {
2024        if (bounds == null) {
2025            return;
2026        }
2027        int minWidth = mMinWidth;
2028        int minHeight = mMinHeight;
2029        // If the task has no requested minimal size, we'd like to enforce a minimal size
2030        // so that the user can not render the task too small to manipulate. We don't need
2031        // to do this for the pinned stack as the bounds are controlled by the system.
2032        if (getStackId() != PINNED_STACK_ID) {
2033            if (minWidth == INVALID_MIN_SIZE) {
2034                minWidth = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask;
2035            }
2036            if (minHeight == INVALID_MIN_SIZE) {
2037                minHeight = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask;
2038            }
2039        }
2040        final boolean adjustWidth = minWidth > bounds.width();
2041        final boolean adjustHeight = minHeight > bounds.height();
2042        if (!(adjustWidth || adjustHeight)) {
2043            return;
2044        }
2045
2046        if (adjustWidth) {
2047            if (mBounds != null && bounds.right == mBounds.right) {
2048                bounds.left = bounds.right - minWidth;
2049            } else {
2050                // Either left bounds match, or neither match, or the previous bounds were
2051                // fullscreen and we default to keeping left.
2052                bounds.right = bounds.left + minWidth;
2053            }
2054        }
2055        if (adjustHeight) {
2056            if (mBounds != null && bounds.bottom == mBounds.bottom) {
2057                bounds.top = bounds.bottom - minHeight;
2058            } else {
2059                // Either top bounds match, or neither match, or the previous bounds were
2060                // fullscreen and we default to keeping top.
2061                bounds.bottom = bounds.top + minHeight;
2062            }
2063        }
2064    }
2065
2066    /**
2067     * @return a new Configuration for this Task, given the provided {@param bounds} and
2068     *         {@param insetBounds}.
2069     */
2070    Configuration computeNewOverrideConfigurationForBounds(Rect bounds, Rect insetBounds) {
2071        // Compute a new override configuration for the given bounds, if fullscreen bounds
2072        // (bounds == null), then leave the override config unset
2073        final Configuration newOverrideConfig = new Configuration();
2074        if (bounds != null) {
2075            newOverrideConfig.setTo(getOverrideConfiguration());
2076            mTmpRect.set(bounds);
2077            adjustForMinimalTaskDimensions(mTmpRect);
2078            computeOverrideConfiguration(newOverrideConfig, mTmpRect, insetBounds,
2079                    mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom);
2080        }
2081
2082        return newOverrideConfig;
2083    }
2084
2085    /**
2086     * Update task's override configuration based on the bounds.
2087     * @param bounds The bounds of the task.
2088     * @return True if the override configuration was updated.
2089     */
2090    boolean updateOverrideConfiguration(Rect bounds) {
2091        return updateOverrideConfiguration(bounds, null /* insetBounds */);
2092    }
2093
2094    /**
2095     * Update task's override configuration based on the bounds.
2096     * @param bounds The bounds of the task.
2097     * @param insetBounds The bounds used to calculate the system insets, which is used here to
2098     *                    subtract the navigation bar/status bar size from the screen size reported
2099     *                    to the application. See {@link IActivityManager#resizeDockedStack}.
2100     * @return True if the override configuration was updated.
2101     */
2102    boolean updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) {
2103        if (Objects.equals(mBounds, bounds)) {
2104            return false;
2105        }
2106        mTmpConfig.setTo(getOverrideConfiguration());
2107        final boolean oldFullscreen = mFullscreen;
2108        final Configuration newConfig = getOverrideConfiguration();
2109
2110        mFullscreen = bounds == null;
2111        if (mFullscreen) {
2112            if (mBounds != null && StackId.persistTaskBounds(mStack.mStackId)) {
2113                mLastNonFullscreenBounds = mBounds;
2114            }
2115            mBounds = null;
2116            newConfig.unset();
2117        } else {
2118            mTmpRect.set(bounds);
2119            adjustForMinimalTaskDimensions(mTmpRect);
2120            if (mBounds == null) {
2121                mBounds = new Rect(mTmpRect);
2122            } else {
2123                mBounds.set(mTmpRect);
2124            }
2125            if (mStack == null || StackId.persistTaskBounds(mStack.mStackId)) {
2126                mLastNonFullscreenBounds = mBounds;
2127            }
2128            computeOverrideConfiguration(newConfig, mTmpRect, insetBounds,
2129                    mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom);
2130        }
2131        onOverrideConfigurationChanged(newConfig);
2132
2133        if (mFullscreen != oldFullscreen) {
2134            mService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
2135        }
2136
2137        return !mTmpConfig.equals(newConfig);
2138    }
2139
2140    /** Clears passed config and fills it with new override values. */
2141    // TODO(b/36505427): TaskRecord.computeOverrideConfiguration() is a utility method that doesn't
2142    // depend on task or stacks, but uses those object to get the display to base the calculation
2143    // on. Probably best to centralize calculations like this in ConfigurationContainer.
2144    void computeOverrideConfiguration(Configuration config, Rect bounds, Rect insetBounds,
2145            boolean overrideWidth, boolean overrideHeight) {
2146        mTmpNonDecorBounds.set(bounds);
2147        mTmpStableBounds.set(bounds);
2148
2149        config.unset();
2150        final Configuration parentConfig = getParent().getConfiguration();
2151
2152        final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
2153
2154        if (mStack != null) {
2155            final StackWindowController stackController = mStack.getWindowContainerController();
2156            stackController.adjustConfigurationForBounds(bounds, insetBounds,
2157                    mTmpNonDecorBounds, mTmpStableBounds, overrideWidth, overrideHeight, density,
2158                    config, parentConfig);
2159        } else {
2160            throw new IllegalArgumentException("Expected stack when calculating override config");
2161        }
2162
2163        config.orientation = (config.screenWidthDp <= config.screenHeightDp)
2164                ? Configuration.ORIENTATION_PORTRAIT
2165                : Configuration.ORIENTATION_LANDSCAPE;
2166
2167        // For calculating screen layout, we need to use the non-decor inset screen area for the
2168        // calculation for compatibility reasons, i.e. screen area without system bars that could
2169        // never go away in Honeycomb.
2170        final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
2171        final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
2172        // We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start override
2173        // calculation with partial default.
2174        final int sl = Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_XLARGE;
2175        final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
2176        final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
2177        config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
2178
2179    }
2180
2181    Rect updateOverrideConfigurationFromLaunchBounds() {
2182        final Rect bounds = validateBounds(getLaunchBounds());
2183        updateOverrideConfiguration(bounds);
2184        if (bounds != null) {
2185            bounds.set(mBounds);
2186        }
2187        return bounds;
2188    }
2189
2190    static Rect validateBounds(Rect bounds) {
2191        if (bounds != null && bounds.isEmpty()) {
2192            Slog.wtf(TAG, "Received strange task bounds: " + bounds, new Throwable());
2193            return null;
2194        }
2195        return bounds;
2196    }
2197
2198    /** Updates the task's bounds and override configuration to match what is expected for the
2199     * input stack. */
2200    void updateOverrideConfigurationForStack(ActivityStack inStack) {
2201        if (mStack != null && mStack == inStack) {
2202            return;
2203        }
2204
2205        if (inStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
2206            if (!isResizeable()) {
2207                throw new IllegalArgumentException("Can not position non-resizeable task="
2208                        + this + " in stack=" + inStack);
2209            }
2210            if (mBounds != null) {
2211                return;
2212            }
2213            if (mLastNonFullscreenBounds != null) {
2214                updateOverrideConfiguration(mLastNonFullscreenBounds);
2215            } else {
2216                inStack.layoutTaskInStack(this, null);
2217            }
2218        } else {
2219            updateOverrideConfiguration(inStack.mBounds);
2220        }
2221    }
2222
2223    /**
2224     * Returns the correct stack to use based on task type and currently set bounds,
2225     * regardless of the focused stack and current stack association of the task.
2226     * The task will be moved (and stack focus changed) later if necessary.
2227     */
2228    int getLaunchStackId() {
2229        if (isRecentsTask()) {
2230            return RECENTS_STACK_ID;
2231        }
2232        if (isHomeTask()) {
2233            return HOME_STACK_ID;
2234        }
2235        if (isAssistantTask()) {
2236            return ASSISTANT_STACK_ID;
2237        }
2238        if (mBounds != null) {
2239            return FREEFORM_WORKSPACE_STACK_ID;
2240        }
2241        return FULLSCREEN_WORKSPACE_STACK_ID;
2242    }
2243
2244    /** Returns the bounds that should be used to launch this task. */
2245    Rect getLaunchBounds() {
2246        if (mStack == null) {
2247            return null;
2248        }
2249
2250        final int stackId = mStack.mStackId;
2251        if (stackId == HOME_STACK_ID
2252                || stackId == RECENTS_STACK_ID
2253                || stackId == ASSISTANT_STACK_ID
2254                || stackId == FULLSCREEN_WORKSPACE_STACK_ID
2255                || (stackId == DOCKED_STACK_ID && !isResizeable())) {
2256            return isResizeable() ? mStack.mBounds : null;
2257        } else if (!StackId.persistTaskBounds(stackId)) {
2258            return mStack.mBounds;
2259        }
2260        return mLastNonFullscreenBounds;
2261    }
2262
2263    void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
2264        for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
2265            final ActivityRecord r = mActivities.get(activityNdx);
2266            if (r.visible) {
2267                r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch);
2268            }
2269        }
2270    }
2271
2272    void dump(PrintWriter pw, String prefix) {
2273        pw.print(prefix); pw.print("userId="); pw.print(userId);
2274                pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
2275                pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
2276                pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
2277                pw.print(" mCallingPackage="); pw.println(mCallingPackage);
2278        if (affinity != null || rootAffinity != null) {
2279            pw.print(prefix); pw.print("affinity="); pw.print(affinity);
2280            if (affinity == null || !affinity.equals(rootAffinity)) {
2281                pw.print(" root="); pw.println(rootAffinity);
2282            } else {
2283                pw.println();
2284            }
2285        }
2286        if (voiceSession != null || voiceInteractor != null) {
2287            pw.print(prefix); pw.print("VOICE: session=0x");
2288            pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
2289            pw.print(" interactor=0x");
2290            pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
2291        }
2292        if (intent != null) {
2293            StringBuilder sb = new StringBuilder(128);
2294            sb.append(prefix); sb.append("intent={");
2295            intent.toShortString(sb, false, true, false, true);
2296            sb.append('}');
2297            pw.println(sb.toString());
2298        }
2299        if (affinityIntent != null) {
2300            StringBuilder sb = new StringBuilder(128);
2301            sb.append(prefix); sb.append("affinityIntent={");
2302            affinityIntent.toShortString(sb, false, true, false, true);
2303            sb.append('}');
2304            pw.println(sb.toString());
2305        }
2306        if (origActivity != null) {
2307            pw.print(prefix); pw.print("origActivity=");
2308            pw.println(origActivity.flattenToShortString());
2309        }
2310        if (realActivity != null) {
2311            pw.print(prefix); pw.print("realActivity=");
2312            pw.println(realActivity.flattenToShortString());
2313        }
2314        if (autoRemoveRecents || isPersistable || taskType != 0 || mTaskToReturnTo != 0
2315                || numFullscreen != 0) {
2316            pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
2317                    pw.print(" isPersistable="); pw.print(isPersistable);
2318                    pw.print(" numFullscreen="); pw.print(numFullscreen);
2319                    pw.print(" taskType="); pw.print(taskType);
2320                    pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
2321        }
2322        if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
2323                || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
2324            pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
2325                    pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
2326                    pw.print(" mReuseTask="); pw.print(mReuseTask);
2327                    pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
2328        }
2329        if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID
2330                || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
2331                || mNextAffiliate != null) {
2332            pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
2333                    pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
2334                    pw.print(" (");
2335                    if (mPrevAffiliate == null) {
2336                        pw.print("null");
2337                    } else {
2338                        pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
2339                    }
2340                    pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
2341                    pw.print(" (");
2342                    if (mNextAffiliate == null) {
2343                        pw.print("null");
2344                    } else {
2345                        pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
2346                    }
2347                    pw.println(")");
2348        }
2349        pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
2350        if (!askedCompatMode || !inRecents || !isAvailable) {
2351            pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
2352                    pw.print(" inRecents="); pw.print(inRecents);
2353                    pw.print(" isAvailable="); pw.println(isAvailable);
2354        }
2355        pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail);
2356                pw.print(" lastThumbnailFile="); pw.println(mLastThumbnailFile);
2357        if (lastDescription != null) {
2358            pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
2359        }
2360        pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
2361        pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
2362                pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
2363                pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
2364                pw.print(" isResizeable=" + isResizeable());
2365                pw.print(" firstActiveTime=" + firstActiveTime);
2366                pw.print(" lastActiveTime=" + lastActiveTime);
2367                pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
2368    }
2369
2370    @Override
2371    public String toString() {
2372        StringBuilder sb = new StringBuilder(128);
2373        if (stringName != null) {
2374            sb.append(stringName);
2375            sb.append(" U=");
2376            sb.append(userId);
2377            sb.append(" StackId=");
2378            sb.append(getStackId());
2379            sb.append(" sz=");
2380            sb.append(mActivities.size());
2381            sb.append('}');
2382            return sb.toString();
2383        }
2384        sb.append("TaskRecord{");
2385        sb.append(Integer.toHexString(System.identityHashCode(this)));
2386        sb.append(" #");
2387        sb.append(taskId);
2388        if (affinity != null) {
2389            sb.append(" A=");
2390            sb.append(affinity);
2391        } else if (intent != null) {
2392            sb.append(" I=");
2393            sb.append(intent.getComponent().flattenToShortString());
2394        } else if (affinityIntent != null) {
2395            sb.append(" aI=");
2396            sb.append(affinityIntent.getComponent().flattenToShortString());
2397        } else {
2398            sb.append(" ??");
2399        }
2400        stringName = sb.toString();
2401        return toString();
2402    }
2403}
2404