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