• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.WindowConfiguration.ACTIVITY_TYPE_HOME;
21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
25 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
26 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
27 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
28 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
29 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
30 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
31 
32 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
33 import static com.android.server.wm.ActivityRecord.State.RESUMED;
34 import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK;
35 import static com.android.server.wm.DisplayContent.alwaysCreateRootTask;
36 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
37 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
38 
39 import android.annotation.ColorInt;
40 import android.annotation.Nullable;
41 import android.app.ActivityOptions;
42 import android.app.WindowConfiguration;
43 import android.content.pm.ActivityInfo;
44 import android.content.pm.ActivityInfo.ScreenOrientation;
45 import android.content.res.Configuration;
46 import android.graphics.Color;
47 import android.os.UserHandle;
48 import android.util.IntArray;
49 import android.util.Slog;
50 import android.view.RemoteAnimationTarget;
51 import android.view.SurfaceControl;
52 
53 import com.android.internal.annotations.VisibleForTesting;
54 import com.android.internal.protolog.common.ProtoLog;
55 import com.android.internal.util.ArrayUtils;
56 import com.android.internal.util.function.pooled.PooledLambda;
57 import com.android.internal.util.function.pooled.PooledPredicate;
58 import com.android.server.wm.LaunchParamsController.LaunchParams;
59 
60 import java.io.PrintWriter;
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.function.BiFunction;
64 import java.util.function.Consumer;
65 import java.util.function.Function;
66 import java.util.function.Predicate;
67 
68 /**
69  * {@link DisplayArea} that represents a section of a screen that contains app window containers.
70  *
71  * The children can be either {@link Task} or {@link TaskDisplayArea}.
72  */
73 final class TaskDisplayArea extends DisplayArea<WindowContainer> {
74 
75     DisplayContent mDisplayContent;
76 
77     /**
78      * Keeps track of the last set color layer so that it can be reset during surface migrations.
79      */
80     private @ColorInt int mBackgroundColor = 0;
81 
82     /**
83      * This counter is used to make sure we don't prematurely clear the background color in the
84      * case that background color animations are interleaved.
85      * NOTE: The last set color will remain until the counter is reset to 0, which means that an
86      * animation background color may sometime remain after the animation has finished through an
87      * animation with a different background color if an animation starts after and ends before
88      * another where both set different background colors. However, this is not a concern as
89      * currently all task animation backgrounds are the same color.
90      */
91     private int mColorLayerCounter = 0;
92 
93     // Cached reference to some special tasks we tend to get a lot so we don't need to loop
94     // through the list to find them.
95     private Task mRootHomeTask;
96     private Task mRootPinnedTask;
97 
98     private final ArrayList<WindowContainer> mTmpAlwaysOnTopChildren = new ArrayList<>();
99     private final ArrayList<WindowContainer> mTmpNormalChildren = new ArrayList<>();
100     private final ArrayList<WindowContainer> mTmpHomeChildren = new ArrayList<>();
101     private final IntArray mTmpNeedsZBoostIndexes = new IntArray();
102 
103     private ArrayList<Task> mTmpTasks = new ArrayList<>();
104 
105     private ActivityTaskManagerService mAtmService;
106 
107     private RootWindowContainer mRootWindowContainer;
108 
109     // Launch root tasks by activityType then by windowingMode.
110     static private class LaunchRootTaskDef {
111         Task task;
112         int[] windowingModes;
113         int[] activityTypes;
114 
contains(int windowingMode, int activityType)115         boolean contains(int windowingMode, int activityType) {
116             return ArrayUtils.contains(windowingModes, windowingMode)
117                     && ArrayUtils.contains(activityTypes, activityType);
118         }
119     }
120     private final ArrayList<LaunchRootTaskDef> mLaunchRootTasks = new ArrayList<>();
121 
122     /**
123      * A launch root task for activity launching with {@link FLAG_ACTIVITY_LAUNCH_ADJACENT} flag.
124      */
125     @VisibleForTesting
126     Task mLaunchAdjacentFlagRootTask;
127 
128     /**
129      * A focusable root task that is purposely to be positioned at the top. Although the root
130      * task may not have the topmost index, it is used as a preferred candidate to prevent being
131      * unable to resume target root task properly when there are other focusable always-on-top
132      * root tasks.
133      */
134     @VisibleForTesting
135     Task mPreferredTopFocusableRootTask;
136 
137     /**
138      * If this is the same as {@link #getFocusedRootTask} then the activity on the top of the
139      * focused root task has been resumed. If root tasks are changing position this will hold the
140      * old root task until the new root task becomes resumed after which it will be set to
141      * current focused root task.
142      */
143     Task mLastFocusedRootTask;
144     /**
145      * All of the root tasks on this display. Order matters, topmost root task is in front of all
146      * other root tasks, bottommost behind. Accessed directly by ActivityManager package classes.
147      * Any calls changing the list should also call {@link #onRootTaskOrderChanged(Task)}.
148      */
149     private ArrayList<OnRootTaskOrderChangedListener> mRootTaskOrderChangedCallbacks =
150             new ArrayList<>();
151 
152     /**
153      * The task display area is removed from the system and we are just waiting for all activities
154      * on it to be finished before removing this object.
155      */
156     private boolean mRemoved;
157 
158     /**
159      * The id of a leaf task that most recently being moved to front.
160      */
161     private int mLastLeafTaskToFrontId;
162 
163     /**
164      * Whether this TaskDisplayArea was created by a {@link android.window.DisplayAreaOrganizer}.
165      * If {@code true}, this will be removed when the organizer is unregistered.
166      */
167     final boolean mCreatedByOrganizer;
168 
169     /**
170      * True if this TaskDisplayArea can have a home task
171      * {@link WindowConfiguration#ACTIVITY_TYPE_HOME}
172      */
173     private final boolean mCanHostHomeTask;
174 
175     private final Configuration mTempConfiguration = new Configuration();
176 
TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name, int displayAreaFeature)177     TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name,
178                     int displayAreaFeature) {
179         this(displayContent, service, name, displayAreaFeature, false /* createdByOrganizer */,
180                 true /* canHostHomeTask */);
181     }
182 
TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name, int displayAreaFeature, boolean createdByOrganizer)183     TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name,
184                     int displayAreaFeature, boolean createdByOrganizer) {
185         this(displayContent, service, name, displayAreaFeature, createdByOrganizer,
186                 true /* canHostHomeTask */);
187     }
188 
TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name, int displayAreaFeature, boolean createdByOrganizer, boolean canHostHomeTask)189     TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name,
190                     int displayAreaFeature, boolean createdByOrganizer,
191                     boolean canHostHomeTask) {
192         super(service, Type.ANY, name, displayAreaFeature);
193         mDisplayContent = displayContent;
194         mRootWindowContainer = service.mRoot;
195         mAtmService = service.mAtmService;
196         mCreatedByOrganizer = createdByOrganizer;
197         mCanHostHomeTask = canHostHomeTask;
198     }
199 
200     /**
201      * Returns the topmost root task on the display that is compatible with the input windowing mode
202      * and activity type. Null is no compatible root task on the display.
203      */
204     @Nullable
getRootTask(int windowingMode, int activityType)205     Task getRootTask(int windowingMode, int activityType) {
206         if (activityType == ACTIVITY_TYPE_HOME) {
207             return mRootHomeTask;
208         }
209         if (windowingMode == WINDOWING_MODE_PINNED) {
210             return mRootPinnedTask;
211         }
212         return getRootTask(rootTask -> {
213             if (activityType == ACTIVITY_TYPE_UNDEFINED
214                     && windowingMode == rootTask.getWindowingMode()) {
215                 // Passing in undefined type means we want to match the topmost root task with the
216                 // windowing mode.
217                 return true;
218             }
219             return rootTask.isCompatible(windowingMode, activityType);
220         });
221     }
222 
223     @VisibleForTesting
224     Task getTopRootTask() {
225         return getRootTask(t -> true);
226     }
227 
228     @Nullable
229     Task getRootHomeTask() {
230         return mRootHomeTask;
231     }
232 
233     Task getRootPinnedTask() {
234         return mRootPinnedTask;
235     }
236 
237     ArrayList<Task> getVisibleTasks() {
238         final ArrayList<Task> visibleTasks = new ArrayList<>();
239         forAllTasks(task -> {
240             if (task.isLeafTask() && task.isVisible()) {
241                 visibleTasks.add(task);
242             }
243         });
244         return visibleTasks;
245     }
246 
247     void onRootTaskWindowingModeChanged(Task rootTask) {
248         removeRootTaskReferenceIfNeeded(rootTask);
249         addRootTaskReferenceIfNeeded(rootTask);
250         if (rootTask == mRootPinnedTask && getTopRootTask() != rootTask) {
251             // Looks like this root task changed windowing mode to pinned. Move it to the top.
252             positionChildAt(POSITION_TOP, rootTask, false /* includingParents */);
253         }
254     }
255 
256     void addRootTaskReferenceIfNeeded(Task rootTask) {
257         if (rootTask.isActivityTypeHome()) {
258             if (mRootHomeTask != null) {
259                 if (!rootTask.isDescendantOf(mRootHomeTask)) {
260                     throw new IllegalArgumentException("addRootTaskReferenceIfNeeded: root home"
261                             + " task=" + mRootHomeTask + " already exist on display=" + this
262                             + " rootTask=" + rootTask);
263                 }
264             } else {
265                 mRootHomeTask = rootTask;
266             }
267         }
268 
269         if (!rootTask.isRootTask()) {
270             return;
271         }
272         final int windowingMode = rootTask.getWindowingMode();
273         if (windowingMode == WINDOWING_MODE_PINNED) {
274             if (mRootPinnedTask != null) {
275                 throw new IllegalArgumentException(
276                         "addRootTaskReferenceIfNeeded: root pinned task=" + mRootPinnedTask
277                                 + " already exist on display=" + this + " rootTask=" + rootTask);
278             }
279             mRootPinnedTask = rootTask;
280         }
281     }
282 
283     void removeRootTaskReferenceIfNeeded(Task rootTask) {
284         if (rootTask == mRootHomeTask) {
285             mRootHomeTask = null;
286         } else if (rootTask == mRootPinnedTask) {
287             mRootPinnedTask = null;
288         }
289     }
290 
291     @Override
292     void setInitialSurfaceControlProperties(SurfaceControl.Builder b) {
293         // We want an effect layer instead of the default container layer so that we can set a
294         // background color on it for task animations.
295         b.setEffectLayer();
296         super.setInitialSurfaceControlProperties(b);
297     }
298 
299     @Override
300     void addChild(WindowContainer child, int position) {
301         if (child.asTaskDisplayArea() != null) {
302             if (DEBUG_ROOT_TASK) {
303                 Slog.d(TAG_WM, "Set TaskDisplayArea=" + child + " on taskDisplayArea=" + this);
304             }
305             super.addChild(child, position);
306         } else if (child.asTask() != null) {
307             addChildTask(child.asTask(), position);
308         } else {
309             throw new IllegalArgumentException(
310                     "TaskDisplayArea can only add Task and TaskDisplayArea, but found "
311                             + child);
312         }
313     }
314 
315     private void addChildTask(Task task, int position) {
316         if (DEBUG_ROOT_TASK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this);
317 
318         addRootTaskReferenceIfNeeded(task);
319         position = findPositionForRootTask(position, task, true /* adding */);
320 
321         super.addChild(task, position);
322         if (mPreferredTopFocusableRootTask != null
323                 && task.isFocusable()
324                 && mPreferredTopFocusableRootTask.compareTo(task) < 0) {
325             // Clear preferred top because the adding focusable task has a higher z-order.
326             mPreferredTopFocusableRootTask = null;
327         }
328 
329         // Update the top resumed activity because the preferred top focusable task may be changed.
330         mAtmService.mTaskSupervisor.updateTopResumedActivityIfNeeded("addChildTask");
331 
332         mAtmService.updateSleepIfNeededLocked();
333         onRootTaskOrderChanged(task);
334     }
335 
336     @Override
337     protected void removeChild(WindowContainer child) {
338         if (child.asTaskDisplayArea() != null) {
339             super.removeChild(child);
340         } else if (child.asTask() != null) {
341             removeChildTask(child.asTask());
342         } else {
343             throw new IllegalArgumentException(
344                     "TaskDisplayArea can only remove Task and TaskDisplayArea, but found "
345                             + child);
346         }
347     }
348 
349     private void removeChildTask(Task task) {
350         super.removeChild(task);
351         onRootTaskRemoved(task);
352         mAtmService.updateSleepIfNeededLocked();
353         removeRootTaskReferenceIfNeeded(task);
354     }
355 
356     @Override
357     boolean isOnTop() {
358         // Considered always on top
359         return true;
360     }
361 
362     @Override
363     void positionChildAt(int position, WindowContainer child, boolean includingParents) {
364         if (child.asTaskDisplayArea() != null) {
365             super.positionChildAt(position, child, includingParents);
366         } else if (child.asTask() != null) {
367             positionChildTaskAt(position, child.asTask(), includingParents);
368         } else {
369             throw new IllegalArgumentException(
370                     "TaskDisplayArea can only position Task and TaskDisplayArea, but found "
371                             + child);
372         }
373     }
374 
375     private void positionChildTaskAt(int position, Task child, boolean includingParents) {
376         final boolean moveToTop = position >= getChildCount() - 1;
377         final boolean moveToBottom = position <= 0;
378 
379         final int oldPosition = mChildren.indexOf(child);
380         if (child.isAlwaysOnTop() && !moveToTop) {
381             // This root task is always-on-top, override the default behavior.
382             Slog.w(TAG_WM, "Ignoring move of always-on-top root task=" + this + " to bottom");
383 
384             // Moving to its current position, as we must call super but we don't want to
385             // perform any meaningful action.
386             super.positionChildAt(oldPosition, child, false /* includingParents */);
387             return;
388         }
389         // We don't allow untrusted display to top when root task moves to top,
390         // until user tapping this display to change display position as top intentionally.
391         //
392         // Displays with {@code mDontMoveToTop} property set to {@code true} won't be
393         // allowed to top neither.
394         if ((!mDisplayContent.isTrusted() || mDisplayContent.mDontMoveToTop)
395                 && !getParent().isOnTop()) {
396             includingParents = false;
397         }
398         final int targetPosition = findPositionForRootTask(position, child, false /* adding */);
399         super.positionChildAt(targetPosition, child, false /* includingParents */);
400 
401         if (includingParents && getParent() != null && (moveToTop || moveToBottom)) {
402             getParent().positionChildAt(moveToTop ? POSITION_TOP : POSITION_BOTTOM,
403                     this /* child */, true /* includingParents */);
404         }
405 
406         child.updateTaskMovement(moveToTop, targetPosition);
407 
408         mDisplayContent.layoutAndAssignWindowLayersIfNeeded();
409 
410         // The insert position may be adjusted to non-top when there is always-on-top root task.
411         // Since the original position is preferred to be top, the root task should have higher
412         // priority when we are looking for top focusable root task. The condition {@code
413         // wasContained} restricts the preferred root task is set only when moving an existing
414         // root task to top instead of adding a new root task that may be too early (e.g. in the
415         // middle of launching or reparenting).
416         final boolean isTopFocusableTask = moveToTop && child.isTopActivityFocusable();
417         if (isTopFocusableTask) {
418             mPreferredTopFocusableRootTask =
419                     child.shouldBeVisible(null /* starting */) ? child : null;
420         } else if (mPreferredTopFocusableRootTask == child) {
421             mPreferredTopFocusableRootTask = null;
422         }
423 
424         // Update the top resumed activity because the preferred top focusable task may be changed.
425         mAtmService.mTaskSupervisor.updateTopResumedActivityIfNeeded("positionChildTaskAt");
426 
427         if (mChildren.indexOf(child) != oldPosition) {
428             onRootTaskOrderChanged(child);
429         }
430     }
431 
432     void onLeafTaskRemoved(int taskId) {
433         if (mLastLeafTaskToFrontId == taskId) {
434             mLastLeafTaskToFrontId = INVALID_TASK_ID;
435         }
436     }
437 
438     void onLeafTaskMoved(Task t, boolean toTop) {
439         if (!toTop) {
440             if (t.mTaskId == mLastLeafTaskToFrontId) {
441                 mLastLeafTaskToFrontId = INVALID_TASK_ID;
442 
443                 // If the previous front-most task is moved to the back, then notify of the new
444                 // front-most task.
445                 final ActivityRecord topMost = getTopMostActivity();
446                 if (topMost != null) {
447                     mAtmService.getTaskChangeNotificationController().notifyTaskMovedToFront(
448                             topMost.getTask().getTaskInfo());
449                 }
450             }
451             return;
452         }
453         if (t.mTaskId == mLastLeafTaskToFrontId || t.topRunningActivityLocked() == null) {
454             return;
455         }
456 
457         mLastLeafTaskToFrontId = t.mTaskId;
458         EventLogTags.writeWmTaskToFront(t.mUserId, t.mTaskId);
459         // Notifying only when a leaf task moved to front. Or the listeners would be notified
460         // couple times from the leaf task all the way up to the root task.
461         mAtmService.getTaskChangeNotificationController().notifyTaskMovedToFront(t.getTaskInfo());
462     }
463 
464     @Override
465     void onChildPositionChanged(WindowContainer child) {
466         super.onChildPositionChanged(child);
467         mRootWindowContainer.invalidateTaskLayers();
468     }
469 
470     @Override
471     boolean forAllTaskDisplayAreas(Predicate<TaskDisplayArea> callback,
472             boolean traverseTopToBottom) {
473         // Apply the callback to all TDAs at or below this container. If the callback returns true,
474         // stop early.
475         if (traverseTopToBottom) {
476             // When it is top to bottom, run on child TDA first as they are on top of the parent.
477             return super.forAllTaskDisplayAreas(callback, traverseTopToBottom)
478                     || callback.test(this);
479         }
480         return callback.test(this) || super.forAllTaskDisplayAreas(callback, traverseTopToBottom);
481     }
482 
483     @Override
484     void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom) {
485         if (traverseTopToBottom) {
486             super.forAllTaskDisplayAreas(callback, traverseTopToBottom);
487             callback.accept(this);
488         } else {
489             callback.accept(this);
490             super.forAllTaskDisplayAreas(callback, traverseTopToBottom);
491         }
492     }
493 
494     @Nullable
495     @Override
496     <R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator,
497             @Nullable R initValue, boolean traverseTopToBottom) {
498         if (traverseTopToBottom) {
499             final R result =
500                     super.reduceOnAllTaskDisplayAreas(accumulator, initValue, traverseTopToBottom);
501             return accumulator.apply(this, result);
502         } else {
503             final R result = accumulator.apply(this, initValue);
504             return super.reduceOnAllTaskDisplayAreas(accumulator, result, traverseTopToBottom);
505 
506         }
507     }
508 
509     @Nullable
510     @Override
511     <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback,
512             boolean traverseTopToBottom) {
513         if (traverseTopToBottom) {
514             final R item = super.getItemFromTaskDisplayAreas(callback, traverseTopToBottom);
515             return item != null ? item : callback.apply(this);
516         } else {
517             final R item = callback.apply(this);
518             return item != null
519                     ? item
520                     : super.getItemFromTaskDisplayAreas(callback, traverseTopToBottom);
521         }
522     }
523 
524     /**
525      * Assigns a priority number to root task types. This priority defines an order between the
526      * types of root task that are added to the task display area.
527      *
528      * Higher priority number indicates that the root task should have a higher z-order.
529      *
530      * For child {@link TaskDisplayArea}, it will be the priority of its top child.
531      *
532      * @return the priority of the root task
533      */
534     private int getPriority(WindowContainer child) {
535         final TaskDisplayArea tda = child.asTaskDisplayArea();
536         if (tda != null) {
537             // Use the top child priority as the TaskDisplayArea priority.
538             return tda.getPriority(tda.getTopChild());
539         }
540         final Task rootTask = child.asTask();
541         if (mWmService.mAssistantOnTopOfDream && rootTask.isActivityTypeAssistant()) return 4;
542         if (rootTask.isActivityTypeDream()) return 3;
543         if (rootTask.inPinnedWindowingMode()) return 2;
544         if (rootTask.isAlwaysOnTop()) return 1;
545         return 0;
546     }
547 
548     private int findMinPositionForRootTask(Task rootTask) {
549         int minPosition = POSITION_BOTTOM;
550         for (int i = 0; i < mChildren.size(); ++i) {
551             if (getPriority(mChildren.get(i)) < getPriority(rootTask)) {
552                 minPosition = i;
553             } else {
554                 break;
555             }
556         }
557 
558         if (rootTask.isAlwaysOnTop()) {
559             // Since a root task could be repositioned while still being one of the children, we
560             // check if this always-on-top root task already exists and if so, set the minPosition
561             // to its previous position.
562             // Use mChildren.indexOf instead of getTaskIndexOf because we need to place the rootTask
563             // as a direct child.
564             final int currentIndex = mChildren.indexOf(rootTask);
565             if (currentIndex > minPosition) {
566                 minPosition = currentIndex;
567             }
568         }
569         return minPosition;
570     }
571 
572     private int findMaxPositionForRootTask(Task rootTask) {
573         for (int i = mChildren.size() - 1; i >= 0; --i) {
574             final WindowContainer curr = mChildren.get(i);
575             // Since a root task could be repositioned while still being one of the children, we
576             // check if 'curr' is the same root task and skip it if so
577             final boolean sameRootTask = curr == rootTask;
578             if (getPriority(curr) <= getPriority(rootTask) && !sameRootTask) {
579                 return i;
580             }
581         }
582         return 0;
583     }
584 
585     /**
586      * When root task is added or repositioned, find a proper position for it.
587      *
588      * The order is defined as:
589      * - Dream is on top of everything
590      * - PiP is directly below the Dream
591      * - always-on-top root tasks are directly below PiP; new always-on-top root tasks are added
592      * above existing ones
593      * - other non-always-on-top root tasks come directly below always-on-top root tasks; new
594      * non-always-on-top root tasks are added directly below always-on-top root tasks and above
595      * existing non-always-on-top root tasks
596      * - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything
597      * (including the Dream); otherwise, it is a normal non-always-on-top root task
598      *
599      * @param requestedPosition Position requested by caller.
600      * @param rootTask          Root task to be added or positioned.
601      * @param adding            Flag indicates whether we're adding a new root task or positioning
602      *                          an existing.
603      * @return The proper position for the root task.
604      */
605     private int findPositionForRootTask(int requestedPosition, Task rootTask, boolean adding) {
606         // The max possible position we can insert the root task at.
607         int maxPosition = findMaxPositionForRootTask(rootTask);
608         // The min possible position we can insert the root task at.
609         int minPosition = findMinPositionForRootTask(rootTask);
610 
611         // Cap the requested position to something reasonable for the previous position check
612         // below.
613         if (requestedPosition == POSITION_TOP) {
614             requestedPosition = mChildren.size();
615         } else if (requestedPosition == POSITION_BOTTOM) {
616             requestedPosition = 0;
617         }
618 
619         int targetPosition = requestedPosition;
620         targetPosition = Math.min(targetPosition, maxPosition);
621         targetPosition = Math.max(targetPosition, minPosition);
622 
623         int prevPosition = mChildren.indexOf(rootTask);
624         // The positions we calculated above (maxPosition, minPosition) do not take into
625         // consideration the following edge cases.
626         // 1) We need to adjust the position depending on the value "adding".
627         // 2) When we are moving a root task to another position, we also need to adjust the
628         //    position depending on whether the root task is moving to a higher or lower position.
629         if ((targetPosition != requestedPosition) && (adding || targetPosition < prevPosition)) {
630             targetPosition++;
631         }
632 
633         return targetPosition;
634     }
635 
636     @Override
637     @ScreenOrientation
638     int getOrientation(@ScreenOrientation int candidate) {
639         final int orientation = super.getOrientation(candidate);
640         if (!canSpecifyOrientation(orientation)) {
641             mLastOrientationSource = null;
642             // We only respect orientation of the focused TDA, which can be a child of this TDA.
643             return reduceOnAllTaskDisplayAreas((taskDisplayArea, taskOrientation) -> {
644                 if (taskDisplayArea == this || taskOrientation != SCREEN_ORIENTATION_UNSET) {
645                     return taskOrientation;
646                 }
647                 return taskDisplayArea.getOrientation(candidate);
648             }, SCREEN_ORIENTATION_UNSET);
649         }
650 
651         if (orientation != SCREEN_ORIENTATION_UNSET
652                 && orientation != SCREEN_ORIENTATION_BEHIND) {
653             ProtoLog.v(WM_DEBUG_ORIENTATION,
654                     "App is requesting an orientation, return %d for display id=%d",
655                     orientation, mDisplayContent.mDisplayId);
656             return orientation;
657         }
658 
659         ProtoLog.v(WM_DEBUG_ORIENTATION,
660                 "No app is requesting an orientation, return %d for display id=%d",
661                 mDisplayContent.getLastOrientation(), mDisplayContent.mDisplayId);
662         // The next app has not been requested to be visible, so we keep the current orientation
663         // to prevent freezing/unfreezing the display too early.
664         return mDisplayContent.getLastOrientation();
665     }
666 
667     @Override
668     void assignChildLayers(SurfaceControl.Transaction t) {
669         assignRootTaskOrdering(t);
670 
671         for (int i = 0; i < mChildren.size(); i++) {
672             mChildren.get(i).assignChildLayers(t);
673         }
674     }
675 
676     void assignRootTaskOrdering(SurfaceControl.Transaction t) {
677         if (getParent() == null) {
678             return;
679         }
680         mTmpAlwaysOnTopChildren.clear();
681         mTmpHomeChildren.clear();
682         mTmpNormalChildren.clear();
683         for (int i = 0; i < mChildren.size(); ++i) {
684             final WindowContainer child = mChildren.get(i);
685             final TaskDisplayArea childTda = child.asTaskDisplayArea();
686             if (childTda != null) {
687                 final Task childTdaTopRootTask = childTda.getTopRootTask();
688                 if (childTdaTopRootTask == null) {
689                     mTmpNormalChildren.add(childTda);
690                 } else if (childTdaTopRootTask.isAlwaysOnTop()) {
691                     mTmpAlwaysOnTopChildren.add(childTda);
692                 } else if (childTdaTopRootTask.isActivityTypeHome()) {
693                     mTmpHomeChildren.add(childTda);
694                 } else {
695                     mTmpNormalChildren.add(childTda);
696                 }
697                 continue;
698             }
699 
700             final Task childTask = child.asTask();
701             if (childTask.isAlwaysOnTop()) {
702                 mTmpAlwaysOnTopChildren.add(childTask);
703             } else if (childTask.isActivityTypeHome()) {
704                 mTmpHomeChildren.add(childTask);
705             } else {
706                 mTmpNormalChildren.add(childTask);
707             }
708         }
709 
710         int layer = 0;
711         // Place root home tasks to the bottom.
712         layer = adjustRootTaskLayer(t, mTmpHomeChildren, layer);
713         layer = adjustRootTaskLayer(t, mTmpNormalChildren, layer);
714         adjustRootTaskLayer(t, mTmpAlwaysOnTopChildren, layer);
715     }
716 
717     /**
718      * Adjusts the layer of the root task which belongs to the same group.
719      * Note that there are three root task groups: home rootTasks, always on top rootTasks, and
720      * normal rootTasks.
721      *
722      * @param startLayer   The beginning layer of this group of rootTasks.
723      * @return The adjusted layer value.
724      */
725     private int adjustRootTaskLayer(SurfaceControl.Transaction t,
726             ArrayList<WindowContainer> children, int startLayer) {
727         mTmpNeedsZBoostIndexes.clear();
728         final int childCount = children.size();
729         boolean hasAdjacentTask = false;
730         for (int i = 0; i < childCount; i++) {
731             final WindowContainer child = children.get(i);
732             final TaskDisplayArea childTda = child.asTaskDisplayArea();
733             final boolean childNeedsZBoost = childTda != null
734                     ? childTda.childrenNeedZBoost()
735                     : child.needsZBoost();
736 
737             if (childNeedsZBoost) {
738                 mTmpNeedsZBoostIndexes.add(i);
739                 continue;
740             }
741 
742             child.assignLayer(t, startLayer++);
743         }
744 
745         final int zBoostSize = mTmpNeedsZBoostIndexes.size();
746         for (int i = 0; i < zBoostSize; i++) {
747             final WindowContainer child = children.get(mTmpNeedsZBoostIndexes.get(i));
748             child.assignLayer(t, startLayer++);
749         }
750         return startLayer;
751     }
752 
753     private boolean childrenNeedZBoost() {
754         final boolean[] needsZBoost = new boolean[1];
755         forAllRootTasks(task -> {
756             needsZBoost[0] |= task.needsZBoost();
757         });
758         return needsZBoost[0];
759     }
760 
761     @Override
762     RemoteAnimationTarget createRemoteAnimationTarget(
763             RemoteAnimationController.RemoteAnimationRecord record) {
764         final ActivityRecord activity = getTopMostActivity();
765         return activity != null ? activity.createRemoteAnimationTarget(record) : null;
766     }
767 
768     void setBackgroundColor(@ColorInt int colorInt) {
769         setBackgroundColor(colorInt, false /* restore */);
770     }
771 
772     void setBackgroundColor(@ColorInt int colorInt, boolean restore) {
773         mBackgroundColor = colorInt;
774         Color color = Color.valueOf(colorInt);
775 
776         // We don't want to increment the mColorLayerCounter if we are restoring the background
777         // color after a surface migration because in that case the mColorLayerCounter already
778         // accounts for setting that background color.
779         if (!restore) {
780             mColorLayerCounter++;
781         }
782 
783         // Only apply the background color if the TDA is actually attached and has a valid surface
784         // to set the background color on. We still want to keep track of the background color state
785         // even if we are not showing it for when/if the TDA is reattached and gets a valid surface
786         if (mSurfaceControl != null) {
787             getPendingTransaction()
788                     .setColor(mSurfaceControl,
789                             new float[]{color.red(), color.green(), color.blue()});
790             scheduleAnimation();
791         }
792     }
793 
794     void clearBackgroundColor() {
795         mColorLayerCounter--;
796 
797         // Only clear the color layer if we have received the same amounts of clear as set
798         // requests and TDA has a non null surface control (i.e. is attached)
799         if (mColorLayerCounter == 0 && mSurfaceControl != null) {
800             getPendingTransaction().unsetColor(mSurfaceControl);
801             scheduleAnimation();
802         }
803     }
804 
805     @Override
806     void migrateToNewSurfaceControl(SurfaceControl.Transaction t) {
807         super.migrateToNewSurfaceControl(t);
808 
809         if (mColorLayerCounter > 0) {
810             setBackgroundColor(mBackgroundColor, true /* restore */);
811         }
812 
813         reassignLayer(t);
814         scheduleAnimation();
815     }
816 
817     void onRootTaskRemoved(Task rootTask) {
818         if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
819             Slog.v(TAG_ROOT_TASK, "onRootTaskRemoved: detaching " + rootTask + " from displayId="
820                     + mDisplayContent.mDisplayId);
821         }
822         if (mPreferredTopFocusableRootTask == rootTask) {
823             mPreferredTopFocusableRootTask = null;
824         }
825         if (mLaunchAdjacentFlagRootTask == rootTask) {
826             mLaunchAdjacentFlagRootTask = null;
827         }
828         mDisplayContent.releaseSelfIfNeeded();
829         onRootTaskOrderChanged(rootTask);
830     }
831 
832     /**
833      * Moves/reparents `task` to the back of whatever container the root home task is in. This is
834      * for when we just want to move a task to "the back" vs. a specific place. The primary use-case
835      * is to make sure that moved-to-back apps go into secondary split when in split-screen mode.
836      */
837     void positionTaskBehindHome(Task task) {
838         final Task home = getOrCreateRootHomeTask();
839         final WindowContainer homeParent = home.getParent();
840         final Task homeParentTask = homeParent != null ? homeParent.asTask() : null;
841         if (homeParentTask == null) {
842             // reparent throws if parent didn't change...
843             if (task.getParent() == this) {
844                 positionChildAt(POSITION_BOTTOM, task, false /*includingParents*/);
845             } else {
846                 task.reparent(this, false /* onTop */);
847             }
848         } else if (homeParentTask == task.getParent()) {
849             // Apparently reparent early-outs if same root task, so we have to explicitly reorder.
850             homeParentTask.positionChildAtBottom(task);
851         } else {
852             task.reparent(homeParentTask, false /* toTop */,
853                     Task.REPARENT_LEAVE_ROOT_TASK_IN_PLACE, false /* animate */,
854                     false /* deferResume */, "positionTaskBehindHome");
855         }
856     }
857 
858     /**
859      * Returns an existing root task compatible with the windowing mode and activity type or
860      * creates one if a compatible root task doesn't exist.
861      *
862      * @see #getOrCreateRootTask(int, int, boolean, Task, Task, ActivityOptions, int)
863      */
864     Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop) {
865         return getOrCreateRootTask(windowingMode, activityType, onTop, null /* candidateTask */,
866                 null /* sourceTask */, null /* options */, 0 /* intent */);
867     }
868 
869     /**
870      * When two level tasks are required for given windowing mode and activity type, returns an
871      * existing compatible root task or creates a new one.
872      * For one level task, the candidate task would be reused to also be the root task or create
873      * a new root task if no candidate task.
874      *
875      * @param windowingMode The windowing mode the root task should be created in.
876      * @param activityType  The activityType the root task should be created in.
877      * @param onTop         If true the root task will be created at the top of the display,
878      *                      else at the bottom.
879      * @param candidateTask The possible task the activity might be launched in. Can be null.
880      * @param sourceTask    The task requesting to start activity. Used to determine which of the
881      *                      adjacent roots should be launch root of the new task. Can be null.
882      * @param options       The activity options used to the launch. Can be null.
883      * @param launchFlags   The launch flags for this launch.
884      * @return The root task to use for the launch.
885      * @see #getRootTask(int, int)
886      */
887     Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,
888             @Nullable Task candidateTask, @Nullable Task sourceTask,
889             @Nullable ActivityOptions options, int launchFlags) {
890         final int resolvedWindowingMode =
891                 windowingMode == WINDOWING_MODE_UNDEFINED ? getWindowingMode() : windowingMode;
892         // Need to pass in a determined windowing mode to see if a new root task should be created,
893         // so use its parent's windowing mode if it is undefined.
894         if (!alwaysCreateRootTask(resolvedWindowingMode, activityType)) {
895             Task rootTask = getRootTask(resolvedWindowingMode, activityType);
896             if (rootTask != null) {
897                 return rootTask;
898             }
899         } else if (candidateTask != null) {
900             final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
901             final Task launchParentTask = getLaunchRootTask(resolvedWindowingMode, activityType,
902                     options, sourceTask, launchFlags, candidateTask);
903             if (launchParentTask != null) {
904                 if (candidateTask.getParent() == null) {
905                     launchParentTask.addChild(candidateTask, position);
906                 } else if (candidateTask.getParent() != launchParentTask) {
907                     candidateTask.reparent(launchParentTask, position);
908                 }
909             } else if (candidateTask.getDisplayArea() != this
910                     || candidateTask.getRootTask().mReparentLeafTaskIfRelaunch) {
911                 if (candidateTask.getParent() == null) {
912                     addChild(candidateTask, position);
913                 } else {
914                     candidateTask.reparent(this, onTop);
915                 }
916             }
917             // Update windowing mode if necessary, e.g. launch into a different windowing mode.
918             if (windowingMode != WINDOWING_MODE_UNDEFINED && candidateTask.isRootTask()
919                     && candidateTask.getWindowingMode() != windowingMode) {
920                 candidateTask.mTransitionController.collect(candidateTask);
921                 candidateTask.setWindowingMode(windowingMode);
922             }
923             return candidateTask.getRootTask();
924         }
925         return new Task.Builder(mAtmService)
926                 .setWindowingMode(windowingMode)
927                 .setActivityType(activityType)
928                 .setOnTop(onTop)
929                 .setParent(this)
930                 .setSourceTask(sourceTask)
931                 .setActivityOptions(options)
932                 .setLaunchFlags(launchFlags)
933                 .build();
934     }
935 
936     /**
937      * Returns an existing root task compatible with the input params or creates one
938      * if a compatible root task doesn't exist.
939      *
940      * @see #getOrCreateRootTask(int, int, boolean)
941      */
942     Task getOrCreateRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
943             @Nullable Task candidateTask, @Nullable Task sourceTask,
944             @Nullable LaunchParams launchParams, int launchFlags, int activityType, boolean onTop) {
945         int windowingMode = WINDOWING_MODE_UNDEFINED;
946         if (launchParams != null) {
947             // If launchParams isn't null, windowing mode is already resolved.
948             windowingMode = launchParams.mWindowingMode;
949         } else if (options != null) {
950             // If launchParams is null and options isn't let's use the windowing mode in the
951             // options.
952             windowingMode = options.getLaunchWindowingMode();
953         }
954         // Validate that our desired windowingMode will work under the current conditions.
955         // UNDEFINED windowing mode is a valid result and means that the new root task will inherit
956         // it's display's windowing mode.
957         windowingMode = validateWindowingMode(windowingMode, r, candidateTask);
958         return getOrCreateRootTask(windowingMode, activityType, onTop, candidateTask, sourceTask,
959                 options, launchFlags);
960     }
961 
962     @VisibleForTesting
963     int getNextRootTaskId() {
964         return mAtmService.mTaskSupervisor.getNextTaskIdForUser();
965     }
966 
967     Task createRootTask(int windowingMode, int activityType, boolean onTop) {
968         return createRootTask(windowingMode, activityType, onTop, null /* activityOptions */);
969     }
970 
971     /**
972      * A convinenit method of creating a root task by providing windowing mode and activity type
973      * on this display.
974      *
975      * @param windowingMode      The windowing mode the root task should be created in. If
976      *                           {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the
977      *                           root task will inherit its parent's windowing mode.
978      * @param activityType       The activityType the root task should be created in. If
979      *                           {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the
980      *                           root task will be created in
981      *                           {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
982      * @param onTop              If true the root task will be created at the top of the display,
983      *                           else at the bottom.
984      * @param opts               The activity options.
985      * @return The newly created root task.
986      */
987     Task createRootTask(int windowingMode, int activityType, boolean onTop, ActivityOptions opts) {
988         return new Task.Builder(mAtmService)
989                 .setWindowingMode(windowingMode)
990                 .setActivityType(activityType)
991                 .setParent(this)
992                 .setOnTop(onTop)
993                 .setActivityOptions(opts)
994                 .build();
995     }
996 
997     // TODO: Also clear when task is removed from system?
998     void setLaunchRootTask(Task rootTask, int[] windowingModes, int[] activityTypes) {
999         if (!rootTask.mCreatedByOrganizer) {
1000             throw new IllegalArgumentException(
1001                     "Can't set not mCreatedByOrganizer as launch root tr=" + rootTask);
1002         }
1003 
1004         LaunchRootTaskDef def = getLaunchRootTaskDef(rootTask);
1005         if (def != null) {
1006             // Remove so we add to the end of the list.
1007             mLaunchRootTasks.remove(def);
1008         } else {
1009             def = new LaunchRootTaskDef();
1010             def.task = rootTask;
1011         }
1012 
1013         def.activityTypes = activityTypes;
1014         def.windowingModes = windowingModes;
1015         if (!ArrayUtils.isEmpty(windowingModes) || !ArrayUtils.isEmpty(activityTypes)) {
1016             mLaunchRootTasks.add(def);
1017         }
1018     }
1019 
1020     void removeLaunchRootTask(Task rootTask) {
1021         LaunchRootTaskDef def = getLaunchRootTaskDef(rootTask);
1022         if (def != null) {
1023             mLaunchRootTasks.remove(def);
1024         }
1025     }
1026 
1027     void setLaunchAdjacentFlagRootTask(@Nullable Task adjacentFlagRootTask) {
1028         if (adjacentFlagRootTask != null) {
1029             if (!adjacentFlagRootTask.mCreatedByOrganizer) {
1030                 throw new IllegalArgumentException(
1031                         "Can't set not mCreatedByOrganizer as launch adjacent flag root tr="
1032                                 + adjacentFlagRootTask);
1033             }
1034 
1035             if (adjacentFlagRootTask.getAdjacentTaskFragment() == null) {
1036                 throw new UnsupportedOperationException(
1037                         "Can't set non-adjacent root as launch adjacent flag root tr="
1038                                 + adjacentFlagRootTask);
1039             }
1040         }
1041 
1042         mLaunchAdjacentFlagRootTask = adjacentFlagRootTask;
1043     }
1044 
1045     private @Nullable LaunchRootTaskDef getLaunchRootTaskDef(Task rootTask) {
1046         LaunchRootTaskDef def = null;
1047         for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
1048             if (mLaunchRootTasks.get(i).task.mTaskId != rootTask.mTaskId) continue;
1049             def = mLaunchRootTasks.get(i);
1050             break;
1051         }
1052         return def;
1053     }
1054 
1055     @Nullable
1056     Task getLaunchRootTask(int windowingMode, int activityType, @Nullable ActivityOptions options,
1057             @Nullable Task sourceTask, int launchFlags) {
1058         return getLaunchRootTask(windowingMode, activityType, options, sourceTask, launchFlags,
1059                 null /* candidateTask */);
1060     }
1061 
1062     @Nullable
1063     Task getLaunchRootTask(int windowingMode, int activityType, @Nullable ActivityOptions options,
1064             @Nullable Task sourceTask, int launchFlags, @Nullable Task candidateTask) {
1065         // Try to use the launch root task in options if available.
1066         if (options != null) {
1067             final Task launchRootTask = Task.fromWindowContainerToken(options.getLaunchRootTask());
1068             // We only allow this for created by organizer tasks.
1069             if (launchRootTask != null && launchRootTask.mCreatedByOrganizer) {
1070                 return launchRootTask;
1071             }
1072         }
1073 
1074         // Use launch-adjacent-flag-root if launching with launch-adjacent flag.
1075         if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0
1076                 && mLaunchAdjacentFlagRootTask != null) {
1077             if (sourceTask != null && sourceTask == candidateTask) {
1078                 // Do nothing when task that is getting opened is same as the source.
1079             } else if (sourceTask != null
1080                     && mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment() != null
1081                     && (sourceTask == mLaunchAdjacentFlagRootTask
1082                     || sourceTask.isDescendantOf(mLaunchAdjacentFlagRootTask))) {
1083                 // If the adjacent launch is coming from the same root, launch to
1084                 // adjacent root instead.
1085                 return mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment().asTask();
1086             } else {
1087                 return mLaunchAdjacentFlagRootTask;
1088             }
1089         }
1090 
1091         for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
1092             if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) {
1093                 final Task launchRootTask = mLaunchRootTasks.get(i).task;
1094                 final TaskFragment adjacentTaskFragment = launchRootTask != null
1095                         ? launchRootTask.getAdjacentTaskFragment() : null;
1096                 final Task adjacentRootTask =
1097                         adjacentTaskFragment != null ? adjacentTaskFragment.asTask() : null;
1098                 if (sourceTask != null && adjacentRootTask != null
1099                         && (sourceTask == adjacentRootTask
1100                         || sourceTask.isDescendantOf(adjacentRootTask))) {
1101                     return adjacentRootTask;
1102                 } else {
1103                     return launchRootTask;
1104                 }
1105             }
1106         }
1107 
1108         // If a task is launching from a created-by-organizer task, it should be launched into the
1109         // same created-by-organizer task as well. Unless, the candidate task is already positioned
1110         // in the another adjacent task.
1111         if (sourceTask != null && (candidateTask == null
1112                 // A pinned task relaunching should be handled by its task organizer. Skip fallback
1113                 // launch target of a pinned task from source task.
1114                 || candidateTask.getWindowingMode() != WINDOWING_MODE_PINNED)) {
1115             Task launchTarget = sourceTask.getCreatedByOrganizerTask();
1116             if (launchTarget != null && launchTarget.getAdjacentTaskFragment() != null) {
1117                 if (candidateTask != null) {
1118                     final Task candidateRoot = candidateTask.getCreatedByOrganizerTask();
1119                     if (candidateRoot != null && candidateRoot != launchTarget
1120                             && launchTarget == candidateRoot.getAdjacentTaskFragment()) {
1121                         launchTarget = candidateRoot;
1122                     }
1123                 }
1124                 return launchTarget;
1125             }
1126         }
1127 
1128         return null;
1129     }
1130 
1131     /**
1132      * Get the preferred focusable root task in priority. If the preferred root task does not exist,
1133      * find a focusable and visible root task from the top of root tasks in this display.
1134      */
1135     Task getFocusedRootTask() {
1136         if (mPreferredTopFocusableRootTask != null) {
1137             return mPreferredTopFocusableRootTask;
1138         }
1139 
1140         for (int i = mChildren.size() - 1; i >= 0; --i) {
1141             final WindowContainer child = mChildren.get(i);
1142             if (child.asTaskDisplayArea() != null) {
1143                 final Task rootTask = child.asTaskDisplayArea().getFocusedRootTask();
1144                 if (rootTask != null) {
1145                     return rootTask;
1146                 }
1147                 continue;
1148             }
1149 
1150             final Task rootTask = mChildren.get(i).asTask();
1151             if (rootTask.isFocusableAndVisible()) {
1152                 return rootTask;
1153             }
1154         }
1155 
1156         return null;
1157     }
1158 
1159     Task getNextFocusableRootTask(Task currentFocus, boolean ignoreCurrent) {
1160         final int currentWindowingMode = currentFocus != null
1161                 ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
1162 
1163         Task candidate = null;
1164         for (int i = mChildren.size() - 1; i >= 0; --i) {
1165             final WindowContainer child = mChildren.get(i);
1166             if (child.asTaskDisplayArea() != null) {
1167                 final Task rootTask = child.asTaskDisplayArea()
1168                         .getNextFocusableRootTask(currentFocus, ignoreCurrent);
1169                 if (rootTask != null) {
1170                     return rootTask;
1171                 }
1172                 continue;
1173             }
1174 
1175             final Task rootTask = mChildren.get(i).asTask();
1176             if (ignoreCurrent && rootTask == currentFocus) {
1177                 continue;
1178             }
1179             if (!rootTask.isFocusableAndVisible()) {
1180                 continue;
1181             }
1182 
1183             return rootTask;
1184         }
1185         return candidate;
1186     }
1187 
1188     ActivityRecord getFocusedActivity() {
1189         final Task focusedRootTask = getFocusedRootTask();
1190         if (focusedRootTask == null) {
1191             return null;
1192         }
1193         // TODO(b/111541062): Move this into Task#getResumedActivity()
1194         // Check if the focused root task has the resumed activity
1195         ActivityRecord resumedActivity = focusedRootTask.getTopResumedActivity();
1196         if (resumedActivity == null || resumedActivity.app == null) {
1197             // If there is no registered resumed activity in the root task or it is not running -
1198             // try to use previously resumed one.
1199             resumedActivity = focusedRootTask.getTopPausingActivity();
1200             if (resumedActivity == null || resumedActivity.app == null) {
1201                 // If previously resumed activity doesn't work either - find the topmost running
1202                 // activity that can be focused.
1203                 resumedActivity = focusedRootTask.topRunningActivity(true /* focusableOnly */);
1204             }
1205         }
1206         return resumedActivity;
1207     }
1208 
1209     Task getLastFocusedRootTask() {
1210         return mLastFocusedRootTask;
1211     }
1212 
1213     void updateLastFocusedRootTask(Task prevFocusedTask, String updateLastFocusedTaskReason) {
1214         if (updateLastFocusedTaskReason == null) {
1215             return;
1216         }
1217 
1218         final Task currentFocusedTask = getFocusedRootTask();
1219         if (currentFocusedTask == prevFocusedTask) {
1220             return;
1221         }
1222 
1223         // Clear last paused activity if focused root task changed while sleeping, so that the
1224         // top activity of current focused task can be resumed.
1225         if (mDisplayContent.isSleeping() && currentFocusedTask != null) {
1226             currentFocusedTask.clearLastPausedActivity();
1227         }
1228 
1229         mLastFocusedRootTask = prevFocusedTask;
1230         EventLogTags.writeWmFocusedRootTask(mRootWindowContainer.mCurrentUser,
1231                 mDisplayContent.mDisplayId,
1232                 currentFocusedTask == null ? -1 : currentFocusedTask.getRootTaskId(),
1233                 mLastFocusedRootTask == null ? -1 : mLastFocusedRootTask.getRootTaskId(),
1234                 updateLastFocusedTaskReason);
1235     }
1236 
1237     boolean allResumedActivitiesComplete() {
1238         for (int i = mChildren.size() - 1; i >= 0; --i) {
1239             final WindowContainer child = mChildren.get(i);
1240             if (child.asTaskDisplayArea() != null) {
1241                 if (!child.asTaskDisplayArea().allResumedActivitiesComplete()) {
1242                     return false;
1243                 }
1244                 continue;
1245             }
1246 
1247             final ActivityRecord r = mChildren.get(i).asTask().getTopResumedActivity();
1248             if (r != null && !r.isState(RESUMED)) {
1249                 return false;
1250             }
1251         }
1252         final Task currentFocusedRootTask = getFocusedRootTask();
1253         if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
1254             Slog.d(TAG_ROOT_TASK, "allResumedActivitiesComplete: currentFocusedRootTask "
1255                     + "changing from=" + mLastFocusedRootTask + " to=" + currentFocusedRootTask);
1256         }
1257         mLastFocusedRootTask = currentFocusedRootTask;
1258         return true;
1259     }
1260 
1261     /**
1262      * Pause all activities in either all of the root tasks or just the back root tasks. This is
1263      * done before resuming a new activity and to make sure that previously active activities are
1264      * paused in root tasks that are no longer visible or in pinned windowing mode. This does not
1265      * pause activities in visible root tasks, so if an activity is launched within the same root
1266      * task, hen we should explicitly pause that root task's top activity.
1267      *
1268      * @param resuming    The resuming activity.
1269      * @return {@code true} if any activity was paused as a result of this call.
1270      */
1271     boolean pauseBackTasks(ActivityRecord resuming) {
1272         final int[] someActivityPaused = {0};
1273         forAllLeafTasks(leafTask -> {
1274             // Check if the direct child resumed activity in the leaf task needed to be paused if
1275             // the leaf task is not a leaf task fragment.
1276             if (!leafTask.isLeafTaskFragment()) {
1277                 final ActivityRecord top = topRunningActivity();
1278                 final ActivityRecord resumedActivity = leafTask.getResumedActivity();
1279                 if (resumedActivity != null && top.getTaskFragment() != leafTask) {
1280                     // Pausing the resumed activity because it is occluded by other task fragment.
1281                     if (leafTask.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
1282                         someActivityPaused[0]++;
1283                     }
1284                 }
1285             }
1286 
1287             leafTask.forAllLeafTaskFragments((taskFrag) -> {
1288                 final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
1289                 if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
1290                     if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
1291                         someActivityPaused[0]++;
1292                     }
1293                 }
1294             }, true /* traverseTopToBottom */);
1295         }, true /* traverseTopToBottom */);
1296         return someActivityPaused[0] > 0;
1297     }
1298 
1299 
1300     /**
1301      * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
1302      *
1303      * @param windowingMode       The windowing mode we are checking support for.
1304      * @param supportsMultiWindow If we should consider support for multi-window mode in general.
1305      * @param supportsFreeform    If we should consider support for freeform multi-window.
1306      * @param supportsPip         If we should consider support for picture-in-picture mutli-window.
1307      * @return true if the windowing mode is supported.
1308      */
1309     static boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
1310             boolean supportsFreeform, boolean supportsPip) {
1311 
1312         if (windowingMode == WINDOWING_MODE_UNDEFINED
1313                 || windowingMode == WINDOWING_MODE_FULLSCREEN) {
1314             return true;
1315         }
1316         if (!supportsMultiWindow) {
1317             return false;
1318         }
1319 
1320         if (windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
1321             return true;
1322         }
1323 
1324         if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
1325             return false;
1326         }
1327 
1328         if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
1329             return false;
1330         }
1331         return true;
1332     }
1333 
1334     /**
1335      * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
1336      * display with the provided parameters.
1337      *
1338      * @param r            The ActivityRecord in question.
1339      * @param options      Options to start with.
1340      * @param task         The task within-which the activity would start.
1341      * @param activityType The type of activity to start.
1342      * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
1343      */
1344     int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
1345             @Nullable Task task) {
1346 
1347         // First preference if the windowing mode in the activity options if set.
1348         int windowingMode = (options != null)
1349                 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
1350 
1351         // If windowing mode is unset, then next preference is the candidate task, then the
1352         // activity record.
1353         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
1354             if (task != null) {
1355                 windowingMode = task.getWindowingMode();
1356             }
1357             if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
1358                 windowingMode = r.getWindowingMode();
1359             }
1360             if (windowingMode == WINDOWING_MODE_UNDEFINED) {
1361                 // Use the display's windowing mode.
1362                 windowingMode = getWindowingMode();
1363             }
1364         }
1365         windowingMode = validateWindowingMode(windowingMode, r, task);
1366         return windowingMode != WINDOWING_MODE_UNDEFINED
1367                 ? windowingMode : WINDOWING_MODE_FULLSCREEN;
1368     }
1369 
1370     /**
1371      * Check if the requested windowing-mode is appropriate for the specified task and/or activity
1372      * on this display.
1373      *
1374      * @param windowingMode The windowing-mode to validate.
1375      * @param r             The {@link ActivityRecord} to check against.
1376      * @param task          The {@link Task} to check against.
1377      * @return {@code true} if windowingMode is valid, {@code false} otherwise.
1378      */
1379     boolean isValidWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task
1380     ) {
1381         // Make sure the windowing mode we are trying to use makes sense for what is supported.
1382         boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
1383         boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement;
1384         boolean supportsPip = mAtmService.mSupportsPictureInPicture;
1385         if (supportsMultiWindow) {
1386             if (task != null) {
1387                 supportsFreeform = task.supportsFreeformInDisplayArea(this);
1388                 supportsMultiWindow = task.supportsMultiWindowInDisplayArea(this)
1389                         // When the activity needs to be moved to PIP while the Task is not in PIP,
1390                         // it can be moved to a new created PIP Task, so WINDOWING_MODE_PINNED is
1391                         // always valid for Task as long as the device supports it.
1392                         || (windowingMode == WINDOWING_MODE_PINNED && supportsPip);
1393             } else if (r != null) {
1394                 supportsFreeform = r.supportsFreeformInDisplayArea(this);
1395                 supportsPip = r.supportsPictureInPicture();
1396                 supportsMultiWindow = r.supportsMultiWindowInDisplayArea(this);
1397             }
1398         }
1399 
1400         return windowingMode != WINDOWING_MODE_UNDEFINED
1401                 && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsFreeform,
1402                 supportsPip);
1403     }
1404 
1405     /**
1406      * Check that the requested windowing-mode is appropriate for the specified task and/or activity
1407      * on this display.
1408      *
1409      * @param windowingMode The windowing-mode to validate.
1410      * @param r             The {@link ActivityRecord} to check against.
1411      * @param task          The {@link Task} to check against.
1412      * @return The provided windowingMode or the closest valid mode which is appropriate.
1413      */
1414     int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task) {
1415         if (!isValidWindowingMode(windowingMode, r, task)) {
1416             return WINDOWING_MODE_UNDEFINED;
1417         }
1418         return windowingMode;
1419     }
1420 
1421     /**
1422      * Whether we can show non-resizable activities in multi window below this
1423      * {@link TaskDisplayArea}
1424      */
1425     boolean supportsNonResizableMultiWindow() {
1426         final int configSupportsNonResizableMultiWindow =
1427                 mAtmService.mSupportsNonResizableMultiWindow;
1428         if (mAtmService.mDevEnableNonResizableMultiWindow
1429                 || configSupportsNonResizableMultiWindow == 1) {
1430             // Device override to support.
1431             return true;
1432         }
1433         if (configSupportsNonResizableMultiWindow == -1) {
1434             // Device override to not support.
1435             return false;
1436         }
1437         // Support on large screen.
1438         return isLargeEnoughForMultiWindow();
1439     }
1440 
1441     /**
1442      * Whether we can show activity requesting the given min width/height in multi window below
1443      * this {@link TaskDisplayArea}.
1444      */
1445     boolean supportsActivityMinWidthHeightMultiWindow(int minWidth, int minHeight,
1446             @Nullable ActivityInfo activityInfo) {
1447         if (activityInfo != null && !activityInfo.shouldCheckMinWidthHeightForMultiWindow()) {
1448             return true;
1449         }
1450         if (minWidth <= 0 && minHeight <= 0) {
1451             // No request min width/height.
1452             return true;
1453         }
1454         final int configRespectsActivityMinWidthHeightMultiWindow =
1455                 mAtmService.mRespectsActivityMinWidthHeightMultiWindow;
1456         if (configRespectsActivityMinWidthHeightMultiWindow == -1) {
1457             // Device override to ignore min width/height.
1458             return true;
1459         }
1460         if (configRespectsActivityMinWidthHeightMultiWindow == 0
1461                 && isLargeEnoughForMultiWindow()) {
1462             // Ignore min width/height on large screen.
1463             return true;
1464         }
1465         // Check if the request min width/height is supported in multi window.
1466         final Configuration config = getConfiguration();
1467         final int orientation = config.orientation;
1468         if (orientation == ORIENTATION_LANDSCAPE) {
1469             final int maxSupportMinWidth = (int) (mAtmService.mMinPercentageMultiWindowSupportWidth
1470                     * config.screenWidthDp * mDisplayContent.getDisplayMetrics().density);
1471             return minWidth <= maxSupportMinWidth;
1472         } else {
1473             final int maxSupportMinHeight =
1474                     (int) (mAtmService.mMinPercentageMultiWindowSupportHeight
1475                             * config.screenHeightDp * mDisplayContent.getDisplayMetrics().density);
1476             return minHeight <= maxSupportMinHeight;
1477         }
1478     }
1479 
1480     /**
1481      * Whether this is large enough to support non-resizable, and activities with min width/height
1482      * in multi window.
1483      */
1484     private boolean isLargeEnoughForMultiWindow() {
1485         return getConfiguration().smallestScreenWidthDp
1486                 >= mAtmService.mLargeScreenSmallestScreenWidthDp;
1487     }
1488 
1489     boolean isTopRootTask(Task rootTask) {
1490         return rootTask == getTopRootTask();
1491     }
1492 
1493     ActivityRecord topRunningActivity() {
1494         return topRunningActivity(false /* considerKeyguardState */);
1495     }
1496 
1497     /**
1498      * Returns the top running activity in the focused root task. In the case the focused root
1499      * task has no such activity, the next focusable root task on this display is returned.
1500      *
1501      * @param considerKeyguardState Indicates whether the locked state should be considered. if
1502      *                              {@code true} and the keyguard is locked, only activities that
1503      *                              can be shown on top of the keyguard will be considered.
1504      * @return The top running activity. {@code null} if none is available.
1505      */
1506     ActivityRecord topRunningActivity(boolean considerKeyguardState) {
1507         ActivityRecord topRunning = null;
1508         final Task focusedRootTask = getFocusedRootTask();
1509         if (focusedRootTask != null) {
1510             topRunning = focusedRootTask.topRunningActivity();
1511         }
1512 
1513         // Look in other focusable root tasks.
1514         if (topRunning == null) {
1515             for (int i = mChildren.size() - 1; i >= 0; --i) {
1516                 final WindowContainer child = mChildren.get(i);
1517                 if (child.asTaskDisplayArea() != null) {
1518                     topRunning =
1519                             child.asTaskDisplayArea().topRunningActivity(considerKeyguardState);
1520                     if (topRunning != null) {
1521                         break;
1522                     }
1523                     continue;
1524                 }
1525                 final Task rootTask = mChildren.get(i).asTask();
1526                 // Only consider focusable root tasks other than the current focused one.
1527                 if (rootTask == focusedRootTask || !rootTask.isTopActivityFocusable()) {
1528                     continue;
1529                 }
1530                 topRunning = rootTask.topRunningActivity();
1531                 if (topRunning != null) {
1532                     break;
1533                 }
1534             }
1535         }
1536 
1537         // This activity can be considered the top running activity if we are not considering
1538         // the locked state, the keyguard isn't locked, or we can show when locked.
1539         if (topRunning != null && considerKeyguardState
1540                 && mRootWindowContainer.mTaskSupervisor.getKeyguardController()
1541                 .isKeyguardLocked(topRunning.getDisplayId())
1542                 && !topRunning.canShowWhenLocked()) {
1543             return null;
1544         }
1545 
1546         return topRunning;
1547     }
1548 
1549     protected int getRootTaskCount() {
1550         final int[] count = new int[1];
1551         forAllRootTasks(task -> {
1552             count[0]++;
1553         });
1554         return count[0];
1555     }
1556 
1557     @Nullable
1558     Task getOrCreateRootHomeTask() {
1559         return getOrCreateRootHomeTask(false /* onTop */);
1560     }
1561 
1562     /**
1563      * Returns the existing root home task or creates and returns a new one if it should exist
1564      * for the display.
1565      *
1566      * @param onTop Only be used when there is no existing root home task. If true the root home
1567      *              task will be created at the top of the display, else at the bottom.
1568      */
1569     @Nullable
1570     Task getOrCreateRootHomeTask(boolean onTop) {
1571         Task homeTask = getRootHomeTask();
1572         // Take into account if this TaskDisplayArea can have a home task before trying to
1573         // create the root task
1574         if (homeTask == null && canHostHomeTask()) {
1575             homeTask = createRootTask(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, onTop);
1576         }
1577         return homeTask;
1578     }
1579 
1580     /**
1581      * Returns the topmost root task on the display that is compatible with the input windowing
1582      * mode. Null is no compatible root task on the display.
1583      */
1584     Task getTopRootTaskInWindowingMode(int windowingMode) {
1585         return getRootTask(windowingMode, ACTIVITY_TYPE_UNDEFINED);
1586     }
1587 
1588     void moveHomeRootTaskToFront(String reason) {
1589         final Task homeRootTask = getOrCreateRootHomeTask();
1590         if (homeRootTask != null) {
1591             homeRootTask.moveToFront(reason);
1592         }
1593     }
1594 
1595     /**
1596      * Moves the focusable home activity to top. If there is no such activity, the root home task
1597      * will still move to top.
1598      */
1599     void moveHomeActivityToTop(String reason) {
1600         final ActivityRecord top = getHomeActivity();
1601         if (top == null) {
1602             moveHomeRootTaskToFront(reason);
1603             return;
1604         }
1605         top.moveFocusableActivityToTop(reason);
1606     }
1607 
1608     @Nullable
1609     ActivityRecord getHomeActivity() {
1610         return getHomeActivityForUser(mRootWindowContainer.mCurrentUser);
1611     }
1612 
1613     @Nullable
1614     ActivityRecord getHomeActivityForUser(int userId) {
1615         final Task rootHomeTask = getRootHomeTask();
1616         if (rootHomeTask == null) {
1617             return null;
1618         }
1619 
1620         final PooledPredicate p = PooledLambda.obtainPredicate(
1621                 TaskDisplayArea::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
1622                 userId);
1623         final ActivityRecord r = rootHomeTask.getActivity(p);
1624         p.recycle();
1625         return r;
1626     }
1627 
1628     private static boolean isHomeActivityForUser(ActivityRecord r, int userId) {
1629         return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId);
1630     }
1631 
1632     /**
1633      * Adjusts the {@param rootTask} behind the last visible rootTask in the display if necessary.
1634      * Generally used in conjunction with {@link #moveRootTaskBehindRootTask}.
1635      */
1636     // TODO(b/151575894): Remove special root task movement methods.
1637     void moveRootTaskBehindBottomMostVisibleRootTask(Task rootTask) {
1638         if (rootTask.shouldBeVisible(null)) {
1639             // Skip if the root task is already visible
1640             return;
1641         }
1642 
1643         // Move the root task to the bottom to not affect the following visibility checks
1644         rootTask.getParent().positionChildAt(POSITION_BOTTOM, rootTask,
1645                 false /* includingParents */);
1646 
1647         // Find the next position where the root task should be placed
1648         final boolean isRootTask = rootTask.isRootTask();
1649         final int numRootTasks =
1650                 isRootTask ? mChildren.size() : rootTask.getParent().getChildCount();
1651         for (int rootTaskNdx = 0; rootTaskNdx < numRootTasks; rootTaskNdx++) {
1652             Task s;
1653             if (isRootTask) {
1654                 final WindowContainer child = mChildren.get(rootTaskNdx);
1655                 if (child.asTaskDisplayArea() != null) {
1656                     s = child.asTaskDisplayArea().getBottomMostVisibleRootTask(rootTask);
1657                 } else {
1658                     s = child.asTask();
1659                 }
1660             } else {
1661                 s = rootTask.getParent().getChildAt(rootTaskNdx).asTask();
1662             }
1663             if (s == rootTask || s == null) {
1664                 continue;
1665             }
1666             final int winMode = s.getWindowingMode();
1667             final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN;
1668             if (s.shouldBeVisible(null) && isValidWindowingMode) {
1669                 // Move the provided root task to behind this root task
1670                 final int position = Math.max(0, rootTaskNdx - 1);
1671                 rootTask.getParent().positionChildAt(position, rootTask,
1672                         false /*includingParents */);
1673                 break;
1674             }
1675         }
1676     }
1677 
1678     @Nullable
1679     private Task getBottomMostVisibleRootTask(Task excludeRootTask) {
1680         return getRootTask(task -> {
1681             final int winMode = task.getWindowingMode();
1682             final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN;
1683             return task.shouldBeVisible(null) && isValidWindowingMode;
1684         }, false /* traverseTopToBottom */);
1685     }
1686 
1687     /**
1688      * Moves the {@param rootTask} behind the given {@param behindRootTask} if possible. If
1689      * {@param behindRootTask} is not currently in the display, then then the root task is moved
1690      * to the back. Generally used in conjunction with
1691      * {@link #moveRootTaskBehindBottomMostVisibleRootTask}.
1692      */
1693     void moveRootTaskBehindRootTask(Task rootTask, Task behindRootTask) {
1694         if (behindRootTask == null || behindRootTask == rootTask) {
1695             return;
1696         }
1697 
1698         final WindowContainer parent = rootTask.getParent();
1699         if (parent == null || parent != behindRootTask.getParent()) {
1700             return;
1701         }
1702 
1703         // Note that positionChildAt will first remove the given root task before inserting into the
1704         // list, so we need to adjust the insertion index to account for the removed index
1705         // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
1706         //       position internally
1707         final int rootTaskIndex = parent.mChildren.indexOf(rootTask);
1708         final int behindRootTaskIndex = parent.mChildren.indexOf(behindRootTask);
1709         final int insertIndex = rootTaskIndex <= behindRootTaskIndex
1710                 ? behindRootTaskIndex - 1 : behindRootTaskIndex;
1711         final int position = Math.max(0, insertIndex);
1712         parent.positionChildAt(position, rootTask, false /* includingParents */);
1713     }
1714 
1715     boolean hasPinnedTask() {
1716         return getRootPinnedTask() != null;
1717     }
1718 
1719     /**
1720      * @return the root task currently above the {@param rootTask}. Can be null if the
1721      * {@param rootTask} is already top-most.
1722      */
1723     static Task getRootTaskAbove(Task rootTask) {
1724         final WindowContainer wc = rootTask.getParent();
1725         final int index = wc.mChildren.indexOf(rootTask) + 1;
1726         return (index < wc.mChildren.size()) ? (Task) wc.mChildren.get(index) : null;
1727     }
1728 
1729     /** Returns true if the root task in the windowing mode is visible. */
1730     boolean isRootTaskVisible(int windowingMode) {
1731         final Task rootTask = getTopRootTaskInWindowingMode(windowingMode);
1732         return rootTask != null && rootTask.isVisible();
1733     }
1734 
1735     void removeRootTask(Task rootTask) {
1736         removeChild(rootTask);
1737     }
1738 
1739     int getDisplayId() {
1740         return mDisplayContent.getDisplayId();
1741     }
1742 
1743     boolean isRemoved() {
1744         return mRemoved;
1745     }
1746 
1747     /**
1748      * Adds a listener to be notified whenever the root task order in the display changes. Currently
1749      * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
1750      * current animation when the system state changes.
1751      */
1752     void registerRootTaskOrderChangedListener(OnRootTaskOrderChangedListener listener) {
1753         if (!mRootTaskOrderChangedCallbacks.contains(listener)) {
1754             mRootTaskOrderChangedCallbacks.add(listener);
1755         }
1756     }
1757 
1758     /**
1759      * Removes a previously registered root task order change listener.
1760      */
1761     void unregisterRootTaskOrderChangedListener(OnRootTaskOrderChangedListener listener) {
1762         mRootTaskOrderChangedCallbacks.remove(listener);
1763     }
1764 
1765     /**
1766      * Notifies of a root task order change
1767      *
1768      * @param rootTask The root task which triggered the order change
1769      */
1770     void onRootTaskOrderChanged(Task rootTask) {
1771         for (int i = mRootTaskOrderChangedCallbacks.size() - 1; i >= 0; i--) {
1772             mRootTaskOrderChangedCallbacks.get(i).onRootTaskOrderChanged(rootTask);
1773         }
1774     }
1775 
1776     @Override
1777     boolean canCreateRemoteAnimationTarget() {
1778         return true;
1779     }
1780 
1781     /**
1782      * Exposes the home task capability of the TaskDisplayArea
1783      */
1784     boolean canHostHomeTask() {
1785         return mDisplayContent.supportsSystemDecorations() && mCanHostHomeTask;
1786     }
1787 
1788     /**
1789      * Callback for when the order of the root tasks in the display changes.
1790      */
1791     interface OnRootTaskOrderChangedListener {
1792         void onRootTaskOrderChanged(Task rootTask);
1793     }
1794 
1795     void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
1796             boolean preserveWindows, boolean notifyClients) {
1797         mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate();
1798         try {
1799             forAllRootTasks(rootTask -> {
1800                 rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,
1801                         notifyClients);
1802             });
1803         } finally {
1804             mAtmService.mTaskSupervisor.endActivityVisibilityUpdate();
1805         }
1806     }
1807 
1808     /**
1809      * Removes the root tasks in the node applying the content removal node from the display.
1810      *
1811      * @return last reparented root task, or {@code null} if the root tasks had to be destroyed.
1812      */
1813     Task remove() {
1814         mPreferredTopFocusableRootTask = null;
1815         // TODO(b/153090332): Allow setting content removal mode per task display area
1816         final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove();
1817         final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
1818         Task lastReparentedRootTask = null;
1819 
1820         // Root tasks could be reparented from the removed display area to other display area. After
1821         // reparenting the last root task of the removed display area, the display area becomes
1822         // ready to be released (no more root tasks). But, we cannot release it at that moment
1823         // or the related WindowContainer will also be removed. So, we set display area as removed
1824         // after reparenting root task finished.
1825         // Keep the order from bottom to top.
1826         int numRootTasks = mChildren.size();
1827 
1828         for (int i = 0; i < numRootTasks; i++) {
1829             final WindowContainer child = mChildren.get(i);
1830             if (child.asTaskDisplayArea() != null) {
1831                 lastReparentedRootTask = child.asTaskDisplayArea().remove();
1832                 continue;
1833             }
1834             final Task task = mChildren.get(i).asTask();
1835             // Always finish non-standard type root tasks and root tasks created by a organizer.
1836             // TODO: For root tasks created by organizer, consider reparenting children tasks if
1837             //       the use case arises in the future.
1838             if (destroyContentOnRemoval
1839                     || !task.isActivityTypeStandardOrUndefined()
1840                     || task.mCreatedByOrganizer) {
1841                 task.remove(false /* withTransition */, "removeTaskDisplayArea");
1842             } else {
1843                 // Reparent task to corresponding launch root or display area.
1844                 final WindowContainer launchRoot = toDisplayArea.getLaunchRootTask(
1845                                         task.getWindowingMode(),
1846                                         task.getActivityType(),
1847                                         null /* options */,
1848                                         null /* sourceTask */,
1849                                         0 /* launchFlags */);
1850                 task.reparent(launchRoot == null ? toDisplayArea : launchRoot, POSITION_TOP);
1851 
1852                 // Set the windowing mode to undefined by default to let the root task inherited the
1853                 // windowing mode.
1854                 task.setWindowingMode(WINDOWING_MODE_UNDEFINED);
1855                 lastReparentedRootTask = task;
1856             }
1857             // Root task may be removed from this display. Ensure each root task will be processed
1858             // and the loop will end.
1859             i -= numRootTasks - mChildren.size();
1860             numRootTasks = mChildren.size();
1861         }
1862 
1863         if (lastReparentedRootTask != null && !lastReparentedRootTask.isRootTask()) {
1864             // Update focus when the last reparented root task is not a root task anymore.
1865             // (For example, if it has been reparented to a split screen root task, move the
1866             // focus to the split root task)
1867             lastReparentedRootTask.getRootTask().moveToFront("display-removed");
1868         }
1869 
1870         mRemoved = true;
1871 
1872         return lastReparentedRootTask;
1873     }
1874 
1875     /** Whether this task display area can request orientation. */
1876     boolean canSpecifyOrientation(@ScreenOrientation int orientation) {
1877         // Only allow to specify orientation if this TDA is the last focused one on this logical
1878         // display that can request orientation request.
1879         return mDisplayContent.getOrientationRequestingTaskDisplayArea() == this
1880                 && !shouldIgnoreOrientationRequest(orientation);
1881     }
1882 
1883     void clearPreferredTopFocusableRootTask() {
1884         mPreferredTopFocusableRootTask = null;
1885     }
1886 
1887     @Override
1888     public void setWindowingMode(int windowingMode) {
1889         mTempConfiguration.setTo(getRequestedOverrideConfiguration());
1890         WindowConfiguration tempRequestWindowConfiguration = mTempConfiguration.windowConfiguration;
1891         tempRequestWindowConfiguration.setWindowingMode(windowingMode);
1892         tempRequestWindowConfiguration.setDisplayWindowingMode(windowingMode);
1893         onRequestedOverrideConfigurationChanged(mTempConfiguration);
1894     }
1895 
1896     @Override
1897     TaskDisplayArea getTaskDisplayArea() {
1898         return this;
1899     }
1900 
1901     @Override
1902     boolean isTaskDisplayArea() {
1903         return true;
1904     }
1905 
1906     @Override
1907     TaskDisplayArea asTaskDisplayArea() {
1908         return this;
1909     }
1910 
1911     @Override
1912     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
1913         pw.println(prefix + "TaskDisplayArea " + getName());
1914         final String doublePrefix = prefix + "  ";
1915         super.dump(pw, doublePrefix, dumpAll);
1916         if (mPreferredTopFocusableRootTask != null) {
1917             pw.println(doublePrefix + "mPreferredTopFocusableRootTask="
1918                     + mPreferredTopFocusableRootTask);
1919         }
1920         if (mLastFocusedRootTask != null) {
1921             pw.println(doublePrefix + "mLastFocusedRootTask=" + mLastFocusedRootTask);
1922         }
1923 
1924         final String triplePrefix = doublePrefix + "  ";
1925 
1926         if (mLaunchRootTasks.size() > 0) {
1927             pw.println(doublePrefix + "mLaunchRootTasks:");
1928             for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
1929                 final LaunchRootTaskDef def = mLaunchRootTasks.get(i);
1930                 pw.println(triplePrefix
1931                         + Arrays.toString(def.activityTypes) + " "
1932                         + Arrays.toString(def.windowingModes) + " "
1933                         + " task=" + def.task);
1934             }
1935         }
1936 
1937         pw.println(doublePrefix + "Application tokens in top down Z order:");
1938         for (int index = getChildCount() - 1; index >= 0; --index) {
1939             final WindowContainer child = getChildAt(index);
1940             if (child.asTaskDisplayArea() != null) {
1941                 child.dump(pw, doublePrefix, dumpAll);
1942                 continue;
1943             }
1944             final Task rootTask = child.asTask();
1945             pw.println(doublePrefix + "* " + rootTask.toFullString());
1946             rootTask.dump(pw, triplePrefix, dumpAll);
1947         }
1948     }
1949 }
1950