blob: 102c2a6364f4edd35735611b734acfd96e02feb3 [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;
Andrii Kulian9ea12da2020-03-27 17:16:38 -070024import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
Andrii Kulian526ad432020-03-27 12:19:51 -070025import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
26import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Andrii Kulian9ea12da2020-03-27 17:16:38 -070027import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
28import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
29import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
Andrii Kulian526ad432020-03-27 12:19:51 -070030import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
31import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
32import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Andrii Kulian526ad432020-03-27 12:19:51 -070033
Andrii Kulian9ea12da2020-03-27 17:16:38 -070034import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
35import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
36import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
37import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
38import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
39import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
40import static com.android.server.wm.DisplayContent.alwaysCreateStack;
Andrii Kulian526ad432020-03-27 12:19:51 -070041import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
42import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
Andrii Kulian9ea12da2020-03-27 17:16:38 -070043import static com.android.server.wm.RootWindowContainer.TAG_STATES;
Andrii Kulian86d676c2020-03-27 19:34:54 -070044import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
Andrii Kulian526ad432020-03-27 12:19:51 -070045import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
46
Andrii Kulian9ea12da2020-03-27 17:16:38 -070047import android.annotation.Nullable;
48import android.app.ActivityOptions;
49import android.app.WindowConfiguration;
50import android.content.Intent;
51import android.content.pm.ActivityInfo;
52import android.content.pm.ApplicationInfo;
53import android.os.UserHandle;
Andrii Kulian526ad432020-03-27 12:19:51 -070054import android.util.Slog;
55import android.view.SurfaceControl;
Andrii Kulian9ea12da2020-03-27 17:16:38 -070056import android.window.WindowContainerTransaction;
Andrii Kulian526ad432020-03-27 12:19:51 -070057
58import com.android.internal.annotations.VisibleForTesting;
59import com.android.internal.util.ToBooleanFunction;
Andrii Kulian9ea12da2020-03-27 17:16:38 -070060import com.android.internal.util.function.pooled.PooledLambda;
61import com.android.internal.util.function.pooled.PooledPredicate;
Andrii Kulian526ad432020-03-27 12:19:51 -070062import com.android.server.protolog.common.ProtoLog;
63
Andrii Kulianf9df4a82020-03-31 12:09:27 -070064import java.io.PrintWriter;
Andrii Kulian526ad432020-03-27 12:19:51 -070065import java.util.ArrayList;
66import java.util.List;
67
68/**
Andrii Kulian86d676c2020-03-27 19:34:54 -070069 * {@link DisplayArea} that represents a section of a screen that contains app window containers.
Andrii Kulian526ad432020-03-27 12:19:51 -070070 */
Andrii Kulian86d676c2020-03-27 19:34:54 -070071final class TaskDisplayArea extends DisplayArea<ActivityStack> {
Andrii Kulian1cb59dd2020-04-10 12:17:17 -070072
Andrii Kulian86d676c2020-03-27 19:34:54 -070073 DisplayContent mDisplayContent;
Andrii Kulian1cb59dd2020-04-10 12:17:17 -070074
Andrii Kulian526ad432020-03-27 12:19:51 -070075 /**
76 * A control placed at the appropriate level for transitions to occur.
77 */
78 private SurfaceControl mAppAnimationLayer;
79 private SurfaceControl mBoostedAppAnimationLayer;
80 private SurfaceControl mHomeAppAnimationLayer;
81
82 /**
83 * Given that the split-screen divider does not have an AppWindowToken, it
84 * will have to live inside of a "NonAppWindowContainer". However, in visual Z order
85 * it will need to be interleaved with some of our children, appearing on top of
86 * both docked stacks but underneath any assistant stacks.
87 *
88 * To solve this problem we have this anchor control, which will always exist so
89 * we can always assign it the correct value in our {@link #assignChildLayers}.
90 * Likewise since it always exists, we can always
91 * assign the divider a layer relative to it. This way we prevent linking lifecycle
92 * events between tasks and the divider window.
93 */
94 private SurfaceControl mSplitScreenDividerAnchor;
95
96 // Cached reference to some special tasks we tend to get a lot so we don't need to loop
97 // through the list to find them.
98 private ActivityStack mRootHomeTask;
99 private ActivityStack mRootPinnedTask;
100 private ActivityStack mRootSplitScreenPrimaryTask;
101
102 private final ArrayList<ActivityStack> mTmpAlwaysOnTopStacks = new ArrayList<>();
103 private final ArrayList<ActivityStack> mTmpNormalStacks = new ArrayList<>();
104 private final ArrayList<ActivityStack> mTmpHomeStacks = new ArrayList<>();
105
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700106 private ArrayList<Task> mTmpTasks = new ArrayList<>();
107
108 private ActivityTaskManagerService mAtmService;
109
110 private RootWindowContainer mRootWindowContainer;
111
112 // When non-null, new tasks get put into this root task.
Andrii Kulian86d676c2020-03-27 19:34:54 -0700113 Task mLaunchRootTask = null;
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700114
115 /**
116 * A focusable stack that is purposely to be positioned at the top. Although the stack may not
117 * have the topmost index, it is used as a preferred candidate to prevent being unable to resume
118 * target stack properly when there are other focusable always-on-top stacks.
119 */
Andrii Kulian86d676c2020-03-27 19:34:54 -0700120 ActivityStack mPreferredTopFocusableStack;
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700121
122 private final RootWindowContainer.FindTaskResult
123 mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
124
Galia Peycheva7ecd6ef2020-03-26 19:59:40 +0100125 // Indicates whether the Assistant should show on top of the Dream (respectively, above
126 // everything else on screen). Otherwise, it will be put under always-on-top stacks.
127 private final boolean mAssistantOnTopOfDream;
128
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700129 /**
130 * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
131 * stack has been resumed. If stacks are changing position this will hold the old stack until
132 * the new stack becomes resumed after which it will be set to current focused stack.
133 */
134 ActivityStack mLastFocusedStack;
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700135 /**
136 * All of the stacks on this display. Order matters, topmost stack is in front of all other
137 * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
138 * changing the list should also call {@link #onStackOrderChanged()}.
139 */
140 private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700141
Andrii Kulianf9df4a82020-03-31 12:09:27 -0700142 /**
143 * The task display area is removed from the system and we are just waiting for all activities
144 * on it to be finished before removing this object.
145 */
146 private boolean mRemoved;
147
Andrii Kulian44b3c562020-04-01 12:49:56 -0700148 TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name,
149 int displayAreaFeature) {
150 super(service, Type.ANY, name, displayAreaFeature);
Andrii Kulian526ad432020-03-27 12:19:51 -0700151 mDisplayContent = displayContent;
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700152 mRootWindowContainer = service.mRoot;
153 mAtmService = service.mAtmService;
Galia Peycheva7ecd6ef2020-03-26 19:59:40 +0100154
155 mAssistantOnTopOfDream = mWmService.mContext.getResources().getBoolean(
156 com.android.internal.R.bool.config_assistantOnTopOfDream);
Andrii Kulian526ad432020-03-27 12:19:51 -0700157 }
158
159 /**
160 * Returns the topmost stack on the display that is compatible with the input windowing mode
161 * and activity type. Null is no compatible stack on the display.
162 */
163 ActivityStack getStack(int windowingMode, int activityType) {
164 if (activityType == ACTIVITY_TYPE_HOME) {
165 return mRootHomeTask;
166 }
167 if (windowingMode == WINDOWING_MODE_PINNED) {
168 return mRootPinnedTask;
169 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
170 return mRootSplitScreenPrimaryTask;
171 }
172 for (int i = getChildCount() - 1; i >= 0; --i) {
173 final ActivityStack stack = getChildAt(i);
174 if (activityType == ACTIVITY_TYPE_UNDEFINED
175 && windowingMode == stack.getWindowingMode()) {
176 // Passing in undefined type means we want to match the topmost stack with the
177 // windowing mode.
178 return stack;
179 }
180 if (stack.isCompatible(windowingMode, activityType)) {
181 return stack;
182 }
183 }
184 return null;
185 }
186
187 @VisibleForTesting
188 ActivityStack getTopStack() {
189 final int count = getChildCount();
190 return count > 0 ? getChildAt(count - 1) : null;
191 }
192
Wale Ogunwale0db64ac2020-04-11 10:00:42 -0700193 // TODO: Figure-out a way to remove since it might be a source of confusion.
Andrii Kulian526ad432020-03-27 12:19:51 -0700194 int getIndexOf(ActivityStack stack) {
195 return mChildren.indexOf(stack);
196 }
197
Charles Chen7d550c42020-05-15 17:32:03 +0800198 @Nullable ActivityStack getRootHomeTask() {
Andrii Kulian526ad432020-03-27 12:19:51 -0700199 return mRootHomeTask;
200 }
201
202 ActivityStack getRootPinnedTask() {
203 return mRootPinnedTask;
204 }
205
206 ActivityStack getRootSplitScreenPrimaryTask() {
207 return mRootSplitScreenPrimaryTask;
208 }
209
210 ArrayList<Task> getVisibleTasks() {
211 final ArrayList<Task> visibleTasks = new ArrayList<>();
212 forAllTasks(task -> {
213 if (task.isLeafTask() && task.isVisible()) {
214 visibleTasks.add(task);
215 }
216 });
217 return visibleTasks;
218 }
219
220 void onStackWindowingModeChanged(ActivityStack stack) {
221 removeStackReferenceIfNeeded(stack);
222 addStackReferenceIfNeeded(stack);
223 if (stack == mRootPinnedTask && getTopStack() != stack) {
224 // Looks like this stack changed windowing mode to pinned. Move it to the top.
225 positionChildAt(POSITION_TOP, stack, false /* includingParents */);
226 }
227 }
228
229 void addStackReferenceIfNeeded(ActivityStack stack) {
230 if (stack.isActivityTypeHome()) {
231 if (mRootHomeTask != null) {
232 if (!stack.isDescendantOf(mRootHomeTask)) {
233 throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
234 + mRootHomeTask + " already exist on display=" + this
235 + " stack=" + stack);
236 }
237 } else {
238 mRootHomeTask = stack;
239 }
240 }
241
242 if (!stack.isRootTask()) {
243 return;
244 }
245 final int windowingMode = stack.getWindowingMode();
246 if (windowingMode == WINDOWING_MODE_PINNED) {
247 if (mRootPinnedTask != null) {
248 throw new IllegalArgumentException(
249 "addStackReferenceIfNeeded: pinned stack=" + mRootPinnedTask
250 + " already exist on display=" + this + " stack=" + stack);
251 }
252 mRootPinnedTask = stack;
253 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
254 if (mRootSplitScreenPrimaryTask != null) {
255 throw new IllegalArgumentException(
256 "addStackReferenceIfNeeded: split screen primary stack="
257 + mRootSplitScreenPrimaryTask
258 + " already exist on display=" + this + " stack=" + stack);
259 }
260 mRootSplitScreenPrimaryTask = stack;
261 }
262 }
263
264 void removeStackReferenceIfNeeded(ActivityStack stack) {
265 if (stack == mRootHomeTask) {
266 mRootHomeTask = null;
267 } else if (stack == mRootPinnedTask) {
268 mRootPinnedTask = null;
269 } else if (stack == mRootSplitScreenPrimaryTask) {
270 mRootSplitScreenPrimaryTask = null;
271 }
272 }
273
274 @Override
275 void addChild(ActivityStack stack, int position) {
Vishnu Nair7c8a2472020-04-17 16:08:29 -0700276 if (DEBUG_STACK) Slog.d(TAG_WM, "Set stack=" + stack + " on taskDisplayArea=" + this);
Andrii Kulian526ad432020-03-27 12:19:51 -0700277 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
Vishnu Nair7c8a2472020-04-17 16:08:29 -0700283 positionStackAt(stack, position);
Andrii Kulian526ad432020-03-27 12:19:51 -0700284 }
285
286 @Override
287 protected void removeChild(ActivityStack stack) {
288 super.removeChild(stack);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700289 onStackRemoved(stack);
290 mAtmService.updateSleepIfNeededLocked();
Andrii Kulian526ad432020-03-27 12:19:51 -0700291 removeStackReferenceIfNeeded(stack);
292 }
293
294 @Override
295 boolean isOnTop() {
296 // Considered always on top
297 return true;
298 }
299
300 @Override
301 void positionChildAt(int position, ActivityStack child, boolean includingParents) {
302 final boolean moveToTop = (position == POSITION_TOP || position == getChildCount());
303 final boolean moveToBottom = (position == POSITION_BOTTOM || position == 0);
304 if (child.getWindowConfiguration().isAlwaysOnTop() && !moveToTop) {
305 // This stack is always-on-top, override the default behavior.
306 Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + this + " to bottom");
307
308 // Moving to its current position, as we must call super but we don't want to
309 // perform any meaningful action.
310 final int currentPosition = mChildren.indexOf(child);
311 super.positionChildAt(currentPosition, child, false /* includingParents */);
312 return;
313 }
314 // We don't allow untrusted display to top when task stack moves to top,
315 // until user tapping this display to change display position as top intentionally.
316 if (mDisplayContent.isUntrustedVirtualDisplay() && !getParent().isOnTop()) {
317 includingParents = false;
318 }
319 final int targetPosition = findPositionForStack(position, child, false /* adding */);
320 super.positionChildAt(targetPosition, child, false /* includingParents */);
321
322 if (includingParents && (moveToTop || moveToBottom)) {
323 // The DisplayContent children do not re-order, but we still want to move the
324 // display of this stack container because the intention of positioning is to have
325 // higher z-order to gain focus.
326 mDisplayContent.positionDisplayAt(moveToTop ? POSITION_TOP : POSITION_BOTTOM,
327 true /* includingParents */);
328 }
329
330 child.updateTaskMovement(moveToTop);
331
332 mDisplayContent.setLayoutNeeded();
333 }
334
335 /**
Galia Peycheva7ecd6ef2020-03-26 19:59:40 +0100336 * Assigns a priority number to stack types. This priority defines an order between the types
337 * of stacks that are added to the task display area.
338 *
339 * Higher priority number indicates that the stack should have a higher z-order.
340 *
341 * @return the priority of the stack
342 */
343 private int getPriority(ActivityStack stack) {
344 if (mAssistantOnTopOfDream && stack.isActivityTypeAssistant()) return 4;
345 if (stack.isActivityTypeDream()) return 3;
346 if (stack.inPinnedWindowingMode()) return 2;
347 if (stack.isAlwaysOnTop()) return 1;
348 return 0;
349 }
350
351 private int findMinPositionForStack(ActivityStack stack) {
352 int minPosition = POSITION_BOTTOM;
353 for (int i = 0; i < mChildren.size(); ++i) {
354 if (getPriority(getStackAt(i)) < getPriority(stack)) {
355 minPosition = i;
356 } else {
357 break;
358 }
359 }
360
361 if (stack.isAlwaysOnTop()) {
362 // Since a stack could be repositioned while still being one of the children, we check
363 // if this always-on-top stack already exists and if so, set the minPosition to its
364 // previous position.
365 final int currentIndex = getIndexOf(stack);
366 if (currentIndex > minPosition) {
367 minPosition = currentIndex;
368 }
369 }
370 return minPosition;
371 }
372
373 private int findMaxPositionForStack(ActivityStack stack) {
374 for (int i = mChildren.size() - 1; i >= 0; --i) {
375 final ActivityStack curr = getStackAt(i);
376 // Since a stack could be repositioned while still being one of the children, we check
377 // if 'curr' is the same stack and skip it if so
378 final boolean sameStack = curr == stack;
379 if (getPriority(curr) <= getPriority(stack) && !sameStack) {
380 return i;
381 }
382 }
383 return 0;
384 }
385
386 /**
Andrii Kulian526ad432020-03-27 12:19:51 -0700387 * When stack is added or repositioned, find a proper position for it.
Galia Peycheva7ecd6ef2020-03-26 19:59:40 +0100388 *
389 * The order is defined as:
390 * - Dream is on top of everything
391 * - PiP is directly below the Dream
392 * - always-on-top stacks are directly below PiP; new always-on-top stacks are added above
393 * existing ones
394 * - other non-always-on-top stacks come directly below always-on-top stacks; new
395 * non-always-on-top stacks are added directly below always-on-top stacks and above existing
396 * non-always-on-top stacks
397 * - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything
398 * (including the Dream); otherwise, it is a normal non-always-on-top stack
399 *
Andrii Kulian526ad432020-03-27 12:19:51 -0700400 * @param requestedPosition Position requested by caller.
401 * @param stack Stack to be added or positioned.
402 * @param adding Flag indicates whether we're adding a new stack or positioning an existing.
403 * @return The proper position for the stack.
404 */
Galia Peycheva7ecd6ef2020-03-26 19:59:40 +0100405 private int findPositionForStack(int requestedPosition, ActivityStack stack, boolean adding) {
Andrii Kulian526ad432020-03-27 12:19:51 -0700406 // The max possible position we can insert the stack at.
Galia Peycheva7ecd6ef2020-03-26 19:59:40 +0100407 int maxPosition = findMaxPositionForStack(stack);
Andrii Kulian526ad432020-03-27 12:19:51 -0700408 // The min possible position we can insert the stack at.
Galia Peycheva7ecd6ef2020-03-26 19:59:40 +0100409 int minPosition = findMinPositionForStack(stack);
Andrii Kulian526ad432020-03-27 12:19:51 -0700410
411 // Cap the requested position to something reasonable for the previous position check
412 // below.
413 if (requestedPosition == POSITION_TOP) {
414 requestedPosition = mChildren.size();
415 } else if (requestedPosition == POSITION_BOTTOM) {
416 requestedPosition = 0;
417 }
418
419 int targetPosition = requestedPosition;
420 targetPosition = Math.min(targetPosition, maxPosition);
421 targetPosition = Math.max(targetPosition, minPosition);
422
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700423 int prevPosition = mChildren.indexOf(stack);
Andrii Kulian526ad432020-03-27 12:19:51 -0700424 // The positions we calculated above (maxPosition, minPosition) do not take into
425 // consideration the following edge cases.
426 // 1) We need to adjust the position depending on the value "adding".
427 // 2) When we are moving a stack to another position, we also need to adjust the
428 // position depending on whether the stack is moving to a higher or lower position.
429 if ((targetPosition != requestedPosition) && (adding || targetPosition < prevPosition)) {
430 targetPosition++;
431 }
432
433 return targetPosition;
434 }
435
436 @Override
437 boolean forAllWindows(ToBooleanFunction<WindowState> callback,
438 boolean traverseTopToBottom) {
439 if (traverseTopToBottom) {
440 if (super.forAllWindows(callback, traverseTopToBottom)) {
441 return true;
442 }
443 if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) {
444 return true;
445 }
446 } else {
447 if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) {
448 return true;
449 }
450 if (super.forAllWindows(callback, traverseTopToBottom)) {
451 return true;
452 }
453 }
454 return false;
455 }
456
457 private boolean forAllExitingAppTokenWindows(ToBooleanFunction<WindowState> callback,
458 boolean traverseTopToBottom) {
459 // For legacy reasons we process the TaskStack.mExitingActivities first here before the
460 // app tokens.
461 // TODO: Investigate if we need to continue to do this or if we can just process them
462 // in-order.
463 if (traverseTopToBottom) {
464 for (int i = mChildren.size() - 1; i >= 0; --i) {
465 final List<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
466 for (int j = activities.size() - 1; j >= 0; --j) {
467 if (activities.get(j).forAllWindowsUnchecked(callback,
468 traverseTopToBottom)) {
469 return true;
470 }
471 }
472 }
473 } else {
474 final int count = mChildren.size();
475 for (int i = 0; i < count; ++i) {
476 final List<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
477 final int appTokensCount = activities.size();
478 for (int j = 0; j < appTokensCount; j++) {
479 if (activities.get(j).forAllWindowsUnchecked(callback,
480 traverseTopToBottom)) {
481 return true;
482 }
483 }
484 }
485 }
486 return false;
487 }
488
489 void setExitingTokensHasVisible(boolean hasVisible) {
490 for (int i = mChildren.size() - 1; i >= 0; --i) {
491 final ArrayList<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
492 for (int j = activities.size() - 1; j >= 0; --j) {
493 activities.get(j).hasVisible = hasVisible;
494 }
495 }
496 }
497
498 void removeExistingAppTokensIfPossible() {
499 for (int i = mChildren.size() - 1; i >= 0; --i) {
500 final ArrayList<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
501 for (int j = activities.size() - 1; j >= 0; --j) {
502 final ActivityRecord activity = activities.get(j);
503 if (!activity.hasVisible && !mDisplayContent.mClosingApps.contains(activity)
504 && (!activity.mIsExiting || activity.isEmpty())) {
505 // Make sure there is no animation running on this activity, so any windows
506 // associated with it will be removed as soon as their animations are
507 // complete.
508 cancelAnimation();
509 ProtoLog.v(WM_DEBUG_ADD_REMOVE,
510 "performLayout: Activity exiting now removed %s", activity);
511 activity.removeIfPossible();
512 }
513 }
514 }
515 }
516
517 @Override
518 int getOrientation(int candidate) {
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700519 if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
Andrii Kulian526ad432020-03-27 12:19:51 -0700520 // Apps and their containers are not allowed to specify an orientation while using
521 // root tasks...except for the home stack if it is not resizable and currently
522 // visible (top of) its root task.
523 if (mRootHomeTask != null && mRootHomeTask.isVisible()) {
524 final Task topMost = mRootHomeTask.getTopMostTask();
525 final boolean resizable = topMost != null && topMost.isResizeable();
526 if (!(resizable && mRootHomeTask.matchParentBounds())) {
527 final int orientation = mRootHomeTask.getOrientation();
528 if (orientation != SCREEN_ORIENTATION_UNSET) {
529 return orientation;
530 }
531 }
532 }
533 return SCREEN_ORIENTATION_UNSPECIFIED;
534 }
535
536 final int orientation = super.getOrientation(candidate);
537 if (orientation != SCREEN_ORIENTATION_UNSET
538 && orientation != SCREEN_ORIENTATION_BEHIND) {
539 ProtoLog.v(WM_DEBUG_ORIENTATION,
540 "App is requesting an orientation, return %d for display id=%d",
541 orientation, mDisplayContent.mDisplayId);
542 return orientation;
543 }
544
545 ProtoLog.v(WM_DEBUG_ORIENTATION,
546 "No app is requesting an orientation, return %d for display id=%d",
547 mDisplayContent.getLastOrientation(), mDisplayContent.mDisplayId);
548 // The next app has not been requested to be visible, so we keep the current orientation
549 // to prevent freezing/unfreezing the display too early.
550 return mDisplayContent.getLastOrientation();
551 }
552
553 @Override
554 void assignChildLayers(SurfaceControl.Transaction t) {
555 assignStackOrdering(t);
556
557 for (int i = 0; i < mChildren.size(); i++) {
558 final ActivityStack s = mChildren.get(i);
559 s.assignChildLayers(t);
560 }
561 }
562
563 void assignStackOrdering(SurfaceControl.Transaction t) {
564 if (getParent() == null) {
565 return;
566 }
567 mTmpAlwaysOnTopStacks.clear();
568 mTmpHomeStacks.clear();
569 mTmpNormalStacks.clear();
570 for (int i = 0; i < mChildren.size(); ++i) {
571 final ActivityStack s = mChildren.get(i);
572 if (s.isAlwaysOnTop()) {
573 mTmpAlwaysOnTopStacks.add(s);
574 } else if (s.isActivityTypeHome()) {
575 mTmpHomeStacks.add(s);
576 } else {
577 mTmpNormalStacks.add(s);
578 }
579 }
580
581 int layer = 0;
582 // Place home stacks to the bottom.
583 for (int i = 0; i < mTmpHomeStacks.size(); i++) {
584 mTmpHomeStacks.get(i).assignLayer(t, layer++);
585 }
586 // The home animation layer is between the home stacks and the normal stacks.
587 final int layerForHomeAnimationLayer = layer++;
588 int layerForSplitScreenDividerAnchor = layer++;
589 int layerForAnimationLayer = layer++;
590 for (int i = 0; i < mTmpNormalStacks.size(); i++) {
591 final ActivityStack s = mTmpNormalStacks.get(i);
592 s.assignLayer(t, layer++);
593 if (s.inSplitScreenWindowingMode()) {
594 // The split screen divider anchor is located above the split screen window.
595 layerForSplitScreenDividerAnchor = layer++;
596 }
597 if (s.isTaskAnimating() || s.isAppTransitioning()) {
598 // The animation layer is located above the highest animating stack and no
599 // higher.
600 layerForAnimationLayer = layer++;
601 }
602 }
603 // The boosted animation layer is between the normal stacks and the always on top
604 // stacks.
605 final int layerForBoostedAnimationLayer = layer++;
606 for (int i = 0; i < mTmpAlwaysOnTopStacks.size(); i++) {
607 mTmpAlwaysOnTopStacks.get(i).assignLayer(t, layer++);
608 }
609
610 t.setLayer(mHomeAppAnimationLayer, layerForHomeAnimationLayer);
611 t.setLayer(mAppAnimationLayer, layerForAnimationLayer);
612 t.setLayer(mSplitScreenDividerAnchor, layerForSplitScreenDividerAnchor);
613 t.setLayer(mBoostedAppAnimationLayer, layerForBoostedAnimationLayer);
614 }
615
616 @Override
617 SurfaceControl getAppAnimationLayer(@AnimationLayer int animationLayer) {
618 switch (animationLayer) {
619 case ANIMATION_LAYER_BOOSTED:
620 return mBoostedAppAnimationLayer;
621 case ANIMATION_LAYER_HOME:
622 return mHomeAppAnimationLayer;
623 case ANIMATION_LAYER_STANDARD:
624 default:
625 return mAppAnimationLayer;
626 }
627 }
628
629 SurfaceControl getSplitScreenDividerAnchor() {
630 return mSplitScreenDividerAnchor;
631 }
632
633 @Override
634 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
635 if (getParent() != null) {
636 super.onParentChanged(newParent, oldParent, () -> {
637 mAppAnimationLayer = makeChildSurface(null)
638 .setName("animationLayer")
639 .build();
640 mBoostedAppAnimationLayer = makeChildSurface(null)
641 .setName("boostedAnimationLayer")
642 .build();
643 mHomeAppAnimationLayer = makeChildSurface(null)
644 .setName("homeAnimationLayer")
645 .build();
646 mSplitScreenDividerAnchor = makeChildSurface(null)
647 .setName("splitScreenDividerAnchor")
648 .build();
chaviw89cc30e2020-05-19 10:36:27 -0700649 getSyncTransaction()
Andrii Kulian526ad432020-03-27 12:19:51 -0700650 .show(mAppAnimationLayer)
651 .show(mBoostedAppAnimationLayer)
652 .show(mHomeAppAnimationLayer)
653 .show(mSplitScreenDividerAnchor);
654 });
655 } else {
656 super.onParentChanged(newParent, oldParent);
657 mWmService.mTransactionFactory.get()
658 .remove(mAppAnimationLayer)
659 .remove(mBoostedAppAnimationLayer)
660 .remove(mHomeAppAnimationLayer)
661 .remove(mSplitScreenDividerAnchor)
662 .apply();
663 mAppAnimationLayer = null;
664 mBoostedAppAnimationLayer = null;
665 mHomeAppAnimationLayer = null;
666 mSplitScreenDividerAnchor = null;
667 }
668 }
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700669
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700670 void onStackRemoved(ActivityStack stack) {
671 if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
672 Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId="
673 + mDisplayContent.mDisplayId);
674 }
675 if (mPreferredTopFocusableStack == stack) {
676 mPreferredTopFocusableStack = null;
677 }
678 mDisplayContent.releaseSelfIfNeeded();
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700679 onStackOrderChanged(stack);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700680 }
681
Winson Chungb5ce37c2020-04-22 10:08:28 -0700682 void resetPreferredTopFocusableStackIfBelow(Task task) {
683 if (mPreferredTopFocusableStack != null
684 && mPreferredTopFocusableStack.compareTo(task) < 0) {
685 mPreferredTopFocusableStack = null;
686 }
687 }
688
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700689 void positionStackAt(int position, ActivityStack child, boolean includingParents) {
690 positionChildAt(position, child, includingParents);
691 mDisplayContent.layoutAndAssignWindowLayersIfNeeded();
692 }
693
694 void positionStackAtTop(ActivityStack stack, boolean includingParents) {
695 positionStackAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
696 }
697
698 void positionStackAtTop(ActivityStack stack, boolean includingParents,
699 String updateLastFocusedStackReason) {
700 positionStackAt(stack, getStackCount(), includingParents,
701 updateLastFocusedStackReason);
702 }
703
704 void positionStackAtBottom(ActivityStack stack) {
705 positionStackAtBottom(stack, null /* updateLastFocusedStackReason */);
706 }
707
708 void positionStackAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
709 positionStackAt(stack, 0, false /* includingParents */,
710 updateLastFocusedStackReason);
711 }
712
713 void positionStackAt(ActivityStack stack, int position) {
714 positionStackAt(stack, position, false /* includingParents */,
715 null /* updateLastFocusedStackReason */);
716 }
717
718 void positionStackAt(ActivityStack stack, int position, boolean includingParents,
719 String updateLastFocusedStackReason) {
720 // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
721 // the position internally, also update the logic here
722 final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
723 ? getFocusedStack() : null;
Wale Ogunwale0db64ac2020-04-11 10:00:42 -0700724 final boolean wasContained = mChildren.contains(stack);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700725 if (mDisplayContent.mSingleTaskInstance && getStackCount() == 1 && !wasContained) {
726 throw new IllegalStateException(
727 "positionStackAt: Can only have one task on display=" + this);
728 }
729
730 final boolean movingToTop = wasContained && position >= getStackCount() - 1;
731 // Reset mPreferredTopFocusableStack before positioning to top or {@link
732 // ActivityStackSupervisor#updateTopResumedActivityIfNeeded()} won't update the top
733 // resumed activity.
734 if (movingToTop && stack.isFocusable()) {
735 mPreferredTopFocusableStack = null;
736 }
737
738 // Since positionChildAt() is called during the creation process of pinned stacks,
739 // ActivityStack#getStack() can be null.
740 positionStackAt(position, stack, includingParents);
741
742 // The insert position may be adjusted to non-top when there is always-on-top stack. Since
743 // the original position is preferred to be top, the stack should have higher priority when
744 // we are looking for top focusable stack. The condition {@code wasContained} restricts the
745 // preferred stack is set only when moving an existing stack to top instead of adding a new
746 // stack that may be too early (e.g. in the middle of launching or reparenting).
747 if (movingToTop && stack.isFocusableAndVisible()) {
748 mPreferredTopFocusableStack = stack;
749 } else if (mPreferredTopFocusableStack == stack) {
750 mPreferredTopFocusableStack = null;
751 }
752
753 if (updateLastFocusedStackReason != null) {
754 final ActivityStack currentFocusedStack = getFocusedStack();
755 if (currentFocusedStack != prevFocusedStack) {
756 mLastFocusedStack = prevFocusedStack;
757 EventLogTags.writeWmFocusedStack(mRootWindowContainer.mCurrentUser,
758 mDisplayContent.mDisplayId,
759 currentFocusedStack == null ? -1 : currentFocusedStack.getRootTaskId(),
760 mLastFocusedStack == null ? -1 : mLastFocusedStack.getRootTaskId(),
761 updateLastFocusedStackReason);
762 }
763 }
764
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700765 onStackOrderChanged(stack);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700766 }
767
Evan Rosky38257982020-05-21 15:45:17 -0700768 /**
769 * Moves/reparents `task` to the back of whatever container the home stack is in. This is for
770 * when we just want to move a task to "the back" vs. a specific place. The primary use-case
771 * is to make sure that moved-to-back apps go into secondary split when in split-screen mode.
772 */
773 void positionTaskBehindHome(ActivityStack task) {
774 final ActivityStack home = getOrCreateRootHomeTask();
775 final WindowContainer homeParent = home.getParent();
776 final Task homeParentTask = homeParent != null ? homeParent.asTask() : null;
777 if (homeParentTask == null) {
778 // reparent throws if parent didn't change...
779 if (task.getParent() == this) {
780 positionStackAtBottom(task);
781 } else {
782 task.reparent(this, false /* onTop */);
783 }
784 } else if (homeParentTask == task.getParent()) {
785 // Apparently reparent early-outs if same stack, so we have to explicitly reorder.
786 ((ActivityStack) homeParentTask).positionChildAtBottom(task);
787 } else {
788 task.reparent((ActivityStack) homeParentTask, false /* toTop */,
789 Task.REPARENT_LEAVE_STACK_IN_PLACE, false /* animate */,
790 false /* deferResume */, "positionTaskBehindHome");
791 }
792 }
793
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700794 ActivityStack getStack(int rootTaskId) {
795 for (int i = getStackCount() - 1; i >= 0; --i) {
796 final ActivityStack stack = getStackAt(i);
797 if (stack.getRootTaskId() == rootTaskId) {
798 return stack;
799 }
800 }
801 return null;
802 }
803
804 /**
805 * Returns an existing stack compatible with the windowing mode and activity type or creates one
806 * if a compatible stack doesn't exist.
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700807 * @see #getOrCreateStack(int, int, boolean, Intent, Task)
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700808 */
809 ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop) {
810 return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700811 null /* candidateTask */);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700812 }
813
814 /**
815 * When two level tasks are required for given windowing mode and activity type, returns an
816 * existing compatible root task or creates a new one.
817 * For one level task, the candidate task would be reused to also be the root task or create
818 * a new root task if no candidate task.
819 * @see #getStack(int, int)
820 * @see #createStack(int, int, boolean)
821 */
822 ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop,
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700823 Intent intent, Task candidateTask) {
Louis Chang6c5d7252020-03-30 15:42:01 +0800824 // Need to pass in a determined windowing mode to see if a new stack should be created,
825 // so use its parent's windowing mode if it is undefined.
826 if (!alwaysCreateStack(
827 windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : getWindowingMode(),
828 activityType)) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700829 ActivityStack stack = getStack(windowingMode, activityType);
830 if (stack != null) {
831 return stack;
832 }
833 } else if (candidateTask != null) {
834 final ActivityStack stack = (ActivityStack) candidateTask;
835 final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700836 Task launchRootTask = updateLaunchRootTask(windowingMode);
837
838 if (launchRootTask != null) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700839 if (stack.getParent() == null) {
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700840 launchRootTask.addChild(stack, position);
841 } else if (stack.getParent() != launchRootTask) {
842 stack.reparent(launchRootTask, position);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700843 }
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700844 } else if (stack.getDisplayArea() != this || !stack.isRootTask()) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700845 if (stack.getParent() == null) {
Vishnu Nair7c8a2472020-04-17 16:08:29 -0700846 addChild(stack, position);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700847 } else {
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700848 stack.reparent(this, onTop);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700849 }
850 }
851 // Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.
852 if (candidateTask.getWindowingMode() != windowingMode) {
853 candidateTask.setWindowingMode(windowingMode);
854 }
855 return stack;
856 }
857 return createStack(windowingMode, activityType, onTop, null /*info*/, intent,
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700858 false /* createdByOrganizer */);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700859 }
860
861 /**
862 * Returns an existing stack compatible with the input params or creates one
863 * if a compatible stack doesn't exist.
864 * @see #getOrCreateStack(int, int, boolean)
865 */
866 ActivityStack getOrCreateStack(@Nullable ActivityRecord r,
867 @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
868 boolean onTop) {
869 // First preference is the windowing mode in the activity options if set.
870 int windowingMode = (options != null)
871 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
872 // Validate that our desired windowingMode will work under the current conditions.
873 // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
874 // it's display's windowing mode.
875 windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
876 return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
Wale Ogunwalec27e1ac2020-03-31 13:18:47 -0700877 candidateTask);
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700878 }
879
880 @VisibleForTesting
881 int getNextStackId() {
882 return mAtmService.mStackSupervisor.getNextTaskIdForUser();
883 }
884
885 ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
886 return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */,
887 false /* createdByOrganizer */);
888 }
889
890 /**
891 * Creates a stack matching the input windowing mode and activity type on this display.
892 * @param windowingMode The windowing mode the stack should be created in. If
893 * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
894 * inherit its parent's windowing mode.
895 * @param activityType The activityType the stack should be created in. If
896 * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
897 * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
898 * @param onTop If true the stack will be created at the top of the display, else at the bottom.
899 * @param info The started activity info.
900 * @param intent The intent that started this task.
901 * @param createdByOrganizer @{code true} if this is created by task organizer, @{code false}
902 * otherwise.
903 * @return The newly created stack.
904 */
905 ActivityStack createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
906 Intent intent, boolean createdByOrganizer) {
907 if (mDisplayContent.mSingleTaskInstance && getStackCount() > 0) {
908 // Create stack on default display instead since this display can only contain 1 stack.
909 // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
910 // this goes away once ActivityView is no longer using virtual displays.
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700911 return mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700912 windowingMode, activityType, onTop, info, intent, createdByOrganizer);
913 }
914
915 if (activityType == ACTIVITY_TYPE_UNDEFINED && !createdByOrganizer) {
916 // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
917 // anything else should be passing it in anyways...except for the task organizer.
918 activityType = ACTIVITY_TYPE_STANDARD;
919 }
920
921 if (activityType != ACTIVITY_TYPE_STANDARD && activityType != ACTIVITY_TYPE_UNDEFINED) {
922 // For now there can be only one stack of a particular non-standard activity type on a
923 // display. So, get that ignoring whatever windowing mode it is currently in.
924 ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
925 if (stack != null) {
926 throw new IllegalArgumentException("Stack=" + stack + " of activityType="
927 + activityType + " already on display=" + this + ". Can't have multiple.");
928 }
929 }
930
931 if (!isWindowingModeSupported(windowingMode, mAtmService.mSupportsMultiWindow,
932 mAtmService.mSupportsSplitScreenMultiWindow,
933 mAtmService.mSupportsFreeformWindowManagement,
934 mAtmService.mSupportsPictureInPicture, activityType)) {
935 throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
936 + windowingMode);
937 }
938
Evan Rosky688c8382020-04-03 17:27:08 -0700939 if (windowingMode == WINDOWING_MODE_PINNED && getRootPinnedTask() != null) {
940 // Only 1 stack can be PINNED at a time, so dismiss the existing one
941 getRootPinnedTask().dismissPip();
942 }
943
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700944 final int stackId = getNextStackId();
945 return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent,
946 createdByOrganizer);
947 }
948
949 /** @return the root task to create the next task in. */
950 private Task updateLaunchRootTask(int windowingMode) {
951 if (!isSplitScreenWindowingMode(windowingMode)) {
952 // Only split-screen windowing modes can do this currently...
953 return null;
954 }
955 for (int i = getStackCount() - 1; i >= 0; --i) {
956 final Task t = getStackAt(i);
957 if (!t.mCreatedByOrganizer || t.getRequestedOverrideWindowingMode() != windowingMode) {
958 continue;
959 }
960 // If not already set, pick a launch root which is not the one we are launching into.
961 if (mLaunchRootTask == null) {
962 for (int j = 0, n = getStackCount(); j < n; ++j) {
963 final Task tt = getStackAt(j);
964 if (tt.mCreatedByOrganizer && tt != t) {
965 mLaunchRootTask = tt;
966 break;
967 }
968 }
969 }
970 return t;
971 }
972 return mLaunchRootTask;
973 }
974
975 @VisibleForTesting
976 ActivityStack createStackUnchecked(int windowingMode, int activityType, int stackId,
977 boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer) {
978 if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
979 throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
980 + "activity type.");
981 }
982 if (info == null) {
983 info = new ActivityInfo();
984 info.applicationInfo = new ApplicationInfo();
985 }
986
987 // Task created by organizer are added as root.
988 Task launchRootTask = createdByOrganizer ? null : updateLaunchRootTask(windowingMode);
989 if (launchRootTask != null) {
990 // Since this stack will be put into a root task, its windowingMode will be inherited.
991 windowingMode = WINDOWING_MODE_UNDEFINED;
992 }
993
Garfield Tan5044a152020-05-01 14:13:35 -0700994 final ActivityStack stack = new ActivityStack(mAtmService, stackId, activityType,
Andrii Kulian9ea12da2020-03-27 17:16:38 -0700995 info, intent, createdByOrganizer);
996 if (launchRootTask != null) {
997 launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
998 if (onTop) {
999 positionStackAtTop((ActivityStack) launchRootTask, false /* includingParents */);
1000 }
1001 } else {
Vishnu Nair7c8a2472020-04-17 16:08:29 -07001002 addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
Evan Rosky50ea8c12020-04-02 20:49:05 -07001003 stack.setWindowingMode(windowingMode, true /* creating */);
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001004 }
1005 return stack;
1006 }
1007
1008 /**
1009 * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
1010 * focusable and visible stack from the top of stacks in this display.
1011 */
1012 ActivityStack getFocusedStack() {
1013 if (mPreferredTopFocusableStack != null) {
1014 return mPreferredTopFocusableStack;
1015 }
1016
1017 for (int i = getStackCount() - 1; i >= 0; --i) {
1018 final ActivityStack stack = getStackAt(i);
1019 if (stack.isFocusableAndVisible()) {
1020 return stack;
1021 }
1022 }
1023
1024 return null;
1025 }
1026
1027 ActivityStack getNextFocusableStack(ActivityStack currentFocus, boolean ignoreCurrent) {
1028 final int currentWindowingMode = currentFocus != null
1029 ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
1030
1031 ActivityStack candidate = null;
1032 for (int i = getStackCount() - 1; i >= 0; --i) {
1033 final ActivityStack stack = getStackAt(i);
1034 if (ignoreCurrent && stack == currentFocus) {
1035 continue;
1036 }
1037 if (!stack.isFocusableAndVisible()) {
1038 continue;
1039 }
1040
1041 if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
1042 && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
1043 // If the currently focused stack is in split-screen secondary we save off the
1044 // top primary split-screen stack as a candidate for focus because we might
1045 // prefer focus to move to an other stack to avoid primary split-screen stack
1046 // overlapping with a fullscreen stack when a fullscreen stack is higher in z
1047 // than the next split-screen stack. Assistant stack, I am looking at you...
1048 // We only move the focus to the primary-split screen stack if there isn't a
1049 // better alternative.
1050 candidate = stack;
1051 continue;
1052 }
1053 if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
1054 // Use the candidate stack since we are now at the secondary split-screen.
1055 return candidate;
1056 }
1057 return stack;
1058 }
1059 return candidate;
1060 }
1061
Andrii Kulianf9df4a82020-03-31 12:09:27 -07001062 ActivityRecord getFocusedActivity() {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001063 final ActivityStack focusedStack = getFocusedStack();
1064 if (focusedStack == null) {
1065 return null;
1066 }
1067 // TODO(b/111541062): Move this into ActivityStack#getResumedActivity()
1068 // Check if the focused stack has the resumed activity
1069 ActivityRecord resumedActivity = focusedStack.getResumedActivity();
1070 if (resumedActivity == null || resumedActivity.app == null) {
1071 // If there is no registered resumed activity in the stack or it is not running -
1072 // try to use previously resumed one.
1073 resumedActivity = focusedStack.mPausingActivity;
1074 if (resumedActivity == null || resumedActivity.app == null) {
1075 // If previously resumed activity doesn't work either - find the topmost running
1076 // activity that can be focused.
1077 resumedActivity = focusedStack.topRunningActivity(true /* focusableOnly */);
1078 }
1079 }
1080 return resumedActivity;
1081 }
1082
1083 ActivityStack getLastFocusedStack() {
1084 return mLastFocusedStack;
1085 }
1086
1087 boolean allResumedActivitiesComplete() {
1088 for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
1089 final ActivityRecord r = getStackAt(stackNdx).getResumedActivity();
1090 if (r != null && !r.isState(RESUMED)) {
1091 return false;
1092 }
1093 }
1094 final ActivityStack currentFocusedStack = getFocusedStack();
1095 if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
1096 Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
1097 + mLastFocusedStack + " to=" + currentFocusedStack);
1098 }
1099 mLastFocusedStack = currentFocusedStack;
1100 return true;
1101 }
1102
1103 /**
1104 * Pause all activities in either all of the stacks or just the back stacks. This is done before
1105 * resuming a new activity and to make sure that previously active activities are
1106 * paused in stacks that are no longer visible or in pinned windowing mode. This does not
1107 * pause activities in visible stacks, so if an activity is launched within the same stack/task,
1108 * then we should explicitly pause that stack's top activity.
1109 * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
1110 * @param resuming The resuming activity.
1111 * @return {@code true} if any activity was paused as a result of this call.
1112 */
1113 boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
1114 boolean someActivityPaused = false;
1115 for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
1116 final ActivityStack stack = getStackAt(stackNdx);
1117 final ActivityRecord resumedActivity = stack.getResumedActivity();
1118 if (resumedActivity != null
1119 && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
1120 || !stack.isTopActivityFocusable())) {
1121 if (DEBUG_STATES) {
1122 Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack
1123 + " mResumedActivity=" + resumedActivity);
1124 }
1125 someActivityPaused |= stack.startPausingLocked(userLeaving, false /* uiSleeping*/,
1126 resuming);
1127 }
1128 }
1129 return someActivityPaused;
1130 }
1131
1132 /**
1133 * Find task for putting the Activity in.
1134 */
Andrii Kulian1cb59dd2020-04-10 12:17:17 -07001135 void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplayArea,
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001136 RootWindowContainer.FindTaskResult result) {
1137 mTmpFindTaskResult.clear();
1138 for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
1139 final ActivityStack stack = getStackAt(stackNdx);
1140 if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) {
1141 if (DEBUG_TASKS) {
1142 Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
1143 }
1144 continue;
1145 }
1146
1147 mTmpFindTaskResult.process(r, stack);
1148 // It is possible to have tasks in multiple stacks with the same root affinity, so
1149 // we should keep looking after finding an affinity match to see if there is a
1150 // better match in another stack. Also, task affinity isn't a good enough reason
1151 // to target a display which isn't the source of the intent, so skip any affinity
1152 // matches not on the specified display.
1153 if (mTmpFindTaskResult.mRecord != null) {
1154 if (mTmpFindTaskResult.mIdealMatch) {
1155 result.setTo(mTmpFindTaskResult);
1156 return;
Andrii Kulian1cb59dd2020-04-10 12:17:17 -07001157 } else if (isPreferredDisplayArea) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001158 // Note: since the traversing through the stacks is top down, the floating
1159 // tasks should always have lower priority than any affinity-matching tasks
1160 // in the fullscreen stacks
1161 result.setTo(mTmpFindTaskResult);
1162 }
1163 }
1164 }
1165 }
1166
1167 /**
1168 * Removes stacks in the input windowing modes from the system if they are of activity type
1169 * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
1170 */
1171 void removeStacksInWindowingModes(int... windowingModes) {
1172 if (windowingModes == null || windowingModes.length == 0) {
1173 return;
1174 }
1175
1176 // Collect the stacks that are necessary to be removed instead of performing the removal
1177 // by looping mStacks, so that we don't miss any stacks after the stack size changed or
1178 // stacks reordered.
1179 final ArrayList<ActivityStack> stacks = new ArrayList<>();
1180 for (int j = windowingModes.length - 1; j >= 0; --j) {
1181 final int windowingMode = windowingModes[j];
1182 for (int i = getStackCount() - 1; i >= 0; --i) {
1183 final ActivityStack stack = getStackAt(i);
1184 if (!stack.isActivityTypeStandardOrUndefined()) {
1185 continue;
1186 }
1187 if (stack.getWindowingMode() != windowingMode) {
1188 continue;
1189 }
1190 stacks.add(stack);
1191 }
1192 }
1193
1194 for (int i = stacks.size() - 1; i >= 0; --i) {
1195 mRootWindowContainer.mStackSupervisor.removeStack(stacks.get(i));
1196 }
1197 }
1198
1199 void removeStacksWithActivityTypes(int... activityTypes) {
1200 if (activityTypes == null || activityTypes.length == 0) {
1201 return;
1202 }
1203
1204 // Collect the stacks that are necessary to be removed instead of performing the removal
1205 // by looping mStacks, so that we don't miss any stacks after the stack size changed or
1206 // stacks reordered.
1207 final ArrayList<ActivityStack> stacks = new ArrayList<>();
1208 for (int j = activityTypes.length - 1; j >= 0; --j) {
1209 final int activityType = activityTypes[j];
1210 for (int i = getStackCount() - 1; i >= 0; --i) {
1211 final ActivityStack stack = getStackAt(i);
1212 // Collect the root tasks that are currently being organized.
Evan Rosky50ea8c12020-04-02 20:49:05 -07001213 if (stack.mCreatedByOrganizer) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001214 for (int k = stack.getChildCount() - 1; k >= 0; --k) {
1215 final ActivityStack childStack = (ActivityStack) stack.getChildAt(k);
1216 if (childStack.getActivityType() == activityType) {
1217 stacks.add(childStack);
1218 }
1219 }
1220 } else if (stack.getActivityType() == activityType) {
1221 stacks.add(stack);
1222 }
1223 }
1224 }
1225
1226 for (int i = stacks.size() - 1; i >= 0; --i) {
1227 mRootWindowContainer.mStackSupervisor.removeStack(stacks.get(i));
1228 }
1229 }
1230
1231 void onSplitScreenModeDismissed() {
Wale Ogunwalefbb81c92020-04-09 18:01:24 -07001232 onSplitScreenModeDismissed(null /* toTop */);
1233 }
1234
1235 void onSplitScreenModeDismissed(ActivityStack toTop) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001236 mAtmService.deferWindowLayout();
1237 try {
1238 mLaunchRootTask = null;
1239 moveSplitScreenTasksToFullScreen();
1240 } finally {
Wale Ogunwalefbb81c92020-04-09 18:01:24 -07001241 final ActivityStack topFullscreenStack = toTop != null
1242 ? toTop : getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001243 final ActivityStack homeStack = getOrCreateRootHomeTask();
Wale Ogunwalefbb81c92020-04-09 18:01:24 -07001244 if (homeStack != null && ((topFullscreenStack != null && !isTopStack(homeStack))
1245 || toTop != null)) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001246 // Whenever split-screen is dismissed we want the home stack directly behind the
1247 // current top fullscreen stack so it shows up when the top stack is finished.
Wale Ogunwalefbb81c92020-04-09 18:01:24 -07001248 // Or, if the caller specified a stack to be on top after split-screen is dismissed.
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001249 // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
1250 // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
1251 // once we have that.
1252 homeStack.moveToFront("onSplitScreenModeDismissed");
1253 topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
1254 }
1255 mAtmService.continueWindowLayout();
1256 }
1257 }
1258
1259 private void moveSplitScreenTasksToFullScreen() {
1260 final WindowContainerTransaction wct = new WindowContainerTransaction();
1261 mTmpTasks.clear();
1262 forAllTasks(task -> {
1263 if (task.mCreatedByOrganizer && task.inSplitScreenWindowingMode() && task.hasChild()) {
1264 mTmpTasks.add(task);
1265 }
1266 });
1267
1268 for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
1269 final Task root = mTmpTasks.get(i);
1270 for (int j = 0; j < root.getChildCount(); j++) {
Wale Ogunwaleadf116e2020-03-27 16:36:01 -07001271 wct.reparent(root.getChildAt(j).mRemoteToken.toWindowContainerToken(),
1272 null, true /* toTop */);
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001273 }
1274 }
1275 mAtmService.mWindowOrganizerController.applyTransaction(wct);
1276 }
1277
1278 /**
1279 * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
1280 * @param windowingMode The windowing mode we are checking support for.
1281 * @param supportsMultiWindow If we should consider support for multi-window mode in general.
1282 * @param supportsSplitScreen If we should consider support for split-screen multi-window.
1283 * @param supportsFreeform If we should consider support for freeform multi-window.
1284 * @param supportsPip If we should consider support for picture-in-picture mutli-window.
1285 * @param activityType The activity type under consideration.
1286 * @return true if the windowing mode is supported.
1287 */
1288 private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
1289 boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
1290 int activityType) {
1291
1292 if (windowingMode == WINDOWING_MODE_UNDEFINED
1293 || windowingMode == WINDOWING_MODE_FULLSCREEN) {
1294 return true;
1295 }
1296 if (!supportsMultiWindow) {
1297 return false;
1298 }
1299
1300 if (windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
1301 return true;
1302 }
1303
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001304 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
1305 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
1306 return supportsSplitScreen
Evan Rosky07acd072020-05-20 19:18:16 -07001307 && WindowConfiguration.supportSplitScreenWindowingMode(activityType);
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001308 }
1309
1310 if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
1311 return false;
1312 }
1313
1314 if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
1315 return false;
1316 }
1317 return true;
1318 }
1319
1320 /**
1321 * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
1322 * display with the provided parameters.
1323 *
1324 * @param r The ActivityRecord in question.
1325 * @param options Options to start with.
1326 * @param task The task within-which the activity would start.
1327 * @param activityType The type of activity to start.
1328 * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
1329 */
1330 int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
1331 @Nullable Task task, int activityType) {
1332
1333 // First preference if the windowing mode in the activity options if set.
1334 int windowingMode = (options != null)
1335 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
1336
1337 // If windowing mode is unset, then next preference is the candidate task, then the
1338 // activity record.
1339 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
1340 if (task != null) {
1341 windowingMode = task.getWindowingMode();
1342 }
1343 if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
1344 windowingMode = r.getWindowingMode();
1345 }
1346 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
1347 // Use the display's windowing mode.
1348 windowingMode = getWindowingMode();
1349 }
1350 }
1351 windowingMode = validateWindowingMode(windowingMode, r, task, activityType);
1352 return windowingMode != WINDOWING_MODE_UNDEFINED
1353 ? windowingMode : WINDOWING_MODE_FULLSCREEN;
1354 }
1355
1356 /**
Evan Rosky2af969c2020-05-08 16:26:31 +00001357 * Check if the requested windowing-mode is appropriate for the specified task and/or activity
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001358 * on this display.
1359 *
1360 * @param windowingMode The windowing-mode to validate.
1361 * @param r The {@link ActivityRecord} to check against.
1362 * @param task The {@link Task} to check against.
1363 * @param activityType An activity type.
Evan Rosky2af969c2020-05-08 16:26:31 +00001364 * @return {@code true} if windowingMode is valid, {@code false} otherwise.
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001365 */
Evan Rosky2af969c2020-05-08 16:26:31 +00001366 boolean isValidWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001367 int activityType) {
1368 // Make sure the windowing mode we are trying to use makes sense for what is supported.
1369 boolean supportsMultiWindow = mAtmService.mSupportsMultiWindow;
1370 boolean supportsSplitScreen = mAtmService.mSupportsSplitScreenMultiWindow;
1371 boolean supportsFreeform = mAtmService.mSupportsFreeformWindowManagement;
1372 boolean supportsPip = mAtmService.mSupportsPictureInPicture;
1373 if (supportsMultiWindow) {
1374 if (task != null) {
1375 supportsMultiWindow = task.isResizeable();
1376 supportsSplitScreen = task.supportsSplitScreenWindowingMode();
1377 // TODO: Do we need to check for freeform and Pip support here?
1378 } else if (r != null) {
1379 supportsMultiWindow = r.isResizeable();
1380 supportsSplitScreen = r.supportsSplitScreenWindowingMode();
1381 supportsFreeform = r.supportsFreeform();
1382 supportsPip = r.supportsPictureInPicture();
1383 }
1384 }
1385
Evan Rosky2af969c2020-05-08 16:26:31 +00001386 return windowingMode != WINDOWING_MODE_UNDEFINED
1387 && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
1388 supportsFreeform, supportsPip, activityType);
1389 }
1390
1391 /**
1392 * Check that the requested windowing-mode is appropriate for the specified task and/or activity
1393 * on this display.
1394 *
1395 * @param windowingMode The windowing-mode to validate.
1396 * @param r The {@link ActivityRecord} to check against.
1397 * @param task The {@link Task} to check against.
1398 * @param activityType An activity type.
1399 * @return The provided windowingMode or the closest valid mode which is appropriate.
1400 */
1401 int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
1402 int activityType) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001403 final boolean inSplitScreenMode = isSplitScreenModeActivated();
Evan Rosky2af969c2020-05-08 16:26:31 +00001404 if (!inSplitScreenMode && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001405 // Switch to the display's windowing mode if we are not in split-screen mode and we are
1406 // trying to launch in split-screen secondary.
1407 windowingMode = WINDOWING_MODE_UNDEFINED;
Evan Rosky2af969c2020-05-08 16:26:31 +00001408 } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_UNDEFINED) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001409 windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
1410 }
Evan Rosky2af969c2020-05-08 16:26:31 +00001411 if (!isValidWindowingMode(windowingMode, r, task, activityType)) {
1412 return WINDOWING_MODE_UNDEFINED;
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001413 }
Evan Rosky2af969c2020-05-08 16:26:31 +00001414 return windowingMode;
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001415 }
1416
1417 boolean isTopStack(ActivityStack stack) {
1418 return stack == getTopStack();
1419 }
1420
1421 boolean isTopNotPinnedStack(ActivityStack stack) {
1422 for (int i = getStackCount() - 1; i >= 0; --i) {
1423 final ActivityStack current = getStackAt(i);
1424 if (!current.inPinnedWindowingMode()) {
1425 return current == stack;
1426 }
1427 }
1428 return false;
1429 }
1430
Andrii Kulian86d676c2020-03-27 19:34:54 -07001431 ActivityRecord topRunningActivity() {
1432 return topRunningActivity(false /* considerKeyguardState */);
1433 }
1434
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001435 /**
1436 * Returns the top running activity in the focused stack. In the case the focused stack has no
1437 * such activity, the next focusable stack on this display is returned.
1438 *
1439 * @param considerKeyguardState Indicates whether the locked state should be considered. if
1440 * {@code true} and the keyguard is locked, only activities that
1441 * can be shown on top of the keyguard will be considered.
1442 * @return The top running activity. {@code null} if none is available.
1443 */
1444 ActivityRecord topRunningActivity(boolean considerKeyguardState) {
1445 ActivityRecord topRunning = null;
1446 final ActivityStack focusedStack = getFocusedStack();
1447 if (focusedStack != null) {
1448 topRunning = focusedStack.topRunningActivity();
1449 }
1450
1451 // Look in other focusable stacks.
1452 if (topRunning == null) {
1453 for (int i = getStackCount() - 1; i >= 0; --i) {
1454 final ActivityStack stack = getStackAt(i);
1455 // Only consider focusable stacks other than the current focused one.
1456 if (stack == focusedStack || !stack.isTopActivityFocusable()) {
1457 continue;
1458 }
1459 topRunning = stack.topRunningActivity();
1460 if (topRunning != null) {
1461 break;
1462 }
1463 }
1464 }
1465
1466 // This activity can be considered the top running activity if we are not considering
1467 // the locked state, the keyguard isn't locked, or we can show when locked.
1468 if (topRunning != null && considerKeyguardState
1469 && mRootWindowContainer.mStackSupervisor.getKeyguardController()
1470 .isKeyguardLocked()
1471 && !topRunning.canShowWhenLocked()) {
1472 return null;
1473 }
1474
1475 return topRunning;
1476 }
1477
1478 protected int getStackCount() {
1479 return mChildren.size();
1480 }
1481
1482 protected ActivityStack getStackAt(int index) {
1483 return mChildren.get(index);
1484 }
1485
Chris Lif95a7762020-04-14 20:03:47 -07001486 @Nullable
1487 ActivityStack getOrCreateRootHomeTask() {
1488 return getOrCreateRootHomeTask(false /* onTop */);
1489 }
1490
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001491 /**
1492 * Returns the existing home stack or creates and returns a new one if it should exist for the
1493 * display.
Chris Lif95a7762020-04-14 20:03:47 -07001494 * @param onTop Only be used when there is no existing home stack. If true the home stack will
1495 * be created at the top of the display, else at the bottom.
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001496 */
1497 @Nullable
Chris Lif95a7762020-04-14 20:03:47 -07001498 ActivityStack getOrCreateRootHomeTask(boolean onTop) {
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001499 ActivityStack homeTask = getRootHomeTask();
1500 if (homeTask == null && mDisplayContent.supportsSystemDecorations()
1501 && !mDisplayContent.isUntrustedVirtualDisplay()) {
Chris Lif95a7762020-04-14 20:03:47 -07001502 homeTask = createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, onTop);
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001503 }
1504 return homeTask;
1505 }
1506
1507 boolean isSplitScreenModeActivated() {
1508 Task task = getRootSplitScreenPrimaryTask();
1509 return task != null && task.hasChild();
1510 }
1511
1512 /**
1513 * Returns the topmost stack on the display that is compatible with the input windowing mode.
1514 * Null is no compatible stack on the display.
1515 */
1516 ActivityStack getTopStackInWindowingMode(int windowingMode) {
1517 return getStack(windowingMode, ACTIVITY_TYPE_UNDEFINED);
1518 }
1519
1520 void moveHomeStackToFront(String reason) {
1521 final ActivityStack homeStack = getOrCreateRootHomeTask();
1522 if (homeStack != null) {
1523 homeStack.moveToFront(reason);
1524 }
1525 }
1526
1527 /**
1528 * Moves the focusable home activity to top. If there is no such activity, the home stack will
1529 * still move to top.
1530 */
1531 void moveHomeActivityToTop(String reason) {
1532 final ActivityRecord top = getHomeActivity();
1533 if (top == null) {
1534 moveHomeStackToFront(reason);
1535 return;
1536 }
1537 top.moveFocusableActivityToTop(reason);
1538 }
1539
1540 @Nullable
1541 ActivityRecord getHomeActivity() {
1542 return getHomeActivityForUser(mRootWindowContainer.mCurrentUser);
1543 }
1544
1545 @Nullable
1546 ActivityRecord getHomeActivityForUser(int userId) {
1547 final ActivityStack homeStack = getRootHomeTask();
1548 if (homeStack == null) {
1549 return null;
1550 }
1551
1552 final PooledPredicate p = PooledLambda.obtainPredicate(
Andrii Kulian86d676c2020-03-27 19:34:54 -07001553 TaskDisplayArea::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
Andrii Kulian9ea12da2020-03-27 17:16:38 -07001554 userId);
1555 final ActivityRecord r = homeStack.getActivity(p);
1556 p.recycle();
1557 return r;
1558 }
1559
1560 private static boolean isHomeActivityForUser(ActivityRecord r, int userId) {
1561 return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId);
1562 }
1563
1564 /**
1565 * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
1566 * Generally used in conjunction with {@link #moveStackBehindStack}.
1567 */
1568 // TODO(b/151575894): Remove special stack movement methods.
1569 void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
1570 if (stack.shouldBeVisible(null)) {
1571 // Skip if the stack is already visible
1572 return;
1573 }
1574
1575 final boolean isRootTask = stack.isRootTask();
1576 if (isRootTask) {
1577 // Move the stack to the bottom to not affect the following visibility checks
1578 positionStackAtBottom(stack);
1579 } else {
1580 stack.getParent().positionChildAt(POSITION_BOTTOM, stack, false /* includingParents */);
1581 }
1582
1583 // Find the next position where the stack should be placed
1584 final int numStacks = isRootTask ? getStackCount() : stack.getParent().getChildCount();
1585 for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
1586 final ActivityStack s = isRootTask ? getStackAt(stackNdx)
1587 : (ActivityStack) stack.getParent().getChildAt(stackNdx);
1588 if (s == stack) {
1589 continue;
1590 }
1591 final int winMode = s.getWindowingMode();
1592 final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
1593 || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
1594 if (s.shouldBeVisible(null) && isValidWindowingMode) {
1595 // Move the provided stack to behind this stack
1596 final int position = Math.max(0, stackNdx - 1);
1597 if (isRootTask) {
1598 positionStackAt(stack, position);
1599 } else {
1600 stack.getParent().positionChildAt(position, stack, false /*includingParents */);
1601 }
1602 break;
1603 }
1604 }
1605 }
1606
1607 /**
1608 * Moves the {@param stack} behind the given {@param behindStack} if possible. If
1609 * {@param behindStack} is not currently in the display, then then the stack is moved to the
1610 * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
1611 */
1612 void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
1613 if (behindStack == null || behindStack == stack) {
1614 return;
1615 }
1616
1617 final WindowContainer parent = stack.getParent();
1618 if (parent == null || parent != behindStack.getParent()) {
1619 return;
1620 }
1621
1622 // Note that positionChildAt will first remove the given stack before inserting into the
1623 // list, so we need to adjust the insertion index to account for the removed index
1624 // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
1625 // position internally
1626 final int stackIndex = parent.mChildren.indexOf(stack);
1627 final int behindStackIndex = parent.mChildren.indexOf(behindStack);
1628 final int insertIndex = stackIndex <= behindStackIndex
1629 ? behindStackIndex - 1 : behindStackIndex;
1630 final int position = Math.max(0, insertIndex);
1631 if (stack.isRootTask()) {
1632 positionStackAt(stack, position);
1633 } else {
1634 parent.positionChildAt(position, stack, false /* includingParents */);
1635 }
1636 }
Andrii Kulian86d676c2020-03-27 19:34:54 -07001637
1638 boolean hasPinnedTask() {
1639 return getRootPinnedTask() != null;
1640 }
1641
1642 /**
1643 * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
1644 * already top-most.
1645 */
1646 static ActivityStack getStackAbove(ActivityStack stack) {
1647 final WindowContainer wc = stack.getParent();
1648 final int index = wc.mChildren.indexOf(stack) + 1;
1649 return (index < wc.mChildren.size()) ? (ActivityStack) wc.mChildren.get(index) : null;
1650 }
1651
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -07001652 /** Returns true if the stack in the windowing mode is visible. */
1653 boolean isStackVisible(int windowingMode) {
1654 final ActivityStack stack = getTopStackInWindowingMode(windowingMode);
1655 return stack != null && stack.isVisible();
1656 }
1657
1658 void removeStack(ActivityStack stack) {
1659 removeChild(stack);
1660 }
1661
Andrii Kulian86d676c2020-03-27 19:34:54 -07001662 int getDisplayId() {
1663 return mDisplayContent.getDisplayId();
1664 }
1665
1666 boolean isRemoved() {
Andrii Kulianf9df4a82020-03-31 12:09:27 -07001667 return mRemoved;
Andrii Kulian86d676c2020-03-27 19:34:54 -07001668 }
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -07001669
1670 /**
1671 * Adds a listener to be notified whenever the stack order in the display changes. Currently
1672 * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
1673 * current animation when the system state changes.
1674 */
1675 void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
1676 if (!mStackOrderChangedCallbacks.contains(listener)) {
1677 mStackOrderChangedCallbacks.add(listener);
1678 }
1679 }
1680
1681 /**
1682 * Removes a previously registered stack order change listener.
1683 */
1684 void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
1685 mStackOrderChangedCallbacks.remove(listener);
1686 }
1687
1688 /**
1689 * Notifies of a stack order change
1690 * @param stack The stack which triggered the order change
1691 */
1692 void onStackOrderChanged(ActivityStack stack) {
1693 for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
1694 mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
1695 }
1696 }
1697
Evan Rosky0ad8d2c2020-03-16 12:09:58 -07001698 @Override
1699 boolean canCreateRemoteAnimationTarget() {
1700 return true;
1701 }
1702
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -07001703 /**
1704 * Callback for when the order of the stacks in the display changes.
1705 */
1706 interface OnStackOrderChangedListener {
1707 void onStackOrderChanged(ActivityStack stack);
1708 }
Andrii Kulianf9df4a82020-03-31 12:09:27 -07001709
1710 void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
1711 boolean preserveWindows, boolean notifyClients) {
1712 for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
1713 final ActivityStack stack = getStackAt(stackNdx);
1714 stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
1715 notifyClients);
1716 }
1717 }
1718
1719 void prepareFreezingTaskBounds() {
1720 for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
1721 final ActivityStack stack = getChildAt(stackNdx);
1722 stack.prepareFreezingTaskBounds();
1723 }
1724 }
1725
1726 /**
1727 * Removes the stacks in the node applying the content removal node from the display.
1728 * @return last reparented stack, or {@code null} if the stacks had to be destroyed.
1729 */
1730 ActivityStack remove() {
1731 mPreferredTopFocusableStack = null;
1732 // TODO(b/153090332): Allow setting content removal mode per task display area
1733 final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove();
1734 final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
1735 ActivityStack lastReparentedStack = null;
1736
1737 // Stacks could be reparented from the removed display area to other display area. After
1738 // reparenting the last stack of the removed display area, the display area becomes ready to
1739 // be released (no more ActivityStack-s). But, we cannot release it at that moment or the
1740 // related WindowContainer will also be removed. So, we set display area as removed after
1741 // reparenting stack finished.
1742 // Keep the order from bottom to top.
1743 int numStacks = getStackCount();
1744 for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
1745 final ActivityStack stack = getStackAt(stackNdx);
1746 // Always finish non-standard type stacks.
1747 if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
1748 stack.finishAllActivitiesImmediately();
1749 } else {
1750 // If default display is in split-window mode, set windowing mode of the
1751 // stack to split-screen secondary. Otherwise, set the windowing mode to
1752 // undefined by default to let stack inherited the windowing mode from the
1753 // new display.
1754 final int windowingMode = toDisplayArea.isSplitScreenModeActivated()
1755 ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
1756 : WINDOWING_MODE_UNDEFINED;
1757 stack.reparent(toDisplayArea, true /* onTop */);
1758 stack.setWindowingMode(windowingMode);
1759 lastReparentedStack = stack;
1760 }
1761 // Stacks may be removed from this display. Ensure each stack will be processed
1762 // and the loop will end.
1763 stackNdx -= numStacks - getStackCount();
1764 numStacks = getStackCount();
1765 }
1766 mRemoved = true;
1767
1768 return lastReparentedStack;
1769 }
1770
1771
1772 @Override
1773 void dump(PrintWriter pw, String prefix, boolean dumpAll) {
1774 pw.println(prefix + "TaskDisplayArea " + getName());
Riddle Hsu4f088b62020-06-05 00:44:26 +08001775 super.dump(pw, prefix, dumpAll);
Andrii Kulianf9df4a82020-03-31 12:09:27 -07001776 if (mPreferredTopFocusableStack != null) {
1777 pw.println(prefix + " mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
1778 }
1779 if (mLastFocusedStack != null) {
1780 pw.println(prefix + " mLastFocusedStack=" + mLastFocusedStack);
1781 }
Riddle Hsu4f088b62020-06-05 00:44:26 +08001782 final String doublePrefix = prefix + " ";
1783 final String triplePrefix = doublePrefix + " ";
1784 pw.println(doublePrefix + "Application tokens in top down Z order:");
Andrii Kulianf9df4a82020-03-31 12:09:27 -07001785 for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
1786 final ActivityStack stack = getChildAt(stackNdx);
Riddle Hsu4f088b62020-06-05 00:44:26 +08001787 pw.println(doublePrefix + "* " + stack);
1788 stack.dump(pw, triplePrefix, dumpAll);
Andrii Kulianf9df4a82020-03-31 12:09:27 -07001789 }
1790 }
Andrii Kulian526ad432020-03-27 12:19:51 -07001791}