blob: 0f42103e41782369b219d7aecb61811e113d2c05 [file] [log] [blame]
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001/*
2 * Copyright (C) 2017 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.am;
18
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070019import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070020import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
21import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
22import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
Wale Ogunwaleab5de372017-10-18 06:46:31 -070023import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070024import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
25import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
26import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
27import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
28import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
29import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
30import static android.view.Display.DEFAULT_DISPLAY;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070031import static android.view.Display.FLAG_PRIVATE;
32import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
33import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
34import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
35import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
36import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070037import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER;
38import static com.android.server.am.ActivityDisplayProto.STACKS;
39import static com.android.server.am.ActivityDisplayProto.ID;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070040
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -070041import android.annotation.Nullable;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070042import android.app.ActivityManagerInternal;
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -070043import android.app.ActivityOptions;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070044import android.app.WindowConfiguration;
Bryce Leef3c6a472017-11-14 14:53:06 -080045import android.graphics.Point;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070046import android.util.IntArray;
47import android.util.Slog;
48import android.util.proto.ProtoOutputStream;
49import android.view.Display;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070050import com.android.internal.annotations.VisibleForTesting;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070051import com.android.server.wm.ConfigurationContainer;
Winson Chung59a47ded2018-01-25 17:46:06 +000052import com.android.server.wm.DisplayWindowController;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070053
Winson Chung59a47ded2018-01-25 17:46:06 +000054import com.android.server.wm.WindowContainerListener;
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070055import java.io.PrintWriter;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070056import java.util.ArrayList;
57
58/**
59 * Exactly one of these classes per Display in the system. Capable of holding zero or more
60 * attached {@link ActivityStack}s.
61 */
Winson Chung59a47ded2018-01-25 17:46:06 +000062class ActivityDisplay extends ConfigurationContainer<ActivityStack>
63 implements WindowContainerListener {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070064 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_AM;
65 private static final String TAG_STACK = TAG + POSTFIX_STACK;
66
67 static final int POSITION_TOP = Integer.MAX_VALUE;
68 static final int POSITION_BOTTOM = Integer.MIN_VALUE;
69
Bryce Leed9cce2c2017-12-04 16:16:27 -080070
71 /**
72 * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
73 */
74 private static int sNextFreeStackId = 0;
75
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070076 private ActivityStackSupervisor mSupervisor;
77 /** Actual Display this object tracks. */
78 int mDisplayId;
79 Display mDisplay;
80
81 /** All of the stacks on this display. Order matters, topmost stack is in front of all other
82 * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070083 private final ArrayList<ActivityStack> mStacks = new ArrayList<>();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070084
85 /** Array of all UIDs that are present on the display. */
86 private IntArray mDisplayAccessUIDs = new IntArray();
87
88 /** All tokens used to put activities on this stack to sleep (including mOffToken) */
89 final ArrayList<ActivityManagerInternal.SleepToken> mAllSleepTokens = new ArrayList<>();
90 /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */
91 ActivityManagerInternal.SleepToken mOffToken;
92
93 private boolean mSleeping;
94
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070095 // Cached reference to some special stacks we tend to get a lot so we don't need to loop
96 // through the list to find them.
97 private ActivityStack mHomeStack = null;
98 private ActivityStack mRecentsStack = null;
99 private ActivityStack mPinnedStack = null;
100 private ActivityStack mSplitScreenPrimaryStack = null;
101
Bryce Leef3c6a472017-11-14 14:53:06 -0800102 // Used in updating the display size
103 private Point mTmpDisplaySize = new Point();
104
Winson Chung59a47ded2018-01-25 17:46:06 +0000105 private DisplayWindowController mWindowContainerController;
106
Wale Ogunwale45477b52018-03-06 12:24:19 -0800107 @VisibleForTesting
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700108 ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
Wale Ogunwale45477b52018-03-06 12:24:19 -0800109 this(supervisor, supervisor.mDisplayManager.getDisplay(displayId));
110 }
111
112 ActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700113 mSupervisor = supervisor;
Wale Ogunwale45477b52018-03-06 12:24:19 -0800114 mDisplayId = display.getDisplayId();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700115 mDisplay = display;
Winson Chung59a47ded2018-01-25 17:46:06 +0000116 mWindowContainerController = createWindowContainerController();
Bryce Leef3c6a472017-11-14 14:53:06 -0800117 updateBounds();
118 }
119
Winson Chung59a47ded2018-01-25 17:46:06 +0000120 protected DisplayWindowController createWindowContainerController() {
Wale Ogunwale45477b52018-03-06 12:24:19 -0800121 return new DisplayWindowController(mDisplay, this);
Winson Chung59a47ded2018-01-25 17:46:06 +0000122 }
123
Bryce Leef3c6a472017-11-14 14:53:06 -0800124 void updateBounds() {
125 mDisplay.getSize(mTmpDisplaySize);
126 setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700127 }
128
129 void addChild(ActivityStack stack, int position) {
130 if (position == POSITION_BOTTOM) {
131 position = 0;
132 } else if (position == POSITION_TOP) {
133 position = mStacks.size();
134 }
135 if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack
136 + " to displayId=" + mDisplayId + " position=" + position);
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700137 addStackReferenceIfNeeded(stack);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700138 positionChildAt(stack, position);
139 mSupervisor.mService.updateSleepIfNeededLocked();
140 }
141
142 void removeChild(ActivityStack stack) {
143 if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack
144 + " from displayId=" + mDisplayId);
145 mStacks.remove(stack);
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700146 removeStackReferenceIfNeeded(stack);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700147 mSupervisor.mService.updateSleepIfNeededLocked();
148 }
149
150 void positionChildAtTop(ActivityStack stack) {
151 positionChildAt(stack, mStacks.size());
152 }
153
154 void positionChildAtBottom(ActivityStack stack) {
155 positionChildAt(stack, 0);
156 }
157
158 private void positionChildAt(ActivityStack stack, int position) {
Winson Chung123e07a2018-02-27 11:47:16 -0800159 // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
160 // the position internally, also update the logic here
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700161 mStacks.remove(stack);
Winson Chung59a47ded2018-01-25 17:46:06 +0000162 final int insertPosition = getTopInsertPosition(stack, position);
163 mStacks.add(insertPosition, stack);
164 mWindowContainerController.positionChildAt(stack.getWindowContainerController(),
165 insertPosition);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700166 }
167
168 private int getTopInsertPosition(ActivityStack stack, int candidatePosition) {
169 int position = mStacks.size();
170 if (position > 0) {
171 final ActivityStack topStack = mStacks.get(position - 1);
172 if (topStack.getWindowConfiguration().isAlwaysOnTop() && topStack != stack) {
173 // If the top stack is always on top, we move this stack just below it.
174 position--;
175 }
176 }
177 return Math.min(position, candidatePosition);
178 }
179
180 <T extends ActivityStack> T getStack(int stackId) {
181 for (int i = mStacks.size() - 1; i >= 0; --i) {
182 final ActivityStack stack = mStacks.get(i);
183 if (stack.mStackId == stackId) {
184 return (T) stack;
185 }
186 }
187 return null;
188 }
189
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700190 /**
191 * @return the topmost stack on the display that is compatible with the input windowing mode and
192 * activity type. {@code null} means no compatible stack on the display.
193 * @see ConfigurationContainer#isCompatible(int, int)
194 */
195 <T extends ActivityStack> T getStack(int windowingMode, int activityType) {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700196 if (activityType == ACTIVITY_TYPE_HOME) {
197 return (T) mHomeStack;
198 } else if (activityType == ACTIVITY_TYPE_RECENTS) {
199 return (T) mRecentsStack;
200 }
201 if (windowingMode == WINDOWING_MODE_PINNED) {
202 return (T) mPinnedStack;
203 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
204 return (T) mSplitScreenPrimaryStack;
205 }
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700206
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700207 for (int i = mStacks.size() - 1; i >= 0; --i) {
208 final ActivityStack stack = mStacks.get(i);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700209 if (stack.isCompatible(windowingMode, activityType)) {
210 return (T) stack;
211 }
212 }
213 return null;
214 }
215
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700216 private boolean alwaysCreateStack(int windowingMode, int activityType) {
217 // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
218 // modes so that we can manage visual ordering and return types correctly.
219 return activityType == ACTIVITY_TYPE_STANDARD
220 && (windowingMode == WINDOWING_MODE_FULLSCREEN
221 || windowingMode == WINDOWING_MODE_FREEFORM
222 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
223 }
224
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700225 /**
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700226 * Returns an existing stack compatible with the windowing mode and activity type or creates one
227 * if a compatible stack doesn't exist.
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700228 * @see #getStack(int, int)
229 * @see #createStack(int, int, boolean)
230 */
231 <T extends ActivityStack> T getOrCreateStack(int windowingMode, int activityType,
232 boolean onTop) {
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700233 if (!alwaysCreateStack(windowingMode, activityType)) {
234 T stack = getStack(windowingMode, activityType);
235 if (stack != null) {
236 return stack;
237 }
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700238 }
239 return createStack(windowingMode, activityType, onTop);
240 }
241
Wale Ogunwale68278562017-09-23 17:13:55 -0700242 /**
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700243 * Returns an existing stack compatible with the input params or creates one
244 * if a compatible stack doesn't exist.
245 * @see #getOrCreateStack(int, int, boolean)
246 */
247 <T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r,
248 @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType,
249 boolean onTop) {
250 final int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType);
251 return getOrCreateStack(windowingMode, activityType, onTop);
252 }
253
Bryce Leed9cce2c2017-12-04 16:16:27 -0800254 private int getNextStackId() {
255 return sNextFreeStackId++;
256 }
257
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700258 /**
Wale Ogunwale68278562017-09-23 17:13:55 -0700259 * Creates a stack matching the input windowing mode and activity type on this display.
260 * @param windowingMode The windowing mode the stack should be created in. If
261 * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
262 * be created in {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}.
263 * @param activityType The activityType the stack should be created in. If
264 * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
265 * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
266 * @param onTop If true the stack will be created at the top of the display, else at the bottom.
267 * @return The newly created stack.
268 */
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700269 <T extends ActivityStack> T createStack(int windowingMode, int activityType, boolean onTop) {
270
Wale Ogunwale68278562017-09-23 17:13:55 -0700271 if (activityType == ACTIVITY_TYPE_UNDEFINED) {
272 // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
273 // anything else should be passing it in anyways...
274 activityType = ACTIVITY_TYPE_STANDARD;
275 }
276
277 if (activityType != ACTIVITY_TYPE_STANDARD) {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700278 // For now there can be only one stack of a particular non-standard activity type on a
279 // display. So, get that ignoring whatever windowing mode it is currently in.
280 T stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
281 if (stack != null) {
282 throw new IllegalArgumentException("Stack=" + stack + " of activityType="
283 + activityType + " already on display=" + this + ". Can't have multiple.");
284 }
285 }
286
287 final ActivityManagerService service = mSupervisor.mService;
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700288 if (!isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow,
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700289 service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement,
290 service.mSupportsPictureInPicture, activityType)) {
291 throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
292 + windowingMode);
293 }
294
295 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
296 // TODO: Should be okay to have stacks with with undefined windowing mode long term, but
297 // have to set them to something for now due to logic that depending on them.
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700298 windowingMode = getWindowingMode(); // Put in current display's windowing mode
299 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
300 // Else fullscreen for now...
301 windowingMode = WINDOWING_MODE_FULLSCREEN;
302 }
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700303 }
304
Bryce Leed9cce2c2017-12-04 16:16:27 -0800305 final int stackId = getNextStackId();
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700306 return createStackUnchecked(windowingMode, activityType, stackId, onTop);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700307 }
308
309 @VisibleForTesting
310 <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
311 int stackId, boolean onTop) {
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700312 if (windowingMode == WINDOWING_MODE_PINNED) {
313 return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700314 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800315 return (T) new ActivityStack(
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700316 this, stackId, mSupervisor, windowingMode, activityType, onTop);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700317 }
318
Wale Ogunwale68278562017-09-23 17:13:55 -0700319 /**
320 * Removes stacks in the input windowing modes from the system if they are of activity type
321 * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
322 */
323 void removeStacksInWindowingModes(int... windowingModes) {
324 if (windowingModes == null || windowingModes.length == 0) {
325 return;
326 }
327
328 for (int j = windowingModes.length - 1 ; j >= 0; --j) {
329 final int windowingMode = windowingModes[j];
330 for (int i = mStacks.size() - 1; i >= 0; --i) {
331 final ActivityStack stack = mStacks.get(i);
332 if (!stack.isActivityTypeStandardOrUndefined()) {
333 continue;
334 }
335 if (stack.getWindowingMode() != windowingMode) {
336 continue;
337 }
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700338 mSupervisor.removeStack(stack);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700339 }
340 }
341 }
342
Wale Ogunwale68278562017-09-23 17:13:55 -0700343 void removeStacksWithActivityTypes(int... activityTypes) {
344 if (activityTypes == null || activityTypes.length == 0) {
345 return;
346 }
347
348 for (int j = activityTypes.length - 1 ; j >= 0; --j) {
349 final int activityType = activityTypes[j];
350 for (int i = mStacks.size() - 1; i >= 0; --i) {
351 final ActivityStack stack = mStacks.get(i);
352 if (stack.getActivityType() == activityType) {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700353 mSupervisor.removeStack(stack);
Wale Ogunwale68278562017-09-23 17:13:55 -0700354 }
355 }
356 }
357 }
358
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700359 void onStackWindowingModeChanged(ActivityStack stack) {
360 removeStackReferenceIfNeeded(stack);
361 addStackReferenceIfNeeded(stack);
362 }
363
364 private void addStackReferenceIfNeeded(ActivityStack stack) {
365 final int activityType = stack.getActivityType();
366 final int windowingMode = stack.getWindowingMode();
367
368 if (activityType == ACTIVITY_TYPE_HOME) {
369 if (mHomeStack != null && mHomeStack != stack) {
370 throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
371 + mHomeStack + " already exist on display=" + this + " stack=" + stack);
372 }
373 mHomeStack = stack;
374 } else if (activityType == ACTIVITY_TYPE_RECENTS) {
375 if (mRecentsStack != null && mRecentsStack != stack) {
376 throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack="
377 + mRecentsStack + " already exist on display=" + this + " stack=" + stack);
378 }
379 mRecentsStack = stack;
380 }
381 if (windowingMode == WINDOWING_MODE_PINNED) {
382 if (mPinnedStack != null && mPinnedStack != stack) {
383 throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack="
384 + mPinnedStack + " already exist on display=" + this
385 + " stack=" + stack);
386 }
387 mPinnedStack = stack;
388 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
389 if (mSplitScreenPrimaryStack != null && mSplitScreenPrimaryStack != stack) {
390 throw new IllegalArgumentException("addStackReferenceIfNeeded:"
391 + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack
392 + " already exist on display=" + this + " stack=" + stack);
393 }
394 mSplitScreenPrimaryStack = stack;
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800395 onSplitScreenModeActivated();
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700396 }
397 }
398
399 private void removeStackReferenceIfNeeded(ActivityStack stack) {
400 if (stack == mHomeStack) {
401 mHomeStack = null;
402 } else if (stack == mRecentsStack) {
403 mRecentsStack = null;
404 } else if (stack == mPinnedStack) {
405 mPinnedStack = null;
406 } else if (stack == mSplitScreenPrimaryStack) {
407 mSplitScreenPrimaryStack = null;
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800408 // Inform the reset of the system that split-screen mode was dismissed so things like
409 // resizing all the other stacks can take place.
410 onSplitScreenModeDismissed();
411 }
412 }
413
414 private void onSplitScreenModeDismissed() {
415 mSupervisor.mWindowManager.deferSurfaceLayout();
416 try {
417 // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
418 for (int i = mStacks.size() - 1; i >= 0; --i) {
419 final ActivityStack otherStack = mStacks.get(i);
420 if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
421 continue;
422 }
Andrii Kulian9da138a2018-04-24 17:12:44 -0700423 otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN, false /* animate */,
424 false /* showRecents */, false /* enteringSplitScreenMode */,
425 true /* deferEnsuringVisibility */);
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800426 }
427 } finally {
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800428 final ActivityStack topFullscreenStack =
Wale Ogunwalef3257852018-01-24 08:52:28 -0800429 getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800430 if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) {
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800431 // Whenever split-screen is dismissed we want the home stack directly behind the
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800432 // current top fullscreen stack so it shows up when the top stack is finished.
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800433 // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
434 // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
435 // once we have that.
436 mHomeStack.moveToFront("onSplitScreenModeDismissed");
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800437 topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800438 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800439 mSupervisor.mWindowManager.continueSurfaceLayout();
440 }
441 }
442
443 private void onSplitScreenModeActivated() {
444 mSupervisor.mWindowManager.deferSurfaceLayout();
445 try {
446 // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
447 for (int i = mStacks.size() - 1; i >= 0; --i) {
448 final ActivityStack otherStack = mStacks.get(i);
449 if (otherStack == mSplitScreenPrimaryStack
450 || !otherStack.affectedBySplitScreenResize()) {
451 continue;
452 }
Wale Ogunwaledf262f52017-12-07 18:17:12 -0800453 otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
454 false /* animate */, false /* showRecents */,
Andrii Kulian9da138a2018-04-24 17:12:44 -0700455 true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */);
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800456 }
457 } finally {
458 mSupervisor.mWindowManager.continueSurfaceLayout();
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700459 }
460 }
461
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700462 /**
463 * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
464 * @param windowingMode The windowing mode we are checking support for.
465 * @param supportsMultiWindow If we should consider support for multi-window mode in general.
466 * @param supportsSplitScreen If we should consider support for split-screen multi-window.
467 * @param supportsFreeform If we should consider support for freeform multi-window.
468 * @param supportsPip If we should consider support for picture-in-picture mutli-window.
469 * @param activityType The activity type under consideration.
470 * @return true if the windowing mode is supported.
471 */
472 private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
473 boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
474 int activityType) {
475
476 if (windowingMode == WINDOWING_MODE_UNDEFINED
477 || windowingMode == WINDOWING_MODE_FULLSCREEN) {
478 return true;
479 }
480 if (!supportsMultiWindow) {
481 return false;
482 }
483
484 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
485 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
Wale Ogunwale2b07da82017-11-08 14:52:40 -0800486 return supportsSplitScreen
487 && WindowConfiguration.supportSplitScreenWindowingMode(activityType);
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700488 }
489
490 if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
491 return false;
492 }
493
494 if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
495 return false;
496 }
497 return true;
498 }
499
500 int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
501 @Nullable TaskRecord task, int activityType) {
502
503 // First preference if the windowing mode in the activity options if set.
504 int windowingMode = (options != null)
505 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
506
507 // If windowing mode is unset, then next preference is the candidate task, then the
508 // activity record.
509 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
510 if (task != null) {
511 windowingMode = task.getWindowingMode();
512 }
513 if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
514 windowingMode = r.getWindowingMode();
515 }
516 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
517 // Use the display's windowing mode.
518 windowingMode = getWindowingMode();
519 }
520 }
521
522 // Make sure the windowing mode we are trying to use makes sense for what is supported.
523 final ActivityManagerService service = mSupervisor.mService;
524 boolean supportsMultiWindow = service.mSupportsMultiWindow;
525 boolean supportsSplitScreen = service.mSupportsSplitScreenMultiWindow;
526 boolean supportsFreeform = service.mSupportsFreeformWindowManagement;
527 boolean supportsPip = service.mSupportsPictureInPicture;
528 if (supportsMultiWindow) {
529 if (task != null) {
530 supportsMultiWindow = task.isResizeable();
531 supportsSplitScreen = task.supportsSplitScreenWindowingMode();
532 // TODO: Do we need to check for freeform and Pip support here?
533 } else if (r != null) {
534 supportsMultiWindow = r.isResizeable();
535 supportsSplitScreen = r.supportsSplitScreenWindowingMode();
536 supportsFreeform = r.supportsFreeform();
537 supportsPip = r.supportsPictureInPicture();
538 }
539 }
540
541 final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
542 if (!inSplitScreenMode
543 && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
544 // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
545 // trying to launch in split-screen secondary.
546 windowingMode = WINDOWING_MODE_FULLSCREEN;
547 } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
548 && supportsSplitScreen) {
549 windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
550 }
551
552 if (windowingMode != WINDOWING_MODE_UNDEFINED
553 && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
554 supportsFreeform, supportsPip, activityType)) {
555 return windowingMode;
556 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800557 // Try to use the display's windowing mode otherwise fallback to fullscreen.
558 windowingMode = getWindowingMode();
559 return windowingMode != WINDOWING_MODE_UNDEFINED
560 ? windowingMode : WINDOWING_MODE_FULLSCREEN;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700561 }
562
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700563 /**
564 * Get the topmost stack on the display. It may be different from focused stack, because
565 * focus may be on another display.
566 */
567 ActivityStack getTopStack() {
568 return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700569 }
570
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700571 boolean isTopStack(ActivityStack stack) {
572 return stack == getTopStack();
573 }
574
chaviw2c500982018-01-04 17:05:05 -0800575 boolean isTopNotPinnedStack(ActivityStack stack) {
Wale Ogunwale2cca8622017-12-11 08:40:13 -0800576 for (int i = mStacks.size() - 1; i >= 0; --i) {
577 final ActivityStack current = mStacks.get(i);
chaviw2c500982018-01-04 17:05:05 -0800578 if (!current.inPinnedWindowingMode()) {
Wale Ogunwale2cca8622017-12-11 08:40:13 -0800579 return current == stack;
580 }
581 }
582 return false;
583 }
584
Wale Ogunwalef3257852018-01-24 08:52:28 -0800585 ActivityStack getTopStackInWindowingMode(int windowingMode) {
586 for (int i = mStacks.size() - 1; i >= 0; --i) {
587 final ActivityStack current = mStacks.get(i);
588 if (windowingMode == current.getWindowingMode()) {
589 return current;
590 }
591 }
592 return null;
593 }
594
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700595 int getIndexOf(ActivityStack stack) {
596 return mStacks.indexOf(stack);
597 }
598
599 void onLockTaskPackagesUpdated() {
600 for (int i = mStacks.size() - 1; i >= 0; --i) {
601 mStacks.get(i).onLockTaskPackagesUpdated();
602 }
603 }
604
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700605 /** We are in the process of exiting split-screen mode. */
606 void onExitingSplitScreenMode() {
607 // Remove reference to the primary-split-screen stack so it no longer has any effect on the
608 // display. For example, we want to be able to create fullscreen stack for standard activity
609 // types when exiting split-screen mode.
610 mSplitScreenPrimaryStack = null;
611 }
612
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700613 ActivityStack getSplitScreenPrimaryStack() {
614 return mSplitScreenPrimaryStack;
615 }
616
617 boolean hasSplitScreenPrimaryStack() {
618 return mSplitScreenPrimaryStack != null;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700619 }
620
621 PinnedActivityStack getPinnedStack() {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700622 return (PinnedActivityStack) mPinnedStack;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700623 }
624
625 boolean hasPinnedStack() {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700626 return mPinnedStack != null;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700627 }
628
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700629 @Override
630 public String toString() {
631 return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
632 }
633
634 @Override
635 protected int getChildCount() {
636 return mStacks.size();
637 }
638
639 @Override
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700640 protected ActivityStack getChildAt(int index) {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700641 return mStacks.get(index);
642 }
643
644 @Override
645 protected ConfigurationContainer getParent() {
646 return mSupervisor;
647 }
648
649 boolean isPrivate() {
650 return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
651 }
652
653 boolean isUidPresent(int uid) {
654 for (ActivityStack stack : mStacks) {
655 if (stack.isUidPresent(uid)) {
656 return true;
657 }
658 }
659 return false;
660 }
661
Bryce Leef19cbe22018-02-02 15:09:21 -0800662 void remove() {
663 final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
664 while (getChildCount() > 0) {
665 final ActivityStack stack = getChildAt(0);
666 if (destroyContentOnRemoval) {
Andrii Kulian823af6e2018-02-28 18:51:36 -0800667 // Override the stack configuration to make it equal to the current applied one, so
668 // that we don't accidentally report configuration change to activities that are
669 // going to be finished.
670 stack.onOverrideConfigurationChanged(stack.getConfiguration());
Bryce Leef19cbe22018-02-02 15:09:21 -0800671 mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY,
672 false /* onTop */);
673 stack.finishAllActivitiesLocked(true /* immediately */);
674 } else {
675 // Moving all tasks to fullscreen stack, because it's guaranteed to be
676 // a valid launch stack for all activities. This way the task history from
677 // external display will be preserved on primary after move.
678 mSupervisor.moveTasksToFullscreenStackLocked(stack, true /* onTop */);
679 }
680 }
681
682 mWindowContainerController.removeContainer();
683 mWindowContainerController = null;
684 }
685
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700686 /** Update and get all UIDs that are present on the display and have access to it. */
687 IntArray getPresentUIDs() {
688 mDisplayAccessUIDs.clear();
689 for (ActivityStack stack : mStacks) {
690 stack.getPresentUIDs(mDisplayAccessUIDs);
691 }
692 return mDisplayAccessUIDs;
693 }
694
Bryce Leef19cbe22018-02-02 15:09:21 -0800695 private boolean shouldDestroyContentOnRemove() {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700696 return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
697 }
698
699 boolean shouldSleep() {
700 return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty())
701 && (mSupervisor.mService.mRunningVoice == null);
702 }
703
Winson Chunge2d72172018-01-25 17:46:20 +0000704 /**
Winson Chung3e2980e2018-03-29 17:28:57 -0700705 * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
706 * already top-most.
Winson Chunge2d72172018-01-25 17:46:20 +0000707 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700708 ActivityStack getStackAbove(ActivityStack stack) {
709 final int stackIndex = mStacks.indexOf(stack) + 1;
Winson Chunge2d72172018-01-25 17:46:20 +0000710 return (stackIndex < mStacks.size()) ? mStacks.get(stackIndex) : null;
711 }
712
713 /**
Winson Chung3e2980e2018-03-29 17:28:57 -0700714 * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
715 * Generally used in conjunction with {@link #moveStackBehindStack}.
Winson Chunge2d72172018-01-25 17:46:20 +0000716 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700717 void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
718 if (stack.shouldBeVisible(null)) {
719 // Skip if the stack is already visible
Winson Chunge2d72172018-01-25 17:46:20 +0000720 return;
721 }
722
Winson Chung3e2980e2018-03-29 17:28:57 -0700723 // Move the stack to the bottom to not affect the following visibility checks
724 positionChildAtBottom(stack);
Winson Chunge2d72172018-01-25 17:46:20 +0000725
Winson Chung3e2980e2018-03-29 17:28:57 -0700726 // Find the next position where the stack should be placed
Winson Chunge2d72172018-01-25 17:46:20 +0000727 final int numStacks = mStacks.size();
728 for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700729 final ActivityStack s = mStacks.get(stackNdx);
730 if (s == stack) {
Winson Chunge2d72172018-01-25 17:46:20 +0000731 continue;
732 }
Winson Chung3e2980e2018-03-29 17:28:57 -0700733 final int winMode = s.getWindowingMode();
Winson Chunge2d72172018-01-25 17:46:20 +0000734 final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN ||
735 winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Winson Chung3e2980e2018-03-29 17:28:57 -0700736 if (s.shouldBeVisible(null) && isValidWindowingMode) {
737 // Move the provided stack to behind this stack
738 positionChildAt(stack, Math.max(0, stackNdx - 1));
Winson Chunge2d72172018-01-25 17:46:20 +0000739 break;
740 }
741 }
742 }
743
744 /**
Winson Chung3e2980e2018-03-29 17:28:57 -0700745 * Moves the {@param stack} behind the given {@param behindStack} if possible. If
746 * {@param behindStack} is not currently in the display, then then the stack is moved to the
747 * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
Winson Chunge2d72172018-01-25 17:46:20 +0000748 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700749 void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
750 if (behindStack == null || behindStack == stack) {
Winson Chunge2d72172018-01-25 17:46:20 +0000751 return;
752 }
753
Winson Chung123e07a2018-02-27 11:47:16 -0800754 // Note that positionChildAt will first remove the given stack before inserting into the
755 // list, so we need to adjust the insertion index to account for the removed index
756 // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
757 // position internally
Winson Chung3e2980e2018-03-29 17:28:57 -0700758 final int stackIndex = mStacks.indexOf(stack);
Winson Chung123e07a2018-02-27 11:47:16 -0800759 final int behindStackIndex = mStacks.indexOf(behindStack);
Winson Chung3e2980e2018-03-29 17:28:57 -0700760 final int insertIndex = stackIndex <= behindStackIndex
Winson Chung123e07a2018-02-27 11:47:16 -0800761 ? behindStackIndex - 1 : behindStackIndex;
Winson Chung3e2980e2018-03-29 17:28:57 -0700762 positionChildAt(stack, Math.max(0, insertIndex));
Winson Chunge2d72172018-01-25 17:46:20 +0000763 }
764
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700765 boolean isSleeping() {
766 return mSleeping;
767 }
768
769 void setIsSleeping(boolean asleep) {
770 mSleeping = asleep;
771 }
772
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700773 public void dump(PrintWriter pw, String prefix) {
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800774 pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size());
775 final String myPrefix = prefix + " ";
776 if (mHomeStack != null) {
777 pw.println(myPrefix + "mHomeStack=" + mHomeStack);
778 }
779 if (mRecentsStack != null) {
780 pw.println(myPrefix + "mRecentsStack=" + mRecentsStack);
781 }
782 if (mPinnedStack != null) {
783 pw.println(myPrefix + "mPinnedStack=" + mPinnedStack);
784 }
785 if (mSplitScreenPrimaryStack != null) {
786 pw.println(myPrefix + "mSplitScreenPrimaryStack=" + mSplitScreenPrimaryStack);
787 }
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700788 }
789
Bryce Lee77a7dd62018-01-22 15:47:09 -0800790 public void dumpStacks(PrintWriter pw) {
791 for (int i = mStacks.size() - 1; i >= 0; --i) {
792 pw.print(mStacks.get(i).mStackId);
793 if (i > 0) {
794 pw.print(",");
795 }
796 }
797 }
798
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700799 public void writeToProto(ProtoOutputStream proto, long fieldId) {
800 final long token = proto.start(fieldId);
Adrian Roos4921ccf2017-09-28 16:54:06 +0200801 super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700802 proto.write(ID, mDisplayId);
803 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
804 final ActivityStack stack = mStacks.get(stackNdx);
805 stack.writeToProto(proto, STACKS);
806 }
807 proto.end(token);
808 }
809}