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