blob: 6016648236b326b3de55a5a0963dd4d2d1a987b8 [file] [log] [blame]
Andrii Kulian526ad432020-03-27 12:19:51 -07001/*
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
17package com.android.server.wm;
18
19import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
Andrii Kulian9ea12da2020-03-27 17:16:38 -070020import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
Andrii Kulian526ad432020-03-27 12:19:51 -070021import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
Andrii Kulian9ea12da2020-03-27 17:16:38 -070022import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
23import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
24import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
25import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
Andrii Kulian526ad432020-03-27 12:19:51 -070026import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
27import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Andrii Kulian9ea12da2020-03-27 17:16:38 -070028import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
29import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
30import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
Andrii Kulian526ad432020-03-27 12:19:51 -070031import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
32import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
33import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Wale Ogunwaleadf116e2020-03-27 16:36:01 -070034import static android.window.DisplayAreaOrganizer.FEATURE_TASK_CONTAINER;
Andrii Kulian526ad432020-03-27 12:19:51 -070035
Andrii Kulian9ea12da2020-03-27 17:16:38 -070036import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
37import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
38import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
39import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
40import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
41import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
42import static com.android.server.wm.DisplayContent.alwaysCreateStack;
Andrii Kulian526ad432020-03-27 12:19:51 -070043import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
44import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
Andrii Kulian9ea12da2020-03-27 17:16:38 -070045import static com.android.server.wm.RootWindowContainer.TAG_STATES;
Andrii Kulian86d676c2020-03-27 19:34:54 -070046import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
Andrii Kulian526ad432020-03-27 12:19:51 -070047import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
48
Andrii Kulian9ea12da2020-03-27 17:16:38 -070049import android.annotation.Nullable;
50import android.app.ActivityOptions;
51import android.app.WindowConfiguration;
52import android.content.Intent;
53import android.content.pm.ActivityInfo;
54import android.content.pm.ApplicationInfo;
55import android.os.UserHandle;
Andrii Kulian526ad432020-03-27 12:19:51 -070056import android.util.Slog;
57import android.view.SurfaceControl;
Andrii Kulian9ea12da2020-03-27 17:16:38 -070058import android.window.WindowContainerTransaction;
Andrii Kulian526ad432020-03-27 12:19:51 -070059
60import com.android.internal.annotations.VisibleForTesting;
61import com.android.internal.util.ToBooleanFunction;
Andrii Kulian9ea12da2020-03-27 17:16:38 -070062import com.android.internal.util.function.pooled.PooledLambda;
63import com.android.internal.util.function.pooled.PooledPredicate;
Andrii Kulian526ad432020-03-27 12:19:51 -070064import com.android.server.protolog.common.ProtoLog;
65
Andrii Kulianf9df4a82020-03-31 12:09:27 -070066import java.io.PrintWriter;
Andrii Kulian526ad432020-03-27 12:19:51 -070067import java.util.ArrayList;
68import java.util.List;
69
70/**
Andrii Kulian86d676c2020-03-27 19:34:54 -070071 * {@link DisplayArea} that represents a section of a screen that contains app window containers.
Andrii Kulian526ad432020-03-27 12:19:51 -070072 */
Andrii Kulian86d676c2020-03-27 19:34:54 -070073final class TaskDisplayArea extends DisplayArea<ActivityStack> {
74 DisplayContent mDisplayContent;
Andrii Kulian526ad432020-03-27 12:19:51 -070075 /**
76 * A control placed at the appropriate level for transitions to occur.
77 */
78 private SurfaceControl mAppAnimationLayer;
79 private SurfaceControl mBoostedAppAnimationLayer;
80 private SurfaceControl mHomeAppAnimationLayer;
81
82 /**
83 * Given that the split-screen divider does not have an AppWindowToken, it
84 * will have to live inside of a "NonAppWindowContainer". However, in visual Z order
85 * it will need to be interleaved with some of our children, appearing on top of
86 * both docked stacks but underneath any assistant stacks.
87 *
88 * To solve this problem we have this anchor control, which will always exist so
89 * we can always assign it the correct value in our {@link #assignChildLayers}.
90 * Likewise since it always exists, we can always
91 * assign the divider a layer relative to it. This way we prevent linking lifecycle
92 * events between tasks and the divider window.
93 */
94 private SurfaceControl mSplitScreenDividerAnchor;
95
96 // Cached reference to some special tasks we tend to get a lot so we don't need to loop
97 // through the list to find them.
98 private ActivityStack mRootHomeTask;
99 private ActivityStack mRootPinnedTask;
100 private ActivityStack mRootSplitScreenPrimaryTask;
101
102 private final ArrayList<ActivityStack> mTmpAlwaysOnTopStacks = new ArrayList<>();
103 private final ArrayList<ActivityStack> mTmpNormalStacks = new ArrayList<>();
104 private final ArrayList<ActivityStack> mTmpHomeStacks = new ArrayList<>();
105
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700106 private ArrayList<Task> mTmpTasks = new ArrayList<>();
107
108 private ActivityTaskManagerService mAtmService;
109
110 private RootWindowContainer mRootWindowContainer;
111
112 // When non-null, new tasks get put into this root task.
Andrii Kulian86d676c2020-03-27 19:34:54 -0700113 Task mLaunchRootTask = null;
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700114
115 /**
116 * A focusable stack that is purposely to be positioned at the top. Although the stack may not
117 * have the topmost index, it is used as a preferred candidate to prevent being unable to resume
118 * target stack properly when there are other focusable always-on-top stacks.
119 */
Andrii Kulian86d676c2020-03-27 19:34:54 -0700120 ActivityStack mPreferredTopFocusableStack;
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700121
122 private final RootWindowContainer.FindTaskResult
123 mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
124
125 /**
126 * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
127 * stack has been resumed. If stacks are changing position this will hold the old stack until
128 * the new stack becomes resumed after which it will be set to current focused stack.
129 */
130 ActivityStack mLastFocusedStack;
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700131 /**
132 * All of the stacks on this display. Order matters, topmost stack is in front of all other
133 * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
134 * changing the list should also call {@link #onStackOrderChanged()}.
135 */
136 private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700137
Andrii Kulianf9df4a82020-03-31 12:09:27 -0700138 /**
139 * The task display area is removed from the system and we are just waiting for all activities
140 * on it to be finished before removing this object.
141 */
142 private boolean mRemoved;
143
Andrii Kulian86d676c2020-03-27 19:34:54 -0700144 TaskDisplayArea(DisplayContent displayContent, WindowManagerService service) {
Andrii Kulian526ad432020-03-27 12:19:51 -0700145 super(service, Type.ANY, "TaskContainers", FEATURE_TASK_CONTAINER);
146 mDisplayContent = displayContent;
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700147 mRootWindowContainer = service.mRoot;
148 mAtmService = service.mAtmService;
Andrii Kulian526ad432020-03-27 12:19:51 -0700149 }
150
151 /**
152 * Returns the topmost stack on the display that is compatible with the input windowing mode
153 * and activity type. Null is no compatible stack on the display.
154 */
155 ActivityStack getStack(int windowingMode, int activityType) {
156 if (activityType == ACTIVITY_TYPE_HOME) {
157 return mRootHomeTask;
158 }
159 if (windowingMode == WINDOWING_MODE_PINNED) {
160 return mRootPinnedTask;
161 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
162 return mRootSplitScreenPrimaryTask;
163 }
164 for (int i = getChildCount() - 1; i >= 0; --i) {
165 final ActivityStack stack = getChildAt(i);
166 if (activityType == ACTIVITY_TYPE_UNDEFINED
167 && windowingMode == stack.getWindowingMode()) {
168 // Passing in undefined type means we want to match the topmost stack with the
169 // windowing mode.
170 return stack;
171 }
172 if (stack.isCompatible(windowingMode, activityType)) {
173 return stack;
174 }
175 }
176 return null;
177 }
178
179 @VisibleForTesting
180 ActivityStack getTopStack() {
181 final int count = getChildCount();
182 return count > 0 ? getChildAt(count - 1) : null;
183 }
184
185 int getIndexOf(ActivityStack stack) {
186 return mChildren.indexOf(stack);
187 }
188
189 ActivityStack getRootHomeTask() {
190 return mRootHomeTask;
191 }
192
193 ActivityStack getRootPinnedTask() {
194 return mRootPinnedTask;
195 }
196
197 ActivityStack getRootSplitScreenPrimaryTask() {
198 return mRootSplitScreenPrimaryTask;
199 }
200
201 ArrayList<Task> getVisibleTasks() {
202 final ArrayList<Task> visibleTasks = new ArrayList<>();
203 forAllTasks(task -> {
204 if (task.isLeafTask() && task.isVisible()) {
205 visibleTasks.add(task);
206 }
207 });
208 return visibleTasks;
209 }
210
211 void onStackWindowingModeChanged(ActivityStack stack) {
212 removeStackReferenceIfNeeded(stack);
213 addStackReferenceIfNeeded(stack);
214 if (stack == mRootPinnedTask && getTopStack() != stack) {
215 // Looks like this stack changed windowing mode to pinned. Move it to the top.
216 positionChildAt(POSITION_TOP, stack, false /* includingParents */);
217 }
218 }
219
220 void addStackReferenceIfNeeded(ActivityStack stack) {
221 if (stack.isActivityTypeHome()) {
222 if (mRootHomeTask != null) {
223 if (!stack.isDescendantOf(mRootHomeTask)) {
224 throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
225 + mRootHomeTask + " already exist on display=" + this
226 + " stack=" + stack);
227 }
228 } else {
229 mRootHomeTask = stack;
230 }
231 }
232
233 if (!stack.isRootTask()) {
234 return;
235 }
236 final int windowingMode = stack.getWindowingMode();
237 if (windowingMode == WINDOWING_MODE_PINNED) {
238 if (mRootPinnedTask != null) {
239 throw new IllegalArgumentException(
240 "addStackReferenceIfNeeded: pinned stack=" + mRootPinnedTask
241 + " already exist on display=" + this + " stack=" + stack);
242 }
243 mRootPinnedTask = stack;
244 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
245 if (mRootSplitScreenPrimaryTask != null) {
246 throw new IllegalArgumentException(
247 "addStackReferenceIfNeeded: split screen primary stack="
248 + mRootSplitScreenPrimaryTask
249 + " already exist on display=" + this + " stack=" + stack);
250 }
251 mRootSplitScreenPrimaryTask = stack;
252 }
253 }
254
255 void removeStackReferenceIfNeeded(ActivityStack stack) {
256 if (stack == mRootHomeTask) {
257 mRootHomeTask = null;
258 } else if (stack == mRootPinnedTask) {
259 mRootPinnedTask = null;
260 } else if (stack == mRootSplitScreenPrimaryTask) {
261 mRootSplitScreenPrimaryTask = null;
262 }
263 }
264
265 @Override
266 void addChild(ActivityStack stack, int position) {
267 addStackReferenceIfNeeded(stack);
268 position = findPositionForStack(position, stack, true /* adding */);
269
270 super.addChild(stack, position);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700271 mAtmService.updateSleepIfNeededLocked();
Andrii Kulian526ad432020-03-27 12:19:51 -0700272
273 // The reparenting case is handled in WindowContainer.
274 if (!stack.mReparenting) {
275 mDisplayContent.setLayoutNeeded();
276 }
277 }
278
279 @Override
280 protected void removeChild(ActivityStack stack) {
281 super.removeChild(stack);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700282 onStackRemoved(stack);
283 mAtmService.updateSleepIfNeededLocked();
Andrii Kulian526ad432020-03-27 12:19:51 -0700284 removeStackReferenceIfNeeded(stack);
285 }
286
287 @Override
288 boolean isOnTop() {
289 // Considered always on top
290 return true;
291 }
292
293 @Override
294 void positionChildAt(int position, ActivityStack child, boolean includingParents) {
295 final boolean moveToTop = (position == POSITION_TOP || position == getChildCount());
296 final boolean moveToBottom = (position == POSITION_BOTTOM || position == 0);
297 if (child.getWindowConfiguration().isAlwaysOnTop() && !moveToTop) {
298 // This stack is always-on-top, override the default behavior.
299 Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + this + " to bottom");
300
301 // Moving to its current position, as we must call super but we don't want to
302 // perform any meaningful action.
303 final int currentPosition = mChildren.indexOf(child);
304 super.positionChildAt(currentPosition, child, false /* includingParents */);
305 return;
306 }
307 // We don't allow untrusted display to top when task stack moves to top,
308 // until user tapping this display to change display position as top intentionally.
309 if (mDisplayContent.isUntrustedVirtualDisplay() && !getParent().isOnTop()) {
310 includingParents = false;
311 }
312 final int targetPosition = findPositionForStack(position, child, false /* adding */);
313 super.positionChildAt(targetPosition, child, false /* includingParents */);
314
315 if (includingParents && (moveToTop || moveToBottom)) {
316 // The DisplayContent children do not re-order, but we still want to move the
317 // display of this stack container because the intention of positioning is to have
318 // higher z-order to gain focus.
319 mDisplayContent.positionDisplayAt(moveToTop ? POSITION_TOP : POSITION_BOTTOM,
320 true /* includingParents */);
321 }
322
323 child.updateTaskMovement(moveToTop);
324
325 mDisplayContent.setLayoutNeeded();
326 }
327
328 /**
329 * When stack is added or repositioned, find a proper position for it.
330 * This will make sure that pinned stack always stays on top.
331 * @param requestedPosition Position requested by caller.
332 * @param stack Stack to be added or positioned.
333 * @param adding Flag indicates whether we're adding a new stack or positioning an existing.
334 * @return The proper position for the stack.
335 */
336 private int findPositionForStack(int requestedPosition, ActivityStack stack,
337 boolean adding) {
338 if (stack.isActivityTypeDream()) {
339 return POSITION_TOP;
340 }
341
342 if (stack.inPinnedWindowingMode()) {
343 return POSITION_TOP;
344 }
345
346 final int topChildPosition = mChildren.size() - 1;
347 int belowAlwaysOnTopPosition = POSITION_BOTTOM;
348 for (int i = topChildPosition; i >= 0; --i) {
349 // Since a stack could be repositioned while being one of the child, return
350 // current index if that's the same stack we are positioning and it is always on
351 // top.
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700352 final boolean sameStack = mChildren.get(i) == stack;
Andrii Kulian526ad432020-03-27 12:19:51 -0700353 if ((sameStack && stack.isAlwaysOnTop())
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700354 || (!sameStack && !mChildren.get(i).isAlwaysOnTop())) {
Andrii Kulian526ad432020-03-27 12:19:51 -0700355 belowAlwaysOnTopPosition = i;
356 break;
357 }
358 }
359
360 // The max possible position we can insert the stack at.
361 int maxPosition = POSITION_TOP;
362 // The min possible position we can insert the stack at.
363 int minPosition = POSITION_BOTTOM;
364
365 if (stack.isAlwaysOnTop()) {
Andrii Kulian86d676c2020-03-27 19:34:54 -0700366 if (hasPinnedTask()) {
Andrii Kulian526ad432020-03-27 12:19:51 -0700367 // Always-on-top stacks go below the pinned stack.
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700368 maxPosition = mChildren.indexOf(mRootPinnedTask) - 1;
Andrii Kulian526ad432020-03-27 12:19:51 -0700369 }
370 // Always-on-top stacks need to be above all other stacks.
371 minPosition = belowAlwaysOnTopPosition
372 != POSITION_BOTTOM ? belowAlwaysOnTopPosition : topChildPosition;
373 } else {
374 // Other stacks need to be below the always-on-top stacks.
375 maxPosition = belowAlwaysOnTopPosition
376 != POSITION_BOTTOM ? belowAlwaysOnTopPosition : 0;
377 }
378
379 // Cap the requested position to something reasonable for the previous position check
380 // below.
381 if (requestedPosition == POSITION_TOP) {
382 requestedPosition = mChildren.size();
383 } else if (requestedPosition == POSITION_BOTTOM) {
384 requestedPosition = 0;
385 }
386
387 int targetPosition = requestedPosition;
388 targetPosition = Math.min(targetPosition, maxPosition);
389 targetPosition = Math.max(targetPosition, minPosition);
390
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700391 int prevPosition = mChildren.indexOf(stack);
Andrii Kulian526ad432020-03-27 12:19:51 -0700392 // The positions we calculated above (maxPosition, minPosition) do not take into
393 // consideration the following edge cases.
394 // 1) We need to adjust the position depending on the value "adding".
395 // 2) When we are moving a stack to another position, we also need to adjust the
396 // position depending on whether the stack is moving to a higher or lower position.
397 if ((targetPosition != requestedPosition) && (adding || targetPosition < prevPosition)) {
398 targetPosition++;
399 }
400
401 return targetPosition;
402 }
403
404 @Override
405 boolean forAllWindows(ToBooleanFunction<WindowState> callback,
406 boolean traverseTopToBottom) {
407 if (traverseTopToBottom) {
408 if (super.forAllWindows(callback, traverseTopToBottom)) {
409 return true;
410 }
411 if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) {
412 return true;
413 }
414 } else {
415 if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) {
416 return true;
417 }
418 if (super.forAllWindows(callback, traverseTopToBottom)) {
419 return true;
420 }
421 }
422 return false;
423 }
424
425 private boolean forAllExitingAppTokenWindows(ToBooleanFunction<WindowState> callback,
426 boolean traverseTopToBottom) {
427 // For legacy reasons we process the TaskStack.mExitingActivities first here before the
428 // app tokens.
429 // TODO: Investigate if we need to continue to do this or if we can just process them
430 // in-order.
431 if (traverseTopToBottom) {
432 for (int i = mChildren.size() - 1; i >= 0; --i) {
433 final List<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
434 for (int j = activities.size() - 1; j >= 0; --j) {
435 if (activities.get(j).forAllWindowsUnchecked(callback,
436 traverseTopToBottom)) {
437 return true;
438 }
439 }
440 }
441 } else {
442 final int count = mChildren.size();
443 for (int i = 0; i < count; ++i) {
444 final List<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
445 final int appTokensCount = activities.size();
446 for (int j = 0; j < appTokensCount; j++) {
447 if (activities.get(j).forAllWindowsUnchecked(callback,
448 traverseTopToBottom)) {
449 return true;
450 }
451 }
452 }
453 }
454 return false;
455 }
456
457 void setExitingTokensHasVisible(boolean hasVisible) {
458 for (int i = mChildren.size() - 1; i >= 0; --i) {
459 final ArrayList<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
460 for (int j = activities.size() - 1; j >= 0; --j) {
461 activities.get(j).hasVisible = hasVisible;
462 }
463 }
464 }
465
466 void removeExistingAppTokensIfPossible() {
467 for (int i = mChildren.size() - 1; i >= 0; --i) {
468 final ArrayList<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
469 for (int j = activities.size() - 1; j >= 0; --j) {
470 final ActivityRecord activity = activities.get(j);
471 if (!activity.hasVisible && !mDisplayContent.mClosingApps.contains(activity)
472 && (!activity.mIsExiting || activity.isEmpty())) {
473 // Make sure there is no animation running on this activity, so any windows
474 // associated with it will be removed as soon as their animations are
475 // complete.
476 cancelAnimation();
477 ProtoLog.v(WM_DEBUG_ADD_REMOVE,
478 "performLayout: Activity exiting now removed %s", activity);
479 activity.removeIfPossible();
480 }
481 }
482 }
483 }
484
485 @Override
486 int getOrientation(int candidate) {
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700487 if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
Andrii Kulian526ad432020-03-27 12:19:51 -0700488 // Apps and their containers are not allowed to specify an orientation while using
489 // root tasks...except for the home stack if it is not resizable and currently
490 // visible (top of) its root task.
491 if (mRootHomeTask != null && mRootHomeTask.isVisible()) {
492 final Task topMost = mRootHomeTask.getTopMostTask();
493 final boolean resizable = topMost != null && topMost.isResizeable();
494 if (!(resizable && mRootHomeTask.matchParentBounds())) {
495 final int orientation = mRootHomeTask.getOrientation();
496 if (orientation != SCREEN_ORIENTATION_UNSET) {
497 return orientation;
498 }
499 }
500 }
501 return SCREEN_ORIENTATION_UNSPECIFIED;
502 }
503
504 final int orientation = super.getOrientation(candidate);
505 if (orientation != SCREEN_ORIENTATION_UNSET
506 && orientation != SCREEN_ORIENTATION_BEHIND) {
507 ProtoLog.v(WM_DEBUG_ORIENTATION,
508 "App is requesting an orientation, return %d for display id=%d",
509 orientation, mDisplayContent.mDisplayId);
510 return orientation;
511 }
512
513 ProtoLog.v(WM_DEBUG_ORIENTATION,
514 "No app is requesting an orientation, return %d for display id=%d",
515 mDisplayContent.getLastOrientation(), mDisplayContent.mDisplayId);
516 // The next app has not been requested to be visible, so we keep the current orientation
517 // to prevent freezing/unfreezing the display too early.
518 return mDisplayContent.getLastOrientation();
519 }
520
521 @Override
522 void assignChildLayers(SurfaceControl.Transaction t) {
523 assignStackOrdering(t);
524
525 for (int i = 0; i < mChildren.size(); i++) {
526 final ActivityStack s = mChildren.get(i);
527 s.assignChildLayers(t);
528 }
529 }
530
531 void assignStackOrdering(SurfaceControl.Transaction t) {
532 if (getParent() == null) {
533 return;
534 }
535 mTmpAlwaysOnTopStacks.clear();
536 mTmpHomeStacks.clear();
537 mTmpNormalStacks.clear();
538 for (int i = 0; i < mChildren.size(); ++i) {
539 final ActivityStack s = mChildren.get(i);
540 if (s.isAlwaysOnTop()) {
541 mTmpAlwaysOnTopStacks.add(s);
542 } else if (s.isActivityTypeHome()) {
543 mTmpHomeStacks.add(s);
544 } else {
545 mTmpNormalStacks.add(s);
546 }
547 }
548
549 int layer = 0;
550 // Place home stacks to the bottom.
551 for (int i = 0; i < mTmpHomeStacks.size(); i++) {
552 mTmpHomeStacks.get(i).assignLayer(t, layer++);
553 }
554 // The home animation layer is between the home stacks and the normal stacks.
555 final int layerForHomeAnimationLayer = layer++;
556 int layerForSplitScreenDividerAnchor = layer++;
557 int layerForAnimationLayer = layer++;
558 for (int i = 0; i < mTmpNormalStacks.size(); i++) {
559 final ActivityStack s = mTmpNormalStacks.get(i);
560 s.assignLayer(t, layer++);
561 if (s.inSplitScreenWindowingMode()) {
562 // The split screen divider anchor is located above the split screen window.
563 layerForSplitScreenDividerAnchor = layer++;
564 }
565 if (s.isTaskAnimating() || s.isAppTransitioning()) {
566 // The animation layer is located above the highest animating stack and no
567 // higher.
568 layerForAnimationLayer = layer++;
569 }
570 }
571 // The boosted animation layer is between the normal stacks and the always on top
572 // stacks.
573 final int layerForBoostedAnimationLayer = layer++;
574 for (int i = 0; i < mTmpAlwaysOnTopStacks.size(); i++) {
575 mTmpAlwaysOnTopStacks.get(i).assignLayer(t, layer++);
576 }
577
578 t.setLayer(mHomeAppAnimationLayer, layerForHomeAnimationLayer);
579 t.setLayer(mAppAnimationLayer, layerForAnimationLayer);
580 t.setLayer(mSplitScreenDividerAnchor, layerForSplitScreenDividerAnchor);
581 t.setLayer(mBoostedAppAnimationLayer, layerForBoostedAnimationLayer);
582 }
583
584 @Override
585 SurfaceControl getAppAnimationLayer(@AnimationLayer int animationLayer) {
586 switch (animationLayer) {
587 case ANIMATION_LAYER_BOOSTED:
588 return mBoostedAppAnimationLayer;
589 case ANIMATION_LAYER_HOME:
590 return mHomeAppAnimationLayer;
591 case ANIMATION_LAYER_STANDARD:
592 default:
593 return mAppAnimationLayer;
594 }
595 }
596
597 SurfaceControl getSplitScreenDividerAnchor() {
598 return mSplitScreenDividerAnchor;
599 }
600
601 @Override
602 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
603 if (getParent() != null) {
604 super.onParentChanged(newParent, oldParent, () -> {
605 mAppAnimationLayer = makeChildSurface(null)
606 .setName("animationLayer")
607 .build();
608 mBoostedAppAnimationLayer = makeChildSurface(null)
609 .setName("boostedAnimationLayer")
610 .build();
611 mHomeAppAnimationLayer = makeChildSurface(null)
612 .setName("homeAnimationLayer")
613 .build();
614 mSplitScreenDividerAnchor = makeChildSurface(null)
615 .setName("splitScreenDividerAnchor")
616 .build();
617 getPendingTransaction()
618 .show(mAppAnimationLayer)
619 .show(mBoostedAppAnimationLayer)
620 .show(mHomeAppAnimationLayer)
621 .show(mSplitScreenDividerAnchor);
622 });
623 } else {
624 super.onParentChanged(newParent, oldParent);
625 mWmService.mTransactionFactory.get()
626 .remove(mAppAnimationLayer)
627 .remove(mBoostedAppAnimationLayer)
628 .remove(mHomeAppAnimationLayer)
629 .remove(mSplitScreenDividerAnchor)
630 .apply();
631 mAppAnimationLayer = null;
632 mBoostedAppAnimationLayer = null;
633 mHomeAppAnimationLayer = null;
634 mSplitScreenDividerAnchor = null;
635 }
636 }
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700637
638 void addStack(ActivityStack stack, int position) {
Andrii Kulian86d676c2020-03-27 19:34:54 -0700639 if (DEBUG_STACK) Slog.d(TAG_WM, "Set stack=" + stack + " on taskDisplayArea=" + this);
640 addChild(stack, position);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700641 positionStackAt(stack, position);
642 }
643
644 void onStackRemoved(ActivityStack stack) {
645 if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
646 Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId="
647 + mDisplayContent.mDisplayId);
648 }
649 if (mPreferredTopFocusableStack == stack) {
650 mPreferredTopFocusableStack = null;
651 }
652 mDisplayContent.releaseSelfIfNeeded();
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700653 onStackOrderChanged(stack);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700654 }
655
656 void positionStackAt(int position, ActivityStack child, boolean includingParents) {
657 positionChildAt(position, child, includingParents);
658 mDisplayContent.layoutAndAssignWindowLayersIfNeeded();
659 }
660
661 void positionStackAtTop(ActivityStack stack, boolean includingParents) {
662 positionStackAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
663 }
664
665 void positionStackAtTop(ActivityStack stack, boolean includingParents,
666 String updateLastFocusedStackReason) {
667 positionStackAt(stack, getStackCount(), includingParents,
668 updateLastFocusedStackReason);
669 }
670
671 void positionStackAtBottom(ActivityStack stack) {
672 positionStackAtBottom(stack, null /* updateLastFocusedStackReason */);
673 }
674
675 void positionStackAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
676 positionStackAt(stack, 0, false /* includingParents */,
677 updateLastFocusedStackReason);
678 }
679
680 void positionStackAt(ActivityStack stack, int position) {
681 positionStackAt(stack, position, false /* includingParents */,
682 null /* updateLastFocusedStackReason */);
683 }
684
685 void positionStackAt(ActivityStack stack, int position, boolean includingParents,
686 String updateLastFocusedStackReason) {
687 // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
688 // the position internally, also update the logic here
689 final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
690 ? getFocusedStack() : null;
691 final boolean wasContained = getIndexOf(stack) >= 0;
692 if (mDisplayContent.mSingleTaskInstance && getStackCount() == 1 && !wasContained) {
693 throw new IllegalStateException(
694 "positionStackAt: Can only have one task on display=" + this);
695 }
696
697 final boolean movingToTop = wasContained && position >= getStackCount() - 1;
698 // Reset mPreferredTopFocusableStack before positioning to top or {@link
699 // ActivityStackSupervisor#updateTopResumedActivityIfNeeded()} won't update the top
700 // resumed activity.
701 if (movingToTop && stack.isFocusable()) {
702 mPreferredTopFocusableStack = null;
703 }
704
705 // Since positionChildAt() is called during the creation process of pinned stacks,
706 // ActivityStack#getStack() can be null.
707 positionStackAt(position, stack, includingParents);
708
709 // The insert position may be adjusted to non-top when there is always-on-top stack. Since
710 // the original position is preferred to be top, the stack should have higher priority when
711 // we are looking for top focusable stack. The condition {@code wasContained} restricts the
712 // preferred stack is set only when moving an existing stack to top instead of adding a new
713 // stack that may be too early (e.g. in the middle of launching or reparenting).
714 if (movingToTop && stack.isFocusableAndVisible()) {
715 mPreferredTopFocusableStack = stack;
716 } else if (mPreferredTopFocusableStack == stack) {
717 mPreferredTopFocusableStack = null;
718 }
719
720 if (updateLastFocusedStackReason != null) {
721 final ActivityStack currentFocusedStack = getFocusedStack();
722 if (currentFocusedStack != prevFocusedStack) {
723 mLastFocusedStack = prevFocusedStack;
724 EventLogTags.writeWmFocusedStack(mRootWindowContainer.mCurrentUser,
725 mDisplayContent.mDisplayId,
726 currentFocusedStack == null ? -1 : currentFocusedStack.getRootTaskId(),
727 mLastFocusedStack == null ? -1 : mLastFocusedStack.getRootTaskId(),
728 updateLastFocusedStackReason);
729 }
730 }
731
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700732 onStackOrderChanged(stack);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700733 }
734
735 ActivityStack getStack(int rootTaskId) {
736 for (int i = getStackCount() - 1; i >= 0; --i) {
737 final ActivityStack stack = getStackAt(i);
738 if (stack.getRootTaskId() == rootTaskId) {
739 return stack;
740 }
741 }
742 return null;
743 }
744
745 /**
746 * Returns an existing stack compatible with the windowing mode and activity type or creates one
747 * if a compatible stack doesn't exist.
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700748 * @see #getOrCreateStack(int, int, boolean, Intent, Task)
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700749 */
750 ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop) {
751 return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700752 null /* candidateTask */);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700753 }
754
755 /**
756 * When two level tasks are required for given windowing mode and activity type, returns an
757 * existing compatible root task or creates a new one.
758 * For one level task, the candidate task would be reused to also be the root task or create
759 * a new root task if no candidate task.
760 * @see #getStack(int, int)
761 * @see #createStack(int, int, boolean)
762 */
763 ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop,
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700764 Intent intent, Task candidateTask) {
Louis Chang6c5d7252020-03-30 15:42:01 +0800765 // Need to pass in a determined windowing mode to see if a new stack should be created,
766 // so use its parent's windowing mode if it is undefined.
767 if (!alwaysCreateStack(
768 windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : getWindowingMode(),
769 activityType)) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700770 ActivityStack stack = getStack(windowingMode, activityType);
771 if (stack != null) {
772 return stack;
773 }
774 } else if (candidateTask != null) {
775 final ActivityStack stack = (ActivityStack) candidateTask;
776 final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700777 Task launchRootTask = updateLaunchRootTask(windowingMode);
778
779 if (launchRootTask != null) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700780 if (stack.getParent() == null) {
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700781 launchRootTask.addChild(stack, position);
782 } else if (stack.getParent() != launchRootTask) {
783 stack.reparent(launchRootTask, position);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700784 }
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700785 } else if (stack.getDisplayArea() != this || !stack.isRootTask()) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700786 if (stack.getParent() == null) {
787 addStack(stack, position);
788 } else {
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700789 stack.reparent(this, onTop);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700790 }
791 }
792 // Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.
793 if (candidateTask.getWindowingMode() != windowingMode) {
794 candidateTask.setWindowingMode(windowingMode);
795 }
796 return stack;
797 }
798 return createStack(windowingMode, activityType, onTop, null /*info*/, intent,
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700799 false /* createdByOrganizer */);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700800 }
801
802 /**
803 * Returns an existing stack compatible with the input params or creates one
804 * if a compatible stack doesn't exist.
805 * @see #getOrCreateStack(int, int, boolean)
806 */
807 ActivityStack getOrCreateStack(@Nullable ActivityRecord r,
808 @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
809 boolean onTop) {
810 // First preference is the windowing mode in the activity options if set.
811 int windowingMode = (options != null)
812 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
813 // Validate that our desired windowingMode will work under the current conditions.
814 // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
815 // it's display's windowing mode.
816 windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
817 return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700818 candidateTask);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700819 }
820
821 @VisibleForTesting
822 int getNextStackId() {
823 return mAtmService.mStackSupervisor.getNextTaskIdForUser();
824 }
825
826 ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
827 return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */,
828 false /* createdByOrganizer */);
829 }
830
831 /**
832 * Creates a stack matching the input windowing mode and activity type on this display.
833 * @param windowingMode The windowing mode the stack should be created in. If
834 * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
835 * inherit its parent's windowing mode.
836 * @param activityType The activityType the stack should be created in. If
837 * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
838 * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
839 * @param onTop If true the stack will be created at the top of the display, else at the bottom.
840 * @param info The started activity info.
841 * @param intent The intent that started this task.
842 * @param createdByOrganizer @{code true} if this is created by task organizer, @{code false}
843 * otherwise.
844 * @return The newly created stack.
845 */
846 ActivityStack createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
847 Intent intent, boolean createdByOrganizer) {
848 if (mDisplayContent.mSingleTaskInstance && getStackCount() > 0) {
849 // Create stack on default display instead since this display can only contain 1 stack.
850 // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
851 // this goes away once ActivityView is no longer using virtual displays.
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700852 return mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700853 windowingMode, activityType, onTop, info, intent, createdByOrganizer);
854 }
855
856 if (activityType == ACTIVITY_TYPE_UNDEFINED && !createdByOrganizer) {
857 // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
858 // anything else should be passing it in anyways...except for the task organizer.
859 activityType = ACTIVITY_TYPE_STANDARD;
860 }
861
862 if (activityType != ACTIVITY_TYPE_STANDARD && activityType != ACTIVITY_TYPE_UNDEFINED) {
863 // For now there can be only one stack of a particular non-standard activity type on a
864 // display. So, get that ignoring whatever windowing mode it is currently in.
865 ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
866 if (stack != null) {
867 throw new IllegalArgumentException("Stack=" + stack + " of activityType="
868 + activityType + " already on display=" + this + ". Can't have multiple.");
869 }
870 }
871
872 if (!isWindowingModeSupported(windowingMode, mAtmService.mSupportsMultiWindow,
873 mAtmService.mSupportsSplitScreenMultiWindow,
874 mAtmService.mSupportsFreeformWindowManagement,
875 mAtmService.mSupportsPictureInPicture, activityType)) {
876 throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
877 + windowingMode);
878 }
879
880 final int stackId = getNextStackId();
881 return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent,
882 createdByOrganizer);
883 }
884
885 /** @return the root task to create the next task in. */
886 private Task updateLaunchRootTask(int windowingMode) {
887 if (!isSplitScreenWindowingMode(windowingMode)) {
888 // Only split-screen windowing modes can do this currently...
889 return null;
890 }
891 for (int i = getStackCount() - 1; i >= 0; --i) {
892 final Task t = getStackAt(i);
893 if (!t.mCreatedByOrganizer || t.getRequestedOverrideWindowingMode() != windowingMode) {
894 continue;
895 }
896 // If not already set, pick a launch root which is not the one we are launching into.
897 if (mLaunchRootTask == null) {
898 for (int j = 0, n = getStackCount(); j < n; ++j) {
899 final Task tt = getStackAt(j);
900 if (tt.mCreatedByOrganizer && tt != t) {
901 mLaunchRootTask = tt;
902 break;
903 }
904 }
905 }
906 return t;
907 }
908 return mLaunchRootTask;
909 }
910
911 @VisibleForTesting
912 ActivityStack createStackUnchecked(int windowingMode, int activityType, int stackId,
913 boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer) {
914 if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
915 throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
916 + "activity type.");
917 }
918 if (info == null) {
919 info = new ActivityInfo();
920 info.applicationInfo = new ApplicationInfo();
921 }
922
923 // Task created by organizer are added as root.
924 Task launchRootTask = createdByOrganizer ? null : updateLaunchRootTask(windowingMode);
925 if (launchRootTask != null) {
926 // Since this stack will be put into a root task, its windowingMode will be inherited.
927 windowingMode = WINDOWING_MODE_UNDEFINED;
928 }
929
930 final ActivityStack stack = (ActivityStack) Task.create(mAtmService, stackId, activityType,
931 info, intent, createdByOrganizer);
932 if (launchRootTask != null) {
933 launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
934 if (onTop) {
935 positionStackAtTop((ActivityStack) launchRootTask, false /* includingParents */);
936 }
937 } else {
938 addStack(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
Evan Rosky50ea8c12020-04-02 20:49:05 -0700939 stack.setWindowingMode(windowingMode, true /* creating */);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700940 }
941 return stack;
942 }
943
944 /**
945 * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
946 * focusable and visible stack from the top of stacks in this display.
947 */
948 ActivityStack getFocusedStack() {
949 if (mPreferredTopFocusableStack != null) {
950 return mPreferredTopFocusableStack;
951 }
952
953 for (int i = getStackCount() - 1; i >= 0; --i) {
954 final ActivityStack stack = getStackAt(i);
955 if (stack.isFocusableAndVisible()) {
956 return stack;
957 }
958 }
959
960 return null;
961 }
962
963 ActivityStack getNextFocusableStack(ActivityStack currentFocus, boolean ignoreCurrent) {
964 final int currentWindowingMode = currentFocus != null
965 ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
966
967 ActivityStack candidate = null;
968 for (int i = getStackCount() - 1; i >= 0; --i) {
969 final ActivityStack stack = getStackAt(i);
970 if (ignoreCurrent && stack == currentFocus) {
971 continue;
972 }
973 if (!stack.isFocusableAndVisible()) {
974 continue;
975 }
976
977 if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
978 && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
979 // If the currently focused stack is in split-screen secondary we save off the
980 // top primary split-screen stack as a candidate for focus because we might
981 // prefer focus to move to an other stack to avoid primary split-screen stack
982 // overlapping with a fullscreen stack when a fullscreen stack is higher in z
983 // than the next split-screen stack. Assistant stack, I am looking at you...
984 // We only move the focus to the primary-split screen stack if there isn't a
985 // better alternative.
986 candidate = stack;
987 continue;
988 }
989 if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
990 // Use the candidate stack since we are now at the secondary split-screen.
991 return candidate;
992 }
993 return stack;
994 }
995 return candidate;
996 }
997
Andrii Kulianf9df4a82020-03-31 12:09:27 -0700998 ActivityRecord getFocusedActivity() {
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700999 final ActivityStack focusedStack = getFocusedStack();
1000 if (focusedStack == null) {
1001 return null;
1002 }
1003 // TODO(b/111541062): Move this into ActivityStack#getResumedActivity()
1004 // Check if the focused stack has the resumed activity
1005 ActivityRecord resumedActivity = focusedStack.getResumedActivity();
1006 if (resumedActivity == null || resumedActivity.app == null) {
1007 // If there is no registered resumed activity in the stack or it is not running -
1008 // try to use previously resumed one.
1009 resumedActivity = focusedStack.mPausingActivity;
1010 if (resumedActivity == null || resumedActivity.app == null) {
1011 // If previously resumed activity doesn't work either - find the topmost running
1012 // activity that can be focused.
1013 resumedActivity = focusedStack.topRunningActivity(true /* focusableOnly */);
1014 }
1015 }
1016 return resumedActivity;
1017 }
1018
1019 ActivityStack getLastFocusedStack() {
1020 return mLastFocusedStack;
1021 }
1022
1023 boolean allResumedActivitiesComplete() {
1024 for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
1025 final ActivityRecord r = getStackAt(stackNdx).getResumedActivity();
1026 if (r != null && !r.isState(RESUMED)) {
1027 return false;
1028 }
1029 }
1030 final ActivityStack currentFocusedStack = getFocusedStack();
1031 if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
1032 Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
1033 + mLastFocusedStack + " to=" + currentFocusedStack);
1034 }
1035 mLastFocusedStack = currentFocusedStack;
1036 return true;
1037 }
1038
1039 /**
1040 * Pause all activities in either all of the stacks or just the back stacks. This is done before
1041 * resuming a new activity and to make sure that previously active activities are
1042 * paused in stacks that are no longer visible or in pinned windowing mode. This does not
1043 * pause activities in visible stacks, so if an activity is launched within the same stack/task,
1044 * then we should explicitly pause that stack's top activity.
1045 * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
1046 * @param resuming The resuming activity.
1047 * @return {@code true} if any activity was paused as a result of this call.
1048 */
1049 boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
1050 boolean someActivityPaused = false;
1051 for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
1052 final ActivityStack stack = getStackAt(stackNdx);
1053 final ActivityRecord resumedActivity = stack.getResumedActivity();
1054 if (resumedActivity != null
1055 && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
1056 || !stack.isTopActivityFocusable())) {
1057 if (DEBUG_STATES) {
1058 Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack
1059 + " mResumedActivity=" + resumedActivity);
1060 }
1061 someActivityPaused |= stack.startPausingLocked(userLeaving, false /* uiSleeping*/,
1062 resuming);
1063 }
1064 }
1065 return someActivityPaused;
1066 }
1067
1068 /**
1069 * Find task for putting the Activity in.
1070 */
1071 void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay,
1072 RootWindowContainer.FindTaskResult result) {
1073 mTmpFindTaskResult.clear();
1074 for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
1075 final ActivityStack stack = getStackAt(stackNdx);
1076 if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) {
1077 if (DEBUG_TASKS) {
1078 Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
1079 }
1080 continue;
1081 }
1082
1083 mTmpFindTaskResult.process(r, stack);
1084 // It is possible to have tasks in multiple stacks with the same root affinity, so
1085 // we should keep looking after finding an affinity match to see if there is a
1086 // better match in another stack. Also, task affinity isn't a good enough reason
1087 // to target a display which isn't the source of the intent, so skip any affinity
1088 // matches not on the specified display.
1089 if (mTmpFindTaskResult.mRecord != null) {
1090 if (mTmpFindTaskResult.mIdealMatch) {
1091 result.setTo(mTmpFindTaskResult);
1092 return;
1093 } else if (isPreferredDisplay) {
1094 // Note: since the traversing through the stacks is top down, the floating
1095 // tasks should always have lower priority than any affinity-matching tasks
1096 // in the fullscreen stacks
1097 result.setTo(mTmpFindTaskResult);
1098 }
1099 }
1100 }
1101 }
1102
1103 /**
1104 * Removes stacks in the input windowing modes from the system if they are of activity type
1105 * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
1106 */
1107 void removeStacksInWindowingModes(int... windowingModes) {
1108 if (windowingModes == null || windowingModes.length == 0) {
1109 return;
1110 }
1111
1112 // Collect the stacks that are necessary to be removed instead of performing the removal
1113 // by looping mStacks, so that we don't miss any stacks after the stack size changed or
1114 // stacks reordered.
1115 final ArrayList<ActivityStack> stacks = new ArrayList<>();
1116 for (int j = windowingModes.length - 1; j >= 0; --j) {
1117 final int windowingMode = windowingModes[j];
1118 for (int i = getStackCount() - 1; i >= 0; --i) {
1119 final ActivityStack stack = getStackAt(i);
1120 if (!stack.isActivityTypeStandardOrUndefined()) {
1121 continue;
1122 }
1123 if (stack.getWindowingMode() != windowingMode) {
1124 continue;
1125 }
1126 stacks.add(stack);
1127 }
1128 }
1129
1130 for (int i = stacks.size() - 1; i >= 0; --i) {
1131 mRootWindowContainer.mStackSupervisor.removeStack(stacks.get(i));
1132 }
1133 }
1134
1135 void removeStacksWithActivityTypes(int... activityTypes) {
1136 if (activityTypes == null || activityTypes.length == 0) {
1137 return;
1138 }
1139
1140 // Collect the stacks that are necessary to be removed instead of performing the removal
1141 // by looping mStacks, so that we don't miss any stacks after the stack size changed or
1142 // stacks reordered.
1143 final ArrayList<ActivityStack> stacks = new ArrayList<>();
1144 for (int j = activityTypes.length - 1; j >= 0; --j) {
1145 final int activityType = activityTypes[j];
1146 for (int i = getStackCount() - 1; i >= 0; --i) {
1147 final ActivityStack stack = getStackAt(i);
1148 // Collect the root tasks that are currently being organized.
Evan Rosky50ea8c12020-04-02 20:49:05 -07001149 if (stack.mCreatedByOrganizer) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001150 for (int k = stack.getChildCount() - 1; k >= 0; --k) {
1151 final ActivityStack childStack = (ActivityStack) stack.getChildAt(k);
1152 if (childStack.getActivityType() == activityType) {
1153 stacks.add(childStack);
1154 }
1155 }
1156 } else if (stack.getActivityType() == activityType) {
1157 stacks.add(stack);
1158 }
1159 }
1160 }
1161
1162 for (int i = stacks.size() - 1; i >= 0; --i) {
1163 mRootWindowContainer.mStackSupervisor.removeStack(stacks.get(i));
1164 }
1165 }
1166
1167 void onSplitScreenModeDismissed() {
Wale Ogunwalefbb81c92020-04-09 18:01:24 -07001168 onSplitScreenModeDismissed(null /* toTop */);
1169 }
1170
1171 void onSplitScreenModeDismissed(ActivityStack toTop) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001172 mAtmService.deferWindowLayout();
1173 try {
1174 mLaunchRootTask = null;
1175 moveSplitScreenTasksToFullScreen();
1176 } finally {
Wale Ogunwalefbb81c92020-04-09 18:01:24 -07001177 final ActivityStack topFullscreenStack = toTop != null
1178 ? toTop : getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001179 final ActivityStack homeStack = getOrCreateRootHomeTask();
Wale Ogunwalefbb81c92020-04-09 18:01:24 -07001180 if (homeStack != null && ((topFullscreenStack != null && !isTopStack(homeStack))
1181 || toTop != null)) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001182 // Whenever split-screen is dismissed we want the home stack directly behind the
1183 // current top fullscreen stack so it shows up when the top stack is finished.
Wale Ogunwalefbb81c92020-04-09 18:01:24 -07001184 // Or, if the caller specified a stack to be on top after split-screen is dismissed.
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001185 // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
1186 // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
1187 // once we have that.
1188 homeStack.moveToFront("onSplitScreenModeDismissed");
1189 topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
1190 }
1191 mAtmService.continueWindowLayout();
1192 }
1193 }
1194
1195 private void moveSplitScreenTasksToFullScreen() {
1196 final WindowContainerTransaction wct = new WindowContainerTransaction();
1197 mTmpTasks.clear();
1198 forAllTasks(task -> {
1199 if (task.mCreatedByOrganizer && task.inSplitScreenWindowingMode() && task.hasChild()) {
1200 mTmpTasks.add(task);
1201 }
1202 });
1203
1204 for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
1205 final Task root = mTmpTasks.get(i);
1206 for (int j = 0; j < root.getChildCount(); j++) {
Wale Ogunwaleadf116e2020-03-27 16:36:01 -07001207 wct.reparent(root.getChildAt(j).mRemoteToken.toWindowContainerToken(),
1208 null, true /* toTop */);
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001209 }
1210 }
1211 mAtmService.mWindowOrganizerController.applyTransaction(wct);
1212 }
1213
1214 /**
1215 * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
1216 * @param windowingMode The windowing mode we are checking support for.
1217 * @param supportsMultiWindow If we should consider support for multi-window mode in general.
1218 * @param supportsSplitScreen If we should consider support for split-screen multi-window.
1219 * @param supportsFreeform If we should consider support for freeform multi-window.
1220 * @param supportsPip If we should consider support for picture-in-picture mutli-window.
1221 * @param activityType The activity type under consideration.
1222 * @return true if the windowing mode is supported.
1223 */
1224 private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
1225 boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
1226 int activityType) {
1227
1228 if (windowingMode == WINDOWING_MODE_UNDEFINED
1229 || windowingMode == WINDOWING_MODE_FULLSCREEN) {
1230 return true;
1231 }
1232 if (!supportsMultiWindow) {
1233 return false;
1234 }
1235
1236 if (windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
1237 return true;
1238 }
1239
1240 final int displayWindowingMode = getWindowingMode();
1241 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
1242 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
1243 return supportsSplitScreen
1244 && WindowConfiguration.supportSplitScreenWindowingMode(activityType)
1245 // Freeform windows and split-screen windows don't mix well, so prevent
1246 // split windowing modes on freeform displays.
1247 && displayWindowingMode != WINDOWING_MODE_FREEFORM;
1248 }
1249
1250 if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
1251 return false;
1252 }
1253
1254 if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
1255 return false;
1256 }
1257 return true;
1258 }
1259
1260 /**
1261 * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
1262 * display with the provided parameters.
1263 *
1264 * @param r The ActivityRecord in question.
1265 * @param options Options to start with.
1266 * @param task The task within-which the activity would start.
1267 * @param activityType The type of activity to start.
1268 * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
1269 */
1270 int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
1271 @Nullable Task task, int activityType) {
1272
1273 // First preference if the windowing mode in the activity options if set.
1274 int windowingMode = (options != null)
1275 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
1276
1277 // If windowing mode is unset, then next preference is the candidate task, then the
1278 // activity record.
1279 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
1280 if (task != null) {
1281 windowingMode = task.getWindowingMode();
1282 }
1283 if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
1284 windowingMode = r.getWindowingMode();
1285 }
1286 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
1287 // Use the display's windowing mode.
1288 windowingMode = getWindowingMode();
1289 }
1290 }
1291 windowingMode = validateWindowingMode(windowingMode, r, task, activityType);
1292 return windowingMode != WINDOWING_MODE_UNDEFINED
1293 ? windowingMode : WINDOWING_MODE_FULLSCREEN;
1294 }
1295
1296 /**
1297 * Check that the requested windowing-mode is appropriate for the specified task and/or activity
1298 * on this display.
1299 *
1300 * @param windowingMode The windowing-mode to validate.
1301 * @param r The {@link ActivityRecord} to check against.
1302 * @param task The {@link Task} to check against.
1303 * @param activityType An activity type.
1304 * @return The provided windowingMode or the closest valid mode which is appropriate.
1305 */
1306 int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
1307 int activityType) {
1308 // Make sure the windowing mode we are trying to use makes sense for what is supported.
1309 boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
1310 boolean supportsSplitScreen = mAtmService.mSupportsSplitScreenMultiWindow;
1311 boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement;
1312 boolean supportsPip = mAtmService.mSupportsPictureInPicture;
1313 if (supportsMultiWindow) {
1314 if (task != null) {
1315 supportsMultiWindow = task.isResizeable();
1316 supportsSplitScreen = task.supportsSplitScreenWindowingMode();
1317 // TODO: Do we need to check for freeform and Pip support here?
1318 } else if (r != null) {
1319 supportsMultiWindow = r.isResizeable();
1320 supportsSplitScreen = r.supportsSplitScreenWindowingMode();
1321 supportsFreeform = r.supportsFreeform();
1322 supportsPip = r.supportsPictureInPicture();
1323 }
1324 }
1325
1326 final boolean inSplitScreenMode = isSplitScreenModeActivated();
1327 if (!inSplitScreenMode
1328 && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
1329 // Switch to the display's windowing mode if we are not in split-screen mode and we are
1330 // trying to launch in split-screen secondary.
1331 windowingMode = WINDOWING_MODE_UNDEFINED;
1332 } else if (inSplitScreenMode && (windowingMode == WINDOWING_MODE_FULLSCREEN
1333 || windowingMode == WINDOWING_MODE_UNDEFINED)
1334 && supportsSplitScreen) {
1335 windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
1336 }
1337
1338 if (windowingMode != WINDOWING_MODE_UNDEFINED
1339 && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
1340 supportsFreeform, supportsPip, activityType)) {
1341 return windowingMode;
1342 }
1343 return WINDOWING_MODE_UNDEFINED;
1344 }
1345
1346 boolean isTopStack(ActivityStack stack) {
1347 return stack == getTopStack();
1348 }
1349
1350 boolean isTopNotPinnedStack(ActivityStack stack) {
1351 for (int i = getStackCount() - 1; i >= 0; --i) {
1352 final ActivityStack current = getStackAt(i);
1353 if (!current.inPinnedWindowingMode()) {
1354 return current == stack;
1355 }
1356 }
1357 return false;
1358 }
1359
Andrii Kulian86d676c2020-03-27 19:34:54 -07001360 ActivityRecord topRunningActivity() {
1361 return topRunningActivity(false /* considerKeyguardState */);
1362 }
1363
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001364 /**
1365 * Returns the top running activity in the focused stack. In the case the focused stack has no
1366 * such activity, the next focusable stack on this display is returned.
1367 *
1368 * @param considerKeyguardState Indicates whether the locked state should be considered. if
1369 * {@code true} and the keyguard is locked, only activities that
1370 * can be shown on top of the keyguard will be considered.
1371 * @return The top running activity. {@code null} if none is available.
1372 */
1373 ActivityRecord topRunningActivity(boolean considerKeyguardState) {
1374 ActivityRecord topRunning = null;
1375 final ActivityStack focusedStack = getFocusedStack();
1376 if (focusedStack != null) {
1377 topRunning = focusedStack.topRunningActivity();
1378 }
1379
1380 // Look in other focusable stacks.
1381 if (topRunning == null) {
1382 for (int i = getStackCount() - 1; i >= 0; --i) {
1383 final ActivityStack stack = getStackAt(i);
1384 // Only consider focusable stacks other than the current focused one.
1385 if (stack == focusedStack || !stack.isTopActivityFocusable()) {
1386 continue;
1387 }
1388 topRunning = stack.topRunningActivity();
1389 if (topRunning != null) {
1390 break;
1391 }
1392 }
1393 }
1394
1395 // This activity can be considered the top running activity if we are not considering
1396 // the locked state, the keyguard isn't locked, or we can show when locked.
1397 if (topRunning != null && considerKeyguardState
1398 && mRootWindowContainer.mStackSupervisor.getKeyguardController()
1399 .isKeyguardLocked()
1400 && !topRunning.canShowWhenLocked()) {
1401 return null;
1402 }
1403
1404 return topRunning;
1405 }
1406
1407 protected int getStackCount() {
1408 return mChildren.size();
1409 }
1410
1411 protected ActivityStack getStackAt(int index) {
1412 return mChildren.get(index);
1413 }
1414
1415 /**
1416 * Returns the existing home stack or creates and returns a new one if it should exist for the
1417 * display.
1418 */
1419 @Nullable
1420 ActivityStack getOrCreateRootHomeTask() {
1421 ActivityStack homeTask = getRootHomeTask();
1422 if (homeTask == null && mDisplayContent.supportsSystemDecorations()
1423 && !mDisplayContent.isUntrustedVirtualDisplay()) {
1424 homeTask = createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME,
1425 false /* onTop */);
1426 }
1427 return homeTask;
1428 }
1429
1430 boolean isSplitScreenModeActivated() {
1431 Task task = getRootSplitScreenPrimaryTask();
1432 return task != null && task.hasChild();
1433 }
1434
1435 /**
1436 * Returns the topmost stack on the display that is compatible with the input windowing mode.
1437 * Null is no compatible stack on the display.
1438 */
1439 ActivityStack getTopStackInWindowingMode(int windowingMode) {
1440 return getStack(windowingMode, ACTIVITY_TYPE_UNDEFINED);
1441 }
1442
1443 void moveHomeStackToFront(String reason) {
1444 final ActivityStack homeStack = getOrCreateRootHomeTask();
1445 if (homeStack != null) {
1446 homeStack.moveToFront(reason);
1447 }
1448 }
1449
1450 /**
1451 * Moves the focusable home activity to top. If there is no such activity, the home stack will
1452 * still move to top.
1453 */
1454 void moveHomeActivityToTop(String reason) {
1455 final ActivityRecord top = getHomeActivity();
1456 if (top == null) {
1457 moveHomeStackToFront(reason);
1458 return;
1459 }
1460 top.moveFocusableActivityToTop(reason);
1461 }
1462
1463 @Nullable
1464 ActivityRecord getHomeActivity() {
1465 return getHomeActivityForUser(mRootWindowContainer.mCurrentUser);
1466 }
1467
1468 @Nullable
1469 ActivityRecord getHomeActivityForUser(int userId) {
1470 final ActivityStack homeStack = getRootHomeTask();
1471 if (homeStack == null) {
1472 return null;
1473 }
1474
1475 final PooledPredicate p = PooledLambda.obtainPredicate(
Andrii Kulian86d676c2020-03-27 19:34:54 -07001476 TaskDisplayArea::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001477 userId);
1478 final ActivityRecord r = homeStack.getActivity(p);
1479 p.recycle();
1480 return r;
1481 }
1482
1483 private static boolean isHomeActivityForUser(ActivityRecord r, int userId) {
1484 return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId);
1485 }
1486
1487 /**
1488 * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
1489 * Generally used in conjunction with {@link #moveStackBehindStack}.
1490 */
1491 // TODO(b/151575894): Remove special stack movement methods.
1492 void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
1493 if (stack.shouldBeVisible(null)) {
1494 // Skip if the stack is already visible
1495 return;
1496 }
1497
1498 final boolean isRootTask = stack.isRootTask();
1499 if (isRootTask) {
1500 // Move the stack to the bottom to not affect the following visibility checks
1501 positionStackAtBottom(stack);
1502 } else {
1503 stack.getParent().positionChildAt(POSITION_BOTTOM, stack, false /* includingParents */);
1504 }
1505
1506 // Find the next position where the stack should be placed
1507 final int numStacks = isRootTask ? getStackCount() : stack.getParent().getChildCount();
1508 for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
1509 final ActivityStack s = isRootTask ? getStackAt(stackNdx)
1510 : (ActivityStack) stack.getParent().getChildAt(stackNdx);
1511 if (s == stack) {
1512 continue;
1513 }
1514 final int winMode = s.getWindowingMode();
1515 final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
1516 || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
1517 if (s.shouldBeVisible(null) && isValidWindowingMode) {
1518 // Move the provided stack to behind this stack
1519 final int position = Math.max(0, stackNdx - 1);
1520 if (isRootTask) {
1521 positionStackAt(stack, position);
1522 } else {
1523 stack.getParent().positionChildAt(position, stack, false /*includingParents */);
1524 }
1525 break;
1526 }
1527 }
1528 }
1529
1530 /**
1531 * Moves the {@param stack} behind the given {@param behindStack} if possible. If
1532 * {@param behindStack} is not currently in the display, then then the stack is moved to the
1533 * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
1534 */
1535 void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
1536 if (behindStack == null || behindStack == stack) {
1537 return;
1538 }
1539
1540 final WindowContainer parent = stack.getParent();
1541 if (parent == null || parent != behindStack.getParent()) {
1542 return;
1543 }
1544
1545 // Note that positionChildAt will first remove the given stack before inserting into the
1546 // list, so we need to adjust the insertion index to account for the removed index
1547 // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
1548 // position internally
1549 final int stackIndex = parent.mChildren.indexOf(stack);
1550 final int behindStackIndex = parent.mChildren.indexOf(behindStack);
1551 final int insertIndex = stackIndex <= behindStackIndex
1552 ? behindStackIndex - 1 : behindStackIndex;
1553 final int position = Math.max(0, insertIndex);
1554 if (stack.isRootTask()) {
1555 positionStackAt(stack, position);
1556 } else {
1557 parent.positionChildAt(position, stack, false /* includingParents */);
1558 }
1559 }
Andrii Kulian86d676c2020-03-27 19:34:54 -07001560
1561 boolean hasPinnedTask() {
1562 return getRootPinnedTask() != null;
1563 }
1564
1565 /**
1566 * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
1567 * already top-most.
1568 */
1569 static ActivityStack getStackAbove(ActivityStack stack) {
1570 final WindowContainer wc = stack.getParent();
1571 final int index = wc.mChildren.indexOf(stack) + 1;
1572 return (index < wc.mChildren.size()) ? (ActivityStack) wc.mChildren.get(index) : null;
1573 }
1574
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -07001575 /** Returns true if the stack in the windowing mode is visible. */
1576 boolean isStackVisible(int windowingMode) {
1577 final ActivityStack stack = getTopStackInWindowingMode(windowingMode);
1578 return stack != null && stack.isVisible();
1579 }
1580
1581 void removeStack(ActivityStack stack) {
1582 removeChild(stack);
1583 }
1584
Andrii Kulian86d676c2020-03-27 19:34:54 -07001585 int getDisplayId() {
1586 return mDisplayContent.getDisplayId();
1587 }
1588
1589 boolean isRemoved() {
Andrii Kulianf9df4a82020-03-31 12:09:27 -07001590 return mRemoved;
Andrii Kulian86d676c2020-03-27 19:34:54 -07001591 }
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -07001592
1593 /**
1594 * Adds a listener to be notified whenever the stack order in the display changes. Currently
1595 * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
1596 * current animation when the system state changes.
1597 */
1598 void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
1599 if (!mStackOrderChangedCallbacks.contains(listener)) {
1600 mStackOrderChangedCallbacks.add(listener);
1601 }
1602 }
1603
1604 /**
1605 * Removes a previously registered stack order change listener.
1606 */
1607 void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
1608 mStackOrderChangedCallbacks.remove(listener);
1609 }
1610
1611 /**
1612 * Notifies of a stack order change
1613 * @param stack The stack which triggered the order change
1614 */
1615 void onStackOrderChanged(ActivityStack stack) {
1616 for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
1617 mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
1618 }
1619 }
1620
Evan Rosky0ad8d2c2020-03-16 12:09:58 -07001621 @Override
1622 boolean canCreateRemoteAnimationTarget() {
1623 return true;
1624 }
1625
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -07001626 /**
1627 * Callback for when the order of the stacks in the display changes.
1628 */
1629 interface OnStackOrderChangedListener {
1630 void onStackOrderChanged(ActivityStack stack);
1631 }
Andrii Kulianf9df4a82020-03-31 12:09:27 -07001632
1633 void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
1634 boolean preserveWindows, boolean notifyClients) {
1635 for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
1636 final ActivityStack stack = getStackAt(stackNdx);
1637 stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
1638 notifyClients);
1639 }
1640 }
1641
1642 void prepareFreezingTaskBounds() {
1643 for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
1644 final ActivityStack stack = getChildAt(stackNdx);
1645 stack.prepareFreezingTaskBounds();
1646 }
1647 }
1648
1649 /**
1650 * Removes the stacks in the node applying the content removal node from the display.
1651 * @return last reparented stack, or {@code null} if the stacks had to be destroyed.
1652 */
1653 ActivityStack remove() {
1654 mPreferredTopFocusableStack = null;
1655 // TODO(b/153090332): Allow setting content removal mode per task display area
1656 final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove();
1657 final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
1658 ActivityStack lastReparentedStack = null;
1659
1660 // Stacks could be reparented from the removed display area to other display area. After
1661 // reparenting the last stack of the removed display area, the display area becomes ready to
1662 // be released (no more ActivityStack-s). But, we cannot release it at that moment or the
1663 // related WindowContainer will also be removed. So, we set display area as removed after
1664 // reparenting stack finished.
1665 // Keep the order from bottom to top.
1666 int numStacks = getStackCount();
1667 for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
1668 final ActivityStack stack = getStackAt(stackNdx);
1669 // Always finish non-standard type stacks.
1670 if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
1671 stack.finishAllActivitiesImmediately();
1672 } else {
1673 // If default display is in split-window mode, set windowing mode of the
1674 // stack to split-screen secondary. Otherwise, set the windowing mode to
1675 // undefined by default to let stack inherited the windowing mode from the
1676 // new display.
1677 final int windowingMode = toDisplayArea.isSplitScreenModeActivated()
1678 ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
1679 : WINDOWING_MODE_UNDEFINED;
1680 stack.reparent(toDisplayArea, true /* onTop */);
1681 stack.setWindowingMode(windowingMode);
1682 lastReparentedStack = stack;
1683 }
1684 // Stacks may be removed from this display. Ensure each stack will be processed
1685 // and the loop will end.
1686 stackNdx -= numStacks - getStackCount();
1687 numStacks = getStackCount();
1688 }
1689 mRemoved = true;
1690
1691 return lastReparentedStack;
1692 }
1693
1694
1695 @Override
1696 void dump(PrintWriter pw, String prefix, boolean dumpAll) {
1697 pw.println(prefix + "TaskDisplayArea " + getName());
1698 if (mPreferredTopFocusableStack != null) {
1699 pw.println(prefix + " mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
1700 }
1701 if (mLastFocusedStack != null) {
1702 pw.println(prefix + " mLastFocusedStack=" + mLastFocusedStack);
1703 }
1704 pw.println(prefix + " Application tokens in top down Z order:");
1705 for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
1706 final ActivityStack stack = getChildAt(stackNdx);
1707 stack.dump(pw, prefix + " ", dumpAll);
1708 }
1709 }
Andrii Kulian526ad432020-03-27 12:19:51 -07001710}