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