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_WHITELISTED;
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_WHITELISTED = 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 whitelists 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         performClearTask("clear-task-all");
1532         mReuseTask = false;
1533     }
1534 
performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags)1535     ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
1536         mReuseTask = true;
1537         final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
1538         mReuseTask = false;
1539         return result;
1540     }
1541 
1542     /**
1543      * Perform clear operation as requested by
1544      * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
1545      * stack to the given task, then look for
1546      * an instance of that activity in the stack and, if found, finish all
1547      * activities on top of it and return the instance.
1548      *
1549      * @param newR Description of the new activity being started.
1550      * @return Returns the old activity that should be continued to be used,
1551      * or {@code null} if none was found.
1552      */
performClearTaskLocked(ActivityRecord newR, int launchFlags)1553     private ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
1554         final ActivityRecord r = findActivityInHistory(newR.mActivityComponent);
1555         if (r == null) return null;
1556 
1557         final PooledFunction f = PooledLambda.obtainFunction(Task::finishActivityAbove,
1558                 PooledLambda.__(ActivityRecord.class), r);
1559         forAllActivities(f);
1560         f.recycle();
1561 
1562         // Finally, if this is a normal launch mode (that is, not expecting onNewIntent()), then we
1563         // will finish the current instance of the activity so a new fresh one can be started.
1564         if (r.launchMode == ActivityInfo.LAUNCH_MULTIPLE
1565                 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
1566                 && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
1567             if (!r.finishing) {
1568                 r.finishIfPossible("clear-task-top", false /* oomAdj */);
1569                 return null;
1570             }
1571         }
1572 
1573         return r;
1574     }
1575 
finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity)1576     private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity) {
1577         // Stop operation once we reach the boundary activity.
1578         if (r == boundaryActivity) return true;
1579 
1580         if (!r.finishing) {
1581             final ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
1582             if (opts != null) {
1583                 // TODO: Why is this updating the boundary activity vs. the current activity???
1584                 boundaryActivity.updateOptionsLocked(opts);
1585             }
1586             r.finishIfPossible("clear-task-stack", false /* oomAdj */);
1587         }
1588 
1589         return false;
1590     }
1591 
lockTaskAuthToString()1592     String lockTaskAuthToString() {
1593         switch (mLockTaskAuth) {
1594             case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
1595             case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
1596             case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
1597             case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
1598             case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
1599             default: return "unknown=" + mLockTaskAuth;
1600         }
1601     }
1602 
setLockTaskAuth()1603     void setLockTaskAuth() {
1604         setLockTaskAuth(getRootActivity());
1605     }
1606 
setLockTaskAuth(@ullable ActivityRecord r)1607     private void setLockTaskAuth(@Nullable ActivityRecord r) {
1608         if (r == null) {
1609             mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
1610             return;
1611         }
1612 
1613         final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
1614         final LockTaskController lockTaskController = mAtmService.getLockTaskController();
1615         switch (r.lockTaskLaunchMode) {
1616             case LOCK_TASK_LAUNCH_MODE_DEFAULT:
1617                 mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
1618                         ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
1619                 break;
1620 
1621             case LOCK_TASK_LAUNCH_MODE_NEVER:
1622                 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
1623                 break;
1624 
1625             case LOCK_TASK_LAUNCH_MODE_ALWAYS:
1626                 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
1627                 break;
1628 
1629             case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
1630                 mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
1631                         ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
1632                 break;
1633         }
1634         if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this
1635                 + " mLockTaskAuth=" + lockTaskAuthToString());
1636     }
1637 
1638     @Override
supportsSplitScreenWindowingMode()1639     public boolean supportsSplitScreenWindowingMode() {
1640         final Task topTask = getTopMostTask();
1641         return super.supportsSplitScreenWindowingMode()
1642                 && (topTask == null || topTask.supportsSplitScreenWindowingModeInner());
1643     }
1644 
supportsSplitScreenWindowingModeInner()1645     private boolean supportsSplitScreenWindowingModeInner() {
1646         // A task can not be docked even if it is considered resizeable because it only supports
1647         // picture-in-picture mode but has a non-resizeable resizeMode
1648         return super.supportsSplitScreenWindowingMode()
1649                 && mAtmService.mSupportsSplitScreenMultiWindow
1650                 && (mAtmService.mForceResizableActivities
1651                         || (isResizeable(false /* checkSupportsPip */)
1652                                 && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
1653     }
1654 
1655     /**
1656      * Check whether this task can be launched on the specified display.
1657      *
1658      * @param displayId Target display id.
1659      * @return {@code true} if either it is the default display or this activity can be put on a
1660      *         secondary display.
1661      */
canBeLaunchedOnDisplay(int displayId)1662     boolean canBeLaunchedOnDisplay(int displayId) {
1663         return mStackSupervisor.canPlaceEntityOnDisplay(displayId,
1664                 -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
1665     }
1666 
1667     /**
1668      * Check that a given bounds matches the application requested orientation.
1669      *
1670      * @param bounds The bounds to be tested.
1671      * @return True if the requested bounds are okay for a resizing request.
1672      */
canResizeToBounds(Rect bounds)1673     private boolean canResizeToBounds(Rect bounds) {
1674         if (bounds == null || !inFreeformWindowingMode()) {
1675             // Note: If not on the freeform workspace, we ignore the bounds.
1676             return true;
1677         }
1678         final boolean landscape = bounds.width() > bounds.height();
1679         final Rect configBounds = getRequestedOverrideBounds();
1680         if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
1681             return configBounds.isEmpty()
1682                     || landscape == (configBounds.width() > configBounds.height());
1683         }
1684         return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
1685                 && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
1686     }
1687 
1688     /**
1689      * @return {@code true} if the task is being cleared for the purposes of being reused.
1690      */
isClearingToReuseTask()1691     boolean isClearingToReuseTask() {
1692         return mReuseTask;
1693     }
1694 
1695     /**
1696      * Find the activity in the history stack within the given task.  Returns
1697      * the index within the history at which it's found, or < 0 if not found.
1698      */
findActivityInHistory(ComponentName component)1699     ActivityRecord findActivityInHistory(ComponentName component) {
1700         final PooledPredicate p = PooledLambda.obtainPredicate(Task::matchesActivityInHistory,
1701                 PooledLambda.__(ActivityRecord.class), component);
1702         final ActivityRecord r = getActivity(p);
1703         p.recycle();
1704         return r;
1705     }
1706 
matchesActivityInHistory( ActivityRecord r, ComponentName activityComponent)1707     private static boolean matchesActivityInHistory(
1708             ActivityRecord r, ComponentName activityComponent) {
1709         return !r.finishing && r.mActivityComponent.equals(activityComponent);
1710     }
1711 
1712     /** Updates the last task description values. */
updateTaskDescription()1713     void updateTaskDescription() {
1714         final ActivityRecord root = getRootActivity(true);
1715         if (root == null) return;
1716 
1717         final TaskDescription taskDescription = new TaskDescription();
1718         final PooledFunction f = PooledLambda.obtainFunction(
1719                 Task::setTaskDescriptionFromActivityAboveRoot,
1720                 PooledLambda.__(ActivityRecord.class), root, taskDescription);
1721         forAllActivities(f);
1722         f.recycle();
1723         taskDescription.setResizeMode(mResizeMode);
1724         taskDescription.setMinWidth(mMinWidth);
1725         taskDescription.setMinHeight(mMinHeight);
1726         setTaskDescription(taskDescription);
1727         // Update the task affiliation color if we are the parent of the group
1728         if (mTaskId == mAffiliatedTaskId) {
1729             mAffiliatedTaskColor = taskDescription.getPrimaryColor();
1730         }
1731         mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
1732                 getTaskInfo());
1733 
1734         final WindowContainer parent = getParent();
1735         if (parent != null) {
1736             final Task t = parent.asTask();
1737             if (t != null) {
1738                 t.updateTaskDescription();
1739             }
1740         }
1741 
1742         if (isOrganized()) {
1743             mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */);
1744         }
1745     }
1746 
setTaskDescriptionFromActivityAboveRoot( ActivityRecord r, ActivityRecord root, TaskDescription td)1747     private static boolean setTaskDescriptionFromActivityAboveRoot(
1748             ActivityRecord r, ActivityRecord root, TaskDescription td) {
1749         if (!r.isTaskOverlay() && r.taskDescription != null) {
1750             final TaskDescription atd = r.taskDescription;
1751             if (td.getLabel() == null) {
1752                 td.setLabel(atd.getLabel());
1753             }
1754             if (td.getRawIcon() == null) {
1755                 td.setIcon(atd.getRawIcon());
1756             }
1757             if (td.getIconFilename() == null) {
1758                 td.setIconFilename(atd.getIconFilename());
1759             }
1760             if (td.getPrimaryColor() == 0) {
1761                 td.setPrimaryColor(atd.getPrimaryColor());
1762             }
1763             if (td.getBackgroundColor() == 0) {
1764                 td.setBackgroundColor(atd.getBackgroundColor());
1765             }
1766             if (td.getStatusBarColor() == 0) {
1767                 td.setStatusBarColor(atd.getStatusBarColor());
1768                 td.setEnsureStatusBarContrastWhenTransparent(
1769                         atd.getEnsureStatusBarContrastWhenTransparent());
1770             }
1771             if (td.getNavigationBarColor() == 0) {
1772                 td.setNavigationBarColor(atd.getNavigationBarColor());
1773                 td.setEnsureNavigationBarContrastWhenTransparent(
1774                         atd.getEnsureNavigationBarContrastWhenTransparent());
1775             }
1776 
1777         }
1778 
1779         // End search once we get to root.
1780         return r == root;
1781     }
1782 
1783     // TODO (AM refactor): Invoke automatically when there is a change in children
1784     @VisibleForTesting
updateEffectiveIntent()1785     void updateEffectiveIntent() {
1786         final ActivityRecord root = getRootActivity(true /*setToBottomIfNone*/);
1787         if (root != null) {
1788             setIntent(root);
1789             // Update the task description when the activities change
1790             updateTaskDescription();
1791         }
1792     }
1793 
adjustForMinimalTaskDimensions(@onNull Rect bounds, @NonNull Rect previousBounds, @NonNull Configuration parentConfig)1794     void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds,
1795             @NonNull Configuration parentConfig) {
1796         int minWidth = mMinWidth;
1797         int minHeight = mMinHeight;
1798         // If the task has no requested minimal size, we'd like to enforce a minimal size
1799         // so that the user can not render the task too small to manipulate. We don't need
1800         // to do this for the pinned stack as the bounds are controlled by the system.
1801         if (!inPinnedWindowingMode()) {
1802             final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp;
1803             final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
1804             final int defaultMinSize = (int) (defaultMinSizeDp * density);
1805 
1806             if (minWidth == INVALID_MIN_SIZE) {
1807                 minWidth = defaultMinSize;
1808             }
1809             if (minHeight == INVALID_MIN_SIZE) {
1810                 minHeight = defaultMinSize;
1811             }
1812         }
1813         if (bounds.isEmpty()) {
1814             // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they
1815             // do, we can just skip.
1816             final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
1817             if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) {
1818                 return;
1819             }
1820             bounds.set(parentBounds);
1821         }
1822         final boolean adjustWidth = minWidth > bounds.width();
1823         final boolean adjustHeight = minHeight > bounds.height();
1824         if (!(adjustWidth || adjustHeight)) {
1825             return;
1826         }
1827 
1828         if (adjustWidth) {
1829             if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
1830                 bounds.left = bounds.right - minWidth;
1831             } else {
1832                 // Either left bounds match, or neither match, or the previous bounds were
1833                 // fullscreen and we default to keeping left.
1834                 bounds.right = bounds.left + minWidth;
1835             }
1836         }
1837         if (adjustHeight) {
1838             if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
1839                 bounds.top = bounds.bottom - minHeight;
1840             } else {
1841                 // Either top bounds match, or neither match, or the previous bounds were
1842                 // fullscreen and we default to keeping top.
1843                 bounds.bottom = bounds.top + minHeight;
1844             }
1845         }
1846     }
1847 
setLastNonFullscreenBounds(Rect bounds)1848     void setLastNonFullscreenBounds(Rect bounds) {
1849         if (mLastNonFullscreenBounds == null) {
1850             mLastNonFullscreenBounds = new Rect(bounds);
1851         } else {
1852             mLastNonFullscreenBounds.set(bounds);
1853         }
1854     }
1855 
1856     /**
1857      * This should be called when an child activity changes state. This should only
1858      * be called from
1859      * {@link ActivityRecord#setState(ActivityState, String)} .
1860      * @param record The {@link ActivityRecord} whose state has changed.
1861      * @param state The new state.
1862      * @param reason The reason for the change.
1863      */
onActivityStateChanged(ActivityRecord record, ActivityState state, String reason)1864     void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
1865         final Task parentTask = getParent().asTask();
1866         if (parentTask != null) {
1867             parentTask.onActivityStateChanged(record, state, reason);
1868             // We still want to update the resumed activity if the parent task is created by
1869             // organizer in order to keep the information synced once got reparented out from the
1870             // organized task.
1871             if (!parentTask.mCreatedByOrganizer) {
1872                 return;
1873             }
1874         }
1875 
1876         if (record == mResumedActivity && state != RESUMED) {
1877             setResumedActivity(null, reason + " - onActivityStateChanged");
1878         }
1879 
1880         if (state == RESUMED) {
1881             if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
1882                 Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:" + reason);
1883             }
1884             setResumedActivity(record, reason + " - onActivityStateChanged");
1885             if (record == mRootWindowContainer.getTopResumedActivity()) {
1886                 mAtmService.setResumedActivityUncheckLocked(record, reason);
1887             }
1888             mStackSupervisor.mRecentTasks.add(record.getTask());
1889         }
1890     }
1891 
1892     @Override
onConfigurationChanged(Configuration newParentConfig)1893     public void onConfigurationChanged(Configuration newParentConfig) {
1894         // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
1895         // restore the last recorded non-fullscreen bounds.
1896         final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
1897         boolean nextPersistTaskBounds =
1898                 getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds();
1899         if (getRequestedOverrideWindowingMode() == WINDOWING_MODE_UNDEFINED) {
1900             nextPersistTaskBounds = newParentConfig.windowConfiguration.persistTaskBounds();
1901         }
1902         if (!prevPersistTaskBounds && nextPersistTaskBounds
1903                 && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
1904             // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
1905             getRequestedOverrideConfiguration().windowConfiguration
1906                     .setBounds(mLastNonFullscreenBounds);
1907         }
1908 
1909         final int prevWinMode = getWindowingMode();
1910         mTmpPrevBounds.set(getBounds());
1911         final boolean wasInMultiWindowMode = inMultiWindowMode();
1912         final boolean wasInPictureInPicture = inPinnedWindowingMode();
1913         super.onConfigurationChanged(newParentConfig);
1914         // Only need to update surface size here since the super method will handle updating
1915         // surface position.
1916         updateSurfaceSize(getSyncTransaction());
1917 
1918         if (wasInPictureInPicture != inPinnedWindowingMode()) {
1919             mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, getStack());
1920         } else if (wasInMultiWindowMode != inMultiWindowMode()) {
1921             mStackSupervisor.scheduleUpdateMultiWindowMode(this);
1922         }
1923 
1924         final int newWinMode = getWindowingMode();
1925         if ((prevWinMode != newWinMode) && (mDisplayContent != null)
1926                 && shouldStartChangeTransition(prevWinMode, newWinMode)) {
1927             initializeChangeTransition(mTmpPrevBounds);
1928         }
1929 
1930         // If the configuration supports persistent bounds (eg. Freeform), keep track of the
1931         // current (non-fullscreen) bounds for persistence.
1932         if (getWindowConfiguration().persistTaskBounds()) {
1933             final Rect currentBounds = getRequestedOverrideBounds();
1934             if (!currentBounds.isEmpty()) {
1935                 setLastNonFullscreenBounds(currentBounds);
1936             }
1937         }
1938 
1939         saveLaunchingStateIfNeeded();
1940         final boolean taskOrgChanged = updateTaskOrganizerState(false /* forceUpdate */);
1941         // If the task organizer has changed, then it will already be receiving taskAppeared with
1942         // the latest task-info thus the task-info won't have changed.
1943         if (!taskOrgChanged && isOrganized()) {
1944             mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */);
1945         }
1946     }
1947 
1948     /**
1949      * Initializes a change transition. See {@link SurfaceFreezer} for more information.
1950      */
initializeChangeTransition(Rect startBounds)1951     private void initializeChangeTransition(Rect startBounds) {
1952         mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
1953                 false /* alwaysKeepCurrent */, 0, false /* forceOverride */);
1954         mDisplayContent.mChangingContainers.add(this);
1955 
1956         mSurfaceFreezer.freeze(getPendingTransaction(), startBounds);
1957     }
1958 
shouldStartChangeTransition(int prevWinMode, int newWinMode)1959     private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
1960         if (mWmService.mDisableTransitionAnimation
1961                 || !isVisible()
1962                 || getDisplayContent().mAppTransition.isTransitionSet()
1963                 || getSurfaceControl() == null
1964                 || !isLeafTask()) {
1965             return false;
1966         }
1967         // Only do an animation into and out-of freeform mode for now. Other mode
1968         // transition animations are currently handled by system-ui.
1969         return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM);
1970     }
1971 
1972     @Override
migrateToNewSurfaceControl()1973     void migrateToNewSurfaceControl() {
1974         super.migrateToNewSurfaceControl();
1975         mLastSurfaceSize.x = 0;
1976         mLastSurfaceSize.y = 0;
1977         updateSurfaceSize(getPendingTransaction());
1978     }
1979 
updateSurfaceSize(SurfaceControl.Transaction transaction)1980     void updateSurfaceSize(SurfaceControl.Transaction transaction) {
1981         if (mSurfaceControl == null || isOrganized()) {
1982             return;
1983         }
1984 
1985         // Apply crop to root tasks only and clear the crops of the descendant tasks.
1986         int width = 0;
1987         int height = 0;
1988         if (isRootTask()) {
1989             final Rect taskBounds = getBounds();
1990             width = taskBounds.width();
1991             height = taskBounds.height();
1992 
1993             final int outset = getTaskOutset();
1994             width += 2 * outset;
1995             height += 2 * outset;
1996         }
1997         if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
1998             return;
1999         }
2000         transaction.setWindowCrop(mSurfaceControl, width, height);
2001         mLastSurfaceSize.set(width, height);
2002     }
2003 
2004     /**
2005      * Calculate an amount by which to expand the task bounds in each direction.
2006      * Used to make room for shadows in the pinned windowing mode.
2007      */
getTaskOutset()2008     int getTaskOutset() {
2009         // If we are drawing shadows on the task then don't outset the stack.
2010         if (mWmService.mRenderShadowsInCompositor) {
2011             return 0;
2012         }
2013         DisplayContent displayContent = getDisplayContent();
2014         if (inPinnedWindowingMode() && displayContent != null) {
2015             final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
2016 
2017             // We multiply by two to match the client logic for converting view elevation
2018             // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets}
2019             return (int) Math.ceil(
2020                     mWmService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP, displayMetrics)
2021                             * 2);
2022         }
2023         return 0;
2024     }
2025 
2026     @VisibleForTesting
getLastSurfaceSize()2027     Point getLastSurfaceSize() {
2028         return mLastSurfaceSize;
2029     }
2030 
2031     @VisibleForTesting
isInChangeTransition()2032     boolean isInChangeTransition() {
2033         return mSurfaceFreezer.hasLeash() || AppTransition.isChangeTransit(mTransit);
2034     }
2035 
2036     @Override
getFreezeSnapshotTarget()2037     public SurfaceControl getFreezeSnapshotTarget() {
2038         final int transit = mDisplayContent.mAppTransition.getAppTransition();
2039         if (!AppTransition.isChangeTransit(transit)) {
2040             return null;
2041         }
2042         // Skip creating snapshot if this transition is controlled by a remote animator which
2043         // doesn't need it.
2044         final ArraySet<Integer> activityTypes = new ArraySet<>();
2045         activityTypes.add(getActivityType());
2046         final RemoteAnimationAdapter adapter =
2047                 mDisplayContent.mAppTransitionController.getRemoteAnimationOverride(
2048                         this, transit, activityTypes);
2049         if (adapter != null && !adapter.getChangeNeedsSnapshot()) {
2050             return null;
2051         }
2052         return getSurfaceControl();
2053     }
2054 
2055     @Override
writeIdentifierToProto(ProtoOutputStream proto, long fieldId)2056     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
2057         final long token = proto.start(fieldId);
2058         proto.write(HASH_CODE, System.identityHashCode(this));
2059         proto.write(USER_ID, mUserId);
2060         proto.write(TITLE, intent != null && intent.getComponent() != null
2061                 ? intent.getComponent().flattenToShortString() : "Task");
2062         proto.end(token);
2063     }
2064 
2065     /**
2066      * Saves launching state if necessary so that we can launch the activity to its latest state.
2067      * It only saves state if this task has been shown to user and it's in fullscreen or freeform
2068      * mode on freeform displays.
2069      */
saveLaunchingStateIfNeeded()2070     private void saveLaunchingStateIfNeeded() {
2071         saveLaunchingStateIfNeeded(getDisplayContent());
2072     }
2073 
saveLaunchingStateIfNeeded(DisplayContent display)2074     private void saveLaunchingStateIfNeeded(DisplayContent display) {
2075         if (!getHasBeenVisible()) {
2076             // Not ever visible to user.
2077             return;
2078         }
2079 
2080         final int windowingMode = getWindowingMode();
2081         if (windowingMode != WINDOWING_MODE_FULLSCREEN
2082                 && windowingMode != WINDOWING_MODE_FREEFORM) {
2083             return;
2084         }
2085 
2086         // Don't persist state if display isn't in freeform mode. Then the task will be launched
2087         // back to its last state in a freeform display when it's launched in a freeform display
2088         // next time.
2089         if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) {
2090             return;
2091         }
2092 
2093         // Saves the new state so that we can launch the activity at the same location.
2094         mStackSupervisor.mLaunchParamsPersister.saveTask(this, display);
2095     }
2096 
2097     /**
2098      * Adjust bounds to stay within stack bounds.
2099      *
2100      * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
2101      * that keep them unchanged, but be contained within the stack bounds.
2102      *
2103      * @param bounds Bounds to be adjusted.
2104      * @param stackBounds Bounds within which the other bounds should remain.
2105      * @param overlapPxX The amount of px required to be visible in the X dimension.
2106      * @param overlapPxY The amount of px required to be visible in the Y dimension.
2107      */
fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX, int overlapPxY)2108     private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX,
2109             int overlapPxY) {
2110         if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) {
2111             return;
2112         }
2113 
2114         // For each side of the parent (eg. left), check if the opposing side of the window (eg.
2115         // right) is at least overlap pixels away. If less, offset the window by that difference.
2116         int horizontalDiff = 0;
2117         // If window is smaller than overlap, use it's smallest dimension instead
2118         int overlapLR = Math.min(overlapPxX, bounds.width());
2119         if (bounds.right < (stackBounds.left + overlapLR)) {
2120             horizontalDiff = overlapLR - (bounds.right - stackBounds.left);
2121         } else if (bounds.left > (stackBounds.right - overlapLR)) {
2122             horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left));
2123         }
2124         int verticalDiff = 0;
2125         int overlapTB = Math.min(overlapPxY, bounds.width());
2126         if (bounds.bottom < (stackBounds.top + overlapTB)) {
2127             verticalDiff = overlapTB - (bounds.bottom - stackBounds.top);
2128         } else if (bounds.top > (stackBounds.bottom - overlapTB)) {
2129             verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top));
2130         }
2131         bounds.offset(horizontalDiff, verticalDiff);
2132     }
2133 
2134     /**
2135      * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
2136      * intersectBounds on a side, then the respective side will not be intersected.
2137      *
2138      * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
2139      * inset on that side is no-longer applicable. This scenario happens when a task's minimal
2140      * bounds are larger than the provided parent/display bounds.
2141      *
2142      * @param inOutBounds the bounds to intersect.
2143      * @param intersectBounds the bounds to intersect with.
2144      * @param intersectInsets insets to apply to intersectBounds before intersecting.
2145      */
intersectWithInsetsIfFits( Rect inOutBounds, Rect intersectBounds, Rect intersectInsets)2146     static void intersectWithInsetsIfFits(
2147             Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
2148         if (inOutBounds.right <= intersectBounds.right) {
2149             inOutBounds.right =
2150                     Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
2151         }
2152         if (inOutBounds.bottom <= intersectBounds.bottom) {
2153             inOutBounds.bottom =
2154                     Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
2155         }
2156         if (inOutBounds.left >= intersectBounds.left) {
2157             inOutBounds.left =
2158                     Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
2159         }
2160         if (inOutBounds.top >= intersectBounds.top) {
2161             inOutBounds.top =
2162                     Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
2163         }
2164     }
2165 
2166     /**
2167      * Gets bounds with non-decor and stable insets applied respectively.
2168      *
2169      * If bounds overhangs the display, those edges will not get insets. See
2170      * {@link #intersectWithInsetsIfFits}
2171      *
2172      * @param outNonDecorBounds where to place bounds with non-decor insets applied.
2173      * @param outStableBounds where to place bounds with stable insets applied.
2174      * @param bounds the bounds to inset.
2175      */
calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, DisplayInfo displayInfo)2176     private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
2177             DisplayInfo displayInfo) {
2178         outNonDecorBounds.set(bounds);
2179         outStableBounds.set(bounds);
2180         if (getStack() == null || getStack().getDisplay() == null) {
2181             return;
2182         }
2183         DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy();
2184         if (policy == null) {
2185             return;
2186         }
2187         mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
2188 
2189         policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
2190                 displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
2191         intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
2192 
2193         policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
2194         intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
2195     }
2196 
2197     /**
2198      * Forces the app bounds related configuration can be computed by
2199      * {@link #computeConfigResourceOverrides(Configuration, Configuration, DisplayInfo,
2200      * ActivityRecord.CompatDisplayInsets)}.
2201      */
invalidateAppBoundsConfig(@onNull Configuration inOutConfig)2202     private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) {
2203         final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds();
2204         if (appBounds != null) {
2205             appBounds.setEmpty();
2206         }
2207         inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
2208         inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
2209     }
2210 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo)2211     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2212             @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
2213         if (overrideDisplayInfo != null) {
2214             // Make sure the screen related configs can be computed by the provided display info.
2215             inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
2216             invalidateAppBoundsConfig(inOutConfig);
2217         }
2218         computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
2219                 null /* compatInsets */);
2220     }
2221 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig)2222     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2223             @NonNull Configuration parentConfig) {
2224         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
2225                 null /* compatInsets */);
2226     }
2227 
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2228     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2229             @NonNull Configuration parentConfig,
2230             @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
2231         if (compatInsets != null) {
2232             // Make sure the app bounds can be computed by the compat insets.
2233             invalidateAppBoundsConfig(inOutConfig);
2234         }
2235         computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
2236                 compatInsets);
2237     }
2238 
2239     /**
2240      * Calculates configuration values used by the client to get resources. This should be run
2241      * using app-facing bounds (bounds unmodified by animations or transient interactions).
2242      *
2243      * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
2244      * configuring an "inherit-bounds" window which means that all configuration settings would
2245      * just be inherited from the parent configuration.
2246      **/
computeConfigResourceOverrides(@onNull Configuration inOutConfig, @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo, @Nullable ActivityRecord.CompatDisplayInsets compatInsets)2247     void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
2248             @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
2249             @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
2250         int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
2251         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
2252             windowingMode = parentConfig.windowConfiguration.getWindowingMode();
2253         }
2254 
2255         float density = inOutConfig.densityDpi;
2256         if (density == Configuration.DENSITY_DPI_UNDEFINED) {
2257             density = parentConfig.densityDpi;
2258         }
2259         density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
2260 
2261         // The bounds may have been overridden at this level. If the parent cannot cover these
2262         // bounds, the configuration is still computed according to the override bounds.
2263         final boolean insideParentBounds;
2264 
2265         final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
2266         final Rect resolvedBounds = inOutConfig.windowConfiguration.getBounds();
2267         if (resolvedBounds == null || resolvedBounds.isEmpty()) {
2268             mTmpFullBounds.set(parentBounds);
2269             insideParentBounds = true;
2270         } else {
2271             mTmpFullBounds.set(resolvedBounds);
2272             insideParentBounds = parentBounds.contains(resolvedBounds);
2273         }
2274 
2275         // Non-null compatibility insets means the activity prefers to keep its original size, so
2276         // out bounds doesn't need to be restricted by the parent or current display
2277         final boolean customContainerPolicy = compatInsets != null;
2278 
2279         Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
2280         if (outAppBounds == null || outAppBounds.isEmpty()) {
2281             // App-bounds hasn't been overridden, so calculate a value for it.
2282             inOutConfig.windowConfiguration.setAppBounds(mTmpFullBounds);
2283             outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
2284 
2285             if (!customContainerPolicy && windowingMode != WINDOWING_MODE_FREEFORM) {
2286                 final Rect containingAppBounds;
2287                 if (insideParentBounds) {
2288                     containingAppBounds = parentConfig.windowConfiguration.getAppBounds();
2289                 } else {
2290                     // Restrict appBounds to display non-decor rather than parent because the
2291                     // override bounds are beyond the parent. Otherwise, it won't match the
2292                     // overridden bounds.
2293                     final TaskDisplayArea displayArea = getDisplayArea();
2294                     containingAppBounds = displayArea != null
2295                             ? displayArea.getWindowConfiguration().getAppBounds() : null;
2296                 }
2297                 if (containingAppBounds != null && !containingAppBounds.isEmpty()) {
2298                     outAppBounds.intersect(containingAppBounds);
2299                 }
2300             }
2301         }
2302 
2303         if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
2304                 || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2305             if (!customContainerPolicy && WindowConfiguration.isFloating(windowingMode)) {
2306                 mTmpNonDecorBounds.set(mTmpFullBounds);
2307                 mTmpStableBounds.set(mTmpFullBounds);
2308             } else if (!customContainerPolicy
2309                     && (overrideDisplayInfo != null || getDisplayContent() != null)) {
2310                 final DisplayInfo di = overrideDisplayInfo != null
2311                         ? overrideDisplayInfo
2312                         : getDisplayContent().getDisplayInfo();
2313 
2314                 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
2315                 // area, i.e. the screen area without the system bars.
2316                 // The non decor inset are areas that could never be removed in Honeycomb. See
2317                 // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
2318                 calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di);
2319             } else {
2320                 // Apply the given non-decor and stable insets to calculate the corresponding bounds
2321                 // for screen size of configuration.
2322                 int rotation = inOutConfig.windowConfiguration.getRotation();
2323                 if (rotation == ROTATION_UNDEFINED) {
2324                     rotation = parentConfig.windowConfiguration.getRotation();
2325                 }
2326                 if (rotation != ROTATION_UNDEFINED && customContainerPolicy) {
2327                     mTmpNonDecorBounds.set(mTmpFullBounds);
2328                     mTmpStableBounds.set(mTmpFullBounds);
2329                     compatInsets.getBoundsByRotation(mTmpBounds, rotation);
2330                     intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
2331                             compatInsets.mNonDecorInsets[rotation]);
2332                     intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
2333                             compatInsets.mStableInsets[rotation]);
2334                     outAppBounds.set(mTmpNonDecorBounds);
2335                 } else {
2336                     // Set to app bounds because it excludes decor insets.
2337                     mTmpNonDecorBounds.set(outAppBounds);
2338                     mTmpStableBounds.set(outAppBounds);
2339                 }
2340             }
2341 
2342             if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
2343                 final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
2344                 inOutConfig.screenWidthDp = (insideParentBounds && !customContainerPolicy)
2345                         ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
2346                         : overrideScreenWidthDp;
2347             }
2348             if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
2349                 final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
2350                 inOutConfig.screenHeightDp = (insideParentBounds && !customContainerPolicy)
2351                         ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
2352                         : overrideScreenHeightDp;
2353             }
2354 
2355             if (inOutConfig.smallestScreenWidthDp
2356                     == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
2357                 if (WindowConfiguration.isFloating(windowingMode)) {
2358                     // For floating tasks, calculate the smallest width from the bounds of the task
2359                     inOutConfig.smallestScreenWidthDp = (int) (
2360                             Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
2361                 }
2362                 // otherwise, it will just inherit
2363             }
2364         }
2365 
2366         if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
2367             inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
2368                     ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
2369         }
2370         if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
2371             // For calculating screen layout, we need to use the non-decor inset screen area for the
2372             // calculation for compatibility reasons, i.e. screen area without system bars that
2373             // could never go away in Honeycomb.
2374             final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
2375             final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
2376             // Reducing the screen layout starting from its parent config.
2377             inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout,
2378                     compatScreenWidthDp, compatScreenHeightDp);
2379         }
2380     }
2381 
2382     /** Computes LONG, SIZE and COMPAT parts of {@link Configuration#screenLayout}. */
computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp, int screenHeightDp)2383     static int computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp,
2384             int screenHeightDp) {
2385         sourceScreenLayout = sourceScreenLayout
2386                 & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
2387         final int longSize = Math.max(screenWidthDp, screenHeightDp);
2388         final int shortSize = Math.min(screenWidthDp, screenHeightDp);
2389         return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize);
2390     }
2391 
2392     @Override
resolveOverrideConfiguration(Configuration newParentConfig)2393     void resolveOverrideConfiguration(Configuration newParentConfig) {
2394         mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
2395         super.resolveOverrideConfiguration(newParentConfig);
2396 
2397         int windowingMode =
2398                 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
2399 
2400         // Resolve override windowing mode to fullscreen for home task (even on freeform
2401         // display), or split-screen if in split-screen mode.
2402         if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) {
2403             final int parentWindowingMode = newParentConfig.windowConfiguration.getWindowingMode();
2404             windowingMode = WindowConfiguration.isSplitScreenWindowingMode(parentWindowingMode)
2405                     ? parentWindowingMode : WINDOWING_MODE_FULLSCREEN;
2406             getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
2407         }
2408 
2409         if (isLeafTask()) {
2410             resolveLeafOnlyOverrideConfigs(newParentConfig, mTmpBounds /* previousBounds */);
2411         }
2412         computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
2413     }
2414 
resolveLeafOnlyOverrideConfigs(Configuration newParentConfig, Rect previousBounds)2415     private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig,
2416             Rect previousBounds) {
2417         int windowingMode =
2418                 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
2419         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
2420             windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
2421         }
2422         Rect outOverrideBounds =
2423                 getResolvedOverrideConfiguration().windowConfiguration.getBounds();
2424 
2425         if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
2426             computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
2427                     newParentConfig.windowConfiguration.getBounds(),
2428                     newParentConfig.orientation);
2429             // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
2430             // the parent or display is smaller than the size, the content may be cropped.
2431             return;
2432         }
2433 
2434         adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig);
2435         if (windowingMode == WINDOWING_MODE_FREEFORM) {
2436             // by policy, make sure the window remains within parent somewhere
2437             final float density =
2438                     ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
2439             final Rect parentBounds =
2440                     new Rect(newParentConfig.windowConfiguration.getBounds());
2441             final DisplayContent display = getDisplayContent();
2442             if (display != null) {
2443                 // If a freeform window moves below system bar, there is no way to move it again
2444                 // by touch. Because its caption is covered by system bar. So we exclude them
2445                 // from stack bounds. and then caption will be shown inside stable area.
2446                 final Rect stableBounds = new Rect();
2447                 display.getStableRect(stableBounds);
2448                 parentBounds.intersect(stableBounds);
2449             }
2450 
2451             fitWithinBounds(outOverrideBounds, parentBounds,
2452                     (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
2453                     (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
2454 
2455             // Prevent to overlap caption with stable insets.
2456             final int offsetTop = parentBounds.top - outOverrideBounds.top;
2457             if (offsetTop > 0) {
2458                 outOverrideBounds.offset(0, offsetTop);
2459             }
2460         }
2461     }
2462 
2463     /**
2464      * Compute bounds (letterbox or pillarbox) for
2465      * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
2466      * orientation change and the requested orientation is different from the parent.
2467      */
computeFullscreenBounds(@onNull Rect outBounds, @Nullable ActivityRecord refActivity, @NonNull Rect parentBounds, int parentOrientation)2468     void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
2469             @NonNull Rect parentBounds, int parentOrientation) {
2470         // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
2471         outBounds.setEmpty();
2472         if (handlesOrientationChangeFromDescendant()) {
2473             return;
2474         }
2475         if (refActivity == null) {
2476             // Use the top activity as the reference of orientation. Don't include overlays because
2477             // it is usually not the actual content or just temporarily shown.
2478             // E.g. ForcedResizableInfoActivity.
2479             refActivity = getTopNonFinishingActivity(false /* includeOverlays */);
2480         }
2481 
2482         // If the task or the reference activity requires a different orientation (either by
2483         // override or activityInfo), make it fit the available bounds by scaling down its bounds.
2484         final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
2485         final int forcedOrientation =
2486                 (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
2487                         ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
2488         if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
2489             return;
2490         }
2491 
2492         final int parentWidth = parentBounds.width();
2493         final int parentHeight = parentBounds.height();
2494         final float aspect = ((float) parentHeight) / parentWidth;
2495         if (forcedOrientation == ORIENTATION_LANDSCAPE) {
2496             final int height = (int) (parentWidth / aspect);
2497             final int top = parentBounds.centerY() - height / 2;
2498             outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
2499         } else {
2500             final int width = (int) (parentHeight * aspect);
2501             final int left = parentBounds.centerX() - width / 2;
2502             outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
2503         }
2504     }
2505 
updateOverrideConfigurationFromLaunchBounds()2506     Rect updateOverrideConfigurationFromLaunchBounds() {
2507         // If the task is controlled by another organized task, do not set override
2508         // configurations and let its parent (organized task) to control it;
2509         final Task rootTask = getRootTask();
2510         final Rect bounds = rootTask != this && rootTask.isOrganized() ? null : getLaunchBounds();
2511         setBounds(bounds);
2512         if (bounds != null && !bounds.isEmpty()) {
2513             // TODO: Review if we actually want to do this - we are setting the launch bounds
2514             // directly here.
2515             bounds.set(getRequestedOverrideBounds());
2516         }
2517         return bounds;
2518     }
2519 
2520     /** Updates the task's bounds and override configuration to match what is expected for the
2521      * input stack. */
updateOverrideConfigurationForStack(ActivityStack inStack)2522     void updateOverrideConfigurationForStack(ActivityStack inStack) {
2523         final ActivityStack stack = getStack();
2524 
2525         if (stack != null && stack == inStack) {
2526             return;
2527         }
2528 
2529         if (inStack.inFreeformWindowingMode()) {
2530             if (!isResizeable()) {
2531                 throw new IllegalArgumentException("Can not position non-resizeable task="
2532                         + this + " in stack=" + inStack);
2533             }
2534             if (!matchParentBounds()) {
2535                 return;
2536             }
2537             if (mLastNonFullscreenBounds != null) {
2538                 setBounds(mLastNonFullscreenBounds);
2539             } else {
2540                 mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
2541             }
2542         } else {
2543             setBounds(inStack.getRequestedOverrideBounds());
2544         }
2545     }
2546 
2547     /** Returns the bounds that should be used to launch this task. */
getLaunchBounds()2548     Rect getLaunchBounds() {
2549         final ActivityStack stack = getStack();
2550         if (stack == null) {
2551             return null;
2552         }
2553 
2554         final int windowingMode = getWindowingMode();
2555         if (!isActivityTypeStandardOrUndefined()
2556                 || windowingMode == WINDOWING_MODE_FULLSCREEN
2557                 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
2558             return isResizeable() ? stack.getRequestedOverrideBounds() : null;
2559         } else if (!getWindowConfiguration().persistTaskBounds()) {
2560             return stack.getRequestedOverrideBounds();
2561         }
2562         return mLastNonFullscreenBounds;
2563     }
2564 
setRootProcess(WindowProcessController proc)2565     void setRootProcess(WindowProcessController proc) {
2566         clearRootProcess();
2567         if (intent != null
2568                 && (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
2569             mRootProcess = proc;
2570             mRootProcess.addRecentTask(this);
2571         }
2572     }
2573 
clearRootProcess()2574     void clearRootProcess() {
2575         if (mRootProcess != null) {
2576             mRootProcess.removeRecentTask(this);
2577             mRootProcess = null;
2578         }
2579     }
2580 
2581     @Override
getDisplayContent()2582     DisplayContent getDisplayContent() {
2583         // TODO: Why aren't we just using our own display content vs. parent's???
2584         final ActivityStack stack = getStack();
2585         return stack != null && stack != this
2586                 ? stack.getDisplayContent() : super.getDisplayContent();
2587     }
2588 
getDisplayId()2589     int getDisplayId() {
2590         final DisplayContent dc = getDisplayContent();
2591         return dc != null ? dc.mDisplayId : INVALID_DISPLAY;
2592     }
2593 
2594     // TODO: Migrate callers to getRootTask()
getStack()2595     ActivityStack getStack() {
2596         return (ActivityStack) getRootTask();
2597     }
2598 
2599     /** @return Id of root task. */
getRootTaskId()2600     int getRootTaskId() {
2601         return getRootTask().mTaskId;
2602     }
2603 
getRootTask()2604     Task getRootTask() {
2605         final WindowContainer parent = getParent();
2606         if (parent == null) return this;
2607 
2608         final Task parentTask = parent.asTask();
2609         return parentTask == null ? this : parentTask.getRootTask();
2610     }
2611 
2612     // TODO(task-merge): Figure out what's the right thing to do for places that used it.
isRootTask()2613     boolean isRootTask() {
2614         return getRootTask() == this;
2615     }
2616 
isLeafTask()2617     boolean isLeafTask() {
2618         for (int i = mChildren.size() - 1; i >= 0; --i) {
2619             if (mChildren.get(i).asTask() != null) {
2620                 return false;
2621             }
2622         }
2623         return true;
2624     }
2625 
getDescendantTaskCount()2626     int getDescendantTaskCount() {
2627         final int[] currentCount = {0};
2628         final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; },
2629                 PooledLambda.__(Task.class), currentCount);
2630         forAllLeafTasks(c, false /* traverseTopToBottom */);
2631         c.recycle();
2632         return currentCount[0];
2633     }
2634 
2635     /**
2636      * Find next proper focusable stack and make it focused.
2637      * @return The stack that now got the focus, {@code null} if none found.
2638      */
adjustFocusToNextFocusableTask(String reason)2639     ActivityStack adjustFocusToNextFocusableTask(String reason) {
2640         return adjustFocusToNextFocusableTask(reason, false /* allowFocusSelf */,
2641                 true /* moveDisplayToTop */);
2642     }
2643 
2644     /** Return the next focusable task by looking from the siblings and parent tasks */
getNextFocusableTask(boolean allowFocusSelf)2645     private Task getNextFocusableTask(boolean allowFocusSelf) {
2646         final WindowContainer parent = getParent();
2647         if (parent == null) {
2648             return null;
2649         }
2650 
2651         final Task focusableTask = parent.getTask((task) -> (allowFocusSelf || task != this)
2652                 && ((ActivityStack) task).isFocusableAndVisible());
2653         if (focusableTask == null && parent.asTask() != null) {
2654             return parent.asTask().getNextFocusableTask(allowFocusSelf);
2655         } else {
2656             return focusableTask;
2657         }
2658     }
2659 
2660     /**
2661      * Find next proper focusable task and make it focused.
2662      * @param reason The reason of making the adjustment.
2663      * @param allowFocusSelf Is the focus allowed to remain on the same task.
2664      * @param moveDisplayToTop Whether to move display to top while making the task focused.
2665      * @return The root task that now got the focus, {@code null} if none found.
2666      */
adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf, boolean moveDisplayToTop)2667     ActivityStack adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf,
2668             boolean moveDisplayToTop) {
2669         ActivityStack focusableTask = (ActivityStack) getNextFocusableTask(allowFocusSelf);
2670         if (focusableTask == null) {
2671             focusableTask = mRootWindowContainer.getNextFocusableStack((ActivityStack) this,
2672                     !allowFocusSelf);
2673         }
2674         if (focusableTask == null) {
2675             return null;
2676         }
2677 
2678         final ActivityStack rootTask = (ActivityStack) focusableTask.getRootTask();
2679         if (!moveDisplayToTop) {
2680             // There may be multiple task layers above this task, so when relocating the task to the
2681             // top, we should move this task and each of its parent task that below display area to
2682             // the top of each layer.
2683             WindowContainer parent = focusableTask.getParent();
2684             WindowContainer next = focusableTask;
2685             do {
2686                 parent.positionChildAt(POSITION_TOP, next, false /* includingParents */);
2687                 next = parent;
2688                 parent = next.getParent();
2689             } while (next.asTask() != null && parent != null);
2690             return rootTask;
2691         }
2692 
2693         final String myReason = reason + " adjustFocusToNextFocusableStack";
2694         final ActivityRecord top = focusableTask.topRunningActivity();
2695         if (focusableTask.isActivityTypeHome() && (top == null || !top.mVisibleRequested)) {
2696             // If we will be focusing on the home stack next and its current top activity isn't
2697             // visible, then use the move the home stack task to top to make the activity visible.
2698             focusableTask.getDisplayArea().moveHomeActivityToTop(myReason);
2699             return rootTask;
2700         }
2701 
2702         // Move the entire hierarchy to top with updating global top resumed activity
2703         // and focused application if needed.
2704         focusableTask.moveToFront(myReason);
2705         // Top display focused stack is changed, update top resumed activity if needed.
2706         if (rootTask.mResumedActivity != null) {
2707             mStackSupervisor.updateTopResumedActivityIfNeeded();
2708             // Set focused app directly because if the next focused activity is already resumed
2709             // (e.g. the next top activity is on a different display), there won't have activity
2710             // state change to update it.
2711             mAtmService.setResumedActivityUncheckLocked(rootTask.mResumedActivity, reason);
2712         }
2713         return rootTask;
2714     }
2715 
2716     /** Calculate the minimum possible position for a task that can be shown to the user.
2717      *  The minimum position will be above all other tasks that can't be shown.
2718      *  @param minPosition The minimum position the caller is suggesting.
2719      *                  We will start adjusting up from here.
2720      *  @param size The size of the current task list.
2721      */
2722     // TODO: Move user to their own window container.
computeMinUserPosition(int minPosition, int size)2723     private int computeMinUserPosition(int minPosition, int size) {
2724         while (minPosition < size) {
2725             final WindowContainer child = mChildren.get(minPosition);
2726             final boolean canShow = child.showToCurrentUser();
2727             if (canShow) {
2728                 break;
2729             }
2730             minPosition++;
2731         }
2732         return minPosition;
2733     }
2734 
2735     /** Calculate the maximum possible position for a task that can't be shown to the user.
2736      *  The maximum position will be below all other tasks that can be shown.
2737      *  @param maxPosition The maximum position the caller is suggesting.
2738      *                  We will start adjusting down from here.
2739      */
2740     // TODO: Move user to their own window container.
computeMaxUserPosition(int maxPosition)2741     private int computeMaxUserPosition(int maxPosition) {
2742         while (maxPosition > 0) {
2743             final WindowContainer child = mChildren.get(maxPosition);
2744             final boolean canShow = child.showToCurrentUser();
2745             if (!canShow) {
2746                 break;
2747             }
2748             maxPosition--;
2749         }
2750         return maxPosition;
2751     }
2752 
getAdjustedChildPosition(WindowContainer wc, int suggestedPosition)2753     private int getAdjustedChildPosition(WindowContainer wc, int suggestedPosition) {
2754         final boolean canShowChild = wc.showToCurrentUser();
2755 
2756         final int size = mChildren.size();
2757 
2758         // Figure-out min/max possible position depending on if child can show for current user.
2759         int minPosition = (canShowChild) ? computeMinUserPosition(0, size) : 0;
2760         int maxPosition = (canShowChild) ? size : computeMaxUserPosition(size - 1);
2761 
2762         // Factor in always-on-top children in max possible position.
2763         if (!wc.isAlwaysOnTop()) {
2764 
2765             // We want to place all non-always-on-top containers below always-on-top ones.
2766             while (maxPosition > minPosition) {
2767                 if (!mChildren.get(maxPosition - 1).isAlwaysOnTop()) break;
2768                 --maxPosition;
2769             }
2770         }
2771 
2772         // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid.
2773         if (suggestedPosition == POSITION_BOTTOM && minPosition == 0) {
2774             return POSITION_BOTTOM;
2775         } else if (suggestedPosition == POSITION_TOP && maxPosition >= (size - 1)) {
2776             return POSITION_TOP;
2777         }
2778         // Reset position based on minimum/maximum possible positions.
2779         return Math.min(Math.max(suggestedPosition, minPosition), maxPosition);
2780     }
2781 
2782     @Override
positionChildAt(int position, WindowContainer child, boolean includingParents)2783     void positionChildAt(int position, WindowContainer child, boolean includingParents) {
2784         position = getAdjustedChildPosition(child, position);
2785         super.positionChildAt(position, child, includingParents);
2786 
2787         // Log positioning.
2788         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "positionChildAt: child=" + child
2789                 + " position=" + position + " parent=" + this);
2790 
2791         final int toTop = position >= (mChildren.size() - 1) ? 1 : 0;
2792         final Task task = child.asTask();
2793         if (task != null) {
2794             EventLogTags.writeWmTaskMoved(task.mTaskId, toTop, position);
2795         }
2796     }
2797 
2798     @VisibleForTesting
hasWindowsAlive()2799     boolean hasWindowsAlive() {
2800         return getActivity(ActivityRecord::hasWindowsAlive) != null;
2801     }
2802 
2803     @VisibleForTesting
shouldDeferRemoval()2804     boolean shouldDeferRemoval() {
2805         if (mChildren.isEmpty()) {
2806             // No reason to defer removal of a Task that doesn't have any child.
2807             return false;
2808         }
2809         return hasWindowsAlive() && getStack().isAnimating(TRANSITION | CHILDREN);
2810     }
2811 
2812     @Override
removeImmediately()2813     void removeImmediately() {
2814         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
2815         EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask");
2816 
2817         if (mDisplayContent != null && mDisplayContent.isSingleTaskInstance()) {
2818             mAtmService.notifySingleTaskDisplayEmpty(mDisplayContent.mDisplayId);
2819         }
2820 
2821         // If applicable let the TaskOrganizer know the Task is vanishing.
2822         setTaskOrganizer(null);
2823 
2824         super.removeImmediately();
2825     }
2826 
2827     // TODO: Consolidate this with Task.reparent()
reparent(ActivityStack stack, int position, boolean moveParents, String reason)2828     void reparent(ActivityStack stack, int position, boolean moveParents, String reason) {
2829         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
2830                 + " from stack=" + getStack());
2831         EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason);
2832 
2833         reparent(stack, position);
2834 
2835         stack.positionChildAt(position, this, moveParents);
2836 
2837         // If we are moving from the fullscreen stack to the pinned stack then we want to preserve
2838         // our insets so that there will not be a jump in the area covered by system decorations.
2839         // We rely on the pinned animation to later unset this value.
2840         mPreserveNonFloatingState = stack.inPinnedWindowingMode();
2841     }
2842 
setBounds(Rect bounds, boolean forceResize)2843     public int setBounds(Rect bounds, boolean forceResize) {
2844         final int boundsChanged = setBounds(bounds);
2845 
2846         if (forceResize && (boundsChanged & BOUNDS_CHANGE_SIZE) != BOUNDS_CHANGE_SIZE) {
2847             onResize();
2848             return BOUNDS_CHANGE_SIZE | boundsChanged;
2849         }
2850 
2851         return boundsChanged;
2852     }
2853 
2854     /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
2855     @Override
setBounds(Rect bounds)2856     public int setBounds(Rect bounds) {
2857         int rotation = Surface.ROTATION_0;
2858         final DisplayContent displayContent = getStack() != null
2859                 ? getStack().getDisplayContent() : null;
2860         if (displayContent != null) {
2861             rotation = displayContent.getDisplayInfo().rotation;
2862         }
2863 
2864         final int boundsChange = super.setBounds(bounds);
2865         mRotation = rotation;
2866         updateSurfacePosition();
2867         return boundsChange;
2868     }
2869 
2870     @Override
onDescendantOrientationChanged(IBinder freezeDisplayToken, ConfigurationContainer requestingContainer)2871     public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
2872             ConfigurationContainer requestingContainer) {
2873         if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) {
2874             return true;
2875         }
2876 
2877         // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill
2878         // it if possible.
2879         if (getParent() != null) {
2880             onConfigurationChanged(getParent().getConfiguration());
2881             return true;
2882         }
2883         return false;
2884     }
2885 
resize(boolean relayout, boolean forced)2886     void resize(boolean relayout, boolean forced) {
2887         if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) {
2888             getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
2889         }
2890     }
2891 
2892     @Override
onDisplayChanged(DisplayContent dc)2893     void onDisplayChanged(DisplayContent dc) {
2894         final boolean isRootTask = isRootTask();
2895         if (!isRootTask) {
2896             adjustBoundsForDisplayChangeIfNeeded(dc);
2897         }
2898         super.onDisplayChanged(dc);
2899         if (isLeafTask()) {
2900             final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY;
2901             mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged(
2902                     mTaskId, displayId);
2903         }
2904     }
2905 
isResizeable(boolean checkSupportsPip)2906     boolean isResizeable(boolean checkSupportsPip) {
2907         return (mAtmService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode)
2908                 || (checkSupportsPip && mSupportsPictureInPicture));
2909     }
2910 
isResizeable()2911     boolean isResizeable() {
2912         return isResizeable(true /* checkSupportsPip */);
2913     }
2914 
2915     /**
2916      * Tests if the orientation should be preserved upon user interactive resizig operations.
2917 
2918      * @return true if orientation should not get changed upon resizing operation.
2919      */
preserveOrientationOnResize()2920     boolean preserveOrientationOnResize() {
2921         return mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY
2922                 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY
2923                 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
2924     }
2925 
cropWindowsToStackBounds()2926     boolean cropWindowsToStackBounds() {
2927         // Don't crop HOME/RECENTS windows to stack bounds. This is because in split-screen
2928         // they extend past their stack and sysui uses the stack surface to control cropping.
2929         // TODO(b/158242495): get rid of this when drag/drop can use surface bounds.
2930         if (isActivityTypeHome() || isActivityTypeRecents()) {
2931             // Make sure this is the top-most non-organizer root task (if not top-most, it means
2932             // another translucent task could be above this, so this needs to stay cropped.
2933             final Task rootTask = getRootTask();
2934             final Task topNonOrgTask =
2935                     rootTask.mCreatedByOrganizer ? rootTask.getTopMostTask() : rootTask;
2936             if (this == topNonOrgTask || isDescendantOf(topNonOrgTask)) {
2937                 return false;
2938             }
2939         }
2940         return isResizeable();
2941     }
2942 
2943     /**
2944      * Prepares the task bounds to be frozen with the current size. See
2945      * {@link ActivityRecord#freezeBounds}.
2946      */
prepareFreezingBounds()2947     void prepareFreezingBounds() {
2948         mPreparedFrozenBounds.set(getBounds());
2949         mPreparedFrozenMergedConfig.setTo(getConfiguration());
2950     }
2951 
2952     @Override
getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, Rect outSurfaceInsets)2953     void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
2954             Rect outSurfaceInsets) {
2955         final WindowState windowState = getTopVisibleAppMainWindow();
2956         if (windowState != null) {
2957             windowState.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
2958         } else {
2959             super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
2960         }
2961     }
2962 
2963     /**
2964      * Calculate the maximum visible area of this task. If the task has only one app,
2965      * the result will be visible frame of that app. If the task has more than one apps,
2966      * we search from top down if the next app got different visible area.
2967      *
2968      * This effort is to handle the case where some task (eg. GMail composer) might pop up
2969      * a dialog that's different in size from the activity below, in which case we should
2970      * be dimming the entire task area behind the dialog.
2971      *
2972      * @param out Rect containing the max visible bounds.
2973      * @return true if the task has some visible app windows; false otherwise.
2974      */
getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop)2975     private static void getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop) {
2976         // skip hidden (or about to hide) apps
2977         if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) {
2978             return;
2979         }
2980         final WindowState win = token.findMainWindow();
2981         if (win == null) {
2982             return;
2983         }
2984         if (!foundTop[0]) {
2985             foundTop[0] = true;
2986             out.setEmpty();
2987         }
2988 
2989         win.getMaxVisibleBounds(out);
2990     }
2991 
2992     /** Bounds of the task to be used for dimming, as well as touch related tests. */
getDimBounds(Rect out)2993     void getDimBounds(Rect out) {
2994         final DisplayContent displayContent = getStack().getDisplayContent();
2995         // It doesn't matter if we in particular are part of the resize, since we couldn't have
2996         // a DimLayer anyway if we weren't visible.
2997         final boolean dockedResizing = displayContent != null
2998                 && displayContent.mDividerControllerLocked.isResizing();
2999         if (inFreeformWindowingMode()) {
3000             boolean[] foundTop = { false };
3001             final PooledConsumer c = PooledLambda.obtainConsumer(Task::getMaxVisibleBounds,
3002                     PooledLambda.__(ActivityRecord.class), out, foundTop);
3003             forAllActivities(c);
3004             c.recycle();
3005             if (foundTop[0]) {
3006                 return;
3007             }
3008         }
3009 
3010         if (!matchParentBounds()) {
3011             // When minimizing the docked stack when going home, we don't adjust the task bounds
3012             // so we need to intersect the task bounds with the stack bounds here.
3013             //
3014             // If we are Docked Resizing with snap points, the task bounds could be smaller than the
3015             // stack bounds and so we don't even want to use them. Even if the app should not be
3016             // resized the Dim should keep up with the divider.
3017             if (dockedResizing) {
3018                 getStack().getBounds(out);
3019             } else {
3020                 getStack().getBounds(mTmpRect);
3021                 mTmpRect.intersect(getBounds());
3022                 out.set(mTmpRect);
3023             }
3024         } else {
3025             out.set(getBounds());
3026         }
3027         return;
3028     }
3029 
setDragResizing(boolean dragResizing, int dragResizeMode)3030     void setDragResizing(boolean dragResizing, int dragResizeMode) {
3031         if (mDragResizing != dragResizing) {
3032             // No need to check if the mode is allowed if it's leaving dragResize
3033             if (dragResizing && !DragResizeMode.isModeAllowedForStack(getStack(), dragResizeMode)) {
3034                 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
3035                         + getRootTaskId() + " dragResizeMode=" + dragResizeMode);
3036             }
3037             mDragResizing = dragResizing;
3038             mDragResizeMode = dragResizeMode;
3039             resetDragResizingChangeReported();
3040         }
3041     }
3042 
isDragResizing()3043     boolean isDragResizing() {
3044         return mDragResizing;
3045     }
3046 
getDragResizeMode()3047     int getDragResizeMode() {
3048         return mDragResizeMode;
3049     }
3050 
adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent)3051     void adjustBoundsForDisplayChangeIfNeeded(final DisplayContent displayContent) {
3052         if (displayContent == null) {
3053             return;
3054         }
3055         if (matchParentBounds()) {
3056             // TODO: Yeah...not sure if this works with WindowConfiguration, but shouldn't be a
3057             // problem once we move mBounds into WindowConfiguration.
3058             setBounds(null);
3059             return;
3060         }
3061         final int displayId = displayContent.getDisplayId();
3062         final int newRotation = displayContent.getDisplayInfo().rotation;
3063         if (displayId != mLastRotationDisplayId) {
3064             // This task is on a display that it wasn't on. There is no point to keep the relative
3065             // position if display rotations for old and new displays are different. Just keep these
3066             // values.
3067             mLastRotationDisplayId = displayId;
3068             mRotation = newRotation;
3069             return;
3070         }
3071 
3072         if (mRotation == newRotation) {
3073             // Rotation didn't change. We don't need to adjust the bounds to keep the relative
3074             // position.
3075             return;
3076         }
3077 
3078         // Device rotation changed.
3079         // - We don't want the task to move around on the screen when this happens, so update the
3080         //   task bounds so it stays in the same place.
3081         // - Rotate the bounds and notify activity manager if the task can be resized independently
3082         //   from its stack. The stack will take care of task rotation for the other case.
3083         mTmpRect2.set(getBounds());
3084 
3085         if (!getWindowConfiguration().canResizeTask()) {
3086             setBounds(mTmpRect2);
3087             return;
3088         }
3089 
3090         displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
3091         if (setBounds(mTmpRect2) != BOUNDS_CHANGE_NONE) {
3092             mAtmService.resizeTask(mTaskId, getBounds(), RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
3093         }
3094     }
3095 
3096     /** Cancels any running app transitions associated with the task. */
cancelTaskWindowTransition()3097     void cancelTaskWindowTransition() {
3098         for (int i = mChildren.size() - 1; i >= 0; --i) {
3099             mChildren.get(i).cancelAnimation();
3100         }
3101     }
3102 
showForAllUsers()3103     boolean showForAllUsers() {
3104         if (mChildren.isEmpty()) return false;
3105         final ActivityRecord r = getTopNonFinishingActivity();
3106         return r != null && r.mShowForAllUsers;
3107     }
3108 
3109     @Override
showToCurrentUser()3110     boolean showToCurrentUser() {
3111         return mForceShowForAllUsers || showForAllUsers()
3112                 || mWmService.isCurrentProfile(getTopMostTask().mUserId);
3113     }
3114 
setForceShowForAllUsers(boolean forceShowForAllUsers)3115     void setForceShowForAllUsers(boolean forceShowForAllUsers) {
3116         mForceShowForAllUsers = forceShowForAllUsers;
3117     }
3118 
3119     @Override
isAttached()3120     public boolean isAttached() {
3121         final TaskDisplayArea taskDisplayArea = getDisplayArea();
3122         return taskDisplayArea != null && !taskDisplayArea.isRemoved();
3123     }
3124 
3125     @Override
3126     @Nullable
getDisplayArea()3127     TaskDisplayArea getDisplayArea() {
3128         return (TaskDisplayArea) super.getDisplayArea();
3129     }
3130 
3131     /**
3132      * When we are in a floating stack (Freeform, Pinned, ...) we calculate
3133      * insets differently. However if we are animating to the fullscreen stack
3134      * we need to begin calculating insets as if we were fullscreen, otherwise
3135      * we will have a jump at the end.
3136      */
isFloating()3137     boolean isFloating() {
3138         return getWindowConfiguration().tasksAreFloating() && !mPreserveNonFloatingState;
3139     }
3140 
3141     /**
3142      * Returns true if the stack is translucent and can have other contents visible behind it if
3143      * needed. A stack is considered translucent if it don't contain a visible or
3144      * starting (about to be visible) activity that is fullscreen (opaque).
3145      * @param starting The currently starting activity or null if there is none.
3146      */
3147     @VisibleForTesting
isTranslucent(ActivityRecord starting)3148     boolean isTranslucent(ActivityRecord starting) {
3149         if (!isAttached() || isForceHidden()) {
3150             return true;
3151         }
3152         final PooledPredicate p = PooledLambda.obtainPredicate(Task::isOpaqueActivity,
3153                 PooledLambda.__(ActivityRecord.class), starting);
3154         final ActivityRecord opaque = getActivity(p);
3155         p.recycle();
3156         return opaque == null;
3157     }
3158 
isOpaqueActivity(ActivityRecord r, ActivityRecord starting)3159     private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) {
3160         if (r.finishing) {
3161             // We don't factor in finishing activities when determining translucency since
3162             // they will be gone soon.
3163             return false;
3164         }
3165 
3166         if (!r.visibleIgnoringKeyguard && r != starting) {
3167             // Also ignore invisible activities that are not the currently starting
3168             // activity (about to be visible).
3169             return false;
3170         }
3171 
3172         if (r.occludesParent() || r.hasWallpaper) {
3173             // Stack isn't translucent if it has at least one fullscreen activity
3174             // that is visible.
3175             return true;
3176         }
3177         return false;
3178     }
3179 
3180     @Override
makeAnimationLeash()3181     public SurfaceControl.Builder makeAnimationLeash() {
3182         return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId);
3183     }
3184 
3185     @Override
getAnimationLeashParent()3186     public SurfaceControl getAnimationLeashParent() {
3187         if (WindowManagerService.sHierarchicalAnimations) {
3188             return super.getAnimationLeashParent();
3189         }
3190         // Currently, only the recents animation will create animation leashes for tasks. In this
3191         // case, reparent the task to the home animation layer while it is being animated to allow
3192         // the home activity to reorder the app windows relative to its own.
3193         return getAppAnimationLayer(ANIMATION_LAYER_HOME);
3194     }
3195 
3196     @Override
getAnimationBounds(int appStackClipMode)3197     Rect getAnimationBounds(int appStackClipMode) {
3198         // TODO(b/131661052): we should remove appStackClipMode with hierarchical animations.
3199         if (appStackClipMode == STACK_CLIP_BEFORE_ANIM && getStack() != null) {
3200             // Using the stack bounds here effectively applies the clipping before animation.
3201             return getStack().getBounds();
3202         }
3203         return super.getAnimationBounds(appStackClipMode);
3204     }
3205 
shouldAnimate()3206     boolean shouldAnimate() {
3207         /**
3208          * Animations are handled by the TaskOrganizer implementation.
3209          */
3210         if (isOrganized()) {
3211             return false;
3212         }
3213         // Don't animate while the task runs recents animation but only if we are in the mode
3214         // where we cancel with deferred screenshot, which means that the controller has
3215         // transformed the task.
3216         final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
3217         if (controller != null && controller.isAnimatingTask(this)
3218                 && controller.shouldDeferCancelUntilNextTransition()) {
3219             return false;
3220         }
3221         return true;
3222     }
3223 
3224     @Override
setInitialSurfaceControlProperties(SurfaceControl.Builder b)3225     void setInitialSurfaceControlProperties(SurfaceControl.Builder b) {
3226         b.setEffectLayer().setMetadata(METADATA_TASK_ID, mTaskId);
3227         super.setInitialSurfaceControlProperties(b);
3228     }
3229 
isTaskAnimating()3230     boolean isTaskAnimating() {
3231         final RecentsAnimationController recentsAnim = mWmService.getRecentsAnimationController();
3232         if (recentsAnim != null) {
3233             if (recentsAnim.isAnimatingTask(this)) {
3234                 return true;
3235             }
3236         }
3237         return forAllTasks((t) -> { return t != this && t.isTaskAnimating(); });
3238     }
3239 
3240     @Override
createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record)3241     RemoteAnimationTarget createRemoteAnimationTarget(
3242             RemoteAnimationController.RemoteAnimationRecord record) {
3243         final ActivityRecord activity = getTopMostActivity();
3244         return activity != null ? activity.createRemoteAnimationTarget(record) : null;
3245     }
3246 
3247     @Override
canCreateRemoteAnimationTarget()3248     boolean canCreateRemoteAnimationTarget() {
3249         return true;
3250     }
3251 
getTopVisibleAppMainWindow()3252     WindowState getTopVisibleAppMainWindow() {
3253         final ActivityRecord activity = getTopVisibleActivity();
3254         return activity != null ? activity.findMainWindow() : null;
3255     }
3256 
topRunningActivity()3257     ActivityRecord topRunningActivity() {
3258         return topRunningActivity(false /* focusableOnly */);
3259     }
3260 
topRunningActivity(boolean focusableOnly)3261     ActivityRecord topRunningActivity(boolean focusableOnly) {
3262         // Split into 2 to avoid object creation due to variable capture.
3263         if (focusableOnly) {
3264             return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
3265         } else {
3266             return getActivity(ActivityRecord::canBeTopRunning);
3267         }
3268     }
3269 
topRunningNonDelayedActivityLocked(ActivityRecord notTop)3270     ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
3271         final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunningNonDelayed
3272                 , PooledLambda.__(ActivityRecord.class), notTop);
3273         final ActivityRecord r = getActivity(p);
3274         p.recycle();
3275         return r;
3276     }
3277 
isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop)3278     private static boolean isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop) {
3279         return !r.delayedResume && r != notTop && r.canBeTopRunning();
3280     }
3281 
3282     /**
3283      * This is a simplified version of topRunningActivity that provides a number of
3284      * optional skip-over modes.  It is intended for use with the ActivityController hook only.
3285      *
3286      * @param token If non-null, any history records matching this token will be skipped.
3287      * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
3288      *
3289      * @return Returns the HistoryRecord of the next activity on the stack.
3290      */
topRunningActivity(IBinder token, int taskId)3291     ActivityRecord topRunningActivity(IBinder token, int taskId) {
3292         final PooledPredicate p = PooledLambda.obtainPredicate(Task::isTopRunning,
3293                 PooledLambda.__(ActivityRecord.class), taskId, token);
3294         final ActivityRecord r = getActivity(p);
3295         p.recycle();
3296         return r;
3297     }
3298 
isTopRunning(ActivityRecord r, int taskId, IBinder notTop)3299     private static boolean isTopRunning(ActivityRecord r, int taskId, IBinder notTop) {
3300         return r.getTask().mTaskId != taskId && r.appToken != notTop && r.canBeTopRunning();
3301     }
3302 
getTopFullscreenActivity()3303     ActivityRecord getTopFullscreenActivity() {
3304         return getActivity((r) -> {
3305             final WindowState win = r.findMainWindow();
3306             return (win != null && win.mAttrs.isFullscreen());
3307         });
3308     }
3309 
3310     ActivityRecord getTopVisibleActivity() {
3311         return getActivity((r) -> {
3312             // skip hidden (or about to hide) apps
3313             return !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested;
3314         });
3315     }
3316 
3317     boolean isTopActivityFocusable() {
3318         final ActivityRecord r = topRunningActivity();
3319         return r != null ? r.isFocusable()
3320                 : (isFocusable() && getWindowConfiguration().canReceiveKeys());
3321     }
3322 
3323     boolean isFocusableAndVisible() {
3324         return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
3325     }
3326 
3327     void positionChildAtTop(ActivityRecord child) {
3328         positionChildAt(child, POSITION_TOP);
3329     }
3330 
3331     void positionChildAt(ActivityRecord child, int position) {
3332         if (child == null) {
3333             Slog.w(TAG_WM,
3334                     "Attempted to position of non-existing app");
3335             return;
3336         }
3337 
3338         positionChildAt(position, child, false /* includeParents */);
3339     }
3340 
3341     void forceWindowsScaleable(boolean force) {
3342         mWmService.openSurfaceTransaction();
3343         try {
3344             for (int i = mChildren.size() - 1; i >= 0; i--) {
3345                 mChildren.get(i).forceWindowsScaleableInTransaction(force);
3346             }
3347         } finally {
3348             mWmService.closeSurfaceTransaction("forceWindowsScaleable");
3349         }
3350     }
3351 
3352     void setTaskDescription(TaskDescription taskDescription) {
3353         mTaskDescription = taskDescription;
3354     }
3355 
3356     void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
3357         mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(
3358                 mTaskId, snapshot);
3359     }
3360 
3361     TaskDescription getTaskDescription() {
3362         return mTaskDescription;
3363     }
3364 
3365     @Override
3366     int getOrientation(int candidate) {
3367         return canSpecifyOrientation() ? super.getOrientation(candidate) : SCREEN_ORIENTATION_UNSET;
3368     }
3369 
3370     private boolean canSpecifyOrientation() {
3371         final int windowingMode = getWindowingMode();
3372         final int activityType = getActivityType();
3373         return windowingMode == WINDOWING_MODE_FULLSCREEN
3374                 || activityType == ACTIVITY_TYPE_HOME
3375                 || activityType == ACTIVITY_TYPE_RECENTS
3376                 || activityType == ACTIVITY_TYPE_ASSISTANT;
3377     }
3378 
3379     @Override
3380     boolean fillsParent() {
3381         return matchParentBounds();
3382     }
3383 
3384     @Override
3385     void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
3386         final int count = mChildren.size();
3387         boolean isLeafTask = true;
3388         if (traverseTopToBottom) {
3389             for (int i = count - 1; i >= 0; --i) {
3390                 final Task child = mChildren.get(i).asTask();
3391                 if (child != null) {
3392                     isLeafTask = false;
3393                     child.forAllLeafTasks(callback, traverseTopToBottom);
3394                 }
3395             }
3396         } else {
3397             for (int i = 0; i < count; i++) {
3398                 final Task child = mChildren.get(i).asTask();
3399                 if (child != null) {
3400                     isLeafTask = false;
3401                     child.forAllLeafTasks(callback, traverseTopToBottom);
3402                 }
3403             }
3404         }
3405         if (isLeafTask) callback.accept(this);
3406     }
3407 
3408     @Override
3409     void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
3410         super.forAllTasks(callback, traverseTopToBottom);
3411         callback.accept(this);
3412     }
3413 
3414     @Override
3415     boolean forAllTasks(Function<Task, Boolean> callback) {
3416         if (super.forAllTasks(callback)) return true;
3417         return callback.apply(this);
3418     }
3419 
3420     @Override
3421     boolean forAllLeafTasks(Function<Task, Boolean> callback) {
3422         boolean isLeafTask = true;
3423         for (int i = mChildren.size() - 1; i >= 0; --i) {
3424             final Task child = mChildren.get(i).asTask();
3425             if (child != null) {
3426                 isLeafTask = false;
3427                 if (child.forAllLeafTasks(callback)) {
3428                     return true;
3429                 }
3430             }
3431         }
3432         if (isLeafTask) {
3433             return callback.apply(this);
3434         }
3435         return false;
3436     }
3437 
3438     @Override
3439     Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) {
3440         final Task t = super.getTask(callback, traverseTopToBottom);
3441         if (t != null) return t;
3442         return callback.test(this) ? this : null;
3443     }
3444 
3445     /**
3446      * @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI
3447      *                               flags. See {@link WindowState#canAffectSystemUiFlags()}.
3448      */
3449     void setCanAffectSystemUiFlags(boolean canAffectSystemUiFlags) {
3450         mCanAffectSystemUiFlags = canAffectSystemUiFlags;
3451     }
3452 
3453     /**
3454      * @see #setCanAffectSystemUiFlags
3455      */
3456     boolean canAffectSystemUiFlags() {
3457         return mCanAffectSystemUiFlags;
3458     }
3459 
3460     void dontAnimateDimExit() {
3461         mDimmer.dontAnimateExit();
3462     }
3463 
3464     String getName() {
3465         return "Task=" + mTaskId;
3466     }
3467 
3468     void clearPreserveNonFloatingState() {
3469         mPreserveNonFloatingState = false;
3470     }
3471 
3472     @Override
3473     Dimmer getDimmer() {
3474         // If the window is in multi-window mode, we want to dim at the Task level to ensure the dim
3475         // bounds match the area the app lives in
3476         if (inMultiWindowMode()) {
3477             return mDimmer;
3478         }
3479 
3480         // If we're not at the root task level, we want to keep traversing through the parents to
3481         // find the root.
3482         // Once at the root task level, we want to check {@link #isTranslucent(ActivityRecord)}.
3483         // If true, we want to get the Dimmer from the level above since we don't want to animate
3484         // the dim with the Task.
3485         if (!isRootTask() || isTranslucent(null)) {
3486             return super.getDimmer();
3487         }
3488 
3489         return mDimmer;
3490     }
3491 
3492     @Override
3493     void prepareSurfaces() {
3494         mDimmer.resetDimStates();
3495         super.prepareSurfaces();
3496         getDimBounds(mTmpDimBoundsRect);
3497 
3498         // Bounds need to be relative, as the dim layer is a child.
3499         if (inFreeformWindowingMode()) {
3500             getBounds(mTmpRect);
3501             mTmpDimBoundsRect.offsetTo(mTmpDimBoundsRect.left - mTmpRect.left,
3502                     mTmpDimBoundsRect.top - mTmpRect.top);
3503         } else {
3504             mTmpDimBoundsRect.offsetTo(0, 0);
3505         }
3506 
3507         updateShadowsRadius(isFocused(), getSyncTransaction());
3508 
3509         if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
3510             scheduleAnimation();
3511         }
3512     }
3513 
3514     @Override
3515     protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
3516             int transit, boolean isVoiceInteraction,
3517             @Nullable ArrayList<WindowContainer> sources) {
3518         final RecentsAnimationController control = mWmService.getRecentsAnimationController();
3519         if (control != null) {
3520             // We let the transition to be controlled by RecentsAnimation, and callback task's
3521             // RemoteAnimationTarget for remote runner to animate.
3522             if (enter) {
3523                 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
3524                         "applyAnimationUnchecked, control: %s, task: %s, transit: %s",
3525                         control, asTask(), AppTransition.appTransitionToString(transit));
3526                 control.addTaskToTargets(this, (type, anim) -> {
3527                     for (int i = 0; i < sources.size(); ++i) {
3528                         sources.get(i).onAnimationFinished(type, anim);
3529                     }
3530                 });
3531             }
3532         } else {
3533             super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
3534         }
3535     }
3536 
3537     @Override
3538     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
3539         super.dump(pw, prefix, dumpAll);
3540         pw.println(prefix + "bounds=" + getBounds().toShortString());
3541         final String doublePrefix = prefix + "  ";
3542         for (int i = mChildren.size() - 1; i >= 0; i--) {
3543             final WindowContainer<?> child = mChildren.get(i);
3544             pw.println(prefix + "* " + child);
3545             // Only dump non-activity because full activity info is already printed by
3546             // RootWindowContainer#dumpActivities.
3547             if (child.asActivityRecord() == null) {
3548                 child.dump(pw, doublePrefix, dumpAll);
3549             }
3550         }
3551     }
3552 
3553 
3554     /**
3555      * Fills in a {@link TaskInfo} with information from this task. Note that the base intent in the
3556      * task info will not include any extras or clip data.
3557      */
3558     void fillTaskInfo(TaskInfo info) {
3559         fillTaskInfo(info, true /* stripExtras */);
3560     }
3561 
3562     /**
3563      * Fills in a {@link TaskInfo} with information from this task.
3564      */
3565     void fillTaskInfo(TaskInfo info, boolean stripExtras) {
3566         getNumRunningActivities(mReuseActivitiesReport);
3567         info.userId = mUserId;
3568         info.stackId = getRootTaskId();
3569         info.taskId = mTaskId;
3570         info.displayId = getDisplayId();
3571         info.isRunning = getTopNonFinishingActivity() != null;
3572         final Intent baseIntent = getBaseIntent();
3573         // Make a copy of base intent because this is like a snapshot info.
3574         // Besides, {@link RecentTasks#getRecentTasksImpl} may modify it.
3575         final int baseIntentFlags = baseIntent == null ? 0 : baseIntent.getFlags();
3576         info.baseIntent = baseIntent == null
3577                 ? new Intent()
3578                 : stripExtras ? baseIntent.cloneFilter() : new Intent(baseIntent);
3579         info.baseIntent.setFlags(baseIntentFlags);
3580         info.baseActivity = mReuseActivitiesReport.base != null
3581                 ? mReuseActivitiesReport.base.intent.getComponent()
3582                 : null;
3583         info.topActivity = mReuseActivitiesReport.top != null
3584                 ? mReuseActivitiesReport.top.mActivityComponent
3585                 : null;
3586         info.origActivity = origActivity;
3587         info.realActivity = realActivity;
3588         info.numActivities = mReuseActivitiesReport.numActivities;
3589         info.lastActiveTime = lastActiveTime;
3590         info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
3591         info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
3592         info.configuration.setTo(getConfiguration());
3593         info.token = mRemoteToken.toWindowContainerToken();
3594 
3595         //TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child
3596         //                    order changes.
3597         final Task top = getTopMostTask();
3598         info.resizeMode = top != null ? top.mResizeMode : mResizeMode;
3599         info.topActivityType = top.getActivityType();
3600         info.isResizeable = isResizeable();
3601 
3602         ActivityRecord rootActivity = top.getRootActivity();
3603         if (rootActivity == null || rootActivity.pictureInPictureArgs.empty()) {
3604             info.pictureInPictureParams = null;
3605         } else {
3606             info.pictureInPictureParams = rootActivity.pictureInPictureArgs;
3607         }
3608         info.topActivityInfo = mReuseActivitiesReport.top != null
3609                 ? mReuseActivitiesReport.top.info
3610                 : null;
3611     }
3612 
3613     /**
3614      * Returns a {@link TaskInfo} with information from this task.
3615      */
3616     ActivityManager.RunningTaskInfo getTaskInfo() {
3617         ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
3618         fillTaskInfo(info);
3619         return info;
3620     }
3621 
3622     boolean isTaskId(int taskId) {
3623         return mTaskId == taskId;
3624     }
3625 
3626     @Override
3627     Task asTask() {
3628         // I'm a task!
3629         return this;
3630     }
3631 
3632     /**
3633      * Returns true if the task should be visible.
3634      *
3635      * @param starting The currently starting activity or null if there is none.
3636      */
3637     boolean shouldBeVisible(ActivityRecord starting) {
3638         return getVisibility(starting) != STACK_VISIBILITY_INVISIBLE;
3639     }
3640 
3641     /**
3642      * Returns true if the task should be visible.
3643      *
3644      * @param starting The currently starting activity or null if there is none.
3645      */
3646     @ActivityStack.StackVisibility
3647     int getVisibility(ActivityRecord starting) {
3648         if (!isAttached() || isForceHidden()) {
3649             return STACK_VISIBILITY_INVISIBLE;
3650         }
3651 
3652         boolean gotSplitScreenStack = false;
3653         boolean gotOpaqueSplitScreenPrimary = false;
3654         boolean gotOpaqueSplitScreenSecondary = false;
3655         boolean gotTranslucentFullscreen = false;
3656         boolean gotTranslucentSplitScreenPrimary = false;
3657         boolean gotTranslucentSplitScreenSecondary = false;
3658         boolean shouldBeVisible = true;
3659 
3660         // This stack is only considered visible if all its parent stacks are considered visible,
3661         // so check the visibility of all ancestor stacks first.
3662         final WindowContainer parent = getParent();
3663         if (parent.asTask() != null) {
3664             final int parentVisibility = parent.asTask().getVisibility(starting);
3665             if (parentVisibility == STACK_VISIBILITY_INVISIBLE) {
3666                 // Can't be visible if parent isn't visible
3667                 return STACK_VISIBILITY_INVISIBLE;
3668             } else if (parentVisibility == STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) {
3669                 // Parent is behind a translucent container so the highest visibility this container
3670                 // can get is that.
3671                 gotTranslucentFullscreen = true;
3672             }
3673         }
3674 
3675         final int windowingMode = getWindowingMode();
3676         final boolean isAssistantType = isActivityTypeAssistant();
3677         for (int i = parent.getChildCount() - 1; i >= 0; --i) {
3678             final WindowContainer wc = parent.getChildAt(i);
3679             final Task other = wc.asTask();
3680             if (other == null) continue;
3681 
3682             final boolean hasRunningActivities = other.topRunningActivity() != null;
3683             if (other == this) {
3684                 // Should be visible if there is no other stack occluding it, unless it doesn't
3685                 // have any running activities, not starting one and not home stack.
3686                 shouldBeVisible = hasRunningActivities || isInTask(starting) != null
3687                         || isActivityTypeHome();
3688                 break;
3689             }
3690 
3691             if (!hasRunningActivities) {
3692                 continue;
3693             }
3694 
3695             final int otherWindowingMode = other.getWindowingMode();
3696 
3697             if (otherWindowingMode == WINDOWING_MODE_FULLSCREEN) {
3698                 if (other.isTranslucent(starting)) {
3699                     // Can be visible behind a translucent fullscreen stack.
3700                     gotTranslucentFullscreen = true;
3701                     continue;
3702                 }
3703                 return STACK_VISIBILITY_INVISIBLE;
3704             } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
3705                     && !gotOpaqueSplitScreenPrimary) {
3706                 gotSplitScreenStack = true;
3707                 gotTranslucentSplitScreenPrimary = other.isTranslucent(starting);
3708                 gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary;
3709                 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
3710                         && gotOpaqueSplitScreenPrimary) {
3711                     // Can not be visible behind another opaque stack in split-screen-primary mode.
3712                     return STACK_VISIBILITY_INVISIBLE;
3713                 }
3714             } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
3715                     && !gotOpaqueSplitScreenSecondary) {
3716                 gotSplitScreenStack = true;
3717                 gotTranslucentSplitScreenSecondary = other.isTranslucent(starting);
3718                 gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary;
3719                 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
3720                         && gotOpaqueSplitScreenSecondary) {
3721                     // Can not be visible behind another opaque stack in split-screen-secondary mode.
3722                     return STACK_VISIBILITY_INVISIBLE;
3723                 }
3724             }
3725             if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) {
3726                 // Can not be visible if we are in split-screen windowing mode and both halves of
3727                 // the screen are opaque.
3728                 return STACK_VISIBILITY_INVISIBLE;
3729             }
3730             if (isAssistantType && gotSplitScreenStack) {
3731                 // Assistant stack can't be visible behind split-screen. In addition to this not
3732                 // making sense, it also works around an issue here we boost the z-order of the
3733                 // assistant window surfaces in window manager whenever it is visible.
3734                 return STACK_VISIBILITY_INVISIBLE;
3735             }
3736         }
3737 
3738         if (!shouldBeVisible) {
3739             return STACK_VISIBILITY_INVISIBLE;
3740         }
3741 
3742         // Handle cases when there can be a translucent split-screen stack on top.
3743         switch (windowingMode) {
3744             case WINDOWING_MODE_FULLSCREEN:
3745                 if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) {
3746                     // At least one of the split-screen stacks that covers this one is translucent.
3747                     return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
3748                 }
3749                 break;
3750             case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
3751                 if (gotTranslucentSplitScreenPrimary) {
3752                     // Covered by translucent primary split-screen on top.
3753                     return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
3754                 }
3755                 break;
3756             case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
3757                 if (gotTranslucentSplitScreenSecondary) {
3758                     // Covered by translucent secondary split-screen on top.
3759                     return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
3760                 }
3761                 break;
3762         }
3763 
3764         // Lastly - check if there is a translucent fullscreen stack on top.
3765         return gotTranslucentFullscreen ? STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
3766                 : STACK_VISIBILITY_VISIBLE;
3767     }
3768 
3769     ActivityRecord isInTask(ActivityRecord r) {
3770         if (r == null) {
3771             return null;
3772         }
3773         if (r.isDescendantOf(this)) {
3774             return r;
3775         }
3776         return null;
3777     }
3778 
3779     void dump(PrintWriter pw, String prefix) {
3780         pw.print(prefix); pw.print("userId="); pw.print(mUserId);
3781         pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
3782         pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
3783         pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
3784         pw.print(" mCallingPackage="); pw.print(mCallingPackage);
3785         pw.print(" mCallingFeatureId="); pw.println(mCallingFeatureId);
3786         if (affinity != null || rootAffinity != null) {
3787             pw.print(prefix); pw.print("affinity="); pw.print(affinity);
3788             if (affinity == null || !affinity.equals(rootAffinity)) {
3789                 pw.print(" root="); pw.println(rootAffinity);
3790             } else {
3791                 pw.println();
3792             }
3793         }
3794         if (mWindowLayoutAffinity != null) {
3795             pw.print(prefix); pw.print("windowLayoutAffinity="); pw.println(mWindowLayoutAffinity);
3796         }
3797         if (voiceSession != null || voiceInteractor != null) {
3798             pw.print(prefix); pw.print("VOICE: session=0x");
3799             pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
3800             pw.print(" interactor=0x");
3801             pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
3802         }
3803         if (intent != null) {
3804             StringBuilder sb = new StringBuilder(128);
3805             sb.append(prefix); sb.append("intent={");
3806             intent.toShortString(sb, false, true, false, false);
3807             sb.append('}');
3808             pw.println(sb.toString());
3809         }
3810         if (affinityIntent != null) {
3811             StringBuilder sb = new StringBuilder(128);
3812             sb.append(prefix); sb.append("affinityIntent={");
3813             affinityIntent.toShortString(sb, false, true, false, false);
3814             sb.append('}');
3815             pw.println(sb.toString());
3816         }
3817         if (origActivity != null) {
3818             pw.print(prefix); pw.print("origActivity=");
3819             pw.println(origActivity.flattenToShortString());
3820         }
3821         if (realActivity != null) {
3822             pw.print(prefix); pw.print("mActivityComponent=");
3823             pw.println(realActivity.flattenToShortString());
3824         }
3825         if (autoRemoveRecents || isPersistable || !isActivityTypeStandard()) {
3826             pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
3827             pw.print(" isPersistable="); pw.print(isPersistable);
3828             pw.print(" activityType="); pw.println(getActivityType());
3829         }
3830         if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
3831                 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
3832             pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
3833             pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
3834             pw.print(" mReuseTask="); pw.print(mReuseTask);
3835             pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
3836         }
3837         if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID
3838                 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
3839                 || mNextAffiliate != null) {
3840             pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
3841             pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
3842             pw.print(" (");
3843             if (mPrevAffiliate == null) {
3844                 pw.print("null");
3845             } else {
3846                 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
3847             }
3848             pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
3849             pw.print(" (");
3850             if (mNextAffiliate == null) {
3851                 pw.print("null");
3852             } else {
3853                 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
3854             }
3855             pw.println(")");
3856         }
3857         pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
3858         if (!askedCompatMode || !inRecents || !isAvailable) {
3859             pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
3860             pw.print(" inRecents="); pw.print(inRecents);
3861             pw.print(" isAvailable="); pw.println(isAvailable);
3862         }
3863         if (lastDescription != null) {
3864             pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
3865         }
3866         if (mRootProcess != null) {
3867             pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
3868         }
3869         pw.print(prefix); pw.print("taskId=" + mTaskId); pw.println(" stackId=" + getRootTaskId());
3870         pw.print(prefix); pw.print("mHasBeenVisible="); pw.println(getHasBeenVisible());
3871         pw.print(prefix); pw.print("mResizeMode=");
3872         pw.print(ActivityInfo.resizeModeToString(mResizeMode));
3873         pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture);
3874         pw.print(" isResizeable="); pw.println(isResizeable());
3875         pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
3876         pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
3877     }
3878 
3879     @Override
3880     public String toString() {
3881         StringBuilder sb = new StringBuilder(128);
3882         if (stringName != null) {
3883             sb.append(stringName);
3884             sb.append(" U=");
3885             sb.append(mUserId);
3886             sb.append(" StackId=");
3887             sb.append(getRootTaskId());
3888             sb.append(" sz=");
3889             sb.append(getChildCount());
3890             sb.append('}');
3891             return sb.toString();
3892         }
3893         sb.append("Task{");
3894         sb.append(Integer.toHexString(System.identityHashCode(this)));
3895         sb.append(" #");
3896         sb.append(mTaskId);
3897         sb.append(" visible=" + shouldBeVisible(null /* starting */));
3898         sb.append(" type=" + activityTypeToString(getActivityType()));
3899         sb.append(" mode=" + windowingModeToString(getWindowingMode()));
3900         sb.append(" translucent=" + isTranslucent(null /* starting */));
3901         if (affinity != null) {
3902             sb.append(" A=");
3903             sb.append(affinity);
3904         } else if (intent != null && intent.getComponent() != null) {
3905             sb.append(" I=");
3906             sb.append(intent.getComponent().flattenToShortString());
3907         } else if (affinityIntent != null && affinityIntent.getComponent() != null) {
3908             sb.append(" aI=");
3909             sb.append(affinityIntent.getComponent().flattenToShortString());
3910         } else {
3911             sb.append(" ??");
3912         }
3913         stringName = sb.toString();
3914         return toString();
3915     }
3916 
3917     /** @see #getNumRunningActivities(TaskActivitiesReport) */
3918     static class TaskActivitiesReport implements Consumer<ActivityRecord> {
3919         int numRunning;
3920         int numActivities;
3921         ActivityRecord top;
3922         ActivityRecord base;
3923 
3924         void reset() {
3925             numRunning = numActivities = 0;
3926             top = base = null;
3927         }
3928 
3929         @Override
3930         public void accept(ActivityRecord r) {
3931             if (r.finishing) {
3932                 return;
3933             }
3934 
3935             base = r;
3936 
3937             // Increment the total number of non-finishing activities
3938             numActivities++;
3939 
3940             if (top == null || (top.isState(ActivityState.INITIALIZING))) {
3941                 top = r;
3942                 // Reset the number of running activities until we hit the first non-initializing
3943                 // activity
3944                 numRunning = 0;
3945             }
3946             if (r.attachedToProcess()) {
3947                 // Increment the number of actually running activities
3948                 numRunning++;
3949             }
3950         }
3951     }
3952 
3953     /**
3954      * Saves this {@link Task} to XML using given serializer.
3955      */
3956     void saveToXml(XmlSerializer out) throws Exception {
3957         if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
3958 
3959         out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
3960         if (realActivity != null) {
3961             out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
3962         }
3963         out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
3964         if (origActivity != null) {
3965             out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
3966         }
3967         // Write affinity, and root affinity if it is different from affinity.
3968         // We use the special string "@" for a null root affinity, so we can identify
3969         // later whether we were given a root affinity or should just make it the
3970         // same as the affinity.
3971         if (affinity != null) {
3972             out.attribute(null, ATTR_AFFINITY, affinity);
3973             if (!affinity.equals(rootAffinity)) {
3974                 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
3975             }
3976         } else if (rootAffinity != null) {
3977             out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
3978         }
3979         if (mWindowLayoutAffinity != null) {
3980             out.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
3981         }
3982         out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
3983         out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
3984         out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
3985         out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
3986         out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
3987         out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
3988         out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
3989         out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
3990         if (lastDescription != null) {
3991             out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
3992         }
3993         if (getTaskDescription() != null) {
3994             getTaskDescription().saveToXml(out);
3995         }
3996         out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
3997         out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
3998         out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
3999         out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
4000         out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
4001         out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
4002         out.attribute(null, ATTR_CALLING_FEATURE_ID,
4003                 mCallingFeatureId == null ? "" : mCallingFeatureId);
4004         out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
4005         out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
4006                 String.valueOf(mSupportsPictureInPicture));
4007         if (mLastNonFullscreenBounds != null) {
4008             out.attribute(
4009                     null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
4010         }
4011         out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
4012         out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
4013         out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
4014 
4015         if (affinityIntent != null) {
4016             out.startTag(null, TAG_AFFINITYINTENT);
4017             affinityIntent.saveToXml(out);
4018             out.endTag(null, TAG_AFFINITYINTENT);
4019         }
4020 
4021         if (intent != null) {
4022             out.startTag(null, TAG_INTENT);
4023             intent.saveToXml(out);
4024             out.endTag(null, TAG_INTENT);
4025         }
4026 
4027         sTmpException = null;
4028         final PooledFunction f = PooledLambda.obtainFunction(Task::saveActivityToXml,
4029                 PooledLambda.__(ActivityRecord.class), getBottomMostActivity(), out);
4030         forAllActivities(f);
4031         f.recycle();
4032         if (sTmpException != null) {
4033             throw sTmpException;
4034         }
4035     }
4036 
4037     private static boolean saveActivityToXml(
4038             ActivityRecord r, ActivityRecord first, XmlSerializer out) {
4039         if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
4040                 || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
4041                 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
4042                 && r != first) {
4043             // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
4044             return true;
4045         }
4046         try {
4047             out.startTag(null, TAG_ACTIVITY);
4048             r.saveToXml(out);
4049             out.endTag(null, TAG_ACTIVITY);
4050             return false;
4051         } catch (Exception e) {
4052             sTmpException = e;
4053             return true;
4054         }
4055     }
4056 
4057     static Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
4058             throws IOException, XmlPullParserException {
4059         Intent intent = null;
4060         Intent affinityIntent = null;
4061         ArrayList<ActivityRecord> activities = new ArrayList<>();
4062         ComponentName realActivity = null;
4063         boolean realActivitySuspended = false;
4064         ComponentName origActivity = null;
4065         String affinity = null;
4066         String rootAffinity = null;
4067         boolean hasRootAffinity = false;
4068         String windowLayoutAffinity = null;
4069         boolean rootHasReset = false;
4070         boolean autoRemoveRecents = false;
4071         boolean askedCompatMode = false;
4072         int taskType = 0;
4073         int userId = 0;
4074         boolean userSetupComplete = true;
4075         int effectiveUid = -1;
4076         String lastDescription = null;
4077         long lastTimeOnTop = 0;
4078         boolean neverRelinquishIdentity = true;
4079         int taskId = INVALID_TASK_ID;
4080         final int outerDepth = in.getDepth();
4081         TaskDescription taskDescription = new TaskDescription();
4082         int taskAffiliation = INVALID_TASK_ID;
4083         int taskAffiliationColor = 0;
4084         int prevTaskId = INVALID_TASK_ID;
4085         int nextTaskId = INVALID_TASK_ID;
4086         int callingUid = -1;
4087         String callingPackage = "";
4088         String callingFeatureId = null;
4089         int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
4090         boolean supportsPictureInPicture = false;
4091         Rect lastNonFullscreenBounds = null;
4092         int minWidth = INVALID_MIN_SIZE;
4093         int minHeight = INVALID_MIN_SIZE;
4094         int persistTaskVersion = 0;
4095 
4096         for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
4097             final String attrName = in.getAttributeName(attrNdx);
4098             final String attrValue = in.getAttributeValue(attrNdx);
4099             if (TaskPersister.DEBUG) {
4100                 Slog.d(TaskPersister.TAG, "Task: attribute name=" + attrName + " value="
4101                         + attrValue);
4102             }
4103             switch (attrName) {
4104                 case ATTR_TASKID:
4105                     if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
4106                     break;
4107                 case ATTR_REALACTIVITY:
4108                     realActivity = ComponentName.unflattenFromString(attrValue);
4109                     break;
4110                 case ATTR_REALACTIVITY_SUSPENDED:
4111                     realActivitySuspended = Boolean.valueOf(attrValue);
4112                     break;
4113                 case ATTR_ORIGACTIVITY:
4114                     origActivity = ComponentName.unflattenFromString(attrValue);
4115                     break;
4116                 case ATTR_AFFINITY:
4117                     affinity = attrValue;
4118                     break;
4119                 case ATTR_ROOT_AFFINITY:
4120                     rootAffinity = attrValue;
4121                     hasRootAffinity = true;
4122                     break;
4123                 case ATTR_WINDOW_LAYOUT_AFFINITY:
4124                     windowLayoutAffinity = attrValue;
4125                     break;
4126                 case ATTR_ROOTHASRESET:
4127                     rootHasReset = Boolean.parseBoolean(attrValue);
4128                     break;
4129                 case ATTR_AUTOREMOVERECENTS:
4130                     autoRemoveRecents = Boolean.parseBoolean(attrValue);
4131                     break;
4132                 case ATTR_ASKEDCOMPATMODE:
4133                     askedCompatMode = Boolean.parseBoolean(attrValue);
4134                     break;
4135                 case ATTR_USERID:
4136                     userId = Integer.parseInt(attrValue);
4137                     break;
4138                 case ATTR_USER_SETUP_COMPLETE:
4139                     userSetupComplete = Boolean.parseBoolean(attrValue);
4140                     break;
4141                 case ATTR_EFFECTIVE_UID:
4142                     effectiveUid = Integer.parseInt(attrValue);
4143                     break;
4144                 case ATTR_TASKTYPE:
4145                     taskType = Integer.parseInt(attrValue);
4146                     break;
4147                 case ATTR_LASTDESCRIPTION:
4148                     lastDescription = attrValue;
4149                     break;
4150                 case ATTR_LASTTIMEMOVED:
4151                     lastTimeOnTop = Long.parseLong(attrValue);
4152                     break;
4153                 case ATTR_NEVERRELINQUISH:
4154                     neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
4155                     break;
4156                 case ATTR_TASK_AFFILIATION:
4157                     taskAffiliation = Integer.parseInt(attrValue);
4158                     break;
4159                 case ATTR_PREV_AFFILIATION:
4160                     prevTaskId = Integer.parseInt(attrValue);
4161                     break;
4162                 case ATTR_NEXT_AFFILIATION:
4163                     nextTaskId = Integer.parseInt(attrValue);
4164                     break;
4165                 case ATTR_TASK_AFFILIATION_COLOR:
4166                     taskAffiliationColor = Integer.parseInt(attrValue);
4167                     break;
4168                 case ATTR_CALLING_UID:
4169                     callingUid = Integer.parseInt(attrValue);
4170                     break;
4171                 case ATTR_CALLING_PACKAGE:
4172                     callingPackage = attrValue;
4173                     break;
4174                 case ATTR_CALLING_FEATURE_ID:
4175                     callingFeatureId = attrValue;
4176                     break;
4177                 case ATTR_RESIZE_MODE:
4178                     resizeMode = Integer.parseInt(attrValue);
4179                     break;
4180                 case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
4181                     supportsPictureInPicture = Boolean.parseBoolean(attrValue);
4182                     break;
4183                 case ATTR_NON_FULLSCREEN_BOUNDS:
4184                     lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
4185                     break;
4186                 case ATTR_MIN_WIDTH:
4187                     minWidth = Integer.parseInt(attrValue);
4188                     break;
4189                 case ATTR_MIN_HEIGHT:
4190                     minHeight = Integer.parseInt(attrValue);
4191                     break;
4192                 case ATTR_PERSIST_TASK_VERSION:
4193                     persistTaskVersion = Integer.parseInt(attrValue);
4194                     break;
4195                 default:
4196                     if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
4197                         Slog.w(TAG, "Task: Unknown attribute=" + attrName);
4198                     }
4199             }
4200         }
4201         taskDescription.restoreFromXml(in);
4202 
4203         int event;
4204         while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
4205                 && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
4206             if (event == XmlPullParser.START_TAG) {
4207                 final String name = in.getName();
4208                 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: START_TAG name=" + name);
4209                 if (TAG_AFFINITYINTENT.equals(name)) {
4210                     affinityIntent = Intent.restoreFromXml(in);
4211                 } else if (TAG_INTENT.equals(name)) {
4212                     intent = Intent.restoreFromXml(in);
4213                 } else if (TAG_ACTIVITY.equals(name)) {
4214                     ActivityRecord activity =
4215                             ActivityRecord.restoreFromXml(in, stackSupervisor);
4216                     if (TaskPersister.DEBUG) {
4217                         Slog.d(TaskPersister.TAG, "Task: activity=" + activity);
4218                     }
4219                     if (activity != null) {
4220                         activities.add(activity);
4221                     }
4222                 } else {
4223                     Slog.e(TAG, "restoreTask: Unexpected name=" + name);
4224                     XmlUtils.skipCurrentTag(in);
4225                 }
4226             }
4227         }
4228         if (!hasRootAffinity) {
4229             rootAffinity = affinity;
4230         } else if ("@".equals(rootAffinity)) {
4231             rootAffinity = null;
4232         }
4233         if (effectiveUid <= 0) {
4234             Intent checkIntent = intent != null ? intent : affinityIntent;
4235             effectiveUid = 0;
4236             if (checkIntent != null) {
4237                 IPackageManager pm = AppGlobals.getPackageManager();
4238                 try {
4239                     ApplicationInfo ai = pm.getApplicationInfo(
4240                             checkIntent.getComponent().getPackageName(),
4241                             PackageManager.MATCH_UNINSTALLED_PACKAGES
4242                                     | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
4243                     if (ai != null) {
4244                         effectiveUid = ai.uid;
4245                     }
4246                 } catch (RemoteException e) {
4247                 }
4248             }
4249             Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
4250                     + ": effectiveUid=" + effectiveUid);
4251         }
4252 
4253         if (persistTaskVersion < 1) {
4254             // We need to convert the resize mode of home activities saved before version one if
4255             // they are marked as RESIZE_MODE_RESIZEABLE to
4256             // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
4257             // before version 1 and the system didn't resize home activities before then.
4258             if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
4259                 resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
4260             }
4261         } else {
4262             // This activity has previously marked itself explicitly as both resizeable and
4263             // supporting picture-in-picture.  Since there is no longer a requirement for
4264             // picture-in-picture activities to be resizeable, we can mark this simply as
4265             // resizeable and supporting picture-in-picture separately.
4266             if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
4267                 resizeMode = RESIZE_MODE_RESIZEABLE;
4268                 supportsPictureInPicture = true;
4269             }
4270         }
4271 
4272         final Task task = new ActivityStack(stackSupervisor.mService, taskId, intent,
4273                 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
4274                 autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
4275                 lastTimeOnTop, neverRelinquishIdentity, taskDescription, taskAffiliation,
4276                 prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
4277                 callingFeatureId, resizeMode, supportsPictureInPicture, realActivitySuspended,
4278                 userSetupComplete, minWidth, minHeight, null /*ActivityInfo*/,
4279                 null /*_voiceSession*/, null /*_voiceInteractor*/, null /* stack */);
4280         task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
4281         task.setBounds(lastNonFullscreenBounds);
4282         task.mWindowLayoutAffinity = windowLayoutAffinity;
4283 
4284         for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
4285             task.addChild(activities.get(activityNdx));
4286         }
4287 
4288         if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
4289         return task;
4290     }
4291 
4292     @Override
4293     boolean isOrganized() {
4294         return mTaskOrganizer != null;
4295     }
4296 
4297     @Override
4298     protected void reparentSurfaceControl(SurfaceControl.Transaction t, SurfaceControl newParent) {
4299         /**
4300          * Avoid reparenting SurfaceControl of the organized tasks that are always on top, since
4301          * the surfaces should be controlled by the organizer itself, like bubbles.
4302          */
4303         if (isOrganized() && isAlwaysOnTop()) {
4304             return;
4305         }
4306         super.reparentSurfaceControl(t, newParent);
4307     }
4308 
4309     void setHasBeenVisible(boolean hasBeenVisible) {
4310         final boolean prevHasBeenVisible = mHasBeenVisible;
4311         mHasBeenVisible = hasBeenVisible;
4312         if (hasBeenVisible) {
4313             // If the task is not yet visible when it is added to the task organizer, then we should
4314             // hide it to allow the task organizer to show it when it is properly reparented. We
4315             // skip this for tasks created by the organizer because they can synchronously update
4316             // the leash before new children are added to the task.
4317             if (!mCreatedByOrganizer && mTaskOrganizer != null && !prevHasBeenVisible) {
4318                 getSyncTransaction().hide(getSurfaceControl());
4319                 commitPendingTransaction();
4320             }
4321 
4322             sendTaskAppeared();
4323             if (!isRootTask()) {
4324                 getRootTask().setHasBeenVisible(true);
4325             }
4326         }
4327     }
4328 
4329     boolean getHasBeenVisible() {
4330         return mHasBeenVisible;
4331     }
4332 
4333     /** In the case that these conditions are true, we want to send the Task to the organizer:
4334      *     1. An organizer has been set
4335      *     2. The Task was created by the organizer
4336      *     or
4337      *     2a. We have a SurfaceControl
4338      *     2b. We have finished drawing
4339      * Any time any of these conditions are updated, the updating code should call
4340      * sendTaskAppeared.
4341      */
4342     boolean taskAppearedReady() {
4343         if (mTaskOrganizer == null) {
4344             return false;
4345         }
4346 
4347         if (mCreatedByOrganizer) {
4348             return true;
4349         }
4350 
4351         return mSurfaceControl != null && getHasBeenVisible();
4352     }
4353 
4354     private void sendTaskAppeared() {
4355         if (mTaskOrganizer != null) {
4356             mAtmService.mTaskOrganizerController.onTaskAppeared(mTaskOrganizer, this);
4357         }
4358     }
4359 
4360     private void sendTaskVanished(ITaskOrganizer organizer) {
4361         if (organizer != null) {
4362             mAtmService.mTaskOrganizerController.onTaskVanished(organizer, this);
4363         }
4364    }
4365 
4366     @VisibleForTesting
4367     boolean setTaskOrganizer(ITaskOrganizer organizer) {
4368         if (mTaskOrganizer == organizer) {
4369             return false;
4370         }
4371 
4372         ITaskOrganizer previousOrganizer = mTaskOrganizer;
4373         // Update the new task organizer before calling sendTaskVanished since it could result in
4374         // a new SurfaceControl getting created that would notify the old organizer about it.
4375         mTaskOrganizer = organizer;
4376         // Let the old organizer know it has lost control.
4377         sendTaskVanished(previousOrganizer);
4378 
4379         if (mTaskOrganizer != null) {
4380             sendTaskAppeared();
4381         } else {
4382             // No longer managed by any organizer.
4383             mTaskAppearedSent = false;
4384             mLastTaskOrganizerWindowingMode = -1;
4385             setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */);
4386             if (mCreatedByOrganizer) {
4387                 removeImmediately();
4388             }
4389         }
4390 
4391         return true;
4392     }
4393 
4394     /**
4395      * Called when the task state changes (ie. from windowing mode change) an the task organizer
4396      * state should also be updated.
4397      *
4398      * @param forceUpdate Updates the task organizer to the one currently specified in the task
4399      *                    org controller for the task's windowing mode, ignoring the cached
4400      *                    windowing mode checks.
4401      * @return {@code true} if task organizer changed.
4402      */
4403     boolean updateTaskOrganizerState(boolean forceUpdate) {
4404         if (!isRootTask()) {
4405             return false;
4406         }
4407 
4408         final int windowingMode = getWindowingMode();
4409         if (!forceUpdate && windowingMode == mLastTaskOrganizerWindowingMode) {
4410             // If our windowing mode hasn't actually changed, then just stick
4411             // with our old organizer. This lets us implement the semantic
4412             // where SysUI can continue to manage it's old tasks
4413             // while CTS temporarily takes over the registration.
4414             return false;
4415         }
4416         /*
4417          * Different windowing modes may be managed by different task organizers. If
4418          * getTaskOrganizer returns null, we still call setTaskOrganizer to
4419          * make sure we clear it.
4420          */
4421         final ITaskOrganizer org =
4422                 mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
4423         final boolean result = setTaskOrganizer(org);
4424         mLastTaskOrganizerWindowingMode = windowingMode;
4425         return result;
4426     }
4427 
4428     @Override
4429     void setSurfaceControl(SurfaceControl sc) {
4430         super.setSurfaceControl(sc);
4431         // If the TaskOrganizer was set before we created the SurfaceControl, we need to
4432         // emit the callbacks now.
4433         sendTaskAppeared();
4434     }
4435 
4436     /**
4437      * @return true if the task is currently focused.
4438      */
4439     private boolean isFocused() {
4440         if (mDisplayContent == null || mDisplayContent.mCurrentFocus == null) {
4441             return false;
4442         }
4443         return mDisplayContent.mCurrentFocus.getTask() == this;
4444     }
4445 
4446     /**
4447      * @return true if the task is visible and has at least one visible child.
4448      */
4449     private boolean hasVisibleChildren() {
4450         if (!isAttached() || isForceHidden()) {
4451             return false;
4452         }
4453 
4454         return getActivity(ActivityRecord::isVisible) != null;
4455     }
4456 
4457     /**
4458      * @return the desired shadow radius in pixels for the current task.
4459      */
4460     private float getShadowRadius(boolean taskIsFocused) {
4461         int elevation = 0;
4462 
4463         // Get elevation for a specific windowing mode.
4464         if (inPinnedWindowingMode()) {
4465             elevation = PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
4466         } else if (inFreeformWindowingMode()) {
4467             elevation = taskIsFocused
4468                     ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
4469         } else {
4470             // For all other windowing modes, do not draw a shadow.
4471             return 0;
4472         }
4473 
4474         // If the task has no visible children, do not draw a shadow.
4475         if (!hasVisibleChildren()) {
4476             return 0;
4477         }
4478 
4479         return dipToPixel(elevation, getDisplayContent().getDisplayMetrics());
4480     }
4481 
4482     /**
4483      * Update the length of the shadow if needed based on windowing mode and task focus state.
4484      */
4485     private void updateShadowsRadius(boolean taskIsFocused,
4486             SurfaceControl.Transaction pendingTransaction) {
4487         if (!mWmService.mRenderShadowsInCompositor || !isRootTask()) return;
4488 
4489         final float newShadowRadius = getShadowRadius(taskIsFocused);
4490         if (mShadowRadius != newShadowRadius) {
4491             mShadowRadius = newShadowRadius;
4492             pendingTransaction.setShadowRadius(getSurfaceControl(), mShadowRadius);
4493         }
4494     }
4495 
4496     /**
4497      * Called on the task of a window which gained or lost focus.
4498      * @param hasFocus
4499      */
4500     void onWindowFocusChanged(boolean hasFocus) {
4501         updateShadowsRadius(hasFocus, getSyncTransaction());
4502     }
4503 
4504     void onPictureInPictureParamsChanged() {
4505         if (isOrganized()) {
4506             mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, true /* force */);
4507         }
4508     }
4509 
4510     /**
4511      * See {@link WindowContainerTransaction#setBoundsChangeTransaction}. In short this
4512      * transaction will be consumed by the next BASE_APPLICATION window within our hierarchy
4513      * to resize, and it will defer the transaction until that resize frame completes.
4514      */
4515     void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) {
4516         setMainWindowSizeChangeTransaction(t, this);
4517         forAllWindows(WindowState::requestRedrawForSync, true);
4518     }
4519 
4520     private void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t, Task origin) {
4521         // This is only meaningful on an activity's task, so put it on the top one.
4522         ActivityRecord topActivity = getTopNonFinishingActivity();
4523         Task leaf = topActivity != null ? topActivity.getTask() : null;
4524         if (leaf == null) {
4525             return;
4526         }
4527         if (leaf != this) {
4528             leaf.setMainWindowSizeChangeTransaction(t, origin);
4529             return;
4530         }
4531         mMainWindowSizeChangeTransaction = t;
4532         mMainWindowSizeChangeTask = t == null ? null : origin;
4533     }
4534 
4535     SurfaceControl.Transaction getMainWindowSizeChangeTransaction() {
4536         return mMainWindowSizeChangeTransaction;
4537     }
4538 
4539     Task getMainWindowSizeChangeTask() {
4540         return mMainWindowSizeChangeTask;
4541     }
4542 
4543     void setActivityWindowingMode(int windowingMode) {
4544         PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setWindowingMode,
4545                 PooledLambda.__(ActivityRecord.class), windowingMode);
4546         forAllActivities(c);
4547         c.recycle();
4548     }
4549 
4550     /**
4551      * Sets/unsets the forced-hidden state flag for this task depending on {@param set}.
4552      * @return Whether the force hidden state changed
4553      */
4554     boolean setForceHidden(int flags, boolean set) {
4555         int newFlags = mForceHiddenFlags;
4556         if (set) {
4557             newFlags |= flags;
4558         } else {
4559             newFlags &= ~flags;
4560         }
4561         if (mForceHiddenFlags == newFlags) {
4562             return false;
4563         }
4564         final boolean wasHidden = isForceHidden();
4565         mForceHiddenFlags = newFlags;
4566         if (wasHidden && isFocusableAndVisible()) {
4567             // The change in force-hidden state will change visibility without triggering a stack
4568             // order change, so we should reset the preferred top focusable stack to ensure it's not
4569             // used if a new activity is started from this task.
4570             getDisplayArea().resetPreferredTopFocusableStackIfBelow(this);
4571         }
4572         return true;
4573     }
4574 
4575     /**
4576      * Returns whether this task is currently forced to be hidden for any reason.
4577      */
4578     protected boolean isForceHidden() {
4579         return mForceHiddenFlags != 0;
4580     }
4581 
4582     @Override
4583     long getProtoFieldId() {
4584         return TASK;
4585     }
4586 
4587 }
4588