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