• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.wm;
18 
19 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
20 import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
21 import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
24 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
25 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
26 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
27 import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
28 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
29 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
30 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
31 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
32 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
33 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
34 import static android.app.WindowConfiguration.activityTypeToString;
35 import static android.app.WindowConfiguration.windowingModeToString;
36 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
37 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
38 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
39 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
40 import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
41 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
42 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
43 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
44 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
45 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
46 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
47 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
48 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
49 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
50 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
51 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
52 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
53 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
54 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
55 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
56 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
57 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
58 import static android.view.Display.INVALID_DISPLAY;
59 import static android.view.SurfaceControl.METADATA_TASK_ID;
60 import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
61 
62 import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
63 import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
64 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
65 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
66 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
67 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
68 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
69 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
70 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
71 import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
72 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
73 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
74 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
75 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
76 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
77 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
78 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
79 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
80 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
81 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
82 import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
83 import static com.android.server.wm.IdentifierProto.HASH_CODE;
84 import static com.android.server.wm.IdentifierProto.TITLE;
85 import static com.android.server.wm.IdentifierProto.USER_ID;
86 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
87 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
88 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
89 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
90 import static com.android.server.wm.WindowContainerChildProto.TASK;
91 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
92 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
93 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
94 import static com.android.server.wm.WindowManagerService.dipToPixel;
95 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
96 
97 import static java.lang.Integer.MAX_VALUE;
98 
99 import android.annotation.IntDef;
100 import android.annotation.NonNull;
101 import android.annotation.Nullable;
102 import android.app.Activity;
103 import android.app.ActivityManager;
104 import android.app.ActivityManager.TaskDescription;
105 import android.app.ActivityManager.TaskSnapshot;
106 import android.app.ActivityOptions;
107 import android.app.ActivityTaskManager;
108 import android.app.AppGlobals;
109 import android.app.TaskInfo;
110 import android.app.WindowConfiguration;
111 import android.content.ComponentName;
112 import android.content.Intent;
113 import android.content.pm.ActivityInfo;
114 import android.content.pm.ApplicationInfo;
115 import android.content.pm.IPackageManager;
116 import android.content.pm.PackageManager;
117 import android.content.res.Configuration;
118 import android.graphics.Point;
119 import android.graphics.Rect;
120 import android.os.Debug;
121 import android.os.IBinder;
122 import android.os.RemoteException;
123 import android.os.SystemClock;
124 import android.os.Trace;
125 import android.os.UserHandle;
126 import android.provider.Settings;
127 import android.service.voice.IVoiceInteractionSession;
128 import android.util.ArraySet;
129 import android.util.DisplayMetrics;
130 import android.util.Slog;
131 import android.util.proto.ProtoOutputStream;
132 import android.view.DisplayInfo;
133 import android.view.RemoteAnimationAdapter;
134 import android.view.RemoteAnimationTarget;
135 import android.view.Surface;
136 import android.view.SurfaceControl;
137 import android.view.WindowManager;
138 import android.window.ITaskOrganizer;
139 
140 import com.android.internal.annotations.VisibleForTesting;
141 import com.android.internal.app.IVoiceInteractor;
142 import com.android.internal.util.XmlUtils;
143 import com.android.internal.util.function.pooled.PooledConsumer;
144 import com.android.internal.util.function.pooled.PooledFunction;
145 import com.android.internal.util.function.pooled.PooledLambda;
146 import com.android.internal.util.function.pooled.PooledPredicate;
147 import com.android.server.protolog.common.ProtoLog;
148 import com.android.server.wm.ActivityStack.ActivityState;
149 
150 import org.xmlpull.v1.XmlPullParser;
151 import org.xmlpull.v1.XmlPullParserException;
152 import org.xmlpull.v1.XmlSerializer;
153 
154 import java.io.IOException;
155 import java.io.PrintWriter;
156 import java.lang.annotation.Retention;
157 import java.lang.annotation.RetentionPolicy;
158 import java.util.ArrayList;
159 import java.util.Objects;
160 import java.util.function.Consumer;
161 import java.util.function.Function;
162 import java.util.function.Predicate;
163 
164 class Task extends WindowContainer<WindowContainer> {
165     private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM;
166     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
167     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
168     private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
169     private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
170 
171     private static final String ATTR_TASKID = "task_id";
172     private static final String TAG_INTENT = "intent";
173     private static final String TAG_AFFINITYINTENT = "affinity_intent";
174     private static final String ATTR_REALACTIVITY = "real_activity";
175     private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
176     private static final String ATTR_ORIGACTIVITY = "orig_activity";
177     private static final String TAG_ACTIVITY = "activity";
178     private static final String ATTR_AFFINITY = "affinity";
179     private static final String ATTR_ROOT_AFFINITY = "root_affinity";
180     private static final String ATTR_ROOTHASRESET = "root_has_reset";
181     private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
182     private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
183     private static final String ATTR_USERID = "user_id";
184     private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
185     private static final String ATTR_EFFECTIVE_UID = "effective_uid";
186     @Deprecated
187     private static final String ATTR_TASKTYPE = "task_type";
188     private static final String ATTR_LASTDESCRIPTION = "last_description";
189     private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
190     private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
191     private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
192     private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
193     private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
194     private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
195     private static final String ATTR_CALLING_UID = "calling_uid";
196     private static final String ATTR_CALLING_PACKAGE = "calling_package";
197     private static final String ATTR_CALLING_FEATURE_ID = "calling_feature_id";
198     private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
199     private static final String ATTR_RESIZE_MODE = "resize_mode";
200     private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
201     private static final String ATTR_MIN_WIDTH = "min_width";
202     private static final String ATTR_MIN_HEIGHT = "min_height";
203     private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
204     private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity";
205 
206     // Current version of the task record we persist. Used to check if we need to run any upgrade
207     // code.
208     static final int PERSIST_TASK_VERSION = 1;
209 
210     static final int INVALID_MIN_SIZE = -1;
211     private float mShadowRadius = 0;
212 
213     /**
214      * The modes to control how the stack is moved to the front when calling {@link Task#reparent}.
215      */
216     @Retention(RetentionPolicy.SOURCE)
217     @IntDef({
218             REPARENT_MOVE_STACK_TO_FRONT,
219             REPARENT_KEEP_STACK_AT_FRONT,
220             REPARENT_LEAVE_STACK_IN_PLACE
221     })
222     @interface ReparentMoveStackMode {}
223     // Moves the stack to the front if it was not at the front
224     static final int REPARENT_MOVE_STACK_TO_FRONT = 0;
225     // Only moves the stack to the front if it was focused or front most already
226     static final int REPARENT_KEEP_STACK_AT_FRONT = 1;
227     // Do not move the stack as a part of reparenting
228     static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
229 
230     String affinity;        // The affinity name for this task, or null; may change identity.
231     String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
232     String mWindowLayoutAffinity; // Launch param affinity of this task or null. Used when saving
233                                 // launch params of this task.
234     IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
235     IVoiceInteractor voiceInteractor;         // Associated interactor to provide to app
236     Intent intent;          // The original intent that started the task. Note that this value can
237                             // be null.
238     Intent affinityIntent;  // Intent of affinity-moved activity that started this task.
239     int effectiveUid;       // The current effective uid of the identity of this task.
240     ComponentName origActivity; // The non-alias activity component of the intent.
241     ComponentName realActivity; // The actual activity component that started the task.
242     boolean realActivitySuspended; // True if the actual activity component that started the
243                                    // task is suspended.
244     boolean inRecents;      // Actually in the recents list?
245     long lastActiveTime;    // Last time this task was active in the current device session,
246                             // including sleep. This time is initialized to the elapsed time when
247                             // restored from disk.
248     boolean isAvailable;    // Is the activity available to be launched?
249     boolean rootWasReset;   // True if the intent at the root of the task had
250                             // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
251     boolean autoRemoveRecents;  // If true, we should automatically remove the task from
252                                 // recents when activity finishes
253     boolean askedCompatMode;// Have asked the user about compat mode for this task.
254     private boolean mHasBeenVisible; // Set if any activities in the task have been visible
255 
256     String stringName;      // caching of toString() result.
257     boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
258                                 // was changed.
259 
260     /** Can't be put in lockTask mode. */
261     final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
262     /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
263     final static int LOCK_TASK_AUTH_PINNABLE = 1;
264     /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
265     final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
266     /** Can enter lockTask without user approval. Can start over existing lockTask task. */
267     final static int LOCK_TASK_AUTH_ALLOWLISTED = 3;
268     /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
269      * lockTask task. */
270     final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
271     int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
272 
273     int mLockTaskUid = -1;  // The uid of the application that called startLockTask().
274 
275     /** The process that had previously hosted the root activity of this task.
276      * Used to know that we should try harder to keep this process around, in case the
277      * user wants to return to it. */
278     private WindowProcessController mRootProcess;
279 
280     /** Takes on same value as first root activity */
281     boolean isPersistable = false;
282     int maxRecents;
283 
284     /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
285      * determining the order when restoring. Sign indicates whether last task movement was to front
286      * (positive) or back (negative). Absolute value indicates time. */
287     long mLastTimeMoved;
288 
289     /** If original intent did not allow relinquishing task identity, save that information */
290     private boolean mNeverRelinquishIdentity = true;
291 
292     // Used in the unique case where we are clearing the task in order to reuse it. In that case we
293     // do not want to delete the stack when the task goes empty.
294     private boolean mReuseTask = false;
295 
296     CharSequence lastDescription; // Last description captured for this item.
297 
298     int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
299     int mAffiliatedTaskColor; // color of the parent task affiliation.
300     Task mPrevAffiliate; // previous task in affiliated chain.
301     int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
302     Task mNextAffiliate; // next task in affiliated chain.
303     int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
304 
305     // For relaunching the task from recents as though it was launched by the original launcher.
306     int mCallingUid;
307     String mCallingPackage;
308     String mCallingFeatureId;
309 
310     private final Rect mTmpStableBounds = new Rect();
311     private final Rect mTmpNonDecorBounds = new Rect();
312     private final Rect mTmpBounds = new Rect();
313     private final Rect mTmpInsets = new Rect();
314     private final Rect mTmpFullBounds = new Rect();
315 
316     // Last non-fullscreen bounds the task was launched in or resized to.
317     // The information is persisted and used to determine the appropriate stack to launch the
318     // task into on restore.
319     Rect mLastNonFullscreenBounds = null;
320     // Minimal width and height of this task when it's resizeable. -1 means it should use the
321     // default minimal width/height.
322     int mMinWidth;
323     int mMinHeight;
324 
325     // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
326     // This number will be assigned when we evaluate OOM scores for all visible tasks.
327     int mLayerRank = -1;
328 
329     /** Helper object used for updating override configuration. */
330     private Configuration mTmpConfig = new Configuration();
331 
332     /** Used by fillTaskInfo */
333     final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
334 
335     final ActivityTaskManagerService mAtmService;
336     final ActivityStackSupervisor mStackSupervisor;
337     final RootWindowContainer mRootWindowContainer;
338 
339     /* Unique identifier for this task. */
340     final int mTaskId;
341     /* User for which this task was created. */
342     // TODO: Make final
343     int mUserId;
344 
345     final Rect mPreparedFrozenBounds = new Rect();
346     final Configuration mPreparedFrozenMergedConfig = new Configuration();
347 
348     // Id of the previous display the stack was on.
349     int mPrevDisplayId = INVALID_DISPLAY;
350 
351     /** ID of the display which rotation {@link #mRotation} has. */
352     private int mLastRotationDisplayId = INVALID_DISPLAY;
353 
354     /**
355      * Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was
356      * moved to a new display.
357      */
358     @Surface.Rotation
359     private int mRotation;
360 
361     /**
362      * Last requested orientation reported to DisplayContent. This is different from {@link
363      * #mOrientation} in the sense that this takes activities' requested orientation into
364      * account. Start with {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} so that we don't need
365      * to notify for activities that don't specify any orientation.
366      */
367     int mLastReportedRequestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
368 
369     // For comparison with DisplayContent bounds.
370     private Rect mTmpRect = new Rect();
371     // For handling display rotations.
372     private Rect mTmpRect2 = new Rect();
373 
374     // Resize mode of the task. See {@link ActivityInfo#resizeMode}
375     // Based on the {@link ActivityInfo#resizeMode} of the root activity.
376     int mResizeMode;
377 
378     // Whether or not this task and its activities support PiP. Based on the
379     // {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity.
380     boolean mSupportsPictureInPicture;
381 
382     // Whether the task is currently being drag-resized
383     private boolean mDragResizing;
384     private int mDragResizeMode;
385 
386     // This represents the last resolved activity values for this task
387     // NOTE: This value needs to be persisted with each task
388     private TaskDescription mTaskDescription;
389 
390     // If set to true, the task will report that it is not in the floating
391     // state regardless of it's stack affiliation. As the floating state drives
392     // production of content insets this can be used to preserve them across
393     // stack moves and we in fact do so when moving from full screen to pinned.
394     private boolean mPreserveNonFloatingState = false;
395 
396     private Dimmer mDimmer = new Dimmer(this);
397     private final Rect mTmpDimBoundsRect = new Rect();
398     private final Point mLastSurfaceSize = new Point();
399 
400     /** @see #setCanAffectSystemUiFlags */
401     private boolean mCanAffectSystemUiFlags = true;
402 
403     private static Exception sTmpException;
404 
405     /** ActivityRecords that are exiting, but still on screen for animations. */
406     final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>();
407 
408     /**
409      * When we are in the process of pausing an activity, before starting the
410      * next one, this variable holds the activity that is currently being paused.
411      */
412     ActivityRecord mPausingActivity = null;
413 
414     /**
415      * This is the last activity that we put into the paused state.  This is
416      * used to determine if we need to do an activity transition while sleeping,
417      * when we normally hold the top activity paused.
418      */
419     ActivityRecord mLastPausedActivity = null;
420 
421     /**
422      * Activities that specify No History must be removed once the user navigates away from them.
423      * If the device goes to sleep with such an activity in the paused state then we save it here
424      * and finish it later if another activity replaces it on wakeup.
425      */
426     ActivityRecord mLastNoHistoryActivity = null;
427 
428     /** Current activity that is resumed, or null if there is none. */
429     ActivityRecord mResumedActivity = null;
430 
431     private boolean mForceShowForAllUsers;
432 
433     /** When set, will force the task to report as invisible. */
434     static final int FLAG_FORCE_HIDDEN_FOR_PINNED_TASK = 1;
435     static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1;
436     private int mForceHiddenFlags = 0;
437 
438     // TODO(b/160201781): Revisit double invocation issue in Task#removeChild.
439     /**
440      * Skip {@link ActivityStackSupervisor#removeTask(Task, boolean, boolean, String)} execution if
441      * {@code true} to prevent double traversal of {@link #mChildren} in a loop.
442      */
443     boolean mInRemoveTask;
444 
445     // When non-null, this is a transaction that will get applied on the next frame returned after
446     // a relayout is requested from the client. While this is only valid on a leaf task; since the
447     // transaction can effect an ancestor task, this also needs to keep track of the ancestor task
448     // that this transaction manipulates because deferUntilFrame acts on individual surfaces.
449     SurfaceControl.Transaction mMainWindowSizeChangeTransaction;
450     Task mMainWindowSizeChangeTask;
451 
452     private final FindRootHelper mFindRootHelper = new FindRootHelper();
453     private class FindRootHelper {
454         private ActivityRecord mRoot;
455 
clear()456         private void clear() {
457             mRoot = null;
458         }
459 
findRoot(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone)460         ActivityRecord findRoot(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
461             final PooledFunction f = PooledLambda.obtainFunction(FindRootHelper::processActivity,
462                     this, PooledLambda.__(ActivityRecord.class), ignoreRelinquishIdentity,
463                     setToBottomIfNone);
464             clear();
465             forAllActivities(f, false /*traverseTopToBottom*/);
466             f.recycle();
467             return mRoot;
468         }
469 
processActivity(ActivityRecord r, boolean ignoreRelinquishIdentity, boolean setToBottomIfNone)470         private boolean processActivity(ActivityRecord r,
471                 boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
472             if (mRoot == null && setToBottomIfNone) {
473                 // This is the first activity we are process. Set it as the candidate root in case
474                 // we don't find a better one.
475                 mRoot = r;
476             }
477 
478             if (r.finishing) return false;
479 
480             // Set this as the candidate root since it isn't finishing.
481             mRoot = r;
482 
483             // Only end search if we are ignore relinquishing identity or we are not relinquishing.
484             return ignoreRelinquishIdentity || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
485         }
486     }
487 
488     /**
489      * The TaskOrganizer which is delegated presentation of this task. If set the Task will
490      * emit an WindowContainerToken (allowing access to it's SurfaceControl leash) to the organizers
491      * taskAppeared callback, and emit a taskRemoved callback when the Task is vanished.
492      */
493     ITaskOrganizer mTaskOrganizer;
494     private int mLastTaskOrganizerWindowingMode = -1;
495     /**
496      * Prevent duplicate calls to onTaskAppeared.
497      */
498     boolean mTaskAppearedSent;
499 
500     /**
501      * This task was created by the task organizer which has the following implementations.
502      * <ul>
503      *     <lis>The task won't be removed when it is empty. Removal has to be an explicit request
504      *     from the task organizer.</li>
505      *     <li>Unlike other non-root tasks, it's direct children are visible to the task
506      *     organizer for ordering purposes.</li>
507      * </ul>
508      */
509     boolean mCreatedByOrganizer;
510 
511     /**
512      * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
513      * ActivityInfo, Intent, TaskDescription)} instead.
514      */
Task(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, TaskDescription _taskDescription, ActivityStack stack)515     Task(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent,
516             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
517             TaskDescription _taskDescription, ActivityStack stack) {
518         this(atmService, _taskId, _intent,  null /*_affinityIntent*/, null /*_affinity*/,
519                 null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/,
520                 false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/,
521                 UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/,
522                 null /*_lastDescription*/, System.currentTimeMillis(),
523                 true /*neverRelinquishIdentity*/,
524                 _taskDescription != null ? _taskDescription : new TaskDescription(),
525                 _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
526                 info.applicationInfo.uid, info.packageName, null /* default featureId */,
527                 info.resizeMode, info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
528                 false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
529                 _voiceSession, _voiceInteractor, stack);
530     }
531 
532     /** Don't use constructor directly. This is only used by XML parser. */
Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent, Intent _affinityIntent, String _affinity, String _rootAffinity, ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, int _effectiveUid, String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, @Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info, IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, ActivityStack stack)533     Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent, Intent _affinityIntent,
534             String _affinity, String _rootAffinity, ComponentName _realActivity,
535             ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents,
536             boolean _askedCompatMode, int _userId, int _effectiveUid, String _lastDescription,
537             long lastTimeMoved, boolean neverRelinquishIdentity,
538             TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
539             int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
540             @Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture,
541             boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight,
542             ActivityInfo info, IVoiceInteractionSession _voiceSession,
543             IVoiceInteractor _voiceInteractor, ActivityStack stack) {
544         super(atmService.mWindowManager);
545 
546         EventLogTags.writeWmTaskCreated(_taskId, stack != null ? getRootTaskId() : INVALID_TASK_ID);
547         mAtmService = atmService;
548         mStackSupervisor = atmService.mStackSupervisor;
549         mRootWindowContainer = mAtmService.mRootWindowContainer;
550         mTaskId = _taskId;
551         mUserId = _userId;
552         mResizeMode = resizeMode;
553         mSupportsPictureInPicture = supportsPictureInPicture;
554         mTaskDescription = _lastTaskDescription;
555         // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
556         setOrientation(SCREEN_ORIENTATION_UNSET);
557         mRemoteToken = new RemoteToken(this);
558         affinityIntent = _affinityIntent;
559         affinity = _affinity;
560         rootAffinity = _rootAffinity;
561         voiceSession = _voiceSession;
562         voiceInteractor = _voiceInteractor;
563         realActivity = _realActivity;
564         realActivitySuspended = _realActivitySuspended;
565         origActivity = _origActivity;
566         rootWasReset = _rootWasReset;
567         isAvailable = true;
568         autoRemoveRecents = _autoRemoveRecents;
569         askedCompatMode = _askedCompatMode;
570         mUserSetupComplete = userSetupComplete;
571         effectiveUid = _effectiveUid;
572         touchActiveTime();
573         lastDescription = _lastDescription;
574         mLastTimeMoved = lastTimeMoved;
575         mNeverRelinquishIdentity = neverRelinquishIdentity;
576         mAffiliatedTaskId = taskAffiliation;
577         mAffiliatedTaskColor = taskAffiliationColor;
578         mPrevAffiliateTaskId = prevTaskId;
579         mNextAffiliateTaskId = nextTaskId;
580         mCallingUid = callingUid;
581         mCallingPackage = callingPackage;
582         mCallingFeatureId = callingFeatureId;
583         mResizeMode = resizeMode;
584         if (info != null) {
585             setIntent(_intent, info);
586             setMinDimensions(info);
587         } else {
588             intent = _intent;
589             mMinWidth = minWidth;
590             mMinHeight = minHeight;
591         }
592         mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
593     }
594 
reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, Intent intent, ActivityInfo info, ActivityRecord activity)595     Task reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
596             Intent intent, ActivityInfo info, ActivityRecord activity) {
597         voiceSession = _voiceSession;
598         voiceInteractor = _voiceInteractor;
599         setIntent(activity, intent, info);
600         setMinDimensions(info);
601         // Before we began to reuse a root task (old ActivityStack) as the leaf task, we used to
602         // create a leaf task in this case. Therefore now we won't send out the task created
603         // notification when we decide to reuse it here, so we send out the notification below.
604         // The reason why the created notification sent out when root task is created doesn't work
605         // is that realActivity isn't set until setIntent() method above is called for the first
606         // time. Eventually this notification will be removed when we can populate those information
607         // when root task is created.
608         mAtmService.getTaskChangeNotificationController().notifyTaskCreated(mTaskId, realActivity);
609         return this;
610     }
611 
cleanUpResourcesForDestroy(ConfigurationContainer oldParent)612     private void cleanUpResourcesForDestroy(ConfigurationContainer oldParent) {
613         if (hasChild()) {
614             return;
615         }
616 
617         if (isLeafTask()) {
618             // This task is going away, so save the last state if necessary.
619             saveLaunchingStateIfNeeded(((WindowContainer) oldParent).getDisplayContent());
620         }
621 
622         // TODO: VI what about activity?
623         final boolean isVoiceSession = voiceSession != null;
624         if (isVoiceSession) {
625             try {
626                 voiceSession.taskFinished(intent, mTaskId);
627             } catch (RemoteException e) {
628             }
629         }
630         if (autoRemoveFromRecents() || isVoiceSession) {
631             // Task creator asked to remove this when done, or this task was a voice
632             // interaction, so it should not remain on the recent tasks list.
633             mStackSupervisor.mRecentTasks.remove(this);
634         }
635 
636         removeIfPossible();
637     }
638 
639     @VisibleForTesting
640     @Override
removeIfPossible()641     void removeIfPossible() {
642         final boolean isRootTask = isRootTask();
643         if (!isRootTask) {
644             mAtmService.getLockTaskController().clearLockedTask(this);
645         }
646         if (shouldDeferRemoval()) {
647             if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
648             return;
649         }
650         removeImmediately();
651         if (isLeafTask()) {
652             mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
653         }
654     }
655 
setResizeMode(int resizeMode)656     void setResizeMode(int resizeMode) {
657         if (mResizeMode == resizeMode) {
658             return;
659         }
660         mResizeMode = resizeMode;
661         mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
662         mRootWindowContainer.resumeFocusedStacksTopActivities();
663         updateTaskDescription();
664     }
665 
resize(Rect bounds, int resizeMode, boolean preserveWindow)666     boolean resize(Rect bounds, int resizeMode, boolean preserveWindow) {
667         mAtmService.deferWindowLayout();
668 
669         try {
670             final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
671 
672             if (getParent() == null) {
673                 // Task doesn't exist in window manager yet (e.g. was restored from recents).
674                 // All we can do for now is update the bounds so it can be used when the task is
675                 // added to window manager.
676                 setBounds(bounds);
677                 if (!inFreeformWindowingMode()) {
678                     // re-restore the task so it can have the proper stack association.
679                     mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
680                 }
681                 return true;
682             }
683 
684             if (!canResizeToBounds(bounds)) {
685                 throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
686                         + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
687             }
688 
689             // Do not move the task to another stack here.
690             // This method assumes that the task is already placed in the right stack.
691             // we do not mess with that decision and we only do the resize!
692 
693             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeTask_" + mTaskId);
694 
695             boolean updatedConfig = false;
696             mTmpConfig.setTo(getResolvedOverrideConfiguration());
697             if (setBounds(bounds) != BOUNDS_CHANGE_NONE) {
698                 updatedConfig = !mTmpConfig.equals(getResolvedOverrideConfiguration());
699             }
700             // This variable holds information whether the configuration didn't change in a
701             // significant way and the activity was kept the way it was. If it's false, it means
702             // the activity had to be relaunched due to configuration change.
703             boolean kept = true;
704             if (updatedConfig) {
705                 final ActivityRecord r = topRunningActivityLocked();
706                 if (r != null) {
707                     kept = r.ensureActivityConfiguration(0 /* globalChanges */,
708                             preserveWindow);
709                     // Preserve other windows for resizing because if resizing happens when there
710                     // is a dialog activity in the front, the activity that still shows some
711                     // content to the user will become black and cause flickers. Note in most cases
712                     // this won't cause tons of irrelevant windows being preserved because only
713                     // activities in this task may experience a bounds change. Configs for other
714                     // activities stay the same.
715                     mRootWindowContainer.ensureActivitiesVisible(r, 0, preserveWindow);
716                     if (!kept) {
717                         mRootWindowContainer.resumeFocusedStacksTopActivities();
718                     }
719                 }
720             }
721             resize(kept, forced);
722 
723             saveLaunchingStateIfNeeded();
724 
725             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
726             return kept;
727         } finally {
728             mAtmService.continueWindowLayout();
729         }
730     }
731 
732     /** Convenience method to reparent a task to the top or bottom position of the stack. */
reparent(ActivityStack preferredStack, boolean toTop, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, String reason)733     boolean reparent(ActivityStack preferredStack, boolean toTop,
734             @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
735             String reason) {
736         return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume,
737                 true /* schedulePictureInPictureModeChange */, reason);
738     }
739 
740     /**
741      * Convenience method to reparent a task to the top or bottom position of the stack, with
742      * an option to skip scheduling the picture-in-picture mode change.
743      */
reparent(ActivityStack preferredStack, boolean toTop, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason)744     boolean reparent(ActivityStack preferredStack, boolean toTop,
745             @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
746             boolean schedulePictureInPictureModeChange, String reason) {
747         return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate,
748                 deferResume, schedulePictureInPictureModeChange, reason);
749     }
750 
751     /** Convenience method to reparent a task to a specific position of the stack. */
reparent(ActivityStack preferredStack, int position, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, String reason)752     boolean reparent(ActivityStack preferredStack, int position,
753             @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
754             String reason) {
755         return reparent(preferredStack, position, moveStackMode, animate, deferResume,
756                 true /* schedulePictureInPictureModeChange */, reason);
757     }
758 
759     /**
760      * Reparents the task into a preferred stack, creating it if necessary.
761      *
762      * @param preferredStack the target stack to move this task
763      * @param position the position to place this task in the new stack
764      * @param animate whether or not we should wait for the new window created as a part of the
765      *            reparenting to be drawn and animated in
766      * @param moveStackMode whether or not to move the stack to the front always, only if it was
767      *            previously focused & in front, or never
768      * @param deferResume whether or not to update the visibility of other tasks and stacks that may
769      *            have changed as a result of this reparenting
770      * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
771      *            change. Callers may set this to false if they are explicitly scheduling PiP mode
772      *            changes themselves, like during the PiP animation
773      * @param reason the caller of this reparenting
774      * @return whether the task was reparented
775      */
776     // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
777     // re-parenting the task. Can only be done when we are no longer using static stack Ids.
reparent(ActivityStack preferredStack, int position, @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume, boolean schedulePictureInPictureModeChange, String reason)778     boolean reparent(ActivityStack preferredStack, int position,
779             @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
780             boolean schedulePictureInPictureModeChange, String reason) {
781         final ActivityStackSupervisor supervisor = mStackSupervisor;
782         final RootWindowContainer root = mRootWindowContainer;
783         final WindowManagerService windowManager = mAtmService.mWindowManager;
784         final ActivityStack sourceStack = getStack();
785         final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack,
786                 position == MAX_VALUE);
787         if (toStack == sourceStack) {
788             return false;
789         }
790         if (!canBeLaunchedOnDisplay(toStack.getDisplayId())) {
791             return false;
792         }
793 
794         final boolean toTopOfStack = position == MAX_VALUE;
795         if (toTopOfStack && toStack.getResumedActivity() != null
796                 && toStack.topRunningActivity() != null) {
797             // Pause the resumed activity on the target stack while re-parenting task on top of it.
798             toStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
799                     null /* resuming */);
800         }
801 
802         final int toStackWindowingMode = toStack.getWindowingMode();
803         final ActivityRecord topActivity = getTopNonFinishingActivity();
804 
805         final boolean mightReplaceWindow = topActivity != null
806                 && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode);
807         if (mightReplaceWindow) {
808             // We are about to relaunch the activity because its configuration changed due to
809             // being maximized, i.e. size change. The activity will first remove the old window
810             // and then add a new one. This call will tell window manager about this, so it can
811             // preserve the old window until the new one is drawn. This prevents having a gap
812             // between the removal and addition, in which no window is visible. We also want the
813             // entrance of the new window to be properly animated.
814             // Note here we always set the replacing window first, as the flags might be needed
815             // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
816             windowManager.setWillReplaceWindow(topActivity.appToken, animate);
817         }
818 
819         mAtmService.deferWindowLayout();
820         boolean kept = true;
821         try {
822             final ActivityRecord r = topRunningActivityLocked();
823             final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack)
824                     && (topRunningActivityLocked() == r);
825             final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r;
826             final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
827 
828             // In some cases the focused stack isn't the front stack. E.g. pinned stack.
829             // Whenever we are moving the top activity from the front stack we want to make sure to
830             // move the stack to the front.
831             final boolean wasFront = r != null && sourceStack.isTopStackInDisplayArea()
832                     && (sourceStack.topRunningActivity() == r);
833 
834             final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
835                     || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
836 
837             reparent(toStack, position, moveStackToFront, reason);
838 
839             if (schedulePictureInPictureModeChange) {
840                 // Notify of picture-in-picture mode changes
841                 supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
842             }
843 
844             // If the task had focus before (or we're requested to move focus), move focus to the
845             // new stack by moving the stack to the front.
846             if (r != null) {
847                 toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed,
848                         wasPaused, reason);
849             }
850             if (!animate) {
851                 mStackSupervisor.mNoAnimActivities.add(topActivity);
852             }
853 
854             // We might trigger a configuration change. Save the current task bounds for freezing.
855             // TODO: Should this call be moved inside the resize method in WM?
856             toStack.prepareFreezingTaskBounds();
857 
858             if (toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
859                     && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
860                 // Move recents to front so it is not behind home stack when going into docked
861                 // mode
862                 mStackSupervisor.moveRecentsStackToFront(reason);
863             }
864         } finally {
865             mAtmService.continueWindowLayout();
866         }
867 
868         if (mightReplaceWindow) {
869             // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
870             // window), we need to clear the replace window settings. Otherwise, we schedule a
871             // timeout to remove the old window if the replacing window is not coming in time.
872             windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
873         }
874 
875         if (!deferResume) {
876             // The task might have already been running and its visibility needs to be synchronized
877             // with the visibility of the stack / windows.
878             root.ensureActivitiesVisible(null, 0, !mightReplaceWindow);
879             root.resumeFocusedStacksTopActivities();
880         }
881 
882         // TODO: Handle incorrect request to move before the actual move, not after.
883         supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
884                 mRootWindowContainer.getDefaultTaskDisplayArea(), toStack);
885 
886         return (preferredStack == toStack);
887     }
888 
889     /**
890      * @return {@code true} if the windows of tasks being moved to the target stack from the
891      * source stack should be replaced, meaning that window manager will keep the old window
892      * around until the new is ready.
893      */
replaceWindowsOnTaskMove( int sourceWindowingMode, int targetWindowingMode)894     private static boolean replaceWindowsOnTaskMove(
895             int sourceWindowingMode, int targetWindowingMode) {
896         return sourceWindowingMode == WINDOWING_MODE_FREEFORM
897                 || targetWindowingMode == WINDOWING_MODE_FREEFORM;
898     }
899 
900     /**
901      * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
902      */
getSnapshot(boolean isLowResolution, boolean restoreFromDisk)903     TaskSnapshot getSnapshot(boolean isLowResolution, boolean restoreFromDisk) {
904 
905         // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
906         // synchronized between AM and WM.
907         return mAtmService.mWindowManager.getTaskSnapshot(mTaskId, mUserId, isLowResolution,
908                 restoreFromDisk);
909     }
910 
touchActiveTime()911     void touchActiveTime() {
912         lastActiveTime = SystemClock.elapsedRealtime();
913     }
914 
getInactiveDuration()915     long getInactiveDuration() {
916         return SystemClock.elapsedRealtime() - lastActiveTime;
917     }
918 
919     /** @see #setIntent(ActivityRecord, Intent, ActivityInfo) */
setIntent(ActivityRecord r)920     void setIntent(ActivityRecord r) {
921         setIntent(r, null /* intent */, null /* info */);
922     }
923 
924     /**
925      * Sets the original intent, and the calling uid and package.
926      *
927      * @param r The activity that started the task
928      * @param intent The task info which could be different from {@code r.intent} if set.
929      * @param info The activity info which could be different from {@code r.info} if set.
930      */
setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info)931     void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) {
932         mCallingUid = r.launchedFromUid;
933         mCallingPackage = r.launchedFromPackage;
934         mCallingFeatureId = r.launchedFromFeatureId;
935         setIntent(intent != null ? intent : r.intent, info != null ? info : r.info);
936         setLockTaskAuth(r);
937 
938         final WindowContainer parent = getParent();
939         if (parent != null) {
940             final Task t = parent.asTask();
941             if (t != null) {
942                 t.setIntent(r);
943             }
944         }
945     }
946 
947     /** Sets the original intent, _without_ updating the calling uid or package. */
setIntent(Intent _intent, ActivityInfo info)948     private void setIntent(Intent _intent, ActivityInfo info) {
949         final boolean isLeaf = isLeafTask();
950         if (intent == null) {
951             mNeverRelinquishIdentity =
952                     (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
953         } else if (mNeverRelinquishIdentity && isLeaf) {
954             return;
955         }
956 
957         affinity = isLeaf ? info.taskAffinity : null;
958         if (intent == null) {
959             // If this task already has an intent associated with it, don't set the root
960             // affinity -- we don't want it changing after initially set, but the initially
961             // set value may be null.
962             rootAffinity = affinity;
963         }
964         effectiveUid = info.applicationInfo.uid;
965         stringName = null;
966 
967         if (info.targetActivity == null) {
968             if (_intent != null) {
969                 // If this Intent has a selector, we want to clear it for the
970                 // recent task since it is not relevant if the user later wants
971                 // to re-launch the app.
972                 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
973                     _intent = new Intent(_intent);
974                     _intent.setSelector(null);
975                     _intent.setSourceBounds(null);
976                 }
977             }
978             if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
979             intent = _intent;
980             realActivity = _intent != null ? _intent.getComponent() : null;
981             origActivity = null;
982         } else {
983             ComponentName targetComponent = new ComponentName(
984                     info.packageName, info.targetActivity);
985             if (_intent != null) {
986                 Intent targetIntent = new Intent(_intent);
987                 targetIntent.setSelector(null);
988                 targetIntent.setSourceBounds(null);
989                 if (DEBUG_TASKS) Slog.v(TAG_TASKS,
990                         "Setting Intent of " + this + " to target " + targetIntent);
991                 intent = targetIntent;
992                 realActivity = targetComponent;
993                 origActivity = _intent.getComponent();
994             } else {
995                 intent = null;
996                 realActivity = targetComponent;
997                 origActivity = new ComponentName(info.packageName, info.name);
998             }
999         }
1000         mWindowLayoutAffinity =
1001                 info.windowLayout == null ? null : info.windowLayout.windowLayoutAffinity;
1002 
1003         final int intentFlags = intent == null ? 0 : intent.getFlags();
1004         if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
1005             // Once we are set to an Intent with this flag, we count this
1006             // task as having a true root activity.
1007             rootWasReset = true;
1008         }
1009         mUserId = UserHandle.getUserId(info.applicationInfo.uid);
1010         mUserSetupComplete = Settings.Secure.getIntForUser(
1011                 mAtmService.mContext.getContentResolver(), USER_SETUP_COMPLETE, 0, mUserId) != 0;
1012         if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
1013             // If the activity itself has requested auto-remove, then just always do it.
1014             autoRemoveRecents = true;
1015         } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
1016                 == FLAG_ACTIVITY_NEW_DOCUMENT) {
1017             // If the caller has not asked for the document to be retained, then we may
1018             // want to turn on auto-remove, depending on whether the target has set its
1019             // own document launch mode.
1020             if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
1021                 autoRemoveRecents = false;
1022             } else {
1023                 autoRemoveRecents = true;
1024             }
1025         } else {
1026             autoRemoveRecents = false;
1027         }
1028         if (mResizeMode != info.resizeMode) {
1029             mResizeMode = info.resizeMode;
1030             updateTaskDescription();
1031         }
1032         mSupportsPictureInPicture = info.supportsPictureInPicture();
1033     }
1034 
1035     /** Sets the original minimal width and height. */
setMinDimensions(ActivityInfo info)1036     void setMinDimensions(ActivityInfo info) {
1037         if (info != null && info.windowLayout != null) {
1038             mMinWidth = info.windowLayout.minWidth;
1039             mMinHeight = info.windowLayout.minHeight;
1040         } else {
1041             mMinWidth = INVALID_MIN_SIZE;
1042             mMinHeight = INVALID_MIN_SIZE;
1043         }
1044     }
1045 
1046     /**
1047      * Return true if the input activity has the same intent filter as the intent this task
1048      * record is based on (normally the root activity intent).
1049      */
isSameIntentFilter(ActivityRecord r)1050     boolean isSameIntentFilter(ActivityRecord r) {
1051         final Intent intent = new Intent(r.intent);
1052         // Make sure the component are the same if the input activity has the same real activity
1053         // as the one in the task because either one of them could be the alias activity.
1054         if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) {
1055             intent.setComponent(this.intent.getComponent());
1056         }
1057         return intent.filterEquals(this.intent);
1058     }
1059 
returnsToHomeStack()1060     boolean returnsToHomeStack() {
1061         if (inMultiWindowMode() || !hasChild()) return false;
1062         if (intent != null) {
1063             final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME;
1064             return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags;
1065         }
1066         final Task bottomTask = getBottomMostTask();
1067         return bottomTask != this && bottomTask.returnsToHomeStack();
1068     }
1069 
setPrevAffiliate(Task prevAffiliate)1070     void setPrevAffiliate(Task prevAffiliate) {
1071         mPrevAffiliate = prevAffiliate;
1072         mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.mTaskId;
1073     }
1074 
setNextAffiliate(Task nextAffiliate)1075     void setNextAffiliate(Task nextAffiliate) {
1076         mNextAffiliate = nextAffiliate;
1077         mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId;
1078     }
1079 
1080     @Override
onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent)1081     void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
1082         final DisplayContent display = newParent != null
1083                 ? ((WindowContainer) newParent).getDisplayContent() : null;
1084         final DisplayContent oldDisplay = oldParent != null
1085                 ? ((WindowContainer) oldParent).getDisplayContent() : null;
1086 
1087         mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY;
1088 
1089         if (oldParent != null && newParent == null) {
1090             cleanUpResourcesForDestroy(oldParent);
1091         }
1092 
1093         if (display != null) {
1094             // TODO(NOW!): Chat with the erosky@ of this code to see if this really makes sense here...
1095             // Rotations are relative to the display. This means if there are 2 displays rotated
1096             // differently (eg. 2 monitors with one landscape and one portrait), moving a stack
1097             // from one to the other could look like a rotation change. To prevent this
1098             // apparent rotation change (and corresponding bounds rotation), pretend like our
1099             // current rotation is already the same as the new display.
1100             // Note, if ActivityStack or related logic ever gets nested, this logic will need
1101             // to move to onConfigurationChanged.
1102             getConfiguration().windowConfiguration.setRotation(
1103                     display.getWindowConfiguration().getRotation());
1104         }
1105 
1106         super.onParentChanged(newParent, oldParent);
1107 
1108         // TODO(NOW): The check for null display content and setting it to null doesn't really
1109         //  make sense here...
1110 
1111         // TODO(stack-merge): This is mostly taking care of the case where the stask is removing from
1112         // the display, so we should probably consolidate it there instead.
1113 
1114         if (getParent() == null && mDisplayContent != null) {
1115             EventLogTags.writeWmStackRemoved(getRootTaskId());
1116             mDisplayContent = null;
1117             mWmService.mWindowPlacerLocked.requestTraversal();
1118         }
1119 
1120         if (oldParent != null) {
1121             final Task oldParentTask = ((WindowContainer) oldParent).asTask();
1122             if (oldParentTask != null) {
1123                 final PooledConsumer c = PooledLambda.obtainConsumer(
1124                         Task::cleanUpActivityReferences, oldParentTask,
1125                         PooledLambda.__(ActivityRecord.class));
1126                 forAllActivities(c);
1127                 c.recycle();
1128             }
1129 
1130             if (oldParent.inPinnedWindowingMode()
1131                     && (newParent == null || !newParent.inPinnedWindowingMode())) {
1132                 // Notify if a task from the pinned stack is being removed
1133                 // (or moved depending on the mode).
1134                 mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
1135             }
1136         }
1137 
1138         if (newParent != null) {
1139             final Task newParentTask = ((WindowContainer) newParent).asTask();
1140             if (newParentTask != null) {
1141                 final ActivityRecord top = newParentTask.getTopNonFinishingActivity(
1142                         false /* includeOverlays */);
1143                 if (top != null && top.isState(RESUMED)) {
1144                     newParentTask.setResumedActivity(top, "addedToTask");
1145                 }
1146             }
1147 
1148             // TODO: Ensure that this is actually necessary here
1149             // Notify the voice session if required
1150             if (voiceSession != null) {
1151                 try {
1152                     voiceSession.taskStarted(intent, mTaskId);
1153                 } catch (RemoteException e) {
1154                 }
1155             }
1156         }
1157 
1158         // First time we are adding the task to the system.
1159         if (oldParent == null && newParent != null) {
1160 
1161             // TODO: Super random place to be doing this, but aligns with what used to be done
1162             // before we unified Task level. Look into if this can be done in a better place.
1163             updateOverrideConfigurationFromLaunchBounds();
1164         }
1165 
1166         // Update task bounds if needed.
1167         adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
1168 
1169         if (getWindowConfiguration().windowsAreScaleable()) {
1170             // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
1171             // while a resize is pending.
1172             forceWindowsScaleable(true /* force */);
1173         } else {
1174             forceWindowsScaleable(false /* force */);
1175         }
1176 
1177         mRootWindowContainer.updateUIDsPresentOnDisplay();
1178     }
1179 
cleanUpActivityReferences(ActivityRecord r)1180     void cleanUpActivityReferences(ActivityRecord r) {
1181         final WindowContainer parent = getParent();
1182         if (parent != null && parent.asTask() != null) {
1183             parent.asTask().cleanUpActivityReferences(r);
1184             return;
1185         }
1186         r.removeTimeouts();
1187         mExitingActivities.remove(r);
1188 
1189         if (mResumedActivity != null && mResumedActivity == r) {
1190             setResumedActivity(null, "cleanUpActivityReferences");
1191         }
1192         if (mPausingActivity != null && mPausingActivity == r) {
1193             mPausingActivity = null;
1194         }
1195     }
1196 
1197     /** @return the currently resumed activity. */
getResumedActivity()1198     ActivityRecord getResumedActivity() {
1199         return mResumedActivity;
1200     }
1201 
setResumedActivity(ActivityRecord r, String reason)1202     void setResumedActivity(ActivityRecord r, String reason) {
1203         if (mResumedActivity == r) {
1204             return;
1205         }
1206 
1207         if (ActivityTaskManagerDebugConfig.DEBUG_STACK) Slog.d(TAG_STACK,
1208                 "setResumedActivity stack:" + this + " + from: "
1209                 + mResumedActivity + " to:" + r + " reason:" + reason);
1210         mResumedActivity = r;
1211         mStackSupervisor.updateTopResumedActivityIfNeeded();
1212     }
1213 
updateTaskMovement(boolean toFront)1214     void updateTaskMovement(boolean toFront) {
1215         if (isPersistable) {
1216             mLastTimeMoved = System.currentTimeMillis();
1217             // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
1218             // recently will be most negative, tasks sent to the bottom before that will be less
1219             // negative. Similarly for recent tasks moved to the top which will be most positive.
1220             if (!toFront) {
1221                 mLastTimeMoved *= -1;
1222             }
1223         }
1224         mRootWindowContainer.invalidateTaskLayers();
1225     }
1226 
1227     // Close up recents linked list.
closeRecentsChain()1228     private void closeRecentsChain() {
1229         if (mPrevAffiliate != null) {
1230             mPrevAffiliate.setNextAffiliate(mNextAffiliate);
1231         }
1232         if (mNextAffiliate != null) {
1233             mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
1234         }
1235         setPrevAffiliate(null);
1236         setNextAffiliate(null);
1237     }
1238 
removedFromRecents()1239     void removedFromRecents() {
1240         closeRecentsChain();
1241         if (inRecents) {
1242             inRecents = false;
1243             mAtmService.notifyTaskPersisterLocked(this, false);
1244         }
1245 
1246         clearRootProcess();
1247 
1248         mAtmService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents(
1249                 mTaskId, mUserId);
1250     }
1251 
setTaskToAffiliateWith(Task taskToAffiliateWith)1252     void setTaskToAffiliateWith(Task taskToAffiliateWith) {
1253         closeRecentsChain();
1254         mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
1255         mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
1256         // Find the end
1257         while (taskToAffiliateWith.mNextAffiliate != null) {
1258             final Task nextRecents = taskToAffiliateWith.mNextAffiliate;
1259             if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
1260                 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
1261                         + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
1262                 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
1263                     nextRecents.setPrevAffiliate(null);
1264                 }
1265                 taskToAffiliateWith.setNextAffiliate(null);
1266                 break;
1267             }
1268             taskToAffiliateWith = nextRecents;
1269         }
1270         taskToAffiliateWith.setNextAffiliate(this);
1271         setPrevAffiliate(taskToAffiliateWith);
1272         setNextAffiliate(null);
1273     }
1274 
1275     /** Returns the intent for the root activity for this task */
getBaseIntent()1276     Intent getBaseIntent() {
1277         if (intent != null) return intent;
1278         if (affinityIntent != null) return affinityIntent;
1279         // Probably a task that contains other tasks, so return the intent for the top task?
1280         final Task topTask = getTopMostTask();
1281         return (topTask != this && topTask != null) ? topTask.getBaseIntent() : null;
1282     }
1283 
1284     /** Returns the first non-finishing activity from the bottom. */
getRootActivity()1285     ActivityRecord getRootActivity() {
1286         // TODO: Figure out why we historical ignore relinquish identity for this case...
1287         return getRootActivity(true /*ignoreRelinquishIdentity*/, false /*setToBottomIfNone*/);
1288     }
1289 
getRootActivity(boolean setToBottomIfNone)1290     ActivityRecord getRootActivity(boolean setToBottomIfNone) {
1291         return getRootActivity(false /*ignoreRelinquishIdentity*/, setToBottomIfNone);
1292     }
1293 
getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone)1294     ActivityRecord getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
1295         return mFindRootHelper.findRoot(ignoreRelinquishIdentity, setToBottomIfNone);
1296     }
1297 
getTopNonFinishingActivity()1298     ActivityRecord getTopNonFinishingActivity() {
1299         return getTopNonFinishingActivity(true /* includeOverlays */);
1300     }
1301 
getTopNonFinishingActivity(boolean includeOverlays)1302     ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
1303         return getTopActivity(false /*includeFinishing*/, includeOverlays);
1304     }
1305 
topRunningActivityLocked()1306     ActivityRecord topRunningActivityLocked() {
1307         if (getParent() == null) {
1308             return null;
1309         }
1310         return getActivity(ActivityRecord::canBeTopRunning);
1311     }
1312 
1313     /**
1314      * Return true if any activities in this task belongs to input uid.
1315      */
isUidPresent(int uid)1316     boolean isUidPresent(int uid) {
1317         final PooledPredicate p = PooledLambda.obtainPredicate(
1318                 ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid);
1319         final boolean isUidPresent = getActivity(p) != null;
1320         p.recycle();
1321         return isUidPresent;
1322     }
1323 
topActivityWithStartingWindow()1324     ActivityRecord topActivityWithStartingWindow() {
1325         if (getParent() == null) {
1326             return null;
1327         }
1328         return getActivity((r) -> r.mStartingWindowState == STARTING_WINDOW_SHOWN
1329                 && r.okToShowLocked());
1330     }
1331 
1332     /**
1333      * Return the number of running activities, and the number of non-finishing/initializing
1334      * activities in the provided {@param reportOut} respectively.
1335      */
getNumRunningActivities(TaskActivitiesReport reportOut)1336     private void getNumRunningActivities(TaskActivitiesReport reportOut) {
1337         reportOut.reset();
1338         forAllActivities(reportOut);
1339     }
1340 
1341     /**
1342      * Reorder the history stack so that the passed activity is brought to the front.
1343      */
moveActivityToFrontLocked(ActivityRecord newTop)1344     final void moveActivityToFrontLocked(ActivityRecord newTop) {
1345         if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
1346                 + newTop + " to stack at top callers=" + Debug.getCallers(4));
1347 
1348         positionChildAtTop(newTop);
1349         updateEffectiveIntent();
1350     }
1351 
1352     @Override
getActivityType()1353     public int getActivityType() {
1354         final int applicationType = super.getActivityType();
1355         if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
1356             return applicationType;
1357         }
1358         return getTopChild().getActivityType();
1359     }
1360 
1361     @Override
addChild(WindowContainer child, int index)1362     void addChild(WindowContainer child, int index) {
1363         // If this task had any child before we added this one.
1364         boolean hadChild = hasChild();
1365         // getActivityType() looks at the top child, so we need to read the type before adding
1366         // a new child in case the new child is on top and UNDEFINED.
1367         final int activityType = getActivityType();
1368 
1369         index = getAdjustedChildPosition(child, index);
1370         super.addChild(child, index);
1371 
1372         ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
1373 
1374         // A rootable task that is now being added to be the child of an organized task. Making
1375         // sure the stack references is keep updated.
1376         if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
1377             getDisplayArea().addStackReferenceIfNeeded((ActivityStack) child);
1378         }
1379 
1380         // Make sure the list of display UID allowlists is updated
1381         // now that this record is in a new task.
1382         mRootWindowContainer.updateUIDsPresentOnDisplay();
1383 
1384         final ActivityRecord r = child.asActivityRecord();
1385         if (r == null) return;
1386 
1387         r.inHistory = true;
1388 
1389         // Only set this based on the first activity
1390         if (!hadChild) {
1391             if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
1392                 // Normally non-standard activity type for the activity record will be set when the
1393                 // object is created, however we delay setting the standard application type until
1394                 // this point so that the task can set the type for additional activities added in
1395                 // the else condition below.
1396                 r.setActivityType(ACTIVITY_TYPE_STANDARD);
1397             }
1398             setActivityType(r.getActivityType());
1399             isPersistable = r.isPersistable();
1400             mCallingUid = r.launchedFromUid;
1401             mCallingPackage = r.launchedFromPackage;
1402             mCallingFeatureId = r.launchedFromFeatureId;
1403             // Clamp to [1, max].
1404             maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
1405                     ActivityTaskManager.getMaxAppRecentsLimitStatic());
1406         } else {
1407             // Otherwise make all added activities match this one.
1408             r.setActivityType(activityType);
1409         }
1410 
1411         updateEffectiveIntent();
1412     }
1413 
addChild(ActivityRecord r)1414     void addChild(ActivityRecord r) {
1415         addChild(r, Integer.MAX_VALUE /* add on top */);
1416     }
1417 
1418     @Override
removeChild(WindowContainer child)1419     void removeChild(WindowContainer child) {
1420         removeChild(child, "removeChild");
1421     }
1422 
removeChild(WindowContainer r, String reason)1423     void removeChild(WindowContainer r, String reason) {
1424         // A rootable child task that is now being removed from an organized task. Making sure
1425         // the stack references is keep updated.
1426         if (mCreatedByOrganizer && r.asTask() != null) {
1427             getDisplayArea().removeStackReferenceIfNeeded((ActivityStack) r);
1428         }
1429         if (!mChildren.contains(r)) {
1430             Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
1431             return;
1432         }
1433 
1434         if (DEBUG_TASK_MOVEMENT) {
1435             Slog.d(TAG_WM, "removeChild: child=" + r + " reason=" + reason);
1436         }
1437         super.removeChild(r);
1438 
1439         if (inPinnedWindowingMode()) {
1440             // We normally notify listeners of task stack changes on pause, however pinned stack
1441             // activities are normally in the paused state so no notification will be sent there
1442             // before the activity is removed. We send it here so instead.
1443             mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
1444         }
1445 
1446         if (hasChild()) {
1447             updateEffectiveIntent();
1448 
1449             // The following block can be executed multiple times if there is more than one overlay.
1450             // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
1451             // of the task by id and exiting early if not found.
1452             if (onlyHasTaskOverlayActivities(true /*includeFinishing*/)) {
1453                 // When destroying a task, tell the supervisor to remove it so that any activity it
1454                 // has can be cleaned up correctly. This is currently the only place where we remove
1455                 // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
1456                 // state into removeChild(), we just clear the task here before the other residual
1457                 // work.
1458                 // TODO: If the callers to removeChild() changes such that we have multiple places
1459                 //       where we are destroying the task, move this back into removeChild()
1460                 mStackSupervisor.removeTask(this, false /* killProcess */,
1461                         !REMOVE_FROM_RECENTS, reason);
1462             }
1463         } else if (!mReuseTask && !mCreatedByOrganizer) {
1464             // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
1465             // or created by task organizer.
1466             if (!isRootTask()) {
1467                 getStack().removeChild(this, reason);
1468             }
1469             EventLogTags.writeWmTaskRemoved(mTaskId,
1470                     "removeChild: last r=" + r + " in t=" + this);
1471             removeIfPossible();
1472         }
1473     }
1474 
1475     /**
1476      * @return whether or not there are ONLY task overlay activities in the task.
1477      *         If {@param includeFinishing} is set, then don't ignore finishing activities in the
1478      *         check. If there are no task overlay activities, this call returns false.
1479      */
onlyHasTaskOverlayActivities(boolean includeFinishing)1480     boolean onlyHasTaskOverlayActivities(boolean includeFinishing) {
1481         int count = 0;
1482         for (int i = getChildCount() - 1; i >= 0; i--) {
1483             final ActivityRecord r = getChildAt(i).asActivityRecord();
1484             if (r == null) {
1485                 // Has a child that is other than Activity.
1486                 return false;
1487             }
1488             if (!includeFinishing && r.finishing) {
1489                 continue;
1490             }
1491             if (!r.isTaskOverlay()) {
1492                 return false;
1493             }
1494             count++;
1495         }
1496         return count > 0;
1497     }
1498 
autoRemoveFromRecents()1499     private boolean autoRemoveFromRecents() {
1500         // We will automatically remove the task either if it has explicitly asked for
1501         // this, or it is empty and has never contained an activity that got shown to
1502         // the user.
1503         return autoRemoveRecents || (!hasChild() && !getHasBeenVisible());
1504     }
1505 
1506     /** Completely remove all activities associated with an existing task. */
performClearTask(String reason)1507     void performClearTask(String reason) {
1508         // Broken down into to cases to avoid object create due to capturing mStack.
1509         if (getStack() == null) {
1510             forAllActivities((r) -> {
1511                 if (r.finishing) return;
1512                 // Task was restored from persistent storage.
1513                 r.takeFromHistory();
1514                 removeChild(r);
1515             });
1516         } else {
1517             forAllActivities((r) -> {
1518                 if (r.finishing) return;
1519                 // TODO: figure-out how to avoid object creation due to capture of reason variable.
1520                 r.finishIfPossible(Activity.RESULT_CANCELED,
1521                         null /* resultData */, null /* resultGrants */, reason, false /* oomAdj */);
1522             });
1523         }
1524     }
1525 
1526     /**
1527      * Completely remove all activities associated with an existing task.
1528      */
performClearTaskLocked()1529     void performClearTaskLocked() {
1530         mReuseTask = true;
1531         mStackSupervisor.beginDeferResume();
1532         try {
1533             performClearTask("clear-task-all");
1534         } finally {
1535             mStackSupervisor.endDeferResume();
1536             mReuseTask = false;
1537         }
1538     }
1539 
performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags)1540     ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
1541         mReuseTask = true;
1542         mStackSupervisor.beginDeferResume();
1543         final ActivityRecord result;
1544         try {
1545             result = performClearTaskLocked(newR, launchFlags);
1546         } finally {
1547             mStackSupervisor.endDeferResume();
1548             mReuseTask = false;
1549         }
1550         return result;
1551     }
1552 
1553     /**
1554      * Perform clear operation as requested by
1555      * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
1556      * stack to the given task, then look for
1557      * an instance of that activity in the stack and, if found, finish all
1558      * activities on top of it and return the instance.
1559      *
1560      * @param newR Description of the new activity being started.
1561      * @return Returns the old activity that should be continued to be used,
1562      * or {@code null} if none was found.
1563      */
performClearTaskLocked(ActivityRecord newR, int launchFlags)1564     private ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
1565         final ActivityRecord r = findActivityInHistory(newR.mActivityComponent);
1566         if (r == null) return null;
1567 
1568         final PooledFunction f = PooledLambda.obtainFunction(Task::finishActivityAbove,
1569                 PooledLambda.__(ActivityRecord.class), r);
1570         forAllActivities(f);
1571         f.recycle();
1572 
1573         // Finally, if this is a normal launch mode (that is, not expecting onNewIntent()), then we
1574         // will finish the current instance of the activity so a new fresh one can be started.
1575         if (r.launchMode == ActivityInfo.LAUNCH_MULTIPLE
1576                 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
1577                 && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
1578             if (!r.finishing) {
1579                 r.finishIfPossible("clear-task-top", false /* oomAdj */);
1580                 return null;
1581             }
1582         }
1583 
1584         return r;
1585     }
1586 
finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity)1587     private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity) {
1588         // Stop operation once we reach the boundary activity.
1589         if (r == boundaryActivity) return true;
1590 
1591         if (!r.finishing) {
1592             final ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
1593             if (opts != null) {
1594                 // TODO: Why is this updating the boundary activity vs. the current activity???
1595                 boundaryActivity.updateOptionsLocked(opts);
1596             }
1597             r.finishIfPossible("clear-task-stack", false /* oomAdj */);
1598         }
1599 
1600         return false;
1601     }
1602 
lockTaskAuthToString()1603     String lockTaskAuthToString() {
1604         switch (mLockTaskAuth) {
1605             case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
1606             case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
1607             case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
1608             case LOCK_TASK_AUTH_ALLOWLISTED: return "LOCK_TASK_AUTH_ALLOWLISTED";
1609             case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
1610             default: return "unknown=" + mLockTaskAuth;
1611         }
1612     }
1613 
setLockTaskAuth()1614     void setLockTaskAuth() {
1615         setLockTaskAuth(getRootActivity());
1616     }
1617 
setLockTaskAuth(@ullable ActivityRecord r)1618     private void setLockTaskAuth(@Nullable ActivityRecord r) {
1619         if (r == null) {
1620             mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
1621             return;
1622         }
1623 
1624         final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
1625         final LockTaskController lockTaskController = mAtmService.getLockTaskController();
1626         switch (r.lockTaskLaunchMode) {
1627             case LOCK_TASK_LAUNCH_MODE_DEFAULT:
1628                 mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
1629                         ? LOCK_TASK_AUTH_ALLOWLISTED : LOCK_TASK_AUTH_PINNABLE;
1630                 break;
1631 
1632             case LOCK_TASK_LAUNCH_MODE_NEVER:
1633                 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
1634                 break;
1635 
1636             case LOCK_TASK_LAUNCH_MODE_ALWAYS:
1637                 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
1638                 break;
1639 
1640             case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
1641                 mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
1642                         ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
1643                 break;
1644         }
1645         if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this
1646                 + " mLockTaskAuth=" + lockTaskAuthToString());
1647     }
1648 
1649     @Override
supportsSplitScreenWindowingMode()1650     public boolean supportsSplitScreenWindowingMode() {
1651         final Task topTask = getTopMostTask();
1652         return super.supportsSplitScreenWindowingMode()
1653                 && (topTask == null || topTask.supportsSplitScreenWindowingModeInner());
1654     }
1655 
supportsSplitScreenWindowingModeInner()1656     private boolean supportsSplitScreenWindowingModeInner() {
1657         // A task can not be docked even if it is considered resizeable because it only supports
1658         // picture-in-picture mode but has a non-resizeable resizeMode
1659         return super.supportsSplitScreenWindowingMode()
1660                 && mAtmService.mSupportsSplitScreenMultiWindow
1661                 && (mAtmService.mForceResizableActivities
1662                         || (isResizeable(false /* checkSupportsPip */)
1663                                 && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
1664     }
1665 
1666     /**
1667      * Check whether this task can be launched on the specified display.
1668      *
1669      * @param displayId Target display id.
1670      * @return {@code true} if either it is the default display or this activity can be put on a
1671      *         secondary display.
1672      */
canBeLaunchedOnDisplay(int displayId)1673     boolean canBeLaunchedOnDisplay(int displayId) {
1674         return mStackSupervisor.canPlaceEntityOnDisplay(displayId,
1675                 -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
1676     }
1677 
1678     /**
1679      * Check that a given bounds matches the application requested orientation.
1680      *
1681      * @param bounds The bounds to be tested.
1682      * @return True if the requested bounds are okay for a resizing request.
1683      */
canResizeToBounds(Rect bounds)1684     private boolean canResizeToBounds(Rect bounds) {
1685         if (bounds == null || !inFreeformWindowingMode()) {
1686             // Note: If not on the freeform workspace, we ignore the bounds.
1687             return true;
1688         }
1689         final boolean landscape = bounds.width() > bounds.height();
1690         final Rect configBounds = getRequestedOverrideBounds();
1691         if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
1692             return configBounds.isEmpty()
1693                     || landscape == (configBounds.width() > configBounds.height());
1694         }
1695         return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
1696                 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
1697     }
1698 
1699     /**
1700      * @return {@code true} if the task is being cleared for the purposes of being reused.
1701      */
isClearingToReuseTask()1702     boolean isClearingToReuseTask() {
1703         return mReuseTask;
1704     }
1705 
1706     /**
1707      * Find the activity in the history stack within the given task.  Returns
1708      * the index within the history at which it's found, or < 0 if not found.
1709      */
findActivityInHistory(ComponentName component)1710     ActivityRecord findActivityInHistory(ComponentName component) {
1711         final PooledPredicate p = PooledLambda.obtainPredicate(Task::matchesActivityInHistory,
1712                 PooledLambda.__(ActivityRecord.class), component);
1713         final ActivityRecord r = getActivity(p);
1714         p.recycle();
1715         return r;
1716     }
1717 
matchesActivityInHistory( ActivityRecord r, ComponentName activityComponent)1718     private static boolean matchesActivityInHistory(
1719             ActivityRecord r, ComponentName activityComponent) {
1720         return !r.finishing && r.mActivityComponent.equals(activityComponent);
1721     }
1722 
1723     /** Updates the last task description values. */
updateTaskDescription()1724     void updateTaskDescription() {
1725         final ActivityRecord root = getRootActivity(true);
1726         if (root == null) return;
1727 
1728         final TaskDescription taskDescription = new TaskDescription();
1729         final PooledFunction f = PooledLambda.obtainFunction(
1730                 Task::setTaskDescriptionFromActivityAboveRoot,
1731                 PooledLambda.__(ActivityRecord.class), root, taskDescription);
1732         forAllActivities(f);
1733         f.recycle();
1734         taskDescription.setResizeMode(mResizeMode);
1735         taskDescription.setMinWidth(mMinWidth);
1736         taskDescription.setMinHeight(mMinHeight);
1737         setTaskDescription(taskDescription);
1738         // Update the task affiliation color if we are the parent of the group
1739         if (mTaskId == mAffiliatedTaskId) {
1740             mAffiliatedTaskColor = taskDescription.getPrimaryColor();
1741         }
1742         mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
1743                 getTaskInfo());
1744 
1745         final WindowContainer parent = getParent();
1746         if (parent != null) {
1747             final Task t = parent.asTask();
1748             if (t != null) {
1749                 t.updateTaskDescription();
1750             }
1751         }
1752 
1753         if (isOrganized()) {
1754             mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */);
1755         }
1756     }
1757 
setTaskDescriptionFromActivityAboveRoot( ActivityRecord r, ActivityRecord root, TaskDescription td)1758     private static boolean setTaskDescriptionFromActivityAboveRoot(
1759             ActivityRecord r, ActivityRecord root, TaskDescription td) {
1760         if (!r.isTaskOverlay() && r.taskDescription != null) {
1761             final TaskDescription atd = r.taskDescription;
1762             if (td.getLabel() == null) {
1763                 td.setLabel(atd.getLabel());
1764             }
1765             if (td.getRawIcon() == null) {
1766                 td.setIcon(atd.getRawIcon());
1767             }
1768             if (td.getIconFilename() == null) {
1769                 td.setIconFilename(atd.getIconFilename());
1770             }
1771             if (td.getPrimaryColor() == 0) {
1772                 td.setPrimaryColor(atd.getPrimaryColor());
1773             }
1774             if (td.getBackgroundColor() == 0) {
1775                 td.setBackgroundColor(atd.getBackgroundColor());
1776             }
1777             if (td.getStatusBarColor() == 0) {
1778                 td.setStatusBarColor(atd.getStatusBarColor());
1779                 td.setEnsureStatusBarContrastWhenTransparent(
1780                         atd.getEnsureStatusBarContrastWhenTransparent());
1781             }
1782             if (td.getNavigationBarColor() == 0) {
1783                 td.setNavigationBarColor(atd.getNavigationBarColor());
1784                 td.setEnsureNavigationBarContrastWhenTransparent(
1785                         atd.getEnsureNavigationBarContrastWhenTransparent());
1786             }
1787 
1788         }
1789 
1790         // End search once we get to root.
1791         return r == root;
1792     }
1793 
1794     // TODO (AM refactor): Invoke automatically when there is a change in children
1795     @VisibleForTesting
updateEffectiveIntent()1796     void updateEffectiveIntent() {
1797         final ActivityRecord root = getRootActivity(true /*setToBottomIfNone*/);
1798         if (root != null) {
1799             setIntent(root);
1800             // Update the task description when the activities change
1801             updateTaskDescription();
1802         }
1803     }
1804 
adjustForMinimalTaskDimensions(@onNull Rect bounds, @NonNull Rect previousBounds, @NonNull Configuration parentConfig)1805     void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds,
1806             @NonNull Configuration parentConfig) {
1807         int minWidth = mMinWidth;
1808         int minHeight = mMinHeight;
1809         // If the task has no requested minimal size, we'd like to enforce a minimal size
1810         // so that the user can not render the task too small to manipulate. We don't need
1811         // to do this for the pinned stack as the bounds are controlled by the system.
1812         if (!inPinnedWindowingMode()) {
1813             final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp;
1814             final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
1815             final int defaultMinSize = (int) (defaultMinSizeDp * density);
1816 
1817             if (minWidth == INVALID_MIN_SIZE) {
1818                 minWidth = defaultMinSize;
1819             }
1820             if (minHeight == INVALID_MIN_SIZE) {
1821                 minHeight = defaultMinSize;
1822             }
1823         }
1824         if (bounds.isEmpty()) {
1825             // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they
1826             // do, we can just skip.
1827             final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
1828             if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) {
1829                 return;
1830             }
1831             bounds.set(parentBounds);
1832         }
1833         final boolean adjustWidth = minWidth > bounds.width();
1834         final boolean adjustHeight = minHeight > bounds.height();
1835         if (!(adjustWidth || adjustHeight)) {
1836             return;
1837         }
1838 
1839         if (adjustWidth) {
1840             if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
1841                 bounds.left = bounds.right - minWidth;
1842             } else {
1843                 // Either left bounds match, or neither match, or the previous bounds were
1844                 // fullscreen and we default to keeping left.
1845                 bounds.right = bounds.left + minWidth;
1846             }
1847         }
1848         if (adjustHeight) {
1849             if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
1850                 bounds.top = bounds.bottom - minHeight;
1851             } else {
1852                 // Either top bounds match, or neither match, or the previous bounds were
1853                 // fullscreen and we default to keeping top.
1854                 bounds.bottom = bounds.top + minHeight;
1855             }
1856         }
1857     }
1858 
setLastNonFullscreenBounds(Rect bounds)1859     void setLastNonFullscreenBounds(Rect bounds) {
1860         if (mLastNonFullscreenBounds == null) {
1861             mLastNonFullscreenBounds = new Rect(bounds);
1862         } else {
1863             mLastNonFullscreenBounds.set(bounds);
1864         }
1865     }
1866 
1867     /**
1868      * This should be called when an child activity changes state. This should only
1869      * be called from
1870      * {@link ActivityRecord#setState(ActivityState, String)} .
1871      * @param record The {@link ActivityRecord} whose state has changed.
1872      * @param state The new state.
1873      * @param reason The reason for the change.
1874      */
onActivityStateChanged(ActivityRecord record, ActivityState state, String reason)1875     void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
1876         final Task parentTask = getParent().asTask();
1877         if (parentTask != null) {
1878             parentTask.onActivityStateChanged(record, state, reason);
1879             // We still want to update the resumed activity if the parent task is created by
1880             // organizer in order to keep the information synced once got reparented out from the
1881             // organized task.
1882             if (!parentTask.mCreatedByOrganizer) {
1883                 return;
1884             }
1885         }
1886 
1887         if (record == mResumedActivity && state != RESUMED) {
1888             setResumedActivity(null, reason + " - onActivityStateChanged");
1889         }
1890 
1891         if (state == RESUMED) {
1892             if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
1893                 Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:" + reason);
1894             }
1895             setResumedActivity(record, reason + " - onActivityStateChanged");
1896             if (record == mRootWindowContainer.getTopResumedActivity()) {
1897                 mAtmService.setResumedActivityUncheckLocked(record, reason);
1898             }
1899             mStackSupervisor.mRecentTasks.add(record.getTask());
1900         }
1901     }
1902 
1903     @Override
onConfigurationChanged(Configuration newParentConfig)1904     public void onConfigurationChanged(Configuration newParentConfig) {
1905         // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
1906         // restore the last recorded non-fullscreen bounds.
1907         final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
1908         boolean nextPersistTaskBounds =
1909                 getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds();
1910         if (getRequestedOverrideWindowingMode() == WINDOWING_MODE_UNDEFINED) {
1911             nextPersistTaskBounds = newParentConfig.windowConfiguration.persistTaskBounds();
1912         }
1913         if (!prevPersistTaskBounds && nextPersistTaskBounds
1914                 && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
1915             // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
1916             getRequestedOverrideConfiguration().windowConfiguration
1917                     .setBounds(mLastNonFullscreenBounds);
1918         }
1919 
1920         final int prevWinMode = getWindowingMode();
1921         mTmpPrevBounds.set(getBounds());
1922         final boolean wasInMultiWindowMode = inMultiWindowMode();
1923         final boolean wasInPictureInPicture = inPinnedWindowingMode();
1924         super.onConfigurationChanged(newParentConfig);
1925         // Only need to update surface size here since the super method will handle updating
1926         // surface position.
1927         updateSurfaceSize(getSyncTransaction());
1928 
1929         if (wasInPictureInPicture != inPinnedWindowingMode()) {
1930             mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, getStack());
1931         } else if (wasInMultiWindowMode != inMultiWindowMode()) {
1932             mStackSupervisor.scheduleUpdateMultiWindowMode(this);
1933         }
1934 
1935         final int newWinMode = getWindowingMode();
1936         if ((prevWinMode != newWinMode) && (mDisplayContent != null)
1937                 && shouldStartChangeTransition(prevWinMode, newWinMode)) {
1938             initializeChangeTransition(mTmpPrevBounds);
1939         }
1940 
1941         // If the configuration supports persistent bounds (eg. Freeform), keep track of the
1942         // current (non-fullscreen) bounds for persistence.
1943         if (getWindowConfiguration().persistTaskBounds()) {
1944             final Rect currentBounds = getRequestedOverrideBounds();
1945             if (!currentBounds.isEmpty()) {
1946                 setLastNonFullscreenBounds(currentBounds);
1947             }
1948         }
1949 
1950         saveLaunchingStateIfNeeded();
1951         final boolean taskOrgChanged = updateTaskOrganizerState(false /* forceUpdate */);
1952         // If the task organizer has changed, then it will already be receiving taskAppeared with
1953         // the latest task-info thus the task-info won't have changed.
1954         if (!taskOrgChanged && isOrganized()) {
1955             mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */);
1956         }
1957     }
1958 
1959     /**
1960      * Initializes a change transition. See {@link SurfaceFreezer} for more information.
1961      */
initializeChangeTransition(Rect startBounds)1962     private void initializeChangeTransition(Rect startBounds) {
1963         mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
1964                 false /* alwaysKeepCurrent */, 0, false /* forceOverride */);
1965         mDisplayContent.mChangingContainers.add(this);
1966 
1967         mSurfaceFreezer.freeze(getPendingTransaction(), startBounds);
1968     }
1969 
shouldStartChangeTransition(int prevWinMode, int newWinMode)1970     private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
1971         if (mWmService.mDisableTransitionAnimation
1972                 || !isVisible()
1973                 || getDisplayContent().mAppTransition.isTransitionSet()
1974                 || getSurfaceControl() == null
1975                 || !isLeafTask()) {
1976             return false;
1977         }
1978         // Only do an animation into and out-of freeform mode for now. Other mode
1979         // transition animations are currently handled by system-ui.
1980         return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM);
1981     }
1982 
1983     @Override
migrateToNewSurfaceControl()1984     void migrateToNewSurfaceControl() {
1985         super.migrateToNewSurfaceControl();
1986         mLastSurfaceSize.x = 0;
1987         mLastSurfaceSize.y = 0;
1988         updateSurfaceSize(getPendingTransaction());
1989     }
1990 
updateSurfaceSize(SurfaceControl.Transaction transaction)1991     void updateSurfaceSize(SurfaceControl.Transaction transaction) {
1992         if (mSurfaceControl == null || isOrganized()) {
1993             return;
1994         }
1995 
1996         // Apply crop to root tasks only and clear the crops of the descendant tasks.
1997         int width = 0;
1998         int height = 0;
1999         if (isRootTask()) {
2000             final Rect taskBounds = getBounds();
2001             width = taskBounds.width();
2002             height = taskBounds.height();
2003 
2004             final int outset = getTaskOutset();
2005             width += 2 * outset;
2006             height += 2 * outset;
2007         }
2008         if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
2009             return;
2010         }
2011         transaction.setWindowCrop(mSurfaceControl, width, height);
2012         mLastSurfaceSize.set(width, height);
2013     }
2014 
2015     /**
2016      * Calculate an amount by which to expand the task bounds in each direction.
2017      * Used to make room for shadows in the pinned windowing mode.
2018      */
getTaskOutset()2019     int getTaskOutset() {
2020         // If we are drawing shadows on the task then don't outset the stack.
2021         if (mWmService.mRenderShadowsInCompositor) {
2022             return 0;
2023         }
2024         DisplayContent displayContent = getDisplayContent();
2025         if (inPinnedWindowingMode() && displayContent != null) {
2026             final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
2027 
2028             // We multiply by two to match the client logic for converting view elevation
2029             // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets}
2030             return (int) Math.ceil(
2031                     mWmService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP, displayMetrics)
2032                             * 2);
2033         }
2034         return 0;
2035     }
2036 
2037     @VisibleForTesting
getLastSurfaceSize()2038     Point getLastSurfaceSize() {
2039         return mLastSurfaceSize;
2040     }
2041 
2042     @VisibleForTesting
isInChangeTransition()2043     boolean isInChangeTransition() {
2044         return mSurfaceFreezer.hasLeash() || AppTransition.isChangeTransit(mTransit);
2045     }
2046 
2047     @Override
getFreezeSnapshotTarget()2048     public SurfaceControl getFreezeSnapshotTarget() {
2049         final int transit = mDisplayContent.mAppTransition.getAppTransition();
2050         if (!AppTransition.isChangeTransit(transit)) {
2051             return null;
2052         }
2053         // Skip creating snapshot if this transition is controlled by a remote animator which
2054         // doesn't need it.
2055         final ArraySet<Integer> activityTypes = new ArraySet<>();
2056         activityTypes.add(getActivityType());
2057         final RemoteAnimationAdapter adapter =
2058                 mDisplayContent.mAppTransitionController.getRemoteAnimationOverride(
2059                         this, transit, activityTypes);
2060         if (adapter != null && !adapter.getChangeNeedsSnapshot()) {
2061             return null;
2062         }
2063         return getSurfaceControl();
2064     }
2065 
2066     @Override
writeIdentifierToProto(ProtoOutputStream proto, long fieldId)2067     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
2068         final long token = proto.start(fieldId);
2069         proto.write(HASH_CODE, System.identityHashCode(this));
2070         proto.write(USER_ID, mUserId);
2071         proto.write(TITLE, intent != null && intent.getComponent() != null
2072                 ? intent.getComponent().flattenToShortString() : "Task");
2073         proto.end(token);
2074     }
2075 
2076     /**
2077      * Saves launching state if necessary so that we can launch the activity to its latest state.
2078      * It only saves state if this task has been shown to user and it's in fullscreen or freeform
2079      * mode on freeform displays.
2080      */
saveLaunchingStateIfNeeded()2081     private void saveLaunchingStateIfNeeded() {
2082         saveLaunchingStateIfNeeded(getDisplayContent());
2083     }
2084 
saveLaunchingStateIfNeeded(DisplayContent display)2085     private void saveLaunchingStateIfNeeded(DisplayContent display) {
2086         if (!getHasBeenVisible()) {
2087             // Not ever visible to user.
2088             return;
2089         }
2090 
2091         final int windowingMode = getWindowingMode();
2092         if (windowingMode != WINDOWING_MODE_FULLSCREEN
2093                 && windowingMode != WINDOWING_MODE_FREEFORM) {
2094             return;
2095         }
2096 
2097         // Don't persist state if display isn't in freeform mode. Then the task will be launched
2098         // back to its last state in a freeform display when it's launched in a freeform display
2099         // next time.
2100         if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) {
2101             return;
2102         }
2103 
2104         // Saves the new state so that we can launch the activity at the same location.
2105         mStackSupervisor.mLaunchParamsPersister.saveTask(this, display);
2106     }
2107 
2108     /**
2109      * Adjust bounds to stay within stack bounds.
2110      *
2111      * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
2112      * that keep them unchanged, but be contained within the stack bounds.
2113      *
2114      * @param bounds Bounds to be adjusted.
2115      * @param stackBounds Bounds within which the other bounds should remain.
2116      * @param overlapPxX The amount of px required to be visible in the X dimension.
2117      * @param overlapPxY The amount of px required to be visible in the Y dimension.
2118      */
fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX, int overlapPxY)2119     private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX,
2120             int overlapPxY) {
2121         if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) {
2122             return;
2123         }
2124 
2125         // For each side of the parent (eg. left), check if the opposing side of the window (eg.
2126         // right) is at least overlap pixels away. If less, offset the window by that difference.
2127         int horizontalDiff = 0;
2128         // If window is smaller than overlap, use it's smallest dimension instead
2129         int overlapLR = Math.min(overlapPxX, bounds.width());
2130         if (bounds.right < (stackBounds.left + overlapLR)) {
2131             horizontalDiff = overlapLR - (bounds.right - stackBounds.left);
2132         } else if (bounds.left > (stackBounds.right - overlapLR)) {
2133             horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left));
2134         }
2135         int verticalDiff = 0;
2136         int overlapTB = Math.min(overlapPxY, bounds.width());
2137         if (bounds.bottom < (stackBounds.top + overlapTB)) {
2138             verticalDiff = overlapTB - (bounds.bottom - stackBounds.top);
2139         } else if (bounds.top > (stackBounds.bottom - overlapTB)) {
2140             verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top));
2141         }
2142         bounds.offset(horizontalDiff, verticalDiff);
2143     }
2144 
2145     /**
2146      * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
2147      * intersectBounds on a side, then the respective side will not be intersected.
2148      *
2149      * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
2150      * inset on that side is no-longer applicable. This scenario happens when a task's minimal
2151      * bounds are larger than the provided parent/display bounds.
2152      *
2153      * @param inOutBounds the bounds to intersect.
2154      * @param intersectBounds the bounds to intersect with.
2155      * @param intersectInsets insets to apply to intersectBounds before intersecting.
2156      */
intersectWithInsetsIfFits( Rect inOutBounds, Rect intersectBounds, Rect intersectInsets)2157     static void intersectWithInsetsIfFits(
2158             Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
2159         if (inOutBounds.right <= intersectBounds.right) {
2160             inOutBounds.right =
2161                     Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
2162         }
2163         if (inOutBounds.bottom <= intersectBounds.bottom) {
2164             inOutBounds.bottom =
2165                     Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
2166         }
2167         if (inOutBounds.left >= intersectBounds.left) {
2168             inOutBounds.left =
2169                     Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
2170         }
2171         if (inOutBounds.top >= intersectBounds.top) {
2172             inOutBounds.top =
2173                     Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
2174         }
2175     }
2176 
2177     /**
2178      * Gets bounds with non-decor and stable insets applied respectively.
2179      *
2180      * If bounds overhangs the display, those edges will not get insets. See
2181      * {@link #intersectWithInsetsIfFits}
2182      *
2183      * @param outNonDecorBounds where to place bounds with non-decor insets applied.
2184      * @param outStableBounds where to place bounds with stable insets applied.
2185      * @param bounds the bounds to inset.
2186      */
calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, DisplayInfo displayInfo)2187     private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
2188             DisplayInfo displayInfo) {
2189         outNonDecorBounds.set(bounds);
2190         outStableBounds.set(bounds);
2191         if (getStack() == null || getStack().getDisplay() == null) {
2192             return;
2193         }
2194         DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy();
2195         if (policy == null) {
2196             return;
2197         }
2198         mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
2199 
2200         policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
2201                 displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
2202         intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
2203 
2204         policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
2205         intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
2206     }
2207 
2208     /**
2209      * Forces the app bounds related configuration can be computed by
2210      * {@link #computeConfigResourceOverrides(Configuration, Configuration, DisplayInfo,
2211      * ActivityRecord.CompatDisplayInsets)}.
2212      */
invalidateAppBoundsConfig(@onNull Configuration inOutConfig)2213     private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) {
2214         final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds();
2215         if (appBounds != null) {
2216             appBounds.setEmpty();
2217         }
2218         inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
2219         inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
2220     }
2221 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo)2222     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2223             @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
2224         if (overrideDisplayInfo != null) {
2225             // Make sure the screen related configs can be computed by the provided display info.
2226             inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
2227             invalidateAppBoundsConfig(inOutConfig);
2228         }
2229         computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
2230                 null /* compatInsets */);
2231     }
2232 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig)2233     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2234             @NonNull Configuration parentConfig) {
2235         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
2236                 null /* compatInsets */);
2237     }
2238 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2239     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2240             @NonNull Configuration parentConfig,
2241             @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
2242         if (compatInsets != null) {
2243             // Make sure the app bounds can be computed by the compat insets.
2244             invalidateAppBoundsConfig(inOutConfig);
2245         }
2246         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
2247                 compatInsets);
2248     }
2249 
2250     /**
2251      * Calculates configuration values used by the client to get resources. This should be run
2252      * using app-facing bounds (bounds unmodified by animations or transient interactions).
2253      *
2254      * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
2255      * configuring an "inherit-bounds" window which means that all configuration settings would
2256      * just be inherited from the parent configuration.
2257      **/
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2258     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2259             @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
2260             @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
2261         int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
2262         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
2263             windowingMode = parentConfig.windowConfiguration.getWindowingMode();
2264         }
2265 
2266         float density = inOutConfig.densityDpi;
2267         if (density == Configuration.DENSITY_DPI_UNDEFINED) {
2268             density = parentConfig.densityDpi;
2269         }
2270         density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
2271 
2272         // The bounds may have been overridden at this level. If the parent cannot cover these
2273         // bounds, the configuration is still computed according to the override bounds.
2274         final boolean insideParentBounds;
2275 
2276         final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
2277         final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds();
2278         if (resolvedBounds == null || resolvedBounds.isEmpty()) {
2279             mTmpFullBounds.set(parentBounds);
2280             insideParentBounds = true;
2281         } else {
2282             mTmpFullBounds.set(resolvedBounds);
2283             insideParentBounds = parentBounds.contains(resolvedBounds);
2284         }
2285 
2286         // Non-null compatibility insets means the activity prefers to keep its original size, so
2287         // out bounds doesn't need to be restricted by the parent or current display
2288         final boolean customContainerPolicy = compatInsets != null;
2289 
2290         Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
2291         if (outAppBounds == null || outAppBounds.isEmpty()) {
2292             // App-bounds hasn't been overridden, so calculate a value for it.
2293             inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds);
2294             outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
2295 
2296             if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) {
2297                 final Rect containingAppBounds;
2298                 if (insideParentBounds) {
2299                     containingAppBounds = parentConfig.windowConfiguration.getAppBounds();
2300                 } else {
2301                     // Restrict appBounds to display non-decor rather than parent because the
2302                     // override bounds are beyond the parent. Otherwise, it won't match the
2303                     // overridden bounds.
2304                     final TaskDisplayArea displayArea = getDisplayArea();
2305                     containingAppBounds = displayArea != null
2306                             ? displayArea.getWindowConfiguration().getAppBounds() : null;
2307                 }
2308                 if (containingAppBounds != null && !containingAppBounds.isEmpty()) {
2309                     outAppBounds.intersect(containingAppBounds);
2310                 }
2311             }
2312         }
2313 
2314         if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
2315                 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2316             if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) {
2317                 mTmpNonDecorBounds.set(mTmpFullBounds);
2318                 mTmpStableBounds.set(mTmpFullBounds);
2319             } else if (!customContainerPolicy
2320                     && (overrideDisplayInfo != null || getDisplayContent() != null)) {
2321                 final DisplayInfo di = overrideDisplayInfo != null
2322                         ? overrideDisplayInfo
2323                         : getDisplayContent().getDisplayInfo();
2324 
2325                 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
2326                 // area, i.e. the screen area without the system bars.
2327                 // The non decor inset are areas that could never be removed in Honeycomb. See
2328                 // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
2329                 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di);
2330             } else {
2331                 // Apply the given non-decor and stable insets to calculate the corresponding bounds
2332                 // for screen size of configuration.
2333                 int rotation = inOutConfig.windowConfiguration.getRotation();
2334                 if (rotation == ROTATION_UNDEFINED) {
2335                     rotation = parentConfig.windowConfiguration.getRotation();
2336                 }
2337                 if (rotation != ROTATION_UNDEFINED && customContainerPolicy) {
2338                     mTmpNonDecorBounds.set(mTmpFullBounds);
2339                     mTmpStableBounds.set(mTmpFullBounds);
2340                     compatInsets.getBoundsByRotation(mTmpBounds, rotation);
2341                     intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
2342                             compatInsets.mNonDecorInsets[rotation]);
2343                     intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
2344                             compatInsets.mStableInsets[rotation]);
2345                     outAppBounds.set(mTmpNonDecorBounds);
2346                 } else {
2347                     // Set to app bounds because it excludes decor insets.
2348                     mTmpNonDecorBounds.set(outAppBounds);
2349                     mTmpStableBounds.set(outAppBounds);
2350                 }
2351             }
2352 
2353             if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
2354                 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
2355                 inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy)
2356                         ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
2357                         : overrideScreenWidthDp;
2358             }
2359             if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2360                 final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
2361                 inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy)
2362                         ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
2363                         : overrideScreenHeightDp;
2364             }
2365 
2366             if (inOutConfig.smallestScreenWidthDp
2367                     == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
2368                 if (WindowConfiguration.isFloating(windowingMode)) {
2369                     // For floating tasks, calculate the smallest width from the bounds of the task
2370                     inOutConfig.smallestScreenWidthDp = (int) (
2371                             Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
2372                 }
2373                 // otherwise, it will just inherit
2374             }
2375         }
2376 
2377         if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
2378             inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
2379                     ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
2380         }
2381         if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
2382             // For calculating screen layout, we need to use the non-decor inset screen area for the
2383             // calculation for compatibility reasons, i.e. screen area without system bars that
2384             // could never go away in Honeycomb.
2385             int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
2386             int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
2387             // Use overrides if provided. If both overrides are provided, mTmpNonDecorBounds is
2388             // undefined so it can't be used.
2389             if (inOutConfig.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
2390                 compatScreenWidthDp = inOutConfig.screenWidthDp;
2391             }
2392             if (inOutConfig.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2393                 compatScreenHeightDp = inOutConfig.screenHeightDp;
2394             }
2395             // Reducing the screen layout starting from its parent config.
2396             inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout,
2397                     compatScreenWidthDp, compatScreenHeightDp);
2398         }
2399     }
2400 
2401     /** Computes LONG, SIZE and COMPAT parts of {@link Configuration#screenLayout}. */
computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp, int screenHeightDp)2402     static int computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp,
2403             int screenHeightDp) {
2404         sourceScreenLayout = sourceScreenLayout
2405                 & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
2406         final int longSize = Math.max(screenWidthDp, screenHeightDp);
2407         final int shortSize = Math.min(screenWidthDp, screenHeightDp);
2408         return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize);
2409     }
2410 
2411     @Override
resolveOverrideConfiguration(Configuration newParentConfig)2412     void resolveOverrideConfiguration(Configuration newParentConfig) {
2413         mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
2414         super.resolveOverrideConfiguration(newParentConfig);
2415 
2416         int windowingMode =
2417                 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
2418 
2419         // Resolve override windowing mode to fullscreen for home task (even on freeform
2420         // display), or split-screen if in split-screen mode.
2421         if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) {
2422             final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode();
2423             windowingMode = WindowConfiguration.isSplitScreenWindowingMode(parentWindowingMode)
2424                     ? parentWindowingMode : WINDOWING_MODE_FULLSCREEN;
2425             getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
2426         }
2427 
2428         if (isLeafTask()) {
2429             resolveLeafOnlyOverrideConfigs(newParentConfig, mTmpBounds /* previousBounds */);
2430         }
2431         computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
2432     }
2433 
resolveLeafOnlyOverrideConfigs(Configuration newParentConfig, Rect previousBounds)2434     private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig,
2435             Rect previousBounds) {
2436         int windowingMode =
2437                 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
2438         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
2439             windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
2440         }
2441         Rect outOverrideBounds =
2442                 getResolvedOverrideConfiguration().windowConfiguration.getBounds();
2443 
2444         if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
2445             computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
2446                     newParentConfig.windowConfiguration.getBounds(),
2447                     newParentConfig.orientation);
2448             // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
2449             // the parent or display is smaller than the size, the content may be cropped.
2450             return;
2451         }
2452 
2453         adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig);
2454         if (windowingMode == WINDOWING_MODE_FREEFORM) {
2455             // by policy, make sure the window remains within parent somewhere
2456             final float density =
2457                     ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
2458             final Rect parentBounds =
2459                     new Rect(newParentConfig.windowConfiguration.getBounds());
2460             final DisplayContent display = getDisplayContent();
2461             if (display != null) {
2462                 // If a freeform window moves below system bar, there is no way to move it again
2463                 // by touch. Because its caption is covered by system bar. So we exclude them
2464                 // from stack bounds. and then caption will be shown inside stable area.
2465                 final Rect stableBounds = new Rect();
2466                 display.getStableRect(stableBounds);
2467                 parentBounds.intersect(stableBounds);
2468             }
2469 
2470             fitWithinBounds(outOverrideBounds, parentBounds,
2471                     (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
2472                     (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
2473 
2474             // Prevent to overlap caption with stable insets.
2475             final int offsetTop = parentBounds.top - outOverrideBounds.top;
2476             if (offsetTop > 0) {
2477                 outOverrideBounds.offset(0, offsetTop);
2478             }
2479         }
2480     }
2481 
2482     /**
2483      * Compute bounds (letterbox or pillarbox) for
2484      * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
2485      * orientation change and the requested orientation is different from the parent.
2486      */
computeFullscreenBounds(@onNull Rect outBounds, @Nullable ActivityRecord refActivity, @NonNull Rect parentBounds, int parentOrientation)2487     void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
2488             @NonNull Rect parentBounds, int parentOrientation) {
2489         // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
2490         outBounds.setEmpty();
2491         if (handlesOrientationChangeFromDescendant()) {
2492             return;
2493         }
2494         if (refActivity == null) {
2495             // Use the top activity as the reference of orientation. Don't include overlays because
2496             // it is usually not the actual content or just temporarily shown.
2497             // E.g. ForcedResizableInfoActivity.
2498             refActivity = getTopNonFinishingActivity(false /* includeOverlays */);
2499         }
2500 
2501         // If the task or the reference activity requires a different orientation (either by
2502         // override or activityInfo), make it fit the available bounds by scaling down its bounds.
2503         final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
2504         final int forcedOrientation =
2505                 (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
2506                         ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
2507         if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
2508             return;
2509         }
2510 
2511         final int parentWidth = parentBounds.width();
2512         final int parentHeight = parentBounds.height();
2513         final float aspect = ((float) parentHeight) / parentWidth;
2514         if (forcedOrientation == ORIENTATION_LANDSCAPE) {
2515             final int height = (int) (parentWidth / aspect);
2516             final int top = parentBounds.centerY() - height / 2;
2517             outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
2518         } else {
2519             final int width = (int) (parentHeight * aspect);
2520             final int left = parentBounds.centerX() - width / 2;
2521             outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
2522         }
2523     }
2524 
updateOverrideConfigurationFromLaunchBounds()2525     Rect updateOverrideConfigurationFromLaunchBounds() {
2526         // If the task is controlled by another organized task, do not set override
2527         // configurations and let its parent (organized task) to control it;
2528         final Task rootTask = getRootTask();
2529         final Rect bounds = rootTask != this && rootTask.isOrganized() ? null : getLaunchBounds();
2530         setBounds(bounds);
2531         if (bounds != null && !bounds.isEmpty()) {
2532             // TODO: Review if we actually want to do this - we are setting the launch bounds
2533             // directly here.
2534             bounds.set(getRequestedOverrideBounds());
2535         }
2536         return bounds;
2537     }
2538 
2539     /** Updates the task's bounds and override configuration to match what is expected for the
2540      * input stack. */
updateOverrideConfigurationForStack(ActivityStack inStack)2541     void updateOverrideConfigurationForStack(ActivityStack inStack) {
2542         final ActivityStack stack = getStack();
2543 
2544         if (stack != null && stack == inStack) {
2545             return;
2546         }
2547 
2548         if (inStack.inFreeformWindowingMode()) {
2549             if (!isResizeable()) {
2550                 throw new IllegalArgumentException("Can not position non-resizeable task="
2551                         + this + " in stack=" + inStack);
2552             }
2553             if (!matchParentBounds()) {
2554                 return;
2555             }
2556             if (mLastNonFullscreenBounds != null) {
2557                 setBounds(mLastNonFullscreenBounds);
2558             } else {
2559                 mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
2560             }
2561         } else {
2562             setBounds(inStack.getRequestedOverrideBounds());
2563         }
2564     }
2565 
2566     /** Returns the bounds that should be used to launch this task. */
getLaunchBounds()2567     Rect getLaunchBounds() {
2568         final ActivityStack stack = getStack();
2569         if (stack == null) {
2570             return null;
2571         }
2572 
2573         final int windowingMode = getWindowingMode();
2574         if (!isActivityTypeStandardOrUndefined()
2575                 || windowingMode == WINDOWING_MODE_FULLSCREEN
2576                 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
2577             return isResizeable() ? stack.getRequestedOverrideBounds() : null;
2578         } else if (!getWindowConfiguration().persistTaskBounds()) {
2579             return stack.getRequestedOverrideBounds();
2580         }
2581         return mLastNonFullscreenBounds;
2582     }
2583 
setRootProcess(WindowProcessController proc)2584     void setRootProcess(WindowProcessController proc) {
2585         clearRootProcess();
2586         if (intent != null
2587                 && (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
2588             mRootProcess = proc;
2589             mRootProcess.addRecentTask(this);
2590         }
2591     }
2592 
clearRootProcess()2593     void clearRootProcess() {
2594         if (mRootProcess != null) {
2595             mRootProcess.removeRecentTask(this);
2596             mRootProcess = null;
2597         }
2598     }
2599 
2600     @Override
getDisplayContent()2601     DisplayContent getDisplayContent() {
2602         // TODO: Why aren't we just using our own display content vs. parent's???
2603         final ActivityStack stack = getStack();
2604         return stack != null && stack != this
2605                 ? stack.getDisplayContent() : super.getDisplayContent();
2606     }
2607 
getDisplayId()2608     int getDisplayId() {
2609         final DisplayContent dc = getDisplayContent();
2610         return dc != null ? dc.mDisplayId : INVALID_DISPLAY;
2611     }
2612 
2613     // TODO: Migrate callers to getRootTask()
getStack()2614     ActivityStack getStack() {
2615         return (ActivityStack) getRootTask();
2616     }
2617 
2618     /** @return Id of root task. */
getRootTaskId()2619     int getRootTaskId() {
2620         return getRootTask().mTaskId;
2621     }
2622 
getRootTask()2623     Task getRootTask() {
2624         final WindowContainer parent = getParent();
2625         if (parent == null) return this;
2626 
2627         final Task parentTask = parent.asTask();
2628         return parentTask == null ? this : parentTask.getRootTask();
2629     }
2630 
2631     // TODO(task-merge): Figure out what's the right thing to do for places that used it.
isRootTask()2632     boolean isRootTask() {
2633         return getRootTask() == this;
2634     }
2635 
isLeafTask()2636     boolean isLeafTask() {
2637         for (int i = mChildren.size() - 1; i >= 0; --i) {
2638             if (mChildren.get(i).asTask() != null) {
2639                 return false;
2640             }
2641         }
2642         return true;
2643     }
2644 
getDescendantTaskCount()2645     int getDescendantTaskCount() {
2646         final int[] currentCount = {0};
2647         final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; },
2648                 PooledLambda.__(Task.class), currentCount);
2649         forAllLeafTasks(c, false /* traverseTopToBottom */);
2650         c.recycle();
2651         return currentCount[0];
2652     }
2653 
2654     /**
2655      * Find next proper focusable stack and make it focused.
2656      * @return The stack that now got the focus, {@code null} if none found.
2657      */
adjustFocusToNextFocusableTask(String reason)2658     ActivityStack adjustFocusToNextFocusableTask(String reason) {
2659         return adjustFocusToNextFocusableTask(reason, false /* allowFocusSelf */,
2660                 true /* moveDisplayToTop */);
2661     }
2662 
2663     /** Return the next focusable task by looking from the siblings and parent tasks */
getNextFocusableTask(boolean allowFocusSelf)2664     private Task getNextFocusableTask(boolean allowFocusSelf) {
2665         final WindowContainer parent = getParent();
2666         if (parent == null) {
2667             return null;
2668         }
2669 
2670         final Task focusableTask = parent.getTask((task) -> (allowFocusSelf || task != this)
2671                 && ((ActivityStack) task).isFocusableAndVisible());
2672         if (focusableTask == null && parent.asTask() != null) {
2673             return parent.asTask().getNextFocusableTask(allowFocusSelf);
2674         } else {
2675             return focusableTask;
2676         }
2677     }
2678 
2679     /**
2680      * Find next proper focusable task and make it focused.
2681      * @param reason The reason of making the adjustment.
2682      * @param allowFocusSelf Is the focus allowed to remain on the same task.
2683      * @param moveDisplayToTop Whether to move display to top while making the task focused.
2684      * @return The root task that now got the focus, {@code null} if none found.
2685      */
adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, boolean moveDisplayToTop)2686     ActivityStack adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf,
2687             boolean moveDisplayToTop) {
2688         ActivityStack focusableTask = (ActivityStack) getNextFocusableTask(allowFocusSelf);
2689         if (focusableTask == null) {
2690             focusableTask = mRootWindowContainer.getNextFocusableStack((ActivityStack) this,
2691                     !allowFocusSelf);
2692         }
2693         if (focusableTask == null) {
2694             return null;
2695         }
2696 
2697         final ActivityStack rootTask = (ActivityStack) focusableTask.getRootTask();
2698         if (!moveDisplayToTop) {
2699             // There may be multiple task layers above this task, so when relocating the task to the
2700             // top, we should move this task and each of its parent task that below display area to
2701             // the top of each layer.
2702             WindowContainer parent = focusableTask.getParent();
2703             WindowContainer next = focusableTask;
2704             do {
2705                 parent.positionChildAt(POSITION_TOP, next, false /* includingParents */);
2706                 next = parent;
2707                 parent = next.getParent();
2708             } while (next.asTask() != null && parent != null);
2709             return rootTask;
2710         }
2711 
2712         final String myReason = reason + " adjustFocusToNextFocusableStack";
2713         final ActivityRecord top = focusableTask.topRunningActivity();
2714         if (focusableTask.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) {
2715             // If we will be focusing on the home stack next and its current top activity isn't
2716             // visible, then use the move the home stack task to top to make the activity visible.
2717             focusableTask.getDisplayArea().moveHomeActivityToTop(myReason);
2718             return rootTask;
2719         }
2720 
2721         // Move the entire hierarchy to top with updating global top resumed activity
2722         // and focused application if needed.
2723         focusableTask.moveToFront(myReason);
2724         // Top display focused stack is changed, update top resumed activity if needed.
2725         if (rootTask.mResumedActivity != null) {
2726             mStackSupervisor.updateTopResumedActivityIfNeeded();
2727             // Set focused app directly because if the next focused activity is already resumed
2728             // (e.g. the next top activity is on a different display), there won't have activity
2729             // state change to update it.
2730             mAtmService.setResumedActivityUncheckLocked(rootTask.mResumedActivity, reason);
2731         }
2732         return rootTask;
2733     }
2734 
2735     /** Calculate the minimum possible position for a task that can be shown to the user.
2736      *  The minimum position will be above all other tasks that can't be shown.
2737      *  @param minPosition The minimum position the caller is suggesting.
2738      *                  We will start adjusting up from here.
2739      *  @param size The size of the current task list.
2740      */
2741     // TODO: Move user to their own window container.
computeMinUserPosition(int minPosition, int size)2742     private int computeMinUserPosition(int minPosition, int size) {
2743         while (minPosition < size) {
2744             final WindowContainer child = mChildren.get(minPosition);
2745             final boolean canShow = child.showToCurrentUser();
2746             if (canShow) {
2747                 break;
2748             }
2749             minPosition++;
2750         }
2751         return minPosition;
2752     }
2753 
2754     /** Calculate the maximum possible position for a task that can't be shown to the user.
2755      *  The maximum position will be below all other tasks that can be shown.
2756      *  @param maxPosition The maximum position the caller is suggesting.
2757      *                  We will start adjusting down from here.
2758      */
2759     // TODO: Move user to their own window container.
computeMaxUserPosition(int maxPosition)2760     private int computeMaxUserPosition(int maxPosition) {
2761         while (maxPosition > 0) {
2762             final WindowContainer child = mChildren.get(maxPosition);
2763             final boolean canShow = child.showToCurrentUser();
2764             if (!canShow) {
2765                 break;
2766             }
2767             maxPosition--;
2768         }
2769         return maxPosition;
2770     }
2771 
getAdjustedChildPosition(WindowContainer wc, int suggestedPosition)2772     private int getAdjustedChildPosition(WindowContainer wc, int suggestedPosition) {
2773         final boolean canShowChild = wc.showToCurrentUser();
2774 
2775         final int size = mChildren.size();
2776 
2777         // Figure-out min/max possible position depending on if child can show for current user.
2778         int minPosition = (canShowChild) ? computeMinUserPosition(0, size) : 0;
2779         int maxPosition = (canShowChild) ? size : computeMaxUserPosition(size - 1);
2780 
2781         // Factor in always-on-top children in max possible position.
2782         if (!wc.isAlwaysOnTop()) {
2783 
2784             // We want to place all non-always-on-top containers below always-on-top ones.
2785             while (maxPosition > minPosition) {
2786                 if (!mChildren.get(maxPosition - 1).isAlwaysOnTop()) break;
2787                 --maxPosition;
2788             }
2789         }
2790 
2791         // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid.
2792         if (suggestedPosition == POSITION_BOTTOM && minPosition == 0) {
2793             return POSITION_BOTTOM;
2794         } else if (suggestedPosition == POSITION_TOP && maxPosition >= (size - 1)) {
2795             return POSITION_TOP;
2796         }
2797         // Reset position based on minimum/maximum possible positions.
2798         return Math.min(Math.max(suggestedPosition, minPosition), maxPosition);
2799     }
2800 
2801     @Override
positionChildAt(int position, WindowContainer child, boolean includingParents)2802     void positionChildAt(int position, WindowContainer child, boolean includingParents) {
2803         position = getAdjustedChildPosition(child, position);
2804         super.positionChildAt(position, child, includingParents);
2805 
2806         // Log positioning.
2807         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "positionChildAt: child=" + child
2808                 + " position=" + position + " parent=" + this);
2809 
2810         final int toTop = position >= (mChildren.size() - 1) ? 1 : 0;
2811         final Task task = child.asTask();
2812         if (task != null) {
2813             EventLogTags.writeWmTaskMoved(task.mTaskId, toTop, position);
2814         }
2815     }
2816 
2817     @VisibleForTesting
hasWindowsAlive()2818     boolean hasWindowsAlive() {
2819         return getActivity(ActivityRecord::hasWindowsAlive) != null;
2820     }
2821 
2822     @VisibleForTesting
shouldDeferRemoval()2823     boolean shouldDeferRemoval() {
2824         if (mChildren.isEmpty()) {
2825             // No reason to defer removal of a Task that doesn't have any child.
2826             return false;
2827         }
2828         return hasWindowsAlive() && getStack().isAnimating(TRANSITION | CHILDREN);
2829     }
2830 
2831     @Override
removeImmediately()2832     void removeImmediately() {
2833         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
2834         EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask");
2835 
2836         if (mDisplayContent != null && mDisplayContent.isSingleTaskInstance()) {
2837             mAtmService.notifySingleTaskDisplayEmpty(mDisplayContent.mDisplayId);
2838         }
2839 
2840         // If applicable let the TaskOrganizer know the Task is vanishing.
2841         setTaskOrganizer(null);
2842 
2843         super.removeImmediately();
2844     }
2845 
2846     // TODO: Consolidate this with Task.reparent()
reparent(ActivityStack stack, int position, boolean moveParents, String reason)2847     void reparent(ActivityStack stack, int position, boolean moveParents, String reason) {
2848         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
2849                 + " from stack=" + getStack());
2850         EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason);
2851 
2852         reparent(stack, position);
2853 
2854         stack.positionChildAt(position, this, moveParents);
2855 
2856         // If we are moving from the fullscreen stack to the pinned stack then we want to preserve
2857         // our insets so that there will not be a jump in the area covered by system decorations.
2858         // We rely on the pinned animation to later unset this value.
2859         mPreserveNonFloatingState = stack.inPinnedWindowingMode();
2860     }
2861 
setBounds(Rect bounds, boolean forceResize)2862     public int setBounds(Rect bounds, boolean forceResize) {
2863         final int boundsChanged = setBounds(bounds);
2864 
2865         if (forceResize && (boundsChanged & BOUNDS_CHANGE_SIZE) != BOUNDS_CHANGE_SIZE) {
2866             onResize();
2867             return BOUNDS_CHANGE_SIZE | boundsChanged;
2868         }
2869 
2870         return boundsChanged;
2871     }
2872 
2873     /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
2874     @Override
setBounds(Rect bounds)2875     public int setBounds(Rect bounds) {
2876         int rotation = Surface.ROTATION_0;
2877         final DisplayContent displayContent = getStack() != null
2878                 ? getStack().getDisplayContent() : null;
2879         if (displayContent != null) {
2880             rotation = displayContent.getDisplayInfo().rotation;
2881         }
2882 
2883         final int boundsChange = super.setBounds(bounds);
2884         mRotation = rotation;
2885         updateSurfacePosition();
2886         return boundsChange;
2887     }
2888 
2889     @Override
onDescendantOrientationChanged(IBinder freezeDisplayToken, ConfigurationContainer requestingContainer)2890     public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
2891             ConfigurationContainer requestingContainer) {
2892         if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) {
2893             return true;
2894         }
2895 
2896         // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill
2897         // it if possible.
2898         if (getParent() != null) {
2899             onConfigurationChanged(getParent().getConfiguration());
2900             return true;
2901         }
2902         return false;
2903     }
2904 
resize(boolean relayout, boolean forced)2905     void resize(boolean relayout, boolean forced) {
2906         if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) {
2907             getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
2908         }
2909     }
2910 
2911     @Override
onDisplayChanged(DisplayContent dc)2912     void onDisplayChanged(DisplayContent dc) {
2913         final boolean isRootTask = isRootTask();
2914         if (!isRootTask) {
2915             adjustBoundsForDisplayChangeIfNeeded(dc);
2916         }
2917         super.onDisplayChanged(dc);
2918         if (isLeafTask()) {
2919             final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY;
2920             mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged(
2921                     mTaskId, displayId);
2922         }
2923     }
2924 
isResizeable(boolean checkSupportsPip)2925     boolean isResizeable(boolean checkSupportsPip) {
2926         return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
2927                 || (checkSupportsPip && mSupportsPictureInPicture));
2928     }
2929 
isResizeable()2930     boolean isResizeable() {
2931         return isResizeable(true /* checkSupportsPip */);
2932     }
2933 
2934     /**
2935      * Tests if the orientation should be preserved upon user interactive resizig operations.
2936 
2937      * @return true if orientation should not get changed upon resizing operation.
2938      */
preserveOrientationOnResize()2939     boolean preserveOrientationOnResize() {
2940         return mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY
2941                 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY
2942                 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
2943     }
2944 
cropWindowsToStackBounds()2945     boolean cropWindowsToStackBounds() {
2946         // Don't crop HOME/RECENTS windows to stack bounds. This is because in split-screen
2947         // they extend past their stack and sysui uses the stack surface to control cropping.
2948         // TODO(b/158242495): get rid of this when drag/drop can use surface bounds.
2949         if (isActivityTypeHome() || isActivityTypeRecents()) {
2950             // Make sure this is the top-most non-organizer root task (if not top-most, it means
2951             // another translucent task could be above this, so this needs to stay cropped.
2952             final Task rootTask = getRootTask();
2953             final Task topNonOrgTask =
2954                     rootTask.mCreatedByOrganizer ? rootTask.getTopMostTask() : rootTask;
2955             if (this == topNonOrgTask || isDescendantOf(topNonOrgTask)) {
2956                 return false;
2957             }
2958         }
2959         return isResizeable();
2960     }
2961 
2962     /**
2963      * Prepares the task bounds to be frozen with the current size. See
2964      * {@link ActivityRecord#freezeBounds}.
2965      */
prepareFreezingBounds()2966     void prepareFreezingBounds() {
2967         mPreparedFrozenBounds.set(getBounds());
2968         mPreparedFrozenMergedConfig.setTo(getConfiguration());
2969     }
2970 
2971     @Override
getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, Rect outSurfaceInsets)2972     void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
2973             Rect outSurfaceInsets) {
2974         final WindowState windowState = getTopVisibleAppMainWindow();
2975         if (windowState != null) {
2976             windowState.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
2977         } else {
2978             super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
2979         }
2980     }
2981 
2982     /**
2983      * Calculate the maximum visible area of this task. If the task has only one app,
2984      * the result will be visible frame of that app. If the task has more than one apps,
2985      * we search from top down if the next app got different visible area.
2986      *
2987      * This effort is to handle the case where some task (eg. GMail composer) might pop up
2988      * a dialog that's different in size from the activity below, in which case we should
2989      * be dimming the entire task area behind the dialog.
2990      *
2991      * @param out Rect containing the max visible bounds.
2992      * @return true if the task has some visible app windows; false otherwise.
2993      */
getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop)2994     private static void getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop) {
2995         // skip hidden (or about to hide) apps
2996         if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) {
2997             return;
2998         }
2999         final WindowState win = token.findMainWindow();
3000         if (win == null) {
3001             return;
3002         }
3003         if (!foundTop[0]) {
3004             foundTop[0] = true;
3005             out.setEmpty();
3006         }
3007 
3008         win.getMaxVisibleBounds(out);
3009     }
3010 
3011     /** Bounds of the task to be used for dimming, as well as touch related tests. */
getDimBounds(Rect out)3012     void getDimBounds(Rect out) {
3013         final DisplayContent displayContent = getStack().getDisplayContent();
3014         // It doesn't matter if we in particular are part of the resize, since we couldn't have
3015         // a DimLayer anyway if we weren't visible.
3016         final boolean dockedResizing = displayContent != null
3017                 && displayContent.mDividerControllerLocked.isResizing();
3018         if (inFreeformWindowingMode()) {
3019             boolean[] foundTop = { false };
3020             final PooledConsumer c = PooledLambda.obtainConsumer(Task::getMaxVisibleBounds,
3021                     PooledLambda.__(ActivityRecord.class), out, foundTop);
3022             forAllActivities(c);
3023             c.recycle();
3024             if (foundTop[0]) {
3025                 return;
3026             }
3027         }
3028 
3029         if (!matchParentBounds()) {
3030             // When minimizing the docked stack when going home, we don't adjust the task bounds
3031             // so we need to intersect the task bounds with the stack bounds here.
3032             //
3033             // If we are Docked Resizing with snap points, the task bounds could be smaller than the
3034             // stack bounds and so we don't even want to use them. Even if the app should not be
3035             // resized the Dim should keep up with the divider.
3036             if (dockedResizing) {
3037                 getStack().getBounds(out);
3038             } else {
3039                 getStack().getBounds(mTmpRect);
3040                 mTmpRect.intersect(getBounds());
3041                 out.set(mTmpRect);
3042             }
3043         } else {
3044             out.set(getBounds());
3045         }
3046         return;
3047     }
3048 
setDragResizing(boolean dragResizing, int dragResizeMode)3049     void setDragResizing(boolean dragResizing, int dragResizeMode) {
3050         if (mDragResizing != dragResizing) {
3051             // No need to check if the mode is allowed if it's leaving dragResize
3052             if (dragResizing && !DragResizeMode.isModeAllowedForStack(getStack(), dragResizeMode)) {
3053                 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
3054                         + getRootTaskId() + " dragResizeMode=" + dragResizeMode);
3055             }
3056             mDragResizing = dragResizing;
3057             mDragResizeMode = dragResizeMode;
3058             resetDragResizingChangeReported();
3059         }
3060     }
3061 
isDragResizing()3062     boolean isDragResizing() {
3063         return mDragResizing;
3064     }
3065 
getDragResizeMode()3066     int getDragResizeMode() {
3067         return mDragResizeMode;
3068     }
3069 
adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent)3070     void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
3071         if (displayContent == null) {
3072             return;
3073         }
3074         if (matchParentBounds()) {
3075             // TODO: Yeah...not sure if this works with WindowConfiguration, but shouldn't be a
3076             // problem once we move mBounds into WindowConfiguration.
3077             setBounds(null);
3078             return;
3079         }
3080         final int displayId = displayContent.getDisplayId();
3081         final int newRotation = displayContent.getDisplayInfo().rotation;
3082         if (displayId != mLastRotationDisplayId) {
3083             // This task is on a display that it wasn't on. There is no point to keep the relative
3084             // position if display rotations for old and new displays are different. Just keep these
3085             // values.
3086             mLastRotationDisplayId = displayId;
3087             mRotation = newRotation;
3088             return;
3089         }
3090 
3091         if (mRotation == newRotation) {
3092             // Rotation didn't change. We don't need to adjust the bounds to keep the relative
3093             // position.
3094             return;
3095         }
3096 
3097         // Device rotation changed.
3098         // - We don't want the task to move around on the screen when this happens, so update the
3099         //   task bounds so it stays in the same place.
3100         // - Rotate the bounds and notify activity manager if the task can be resized independently
3101         //   from its stack. The stack will take care of task rotation for the other case.
3102         mTmpRect2.set(getBounds());
3103 
3104         if (!getWindowConfiguration().canResizeTask()) {
3105             setBounds(mTmpRect2);
3106             return;
3107         }
3108 
3109         displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
3110         if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) {
3111             mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
3112         }
3113     }
3114 
3115     /** Cancels any running app transitions associated with the task. */
cancelTaskWindowTransition()3116     void cancelTaskWindowTransition() {
3117         for (int i = mChildren.size() - 1; i >= 0; --i) {
3118             mChildren.get(i).cancelAnimation();
3119         }
3120     }
3121 
showForAllUsers()3122     boolean showForAllUsers() {
3123         if (mChildren.isEmpty()) return false;
3124         final ActivityRecord r = getTopNonFinishingActivity();
3125         return r != null && r.mShowForAllUsers;
3126     }
3127 
3128     @Override
showToCurrentUser()3129     boolean showToCurrentUser() {
3130         return mForceShowForAllUsers || showForAllUsers()
3131                 || mWmService.isCurrentProfile(getTopMostTask().mUserId);
3132     }
3133 
setForceShowForAllUsers(boolean forceShowForAllUsers)3134     void setForceShowForAllUsers(boolean forceShowForAllUsers) {
3135         mForceShowForAllUsers = forceShowForAllUsers;
3136     }
3137 
3138     @Override
isAttached()3139     public boolean isAttached() {
3140         final TaskDisplayArea taskDisplayArea = getDisplayArea();
3141         return taskDisplayArea != null && !taskDisplayArea.isRemoved();
3142     }
3143 
3144     @Override
3145     @Nullable
getDisplayArea()3146     TaskDisplayArea getDisplayArea() {
3147         return (TaskDisplayArea) super.getDisplayArea();
3148     }
3149 
3150     /**
3151      * When we are in a floating stack (Freeform, Pinned, ...) we calculate
3152      * insets differently. However if we are animating to the fullscreen stack
3153      * we need to begin calculating insets as if we were fullscreen, otherwise
3154      * we will have a jump at the end.
3155      */
isFloating()3156     boolean isFloating() {
3157         return getWindowConfiguration().tasksAreFloating() && !mPreserveNonFloatingState;
3158     }
3159 
3160     /**
3161      * Returns true if the stack is translucent and can have other contents visible behind it if
3162      * needed. A stack is considered translucent if it don't contain a visible or
3163      * starting (about to be visible) activity that is fullscreen (opaque).
3164      * @param starting The currently starting activity or null if there is none.
3165      */
3166     @VisibleForTesting
isTranslucent(ActivityRecord starting)3167     boolean isTranslucent(ActivityRecord starting) {
3168         if (!isAttached() || isForceHidden()) {
3169             return true;
3170         }
3171         final PooledPredicate p = PooledLambda.obtainPredicate(Task::isOpaqueActivity,
3172                 PooledLambda.__(ActivityRecord.class), starting);
3173         final ActivityRecord opaque = getActivity(p);
3174         p.recycle();
3175         return opaque == null;
3176     }
3177 
isOpaqueActivity(ActivityRecord r, ActivityRecord starting)3178     private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) {
3179         if (r.finishing) {
3180             // We don't factor in finishing activities when determining translucency since
3181             // they will be gone soon.
3182             return false;
3183         }
3184 
3185         if (!r.visibleIgnoringKeyguard && r != starting) {
3186             // Also ignore invisible activities that are not the currently starting
3187             // activity (about to be visible).
3188             return false;
3189         }
3190 
3191         if (r.occludesParent() || r.hasWallpaper) {
3192             // Stack isn't translucent if it has at least one fullscreen activity
3193             // that is visible.
3194             return true;
3195         }
3196         return false;
3197     }
3198 
3199     @Override
makeAnimationLeash()3200     public SurfaceControl.Builder makeAnimationLeash() {
3201         return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId);
3202     }
3203 
3204     @Override
getAnimationLeashParent()3205     public SurfaceControl getAnimationLeashParent() {
3206         if (WindowManagerService.sHierarchicalAnimations) {
3207             return super.getAnimationLeashParent();
3208         }
3209         // Currently, only the recents animation will create animation leashes for tasks. In this
3210         // case, reparent the task to the home animation layer while it is being animated to allow
3211         // the home activity to reorder the app windows relative to its own.
3212         return getAppAnimationLayer(ANIMATION_LAYER_HOME);
3213     }
3214 
3215     @Override
getAnimationBounds(int appStackClipMode)3216     Rect getAnimationBounds(int appStackClipMode) {
3217         // TODO(b/131661052): we should remove appStackClipMode with hierarchical animations.
3218         if (appStackClipMode == STACK_CLIP_BEFORE_ANIM && getStack() != null) {
3219             // Using the stack bounds here effectively applies the clipping before animation.
3220             return getStack().getBounds();
3221         }
3222         return super.getAnimationBounds(appStackClipMode);
3223     }
3224 
shouldAnimate()3225     boolean shouldAnimate() {
3226         /**
3227          * Animations are handled by the TaskOrganizer implementation.
3228          */
3229         if (isOrganized()) {
3230             return false;
3231         }
3232         // Don't animate while the task runs recents animation but only if we are in the mode
3233         // where we cancel with deferred screenshot, which means that the controller has
3234         // transformed the task.
3235         final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
3236         if (controller != null && controller.isAnimatingTask(this)
3237                 && controller.shouldDeferCancelUntilNextTransition()) {
3238             return false;
3239         }
3240         return true;
3241     }
3242 
3243     @Override
setInitialSurfaceControlProperties(SurfaceControl.Builder b)3244     void setInitialSurfaceControlProperties(SurfaceControl.Builder b) {
3245         b.setEffectLayer().setMetadata(METADATA_TASK_ID, mTaskId);
3246         super.setInitialSurfaceControlProperties(b);
3247     }
3248 
isTaskAnimating()3249     boolean isTaskAnimating() {
3250         final RecentsAnimationController recentsAnim = mWmService.getRecentsAnimationController();
3251         if (recentsAnim != null) {
3252             if (recentsAnim.isAnimatingTask(this)) {
3253                 return true;
3254             }
3255         }
3256         return forAllTasks((t) -> { return t != this && t.isTaskAnimating(); });
3257     }
3258 
3259     @Override
createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record)3260     RemoteAnimationTarget createRemoteAnimationTarget(
3261             RemoteAnimationController.RemoteAnimationRecord record) {
3262         final ActivityRecord activity = getTopMostActivity();
3263         return activity != null ? activity.createRemoteAnimationTarget(record) : null;
3264     }
3265 
3266     @Override
canCreateRemoteAnimationTarget()3267     boolean canCreateRemoteAnimationTarget() {
3268         return true;
3269     }
3270 
getTopVisibleAppMainWindow()3271     WindowState getTopVisibleAppMainWindow() {
3272         final ActivityRecord activity = getTopVisibleActivity();
3273         return activity != null ? activity.findMainWindow() : null;
3274     }
3275 
topRunningActivity()3276     ActivityRecord topRunningActivity() {
3277         return topRunningActivity(false /* focusableOnly */);
3278     }
3279 
topRunningActivity(boolean focusableOnly)3280     ActivityRecord topRunningActivity(boolean focusableOnly) {
3281         // Split into 2 to avoid object creation due to variable capture.
3282         if (focusableOnly) {
3283             return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
3284         } else {
3285             return getActivity(ActivityRecord::canBeTopRunning);
3286         }
3287     }
3288 
topRunningNonDelayedActivityLocked(ActivityRecord notTop)3289     ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
3290         final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunningNonDelayed
3291                 , PooledLambda.__(ActivityRecord.class), notTop);
3292         final ActivityRecord r = getActivity(p);
3293         p.recycle();
3294         return r;
3295     }
3296 
isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop)3297     private static boolean isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop) {
3298         return !r.delayedResume && r != notTop && r.canBeTopRunning();
3299     }
3300 
3301     /**
3302      * This is a simplified version of topRunningActivity that provides a number of
3303      * optional skip-over modes.  It is intended for use with the ActivityController hook only.
3304      *
3305      * @param token If non-null, any history records matching this token will be skipped.
3306      * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
3307      *
3308      * @return Returns the HistoryRecord of the next activity on the stack.
3309      */
topRunningActivity(IBinder token, int taskId)3310     ActivityRecord topRunningActivity(IBinder token, int taskId) {
3311         final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunning,
3312                 PooledLambda.__(ActivityRecord.class), taskId, token);
3313         final ActivityRecord r = getActivity(p);
3314         p.recycle();
3315         return r;
3316     }
3317 
isTopRunning(ActivityRecord r, int taskId, IBinder notTop)3318     private static boolean isTopRunning(ActivityRecord r, int taskId, IBinder notTop) {
3319         return r.getTask().mTaskId != taskId && r.appToken != notTop && r.canBeTopRunning();
3320     }
3321 
getTopFullscreenActivity()3322     ActivityRecord getTopFullscreenActivity() {
3323         return getActivity((r) -> {
3324             final WindowState win = r.findMainWindow();
3325             return (win != null && win.mAttrs.isFullscreen());
3326         });
3327     }
3328 
3329     ActivityRecord getTopVisibleActivity() {
3330         return getActivity((r) -> {
3331             // skip hidden (or about to hide) apps
3332             return !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested;
3333         });
3334     }
3335 
3336     boolean isTopActivityFocusable() {
3337         final ActivityRecord r = topRunningActivity();
3338         return r != null ? r.isFocusable()
3339                 : (isFocusable() && getWindowConfiguration().canReceiveKeys());
3340     }
3341 
3342     boolean isFocusableAndVisible() {
3343         return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
3344     }
3345 
3346     void positionChildAtTop(ActivityRecord child) {
3347         positionChildAt(child, POSITION_TOP);
3348     }
3349 
3350     void positionChildAt(ActivityRecord child, int position) {
3351         if (child == null) {
3352             Slog.w(TAG_WM,
3353                     "Attempted to position of non-existing app");
3354             return;
3355         }
3356 
3357         positionChildAt(position, child, false /* includeParents */);
3358     }
3359 
3360     void forceWindowsScaleable(boolean force) {
3361         mWmService.openSurfaceTransaction();
3362         try {
3363             for (int i = mChildren.size() - 1; i >= 0; i--) {
3364                 mChildren.get(i).forceWindowsScaleableInTransaction(force);
3365             }
3366         } finally {
3367             mWmService.closeSurfaceTransaction("forceWindowsScaleable");
3368         }
3369     }
3370 
3371     void setTaskDescription(TaskDescription taskDescription) {
3372         mTaskDescription = taskDescription;
3373     }
3374 
3375     void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
3376         mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(
3377                 mTaskId, snapshot);
3378     }
3379 
3380     TaskDescription getTaskDescription() {
3381         return mTaskDescription;
3382     }
3383 
3384     @Override
3385     int getOrientation(int candidate) {
3386         return canSpecifyOrientation() ? super.getOrientation(candidate) : SCREEN_ORIENTATION_UNSET;
3387     }
3388 
3389     private boolean canSpecifyOrientation() {
3390         final int windowingMode = getWindowingMode();
3391         final int activityType = getActivityType();
3392         return windowingMode == WINDOWING_MODE_FULLSCREEN
3393                 || activityType == ACTIVITY_TYPE_HOME
3394                 || activityType == ACTIVITY_TYPE_RECENTS
3395                 || activityType == ACTIVITY_TYPE_ASSISTANT;
3396     }
3397 
3398     @Override
3399     boolean fillsParent() {
3400         return matchParentBounds();
3401     }
3402 
3403     @Override
3404     void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
3405         final int count = mChildren.size();
3406         boolean isLeafTask = true;
3407         if (traverseTopToBottom) {
3408             for (int i = count - 1; i >= 0; --i) {
3409                 final Task child = mChildren.get(i).asTask();
3410                 if (child != null) {
3411                     isLeafTask = false;
3412                     child.forAllLeafTasks(callback, traverseTopToBottom);
3413                 }
3414             }
3415         } else {
3416             for (int i = 0; i < count; i++) {
3417                 final Task child = mChildren.get(i).asTask();
3418                 if (child != null) {
3419                     isLeafTask = false;
3420                     child.forAllLeafTasks(callback, traverseTopToBottom);
3421                 }
3422             }
3423         }
3424         if (isLeafTask) callback.accept(this);
3425     }
3426 
3427     @Override
3428     void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
3429         super.forAllTasks(callback, traverseTopToBottom);
3430         callback.accept(this);
3431     }
3432 
3433     @Override
3434     boolean forAllTasks(Function<Task, Boolean> callback) {
3435         if (super.forAllTasks(callback)) return true;
3436         return callback.apply(this);
3437     }
3438 
3439     @Override
3440     boolean forAllLeafTasks(Function<Task, Boolean> callback) {
3441         boolean isLeafTask = true;
3442         for (int i = mChildren.size() - 1; i >= 0; --i) {
3443             final Task child = mChildren.get(i).asTask();
3444             if (child != null) {
3445                 isLeafTask = false;
3446                 if (child.forAllLeafTasks(callback)) {
3447                     return true;
3448                 }
3449             }
3450         }
3451         if (isLeafTask) {
3452             return callback.apply(this);
3453         }
3454         return false;
3455     }
3456 
3457     @Override
3458     Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) {
3459         final Task t = super.getTask(callback, traverseTopToBottom);
3460         if (t != null) return t;
3461         return callback.test(this) ? this : null;
3462     }
3463 
3464     /**
3465      * @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI
3466      *                               flags. See {@link WindowState#canAffectSystemUiFlags()}.
3467      */
3468     void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) {
3469         mCanAffectSystemUiFlags = canAffectSystemUiFlags;
3470     }
3471 
3472     /**
3473      * @see #setCanAffectSystemUiFlags
3474      */
3475     boolean canAffectSystemUiFlags() {
3476         return mCanAffectSystemUiFlags;
3477     }
3478 
3479     void dontAnimateDimExit() {
3480         mDimmer.dontAnimateExit();
3481     }
3482 
3483     String getName() {
3484         return "Task=" + mTaskId;
3485     }
3486 
3487     void clearPreserveNonFloatingState() {
3488         mPreserveNonFloatingState = false;
3489     }
3490 
3491     @Override
3492     Dimmer getDimmer() {
3493         // If the window is in multi-window mode, we want to dim at the Task level to ensure the dim
3494         // bounds match the area the app lives in
3495         if (inMultiWindowMode()) {
3496             return mDimmer;
3497         }
3498 
3499         // If we're not at the root task level, we want to keep traversing through the parents to
3500         // find the root.
3501         // Once at the root task level, we want to check {@link #isTranslucent(ActivityRecord)}.
3502         // If true, we want to get the Dimmer from the level above since we don't want to animate
3503         // the dim with the Task.
3504         if (!isRootTask() || isTranslucent(null)) {
3505             return super.getDimmer();
3506         }
3507 
3508         return mDimmer;
3509     }
3510 
3511     @Override
3512     void prepareSurfaces() {
3513         mDimmer.resetDimStates();
3514         super.prepareSurfaces();
3515         getDimBounds(mTmpDimBoundsRect);
3516 
3517         // Bounds need to be relative, as the dim layer is a child.
3518         if (inFreeformWindowingMode()) {
3519             getBounds(mTmpRect);
3520             mTmpDimBoundsRect.offsetTo(mTmpDimBoundsRect.left - mTmpRect.left,
3521                     mTmpDimBoundsRect.top - mTmpRect.top);
3522         } else {
3523             mTmpDimBoundsRect.offsetTo(0, 0);
3524         }
3525 
3526         updateShadowsRadius(isFocused(), getSyncTransaction());
3527 
3528         if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
3529             scheduleAnimation();
3530         }
3531     }
3532 
3533     @Override
3534     protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
3535             int transit, boolean isVoiceInteraction,
3536             @Nullable ArrayList<WindowContainer> sources) {
3537         final RecentsAnimationController control = mWmService.getRecentsAnimationController();
3538         if (control != null) {
3539             // We let the transition to be controlled by RecentsAnimation, and callback task's
3540             // RemoteAnimationTarget for remote runner to animate.
3541             if (enter) {
3542                 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
3543                         "applyAnimationUnchecked, control: %s, task: %s, transit: %s",
3544                         control, asTask(), AppTransition.appTransitionToString(transit));
3545                 control.addTaskToTargets(this, (type, anim) -> {
3546                     for (int i = 0; i < sources.size(); ++i) {
3547                         sources.get(i).onAnimationFinished(type, anim);
3548                     }
3549                 });
3550             }
3551         } else {
3552             super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
3553         }
3554     }
3555 
3556     @Override
3557     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
3558         super.dump(pw, prefix, dumpAll);
3559         pw.println(prefix + "bounds=" + getBounds().toShortString());
3560         final String doublePrefix = prefix + "  ";
3561         for (int i = mChildren.size() - 1; i >= 0; i--) {
3562             final WindowContainer<?> child = mChildren.get(i);
3563             pw.println(prefix + "* " + child);
3564             // Only dump non-activity because full activity info is already printed by
3565             // RootWindowContainer#dumpActivities.
3566             if (child.asActivityRecord() == null) {
3567                 child.dump(pw, doublePrefix, dumpAll);
3568             }
3569         }
3570     }
3571 
3572 
3573     /**
3574      * Fills in a {@link TaskInfo} with information from this task. Note that the base intent in the
3575      * task info will not include any extras or clip data.
3576      */
3577     void fillTaskInfo(TaskInfo info) {
3578         fillTaskInfo(info, true /* stripExtras */);
3579     }
3580 
3581     /**
3582      * Fills in a {@link TaskInfo} with information from this task.
3583      */
3584     void fillTaskInfo(TaskInfo info, boolean stripExtras) {
3585         getNumRunningActivities(mReuseActivitiesReport);
3586         info.userId = mUserId;
3587         info.stackId = getRootTaskId();
3588         info.taskId = mTaskId;
3589         info.displayId = getDisplayId();
3590         info.isRunning = getTopNonFinishingActivity() != null;
3591         final Intent baseIntent = getBaseIntent();
3592         // Make a copy of base intent because this is like a snapshot info.
3593         // Besides, {@link RecentTasks#getRecentTasksImpl} may modify it.
3594         final int baseIntentFlags = baseIntent == null ? 0 : baseIntent.getFlags();
3595         info.baseIntent = baseIntent == null
3596                 ? new Intent()
3597                 : stripExtras ? baseIntent.cloneFilter() : new Intent(baseIntent);
3598         info.baseIntent.setFlags(baseIntentFlags);
3599         info.baseActivity = mReuseActivitiesReport.base != null
3600                 ? mReuseActivitiesReport.base.intent.getComponent()
3601                 : null;
3602         info.topActivity = mReuseActivitiesReport.top != null
3603                 ? mReuseActivitiesReport.top.mActivityComponent
3604                 : null;
3605         info.origActivity = origActivity;
3606         info.realActivity = realActivity;
3607         info.numActivities = mReuseActivitiesReport.numActivities;
3608         info.lastActiveTime = lastActiveTime;
3609         info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
3610         info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
3611         info.configuration.setTo(getConfiguration());
3612         info.token = mRemoteToken.toWindowContainerToken();
3613 
3614         //TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child
3615         //                    order changes.
3616         final Task top = getTopMostTask();
3617         info.resizeMode = top != null ? top.mResizeMode : mResizeMode;
3618         info.topActivityType = top.getActivityType();
3619         info.isResizeable = isResizeable();
3620 
3621         ActivityRecord rootActivity = top.getRootActivity();
3622         if (rootActivity == null || rootActivity.pictureInPictureArgs.empty()) {
3623             info.pictureInPictureParams = null;
3624         } else {
3625             info.pictureInPictureParams = rootActivity.pictureInPictureArgs;
3626         }
3627         info.topActivityInfo = mReuseActivitiesReport.top != null
3628                 ? mReuseActivitiesReport.top.info
3629                 : null;
3630         info.requestedOrientation = mReuseActivitiesReport.base != null
3631                 ? mReuseActivitiesReport.base.getRequestedOrientation()
3632                 : SCREEN_ORIENTATION_UNSET;
3633     }
3634 
3635     /**
3636      * Returns a {@link TaskInfo} with information from this task.
3637      */
3638     ActivityManager.RunningTaskInfo getTaskInfo() {
3639         ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
3640         fillTaskInfo(info);
3641         return info;
3642     }
3643 
3644     boolean isTaskId(int taskId) {
3645         return mTaskId == taskId;
3646     }
3647 
3648     @Override
3649     Task asTask() {
3650         // I'm a task!
3651         return this;
3652     }
3653 
3654     /**
3655      * Returns true if the task should be visible.
3656      *
3657      * @param starting The currently starting activity or null if there is none.
3658      */
3659     boolean shouldBeVisible(ActivityRecord starting) {
3660         return getVisibility(starting) != STACK_VISIBILITY_INVISIBLE;
3661     }
3662 
3663     /**
3664      * Returns true if the task should be visible.
3665      *
3666      * @param starting The currently starting activity or null if there is none.
3667      */
3668     @ActivityStack.StackVisibility
3669     int getVisibility(ActivityRecord starting) {
3670         if (!isAttached() || isForceHidden()) {
3671             return STACK_VISIBILITY_INVISIBLE;
3672         }
3673 
3674         if (isTopActivityLaunchedBehind()) {
3675             return STACK_VISIBILITY_VISIBLE;
3676         }
3677 
3678         boolean gotSplitScreenStack = false;
3679         boolean gotOpaqueSplitScreenPrimary = false;
3680         boolean gotOpaqueSplitScreenSecondary = false;
3681         boolean gotTranslucentFullscreen = false;
3682         boolean gotTranslucentSplitScreenPrimary = false;
3683         boolean gotTranslucentSplitScreenSecondary = false;
3684         boolean shouldBeVisible = true;
3685 
3686         // This stack is only considered visible if all its parent stacks are considered visible,
3687         // so check the visibility of all ancestor stacks first.
3688         final WindowContainer parent = getParent();
3689         if (parent.asTask() != null) {
3690             final int parentVisibility = parent.asTask().getVisibility(starting);
3691             if (parentVisibility == STACK_VISIBILITY_INVISIBLE) {
3692                 // Can't be visible if parent isn't visible
3693                 return STACK_VISIBILITY_INVISIBLE;
3694             } else if (parentVisibility == STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) {
3695                 // Parent is behind a translucent container so the highest visibility this container
3696                 // can get is that.
3697                 gotTranslucentFullscreen = true;
3698             }
3699         }
3700 
3701         final int windowingMode = getWindowingMode();
3702         final boolean isAssistantType = isActivityTypeAssistant();
3703         for (int i = parent.getChildCount() - 1; i >= 0; --i) {
3704             final WindowContainer wc = parent.getChildAt(i);
3705             final Task other = wc.asTask();
3706             if (other == null) continue;
3707 
3708             final boolean hasRunningActivities = other.topRunningActivity() != null;
3709             if (other == this) {
3710                 // Should be visible if there is no other stack occluding it, unless it doesn't
3711                 // have any running activities, not starting one and not home stack.
3712                 shouldBeVisible = hasRunningActivities || isInTask(starting) != null
3713                         || isActivityTypeHome();
3714                 break;
3715             }
3716 
3717             if (!hasRunningActivities) {
3718                 continue;
3719             }
3720 
3721             final int otherWindowingMode = other.getWindowingMode();
3722 
3723             if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) {
3724                 if (other.isTranslucent(starting)) {
3725                     // Can be visible behind a translucent fullscreen stack.
3726                     gotTranslucentFullscreen = true;
3727                     continue;
3728                 }
3729                 return STACK_VISIBILITY_INVISIBLE;
3730             } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
3731                     && !gotOpaqueSplitScreenPrimary) {
3732                 gotSplitScreenStack = true;
3733                 gotTranslucentSplitScreenPrimary = other.isTranslucent(starting);
3734                 gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary;
3735                 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
3736                         && gotOpaqueSplitScreenPrimary) {
3737                     // Can not be visible behind another opaque stack in split-screen-primary mode.
3738                     return STACK_VISIBILITY_INVISIBLE;
3739                 }
3740             } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
3741                     && !gotOpaqueSplitScreenSecondary) {
3742                 gotSplitScreenStack = true;
3743                 gotTranslucentSplitScreenSecondary = other.isTranslucent(starting);
3744                 gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary;
3745                 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
3746                         && gotOpaqueSplitScreenSecondary) {
3747                     // Can not be visible behind another opaque stack in split-screen-secondary mode.
3748                     return STACK_VISIBILITY_INVISIBLE;
3749                 }
3750             }
3751             if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) {
3752                 // Can not be visible if we are in split-screen windowing mode and both halves of
3753                 // the screen are opaque.
3754                 return STACK_VISIBILITY_INVISIBLE;
3755             }
3756             if (isAssistantType && gotSplitScreenStack) {
3757                 // Assistant stack can't be visible behind split-screen. In addition to this not
3758                 // making sense, it also works around an issue here we boost the z-order of the
3759                 // assistant window surfaces in window manager whenever it is visible.
3760                 return STACK_VISIBILITY_INVISIBLE;
3761             }
3762         }
3763 
3764         if (!shouldBeVisible) {
3765             return STACK_VISIBILITY_INVISIBLE;
3766         }
3767 
3768         // Handle cases when there can be a translucent split-screen stack on top.
3769         switch (windowingMode) {
3770             case WINDOWING_MODE_FULLSCREEN:
3771                 if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) {
3772                     // At least one of the split-screen stacks that covers this one is translucent.
3773                     return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
3774                 }
3775                 break;
3776             case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
3777                 if (gotTranslucentSplitScreenPrimary) {
3778                     // Covered by translucent primary split-screen on top.
3779                     return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
3780                 }
3781                 break;
3782             case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
3783                 if (gotTranslucentSplitScreenSecondary) {
3784                     // Covered by translucent secondary split-screen on top.
3785                     return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
3786                 }
3787                 break;
3788         }
3789 
3790         // Lastly - check if there is a translucent fullscreen stack on top.
3791         return gotTranslucentFullscreen ? STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
3792                 : STACK_VISIBILITY_VISIBLE;
3793     }
3794 
3795     private boolean isTopActivityLaunchedBehind() {
3796         final ActivityRecord top = topRunningActivity();
3797         if (top != null && top.mLaunchTaskBehind) {
3798             return true;
3799         }
3800         return false;
3801     }
3802 
3803     ActivityRecord isInTask(ActivityRecord r) {
3804         if (r == null) {
3805             return null;
3806         }
3807         if (r.isDescendantOf(this)) {
3808             return r;
3809         }
3810         return null;
3811     }
3812 
3813     void dump(PrintWriter pw, String prefix) {
3814         pw.print(prefix); pw.print("userId="); pw.print(mUserId);
3815         pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
3816         pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
3817         pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
3818         pw.print(" mCallingPackage="); pw.print(mCallingPackage);
3819         pw.print(" mCallingFeatureId="); pw.println(mCallingFeatureId);
3820         if (affinity != null || rootAffinity != null) {
3821             pw.print(prefix); pw.print("affinity="); pw.print(affinity);
3822             if (affinity == null || !affinity.equals(rootAffinity)) {
3823                 pw.print(" root="); pw.println(rootAffinity);
3824             } else {
3825                 pw.println();
3826             }
3827         }
3828         if (mWindowLayoutAffinity != null) {
3829             pw.print(prefix); pw.print("windowLayoutAffinity="); pw.println(mWindowLayoutAffinity);
3830         }
3831         if (voiceSession != null || voiceInteractor != null) {
3832             pw.print(prefix); pw.print("VOICE: session=0x");
3833             pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
3834             pw.print(" interactor=0x");
3835             pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
3836         }
3837         if (intent != null) {
3838             StringBuilder sb = new StringBuilder(128);
3839             sb.append(prefix); sb.append("intent={");
3840             intent.toShortString(sb, false, true, false, false);
3841             sb.append('}');
3842             pw.println(sb.toString());
3843         }
3844         if (affinityIntent != null) {
3845             StringBuilder sb = new StringBuilder(128);
3846             sb.append(prefix); sb.append("affinityIntent={");
3847             affinityIntent.toShortString(sb, false, true, false, false);
3848             sb.append('}');
3849             pw.println(sb.toString());
3850         }
3851         if (origActivity != null) {
3852             pw.print(prefix); pw.print("origActivity=");
3853             pw.println(origActivity.flattenToShortString());
3854         }
3855         if (realActivity != null) {
3856             pw.print(prefix); pw.print("mActivityComponent=");
3857             pw.println(realActivity.flattenToShortString());
3858         }
3859         if (autoRemoveRecents || isPersistable || !isActivityTypeStandard()) {
3860             pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
3861             pw.print(" isPersistable="); pw.print(isPersistable);
3862             pw.print(" activityType="); pw.println(getActivityType());
3863         }
3864         if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
3865                 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
3866             pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
3867             pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
3868             pw.print(" mReuseTask="); pw.print(mReuseTask);
3869             pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
3870         }
3871         if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID
3872                 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
3873                 || mNextAffiliate != null) {
3874             pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
3875             pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
3876             pw.print(" (");
3877             if (mPrevAffiliate == null) {
3878                 pw.print("null");
3879             } else {
3880                 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
3881             }
3882             pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
3883             pw.print(" (");
3884             if (mNextAffiliate == null) {
3885                 pw.print("null");
3886             } else {
3887                 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
3888             }
3889             pw.println(")");
3890         }
3891         pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
3892         if (!askedCompatMode || !inRecents || !isAvailable) {
3893             pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
3894             pw.print(" inRecents="); pw.print(inRecents);
3895             pw.print(" isAvailable="); pw.println(isAvailable);
3896         }
3897         if (lastDescription != null) {
3898             pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
3899         }
3900         if (mRootProcess != null) {
3901             pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
3902         }
3903         pw.print(prefix); pw.print("taskId=" + mTaskId); pw.println(" stackId=" + getRootTaskId());
3904         pw.print(prefix); pw.print("mHasBeenVisible="); pw.println(getHasBeenVisible());
3905         pw.print(prefix); pw.print("mResizeMode=");
3906         pw.print(ActivityInfo.resizeModeToString(mResizeMode));
3907         pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture);
3908         pw.print(" isResizeable="); pw.println(isResizeable());
3909         pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
3910         pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
3911     }
3912 
3913     @Override
3914     public String toString() {
3915         StringBuilder sb = new StringBuilder(128);
3916         if (stringName != null) {
3917             sb.append(stringName);
3918             sb.append(" U=");
3919             sb.append(mUserId);
3920             sb.append(" StackId=");
3921             sb.append(getRootTaskId());
3922             sb.append(" sz=");
3923             sb.append(getChildCount());
3924             sb.append('}');
3925             return sb.toString();
3926         }
3927         sb.append("Task{");
3928         sb.append(Integer.toHexString(System.identityHashCode(this)));
3929         sb.append(" #");
3930         sb.append(mTaskId);
3931         sb.append(" visible=" + shouldBeVisible(null /* starting */));
3932         sb.append(" type=" + activityTypeToString(getActivityType()));
3933         sb.append(" mode=" + windowingModeToString(getWindowingMode()));
3934         sb.append(" translucent=" + isTranslucent(null /* starting */));
3935         if (affinity != null) {
3936             sb.append(" A=");
3937             sb.append(affinity);
3938         } else if (intent != null && intent.getComponent() != null) {
3939             sb.append(" I=");
3940             sb.append(intent.getComponent().flattenToShortString());
3941         } else if (affinityIntent != null && affinityIntent.getComponent() != null) {
3942             sb.append(" aI=");
3943             sb.append(affinityIntent.getComponent().flattenToShortString());
3944         } else {
3945             sb.append(" ??");
3946         }
3947         stringName = sb.toString();
3948         return toString();
3949     }
3950 
3951     /** @see #getNumRunningActivities(TaskActivitiesReport) */
3952     static class TaskActivitiesReport implements Consumer<ActivityRecord> {
3953         int numRunning;
3954         int numActivities;
3955         ActivityRecord top;
3956         ActivityRecord base;
3957 
3958         void reset() {
3959             numRunning = numActivities = 0;
3960             top = base = null;
3961         }
3962 
3963         @Override
3964         public void accept(ActivityRecord r) {
3965             if (r.finishing) {
3966                 return;
3967             }
3968 
3969             base = r;
3970 
3971             // Increment the total number of non-finishing activities
3972             numActivities++;
3973 
3974             if (top == null || (top.isState(ActivityState.INITIALIZING))) {
3975                 top = r;
3976                 // Reset the number of running activities until we hit the first non-initializing
3977                 // activity
3978                 numRunning = 0;
3979             }
3980             if (r.attachedToProcess()) {
3981                 // Increment the number of actually running activities
3982                 numRunning++;
3983             }
3984         }
3985     }
3986 
3987     /**
3988      * Saves this {@link Task} to XML using given serializer.
3989      */
3990     void saveToXml(XmlSerializer out) throws Exception {
3991         if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
3992 
3993         out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
3994         if (realActivity != null) {
3995             out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
3996         }
3997         out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
3998         if (origActivity != null) {
3999             out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
4000         }
4001         // Write affinity, and root affinity if it is different from affinity.
4002         // We use the special string "@" for a null root affinity, so we can identify
4003         // later whether we were given a root affinity or should just make it the
4004         // same as the affinity.
4005         if (affinity != null) {
4006             out.attribute(null, ATTR_AFFINITY, affinity);
4007             if (!affinity.equals(rootAffinity)) {
4008                 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
4009             }
4010         } else if (rootAffinity != null) {
4011             out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
4012         }
4013         if (mWindowLayoutAffinity != null) {
4014             out.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
4015         }
4016         out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
4017         out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
4018         out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
4019         out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
4020         out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
4021         out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
4022         out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
4023         out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
4024         if (lastDescription != null) {
4025             out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
4026         }
4027         if (getTaskDescription() != null) {
4028             getTaskDescription().saveToXml(out);
4029         }
4030         out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
4031         out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
4032         out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
4033         out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
4034         out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
4035         out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
4036         out.attribute(null, ATTR_CALLING_FEATURE_ID,
4037                 mCallingFeatureId == null ? "" : mCallingFeatureId);
4038         out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
4039         out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
4040                 String.valueOf(mSupportsPictureInPicture));
4041         if (mLastNonFullscreenBounds != null) {
4042             out.attribute(
4043                     null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
4044         }
4045         out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
4046         out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
4047         out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
4048 
4049         if (affinityIntent != null) {
4050             out.startTag(null, TAG_AFFINITYINTENT);
4051             affinityIntent.saveToXml(out);
4052             out.endTag(null, TAG_AFFINITYINTENT);
4053         }
4054 
4055         if (intent != null) {
4056             out.startTag(null, TAG_INTENT);
4057             intent.saveToXml(out);
4058             out.endTag(null, TAG_INTENT);
4059         }
4060 
4061         sTmpException = null;
4062         final PooledFunction f = PooledLambda.obtainFunction(Task::saveActivityToXml,
4063                 PooledLambda.__(ActivityRecord.class), getBottomMostActivity(), out);
4064         forAllActivities(f);
4065         f.recycle();
4066         if (sTmpException != null) {
4067             throw sTmpException;
4068         }
4069     }
4070 
4071     private static boolean saveActivityToXml(
4072             ActivityRecord r, ActivityRecord first, XmlSerializer out) {
4073         if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
4074                 || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
4075                 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
4076                 && r != first) {
4077             // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
4078             return true;
4079         }
4080         try {
4081             out.startTag(null, TAG_ACTIVITY);
4082             r.saveToXml(out);
4083             out.endTag(null, TAG_ACTIVITY);
4084             return false;
4085         } catch (Exception e) {
4086             sTmpException = e;
4087             return true;
4088         }
4089     }
4090 
4091     static Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
4092             throws IOException, XmlPullParserException {
4093         Intent intent = null;
4094         Intent affinityIntent = null;
4095         ArrayList<ActivityRecord> activities = new ArrayList<>();
4096         ComponentName realActivity = null;
4097         boolean realActivitySuspended = false;
4098         ComponentName origActivity = null;
4099         String affinity = null;
4100         String rootAffinity = null;
4101         boolean hasRootAffinity = false;
4102         String windowLayoutAffinity = null;
4103         boolean rootHasReset = false;
4104         boolean autoRemoveRecents = false;
4105         boolean askedCompatMode = false;
4106         int taskType = 0;
4107         int userId = 0;
4108         boolean userSetupComplete = true;
4109         int effectiveUid = -1;
4110         String lastDescription = null;
4111         long lastTimeOnTop = 0;
4112         boolean neverRelinquishIdentity = true;
4113         int taskId = INVALID_TASK_ID;
4114         final int outerDepth = in.getDepth();
4115         TaskDescription taskDescription = new TaskDescription();
4116         int taskAffiliation = INVALID_TASK_ID;
4117         int taskAffiliationColor = 0;
4118         int prevTaskId = INVALID_TASK_ID;
4119         int nextTaskId = INVALID_TASK_ID;
4120         int callingUid = -1;
4121         String callingPackage = "";
4122         String callingFeatureId = null;
4123         int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
4124         boolean supportsPictureInPicture = false;
4125         Rect lastNonFullscreenBounds = null;
4126         int minWidth = INVALID_MIN_SIZE;
4127         int minHeight = INVALID_MIN_SIZE;
4128         int persistTaskVersion = 0;
4129 
4130         for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
4131             final String attrName = in.getAttributeName(attrNdx);
4132             final String attrValue = in.getAttributeValue(attrNdx);
4133             if (TaskPersister.DEBUG) {
4134                 Slog.d(TaskPersister.TAG, "Task: attribute name=" + attrName + " value="
4135                         + attrValue);
4136             }
4137             switch (attrName) {
4138                 case ATTR_TASKID:
4139                     if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
4140                     break;
4141                 case ATTR_REALACTIVITY:
4142                     realActivity = ComponentName.unflattenFromString(attrValue);
4143                     break;
4144                 case ATTR_REALACTIVITY_SUSPENDED:
4145                     realActivitySuspended = Boolean.valueOf(attrValue);
4146                     break;
4147                 case ATTR_ORIGACTIVITY:
4148                     origActivity = ComponentName.unflattenFromString(attrValue);
4149                     break;
4150                 case ATTR_AFFINITY:
4151                     affinity = attrValue;
4152                     break;
4153                 case ATTR_ROOT_AFFINITY:
4154                     rootAffinity = attrValue;
4155                     hasRootAffinity = true;
4156                     break;
4157                 case ATTR_WINDOW_LAYOUT_AFFINITY:
4158                     windowLayoutAffinity = attrValue;
4159                     break;
4160                 case ATTR_ROOTHASRESET:
4161                     rootHasReset = Boolean.parseBoolean(attrValue);
4162                     break;
4163                 case ATTR_AUTOREMOVERECENTS:
4164                     autoRemoveRecents = Boolean.parseBoolean(attrValue);
4165                     break;
4166                 case ATTR_ASKEDCOMPATMODE:
4167                     askedCompatMode = Boolean.parseBoolean(attrValue);
4168                     break;
4169                 case ATTR_USERID:
4170                     userId = Integer.parseInt(attrValue);
4171                     break;
4172                 case ATTR_USER_SETUP_COMPLETE:
4173                     userSetupComplete = Boolean.parseBoolean(attrValue);
4174                     break;
4175                 case ATTR_EFFECTIVE_UID:
4176                     effectiveUid = Integer.parseInt(attrValue);
4177                     break;
4178                 case ATTR_TASKTYPE:
4179                     taskType = Integer.parseInt(attrValue);
4180                     break;
4181                 case ATTR_LASTDESCRIPTION:
4182                     lastDescription = attrValue;
4183                     break;
4184                 case ATTR_LASTTIMEMOVED:
4185                     lastTimeOnTop = Long.parseLong(attrValue);
4186                     break;
4187                 case ATTR_NEVERRELINQUISH:
4188                     neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
4189                     break;
4190                 case ATTR_TASK_AFFILIATION:
4191                     taskAffiliation = Integer.parseInt(attrValue);
4192                     break;
4193                 case ATTR_PREV_AFFILIATION:
4194                     prevTaskId = Integer.parseInt(attrValue);
4195                     break;
4196                 case ATTR_NEXT_AFFILIATION:
4197                     nextTaskId = Integer.parseInt(attrValue);
4198                     break;
4199                 case ATTR_TASK_AFFILIATION_COLOR:
4200                     taskAffiliationColor = Integer.parseInt(attrValue);
4201                     break;
4202                 case ATTR_CALLING_UID:
4203                     callingUid = Integer.parseInt(attrValue);
4204                     break;
4205                 case ATTR_CALLING_PACKAGE:
4206                     callingPackage = attrValue;
4207                     break;
4208                 case ATTR_CALLING_FEATURE_ID:
4209                     callingFeatureId = attrValue;
4210                     break;
4211                 case ATTR_RESIZE_MODE:
4212                     resizeMode = Integer.parseInt(attrValue);
4213                     break;
4214                 case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
4215                     supportsPictureInPicture = Boolean.parseBoolean(attrValue);
4216                     break;
4217                 case ATTR_NON_FULLSCREEN_BOUNDS:
4218                     lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
4219                     break;
4220                 case ATTR_MIN_WIDTH:
4221                     minWidth = Integer.parseInt(attrValue);
4222                     break;
4223                 case ATTR_MIN_HEIGHT:
4224                     minHeight = Integer.parseInt(attrValue);
4225                     break;
4226                 case ATTR_PERSIST_TASK_VERSION:
4227                     persistTaskVersion = Integer.parseInt(attrValue);
4228                     break;
4229                 default:
4230                     if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
4231                         Slog.w(TAG, "Task: Unknown attribute=" + attrName);
4232                     }
4233             }
4234         }
4235         taskDescription.restoreFromXml(in);
4236 
4237         int event;
4238         while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
4239                 && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
4240             if (event == XmlPullParser.START_TAG) {
4241                 final String name = in.getName();
4242                 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: START_TAG name=" + name);
4243                 if (TAG_AFFINITYINTENT.equals(name)) {
4244                     affinityIntent = Intent.restoreFromXml(in);
4245                 } else if (TAG_INTENT.equals(name)) {
4246                     intent = Intent.restoreFromXml(in);
4247                 } else if (TAG_ACTIVITY.equals(name)) {
4248                     ActivityRecord activity =
4249                             ActivityRecord.restoreFromXml(in, stackSupervisor);
4250                     if (TaskPersister.DEBUG) {
4251                         Slog.d(TaskPersister.TAG, "Task: activity=" + activity);
4252                     }
4253                     if (activity != null) {
4254                         activities.add(activity);
4255                     }
4256                 } else {
4257                     Slog.e(TAG, "restoreTask: Unexpected name=" + name);
4258                     XmlUtils.skipCurrentTag(in);
4259                 }
4260             }
4261         }
4262         if (!hasRootAffinity) {
4263             rootAffinity = affinity;
4264         } else if ("@".equals(rootAffinity)) {
4265             rootAffinity = null;
4266         }
4267         if (effectiveUid <= 0) {
4268             Intent checkIntent = intent != null ? intent : affinityIntent;
4269             effectiveUid = 0;
4270             if (checkIntent != null) {
4271                 IPackageManager pm = AppGlobals.getPackageManager();
4272                 try {
4273                     ApplicationInfo ai = pm.getApplicationInfo(
4274                             checkIntent.getComponent().getPackageName(),
4275                             PackageManager.MATCH_UNINSTALLED_PACKAGES
4276                                     | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
4277                     if (ai != null) {
4278                         effectiveUid = ai.uid;
4279                     }
4280                 } catch (RemoteException e) {
4281                 }
4282             }
4283             Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
4284                     + ": effectiveUid=" + effectiveUid);
4285         }
4286 
4287         if (persistTaskVersion < 1) {
4288             // We need to convert the resize mode of home activities saved before version one if
4289             // they are marked as RESIZE_MODE_RESIZEABLE to
4290             // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
4291             // before version 1 and the system didn't resize home activities before then.
4292             if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
4293                 resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
4294             }
4295         } else {
4296             // This activity has previously marked itself explicitly as both resizeable and
4297             // supporting picture-in-picture.  Since there is no longer a requirement for
4298             // picture-in-picture activities to be resizeable, we can mark this simply as
4299             // resizeable and supporting picture-in-picture separately.
4300             if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
4301                 resizeMode = RESIZE_MODE_RESIZEABLE;
4302                 supportsPictureInPicture = true;
4303             }
4304         }
4305 
4306         final Task task = new ActivityStack(stackSupervisor.mService, taskId, intent,
4307                 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
4308                 autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
4309                 lastTimeOnTop, neverRelinquishIdentity, taskDescription, taskAffiliation,
4310                 prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
4311                 callingFeatureId, resizeMode, supportsPictureInPicture, realActivitySuspended,
4312                 userSetupComplete, minWidth, minHeight, null /*ActivityInfo*/,
4313                 null /*_voiceSession*/, null /*_voiceInteractor*/, null /* stack */);
4314         task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
4315         task.setBounds(lastNonFullscreenBounds);
4316         task.mWindowLayoutAffinity = windowLayoutAffinity;
4317 
4318         for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
4319             task.addChild(activities.get(activityNdx));
4320         }
4321 
4322         if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
4323         return task;
4324     }
4325 
4326     @Override
4327     boolean isOrganized() {
4328         return mTaskOrganizer != null;
4329     }
4330 
4331     @Override
4332     protected void reparentSurfaceControl(SurfaceControl.Transaction t, SurfaceControl newParent) {
4333         /**
4334          * Avoid reparenting SurfaceControl of the organized tasks that are always on top, since
4335          * the surfaces should be controlled by the organizer itself, like bubbles.
4336          */
4337         if (isOrganized() && isAlwaysOnTop()) {
4338             return;
4339         }
4340         super.reparentSurfaceControl(t, newParent);
4341     }
4342 
4343     void setHasBeenVisible(boolean hasBeenVisible) {
4344         final boolean prevHasBeenVisible = mHasBeenVisible;
4345         mHasBeenVisible = hasBeenVisible;
4346         if (hasBeenVisible) {
4347             // If the task is not yet visible when it is added to the task organizer, then we should
4348             // hide it to allow the task organizer to show it when it is properly reparented. We
4349             // skip this for tasks created by the organizer because they can synchronously update
4350             // the leash before new children are added to the task.
4351             if (!mCreatedByOrganizer && mTaskOrganizer != null && !prevHasBeenVisible) {
4352                 getSyncTransaction().hide(getSurfaceControl());
4353                 commitPendingTransaction();
4354             }
4355 
4356             sendTaskAppeared();
4357             if (!isRootTask()) {
4358                 getRootTask().setHasBeenVisible(true);
4359             }
4360         }
4361     }
4362 
4363     boolean getHasBeenVisible() {
4364         return mHasBeenVisible;
4365     }
4366 
4367     /** In the case that these conditions are true, we want to send the Task to the organizer:
4368      *     1. An organizer has been set
4369      *     2. The Task was created by the organizer
4370      *     or
4371      *     2a. We have a SurfaceControl
4372      *     2b. We have finished drawing
4373      * Any time any of these conditions are updated, the updating code should call
4374      * sendTaskAppeared.
4375      */
4376     boolean taskAppearedReady() {
4377         if (mTaskOrganizer == null) {
4378             return false;
4379         }
4380 
4381         if (mCreatedByOrganizer) {
4382             return true;
4383         }
4384 
4385         return mSurfaceControl != null && getHasBeenVisible();
4386     }
4387 
4388     private void sendTaskAppeared() {
4389         if (mTaskOrganizer != null) {
4390             mAtmService.mTaskOrganizerController.onTaskAppeared(mTaskOrganizer, this);
4391         }
4392     }
4393 
4394     private void sendTaskVanished(ITaskOrganizer organizer) {
4395         if (organizer != null) {
4396             mAtmService.mTaskOrganizerController.onTaskVanished(organizer, this);
4397         }
4398    }
4399 
4400     @VisibleForTesting
4401     boolean setTaskOrganizer(ITaskOrganizer organizer) {
4402         if (mTaskOrganizer == organizer) {
4403             return false;
4404         }
4405 
4406         ITaskOrganizer previousOrganizer = mTaskOrganizer;
4407         // Update the new task organizer before calling sendTaskVanished since it could result in
4408         // a new SurfaceControl getting created that would notify the old organizer about it.
4409         mTaskOrganizer = organizer;
4410         // Let the old organizer know it has lost control.
4411         sendTaskVanished(previousOrganizer);
4412 
4413         if (mTaskOrganizer != null) {
4414             sendTaskAppeared();
4415         } else {
4416             // No longer managed by any organizer.
4417             mTaskAppearedSent = false;
4418             mLastTaskOrganizerWindowingMode = -1;
4419             setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */);
4420             if (mCreatedByOrganizer) {
4421                 removeImmediately();
4422             }
4423         }
4424 
4425         return true;
4426     }
4427 
4428     /**
4429      * Called when the task state changes (ie. from windowing mode change) an the task organizer
4430      * state should also be updated.
4431      *
4432      * @param forceUpdate Updates the task organizer to the one currently specified in the task
4433      *                    org controller for the task's windowing mode, ignoring the cached
4434      *                    windowing mode checks.
4435      * @return {@code true} if task organizer changed.
4436      */
4437     boolean updateTaskOrganizerState(boolean forceUpdate) {
4438         if (!isRootTask()) {
4439             return false;
4440         }
4441 
4442         final int windowingMode = getWindowingMode();
4443         if (!forceUpdate && windowingMode == mLastTaskOrganizerWindowingMode) {
4444             // If our windowing mode hasn't actually changed, then just stick
4445             // with our old organizer. This lets us implement the semantic
4446             // where SysUI can continue to manage it's old tasks
4447             // while CTS temporarily takes over the registration.
4448             return false;
4449         }
4450         /*
4451          * Different windowing modes may be managed by different task organizers. If
4452          * getTaskOrganizer returns null, we still call setTaskOrganizer to
4453          * make sure we clear it.
4454          */
4455         final ITaskOrganizer org =
4456                 mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
4457         final boolean result = setTaskOrganizer(org);
4458         mLastTaskOrganizerWindowingMode = windowingMode;
4459         return result;
4460     }
4461 
4462     @Override
4463     void setSurfaceControl(SurfaceControl sc) {
4464         super.setSurfaceControl(sc);
4465         // If the TaskOrganizer was set before we created the SurfaceControl, we need to
4466         // emit the callbacks now.
4467         sendTaskAppeared();
4468     }
4469 
4470     /**
4471      * @return true if the task is currently focused.
4472      */
4473     private boolean isFocused() {
4474         if (mDisplayContent == null || mDisplayContent.mCurrentFocus == null) {
4475             return false;
4476         }
4477         return mDisplayContent.mCurrentFocus.getTask() == this;
4478     }
4479 
4480     /**
4481      * @return true if the task is visible and has at least one visible child.
4482      */
4483     private boolean hasVisibleChildren() {
4484         if (!isAttached() || isForceHidden()) {
4485             return false;
4486         }
4487 
4488         return getActivity(ActivityRecord::isVisible) != null;
4489     }
4490 
4491     /**
4492      * @return the desired shadow radius in pixels for the current task.
4493      */
4494     private float getShadowRadius(boolean taskIsFocused) {
4495         int elevation = 0;
4496 
4497         // Get elevation for a specific windowing mode.
4498         if (inPinnedWindowingMode()) {
4499             elevation = PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
4500         } else if (inFreeformWindowingMode()) {
4501             elevation = taskIsFocused
4502                     ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
4503         } else {
4504             // For all other windowing modes, do not draw a shadow.
4505             return 0;
4506         }
4507 
4508         // If the task has no visible children, do not draw a shadow.
4509         if (!hasVisibleChildren()) {
4510             return 0;
4511         }
4512 
4513         return dipToPixel(elevation, getDisplayContent().getDisplayMetrics());
4514     }
4515 
4516     /**
4517      * Update the length of the shadow if needed based on windowing mode and task focus state.
4518      */
4519     private void updateShadowsRadius(boolean taskIsFocused,
4520             SurfaceControl.Transaction pendingTransaction) {
4521         if (!mWmService.mRenderShadowsInCompositor || !isRootTask()) return;
4522 
4523         final float newShadowRadius = getShadowRadius(taskIsFocused);
4524         if (mShadowRadius != newShadowRadius) {
4525             mShadowRadius = newShadowRadius;
4526             pendingTransaction.setShadowRadius(getSurfaceControl(), mShadowRadius);
4527         }
4528     }
4529 
4530     /**
4531      * Called on the task of a window which gained or lost focus.
4532      * @param hasFocus
4533      */
4534     void onWindowFocusChanged(boolean hasFocus) {
4535         updateShadowsRadius(hasFocus, getSyncTransaction());
4536     }
4537 
4538     void onPictureInPictureParamsChanged() {
4539         if (isOrganized()) {
4540             mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, true /* force */);
4541         }
4542     }
4543 
4544     /**
4545      * See {@link WindowContainerTransaction#setBoundsChangeTransaction}. In short this
4546      * transaction will be consumed by the next BASE_APPLICATION window within our hierarchy
4547      * to resize, and it will defer the transaction until that resize frame completes.
4548      */
4549     void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) {
4550         setMainWindowSizeChangeTransaction(t, this);
4551         forAllWindows(WindowState::requestRedrawForSync, true);
4552     }
4553 
4554     private void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t, Task origin) {
4555         // This is only meaningful on an activity's task, so put it on the top one.
4556         ActivityRecord topActivity = getTopNonFinishingActivity();
4557         Task leaf = topActivity != null ? topActivity.getTask() : null;
4558         if (leaf == null) {
4559             return;
4560         }
4561         if (leaf != this) {
4562             leaf.setMainWindowSizeChangeTransaction(t, origin);
4563             return;
4564         }
4565         mMainWindowSizeChangeTransaction = t;
4566         mMainWindowSizeChangeTask = t == null ? null : origin;
4567     }
4568 
4569     SurfaceControl.Transaction getMainWindowSizeChangeTransaction() {
4570         return mMainWindowSizeChangeTransaction;
4571     }
4572 
4573     Task getMainWindowSizeChangeTask() {
4574         return mMainWindowSizeChangeTask;
4575     }
4576 
4577     void setActivityWindowingMode(int windowingMode) {
4578         PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setWindowingMode,
4579                 PooledLambda.__(ActivityRecord.class), windowingMode);
4580         forAllActivities(c);
4581         c.recycle();
4582     }
4583 
4584     /**
4585      * Sets/unsets the forced-hidden state flag for this task depending on {@param set}.
4586      * @return Whether the force hidden state changed
4587      */
4588     boolean setForceHidden(int flags, boolean set) {
4589         int newFlags = mForceHiddenFlags;
4590         if (set) {
4591             newFlags |= flags;
4592         } else {
4593             newFlags &= ~flags;
4594         }
4595         if (mForceHiddenFlags == newFlags) {
4596             return false;
4597         }
4598         final boolean wasHidden = isForceHidden();
4599         mForceHiddenFlags = newFlags;
4600         if (wasHidden != isForceHidden() && isTopActivityFocusable()) {
4601             // The change in force-hidden state will change visibility without triggering a root
4602             // task order change, so we should reset the preferred top focusable root task to ensure
4603             // it's not used if a new activity is started from this task.
4604             getDisplayArea().resetPreferredTopFocusableRootTaskIfNeeded(this);
4605         }
4606         return true;
4607     }
4608 
4609     /**
4610      * Returns whether this task is currently forced to be hidden for any reason.
4611      */
4612     protected boolean isForceHidden() {
4613         return mForceHiddenFlags != 0;
4614     }
4615 
4616     @Override
4617     long getProtoFieldId() {
4618         return TASK;
4619     }
4620 
4621 }
4622