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