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