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