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