blob: fac3f92463af1be0fe23ebc1421a5aff2e286581 [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 }
423 otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
424 }
425 } finally {
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800426 final ActivityStack topFullscreenStack =
Wale Ogunwalef3257852018-01-24 08:52:28 -0800427 getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800428 if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) {
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800429 // Whenever split-screen is dismissed we want the home stack directly behind the
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800430 // current top fullscreen stack so it shows up when the top stack is finished.
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800431 // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
432 // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
433 // once we have that.
434 mHomeStack.moveToFront("onSplitScreenModeDismissed");
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800435 topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800436 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800437 mSupervisor.mWindowManager.continueSurfaceLayout();
438 }
439 }
440
441 private void onSplitScreenModeActivated() {
442 mSupervisor.mWindowManager.deferSurfaceLayout();
443 try {
444 // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
445 for (int i = mStacks.size() - 1; i >= 0; --i) {
446 final ActivityStack otherStack = mStacks.get(i);
447 if (otherStack == mSplitScreenPrimaryStack
448 || !otherStack.affectedBySplitScreenResize()) {
449 continue;
450 }
Wale Ogunwaledf262f52017-12-07 18:17:12 -0800451 otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
452 false /* animate */, false /* showRecents */,
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800453 true /* enteringSplitScreenMode */);
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800454 }
455 } finally {
456 mSupervisor.mWindowManager.continueSurfaceLayout();
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700457 }
458 }
459
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700460 /**
461 * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
462 * @param windowingMode The windowing mode we are checking support for.
463 * @param supportsMultiWindow If we should consider support for multi-window mode in general.
464 * @param supportsSplitScreen If we should consider support for split-screen multi-window.
465 * @param supportsFreeform If we should consider support for freeform multi-window.
466 * @param supportsPip If we should consider support for picture-in-picture mutli-window.
467 * @param activityType The activity type under consideration.
468 * @return true if the windowing mode is supported.
469 */
470 private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
471 boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
472 int activityType) {
473
474 if (windowingMode == WINDOWING_MODE_UNDEFINED
475 || windowingMode == WINDOWING_MODE_FULLSCREEN) {
476 return true;
477 }
478 if (!supportsMultiWindow) {
479 return false;
480 }
481
482 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
483 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
Wale Ogunwale2b07da82017-11-08 14:52:40 -0800484 return supportsSplitScreen
485 && WindowConfiguration.supportSplitScreenWindowingMode(activityType);
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700486 }
487
488 if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
489 return false;
490 }
491
492 if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
493 return false;
494 }
495 return true;
496 }
497
498 int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
499 @Nullable TaskRecord task, int activityType) {
500
501 // First preference if the windowing mode in the activity options if set.
502 int windowingMode = (options != null)
503 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
504
505 // If windowing mode is unset, then next preference is the candidate task, then the
506 // activity record.
507 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
508 if (task != null) {
509 windowingMode = task.getWindowingMode();
510 }
511 if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
512 windowingMode = r.getWindowingMode();
513 }
514 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
515 // Use the display's windowing mode.
516 windowingMode = getWindowingMode();
517 }
518 }
519
520 // Make sure the windowing mode we are trying to use makes sense for what is supported.
521 final ActivityManagerService service = mSupervisor.mService;
522 boolean supportsMultiWindow = service.mSupportsMultiWindow;
523 boolean supportsSplitScreen = service.mSupportsSplitScreenMultiWindow;
524 boolean supportsFreeform = service.mSupportsFreeformWindowManagement;
525 boolean supportsPip = service.mSupportsPictureInPicture;
526 if (supportsMultiWindow) {
527 if (task != null) {
528 supportsMultiWindow = task.isResizeable();
529 supportsSplitScreen = task.supportsSplitScreenWindowingMode();
530 // TODO: Do we need to check for freeform and Pip support here?
531 } else if (r != null) {
532 supportsMultiWindow = r.isResizeable();
533 supportsSplitScreen = r.supportsSplitScreenWindowingMode();
534 supportsFreeform = r.supportsFreeform();
535 supportsPip = r.supportsPictureInPicture();
536 }
537 }
538
539 final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
540 if (!inSplitScreenMode
541 && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
542 // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
543 // trying to launch in split-screen secondary.
544 windowingMode = WINDOWING_MODE_FULLSCREEN;
545 } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
546 && supportsSplitScreen) {
547 windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
548 }
549
550 if (windowingMode != WINDOWING_MODE_UNDEFINED
551 && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
552 supportsFreeform, supportsPip, activityType)) {
553 return windowingMode;
554 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800555 // Try to use the display's windowing mode otherwise fallback to fullscreen.
556 windowingMode = getWindowingMode();
557 return windowingMode != WINDOWING_MODE_UNDEFINED
558 ? windowingMode : WINDOWING_MODE_FULLSCREEN;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700559 }
560
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700561 /**
562 * Get the topmost stack on the display. It may be different from focused stack, because
563 * focus may be on another display.
564 */
565 ActivityStack getTopStack() {
566 return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700567 }
568
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700569 boolean isTopStack(ActivityStack stack) {
570 return stack == getTopStack();
571 }
572
chaviw2c500982018-01-04 17:05:05 -0800573 boolean isTopNotPinnedStack(ActivityStack stack) {
Wale Ogunwale2cca8622017-12-11 08:40:13 -0800574 for (int i = mStacks.size() - 1; i >= 0; --i) {
575 final ActivityStack current = mStacks.get(i);
chaviw2c500982018-01-04 17:05:05 -0800576 if (!current.inPinnedWindowingMode()) {
Wale Ogunwale2cca8622017-12-11 08:40:13 -0800577 return current == stack;
578 }
579 }
580 return false;
581 }
582
Wale Ogunwalef3257852018-01-24 08:52:28 -0800583 ActivityStack getTopStackInWindowingMode(int windowingMode) {
584 for (int i = mStacks.size() - 1; i >= 0; --i) {
585 final ActivityStack current = mStacks.get(i);
586 if (windowingMode == current.getWindowingMode()) {
587 return current;
588 }
589 }
590 return null;
591 }
592
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700593 int getIndexOf(ActivityStack stack) {
594 return mStacks.indexOf(stack);
595 }
596
597 void onLockTaskPackagesUpdated() {
598 for (int i = mStacks.size() - 1; i >= 0; --i) {
599 mStacks.get(i).onLockTaskPackagesUpdated();
600 }
601 }
602
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700603 /** We are in the process of exiting split-screen mode. */
604 void onExitingSplitScreenMode() {
605 // Remove reference to the primary-split-screen stack so it no longer has any effect on the
606 // display. For example, we want to be able to create fullscreen stack for standard activity
607 // types when exiting split-screen mode.
608 mSplitScreenPrimaryStack = null;
609 }
610
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700611 ActivityStack getSplitScreenPrimaryStack() {
612 return mSplitScreenPrimaryStack;
613 }
614
615 boolean hasSplitScreenPrimaryStack() {
616 return mSplitScreenPrimaryStack != null;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700617 }
618
619 PinnedActivityStack getPinnedStack() {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700620 return (PinnedActivityStack) mPinnedStack;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700621 }
622
623 boolean hasPinnedStack() {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700624 return mPinnedStack != null;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700625 }
626
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700627 @Override
628 public String toString() {
629 return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
630 }
631
632 @Override
633 protected int getChildCount() {
634 return mStacks.size();
635 }
636
637 @Override
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700638 protected ActivityStack getChildAt(int index) {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700639 return mStacks.get(index);
640 }
641
642 @Override
643 protected ConfigurationContainer getParent() {
644 return mSupervisor;
645 }
646
647 boolean isPrivate() {
648 return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
649 }
650
651 boolean isUidPresent(int uid) {
652 for (ActivityStack stack : mStacks) {
653 if (stack.isUidPresent(uid)) {
654 return true;
655 }
656 }
657 return false;
658 }
659
Bryce Leef19cbe22018-02-02 15:09:21 -0800660 void remove() {
661 final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
662 while (getChildCount() > 0) {
663 final ActivityStack stack = getChildAt(0);
664 if (destroyContentOnRemoval) {
Andrii Kulian823af6e2018-02-28 18:51:36 -0800665 // Override the stack configuration to make it equal to the current applied one, so
666 // that we don't accidentally report configuration change to activities that are
667 // going to be finished.
668 stack.onOverrideConfigurationChanged(stack.getConfiguration());
Bryce Leef19cbe22018-02-02 15:09:21 -0800669 mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY,
670 false /* onTop */);
671 stack.finishAllActivitiesLocked(true /* immediately */);
672 } else {
673 // Moving all tasks to fullscreen stack, because it's guaranteed to be
674 // a valid launch stack for all activities. This way the task history from
675 // external display will be preserved on primary after move.
676 mSupervisor.moveTasksToFullscreenStackLocked(stack, true /* onTop */);
677 }
678 }
679
680 mWindowContainerController.removeContainer();
681 mWindowContainerController = null;
682 }
683
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700684 /** Update and get all UIDs that are present on the display and have access to it. */
685 IntArray getPresentUIDs() {
686 mDisplayAccessUIDs.clear();
687 for (ActivityStack stack : mStacks) {
688 stack.getPresentUIDs(mDisplayAccessUIDs);
689 }
690 return mDisplayAccessUIDs;
691 }
692
Bryce Leef19cbe22018-02-02 15:09:21 -0800693 private boolean shouldDestroyContentOnRemove() {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700694 return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
695 }
696
697 boolean shouldSleep() {
698 return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty())
699 && (mSupervisor.mService.mRunningVoice == null);
700 }
701
Winson Chunge2d72172018-01-25 17:46:20 +0000702 /**
Winson Chung3e2980e2018-03-29 17:28:57 -0700703 * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
704 * already top-most.
Winson Chunge2d72172018-01-25 17:46:20 +0000705 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700706 ActivityStack getStackAbove(ActivityStack stack) {
707 final int stackIndex = mStacks.indexOf(stack) + 1;
Winson Chunge2d72172018-01-25 17:46:20 +0000708 return (stackIndex < mStacks.size()) ? mStacks.get(stackIndex) : null;
709 }
710
711 /**
Winson Chung3e2980e2018-03-29 17:28:57 -0700712 * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
713 * Generally used in conjunction with {@link #moveStackBehindStack}.
Winson Chunge2d72172018-01-25 17:46:20 +0000714 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700715 void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
716 if (stack.shouldBeVisible(null)) {
717 // Skip if the stack is already visible
Winson Chunge2d72172018-01-25 17:46:20 +0000718 return;
719 }
720
Winson Chung3e2980e2018-03-29 17:28:57 -0700721 // Move the stack to the bottom to not affect the following visibility checks
722 positionChildAtBottom(stack);
Winson Chunge2d72172018-01-25 17:46:20 +0000723
Winson Chung3e2980e2018-03-29 17:28:57 -0700724 // Find the next position where the stack should be placed
Winson Chunge2d72172018-01-25 17:46:20 +0000725 final int numStacks = mStacks.size();
726 for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700727 final ActivityStack s = mStacks.get(stackNdx);
728 if (s == stack) {
Winson Chunge2d72172018-01-25 17:46:20 +0000729 continue;
730 }
Winson Chung3e2980e2018-03-29 17:28:57 -0700731 final int winMode = s.getWindowingMode();
Winson Chunge2d72172018-01-25 17:46:20 +0000732 final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN ||
733 winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Winson Chung3e2980e2018-03-29 17:28:57 -0700734 if (s.shouldBeVisible(null) && isValidWindowingMode) {
735 // Move the provided stack to behind this stack
736 positionChildAt(stack, Math.max(0, stackNdx - 1));
Winson Chunge2d72172018-01-25 17:46:20 +0000737 break;
738 }
739 }
740 }
741
742 /**
Winson Chung3e2980e2018-03-29 17:28:57 -0700743 * Moves the {@param stack} behind the given {@param behindStack} if possible. If
744 * {@param behindStack} is not currently in the display, then then the stack is moved to the
745 * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
Winson Chunge2d72172018-01-25 17:46:20 +0000746 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700747 void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
748 if (behindStack == null || behindStack == stack) {
Winson Chunge2d72172018-01-25 17:46:20 +0000749 return;
750 }
751
Winson Chung123e07a2018-02-27 11:47:16 -0800752 // Note that positionChildAt will first remove the given stack before inserting into the
753 // list, so we need to adjust the insertion index to account for the removed index
754 // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
755 // position internally
Winson Chung3e2980e2018-03-29 17:28:57 -0700756 final int stackIndex = mStacks.indexOf(stack);
Winson Chung123e07a2018-02-27 11:47:16 -0800757 final int behindStackIndex = mStacks.indexOf(behindStack);
Winson Chung3e2980e2018-03-29 17:28:57 -0700758 final int insertIndex = stackIndex <= behindStackIndex
Winson Chung123e07a2018-02-27 11:47:16 -0800759 ? behindStackIndex - 1 : behindStackIndex;
Winson Chung3e2980e2018-03-29 17:28:57 -0700760 positionChildAt(stack, Math.max(0, insertIndex));
Winson Chunge2d72172018-01-25 17:46:20 +0000761 }
762
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700763 boolean isSleeping() {
764 return mSleeping;
765 }
766
767 void setIsSleeping(boolean asleep) {
768 mSleeping = asleep;
769 }
770
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700771 public void dump(PrintWriter pw, String prefix) {
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800772 pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size());
773 final String myPrefix = prefix + " ";
774 if (mHomeStack != null) {
775 pw.println(myPrefix + "mHomeStack=" + mHomeStack);
776 }
777 if (mRecentsStack != null) {
778 pw.println(myPrefix + "mRecentsStack=" + mRecentsStack);
779 }
780 if (mPinnedStack != null) {
781 pw.println(myPrefix + "mPinnedStack=" + mPinnedStack);
782 }
783 if (mSplitScreenPrimaryStack != null) {
784 pw.println(myPrefix + "mSplitScreenPrimaryStack=" + mSplitScreenPrimaryStack);
785 }
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700786 }
787
Bryce Lee77a7dd62018-01-22 15:47:09 -0800788 public void dumpStacks(PrintWriter pw) {
789 for (int i = mStacks.size() - 1; i >= 0; --i) {
790 pw.print(mStacks.get(i).mStackId);
791 if (i > 0) {
792 pw.print(",");
793 }
794 }
795 }
796
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700797 public void writeToProto(ProtoOutputStream proto, long fieldId) {
798 final long token = proto.start(fieldId);
Adrian Roos4921ccf2017-09-28 16:54:06 +0200799 super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700800 proto.write(ID, mDisplayId);
801 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
802 final ActivityStack stack = mStacks.get(stackNdx);
803 stack.writeToProto(proto, STACKS);
804 }
805 proto.end(token);
806 }
807}