blob: 9bfdd0c5009c66dd6b62600b4ce218cb7854c912 [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;
37import static com.android.server.am.proto.ActivityDisplayProto.CONFIGURATION_CONTAINER;
38import static com.android.server.am.proto.ActivityDisplayProto.STACKS;
39import static com.android.server.am.proto.ActivityDisplayProto.ID;
40
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;
46import android.graphics.Rect;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070047import android.util.IntArray;
48import android.util.Slog;
49import android.util.proto.ProtoOutputStream;
50import android.view.Display;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070051import com.android.internal.annotations.VisibleForTesting;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070052import com.android.server.wm.ConfigurationContainer;
53
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070054import java.io.PrintWriter;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070055import java.util.ArrayList;
56
57/**
58 * Exactly one of these classes per Display in the system. Capable of holding zero or more
59 * attached {@link ActivityStack}s.
60 */
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070061class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070062 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_AM;
63 private static final String TAG_STACK = TAG + POSTFIX_STACK;
64
65 static final int POSITION_TOP = Integer.MAX_VALUE;
66 static final int POSITION_BOTTOM = Integer.MIN_VALUE;
67
Bryce Leed9cce2c2017-12-04 16:16:27 -080068
69 /**
70 * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
71 */
72 private static int sNextFreeStackId = 0;
73
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070074 private ActivityStackSupervisor mSupervisor;
75 /** Actual Display this object tracks. */
76 int mDisplayId;
77 Display mDisplay;
78
79 /** All of the stacks on this display. Order matters, topmost stack is in front of all other
80 * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070081 private final ArrayList<ActivityStack> mStacks = new ArrayList<>();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070082
83 /** Array of all UIDs that are present on the display. */
84 private IntArray mDisplayAccessUIDs = new IntArray();
85
86 /** All tokens used to put activities on this stack to sleep (including mOffToken) */
87 final ArrayList<ActivityManagerInternal.SleepToken> mAllSleepTokens = new ArrayList<>();
88 /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */
89 ActivityManagerInternal.SleepToken mOffToken;
90
91 private boolean mSleeping;
92
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070093 // Cached reference to some special stacks we tend to get a lot so we don't need to loop
94 // through the list to find them.
95 private ActivityStack mHomeStack = null;
96 private ActivityStack mRecentsStack = null;
97 private ActivityStack mPinnedStack = null;
98 private ActivityStack mSplitScreenPrimaryStack = null;
99
Bryce Leef3c6a472017-11-14 14:53:06 -0800100 // Used in updating the display size
101 private Point mTmpDisplaySize = new Point();
102
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700103 ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
104 mSupervisor = supervisor;
105 mDisplayId = displayId;
106 final Display display = supervisor.mDisplayManager.getDisplay(displayId);
107 if (display == null) {
108 throw new IllegalStateException("Display does not exist displayId=" + displayId);
109 }
110 mDisplay = display;
Bryce Leef3c6a472017-11-14 14:53:06 -0800111
112 updateBounds();
113 }
114
115 void updateBounds() {
116 mDisplay.getSize(mTmpDisplaySize);
117 setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700118 }
119
120 void addChild(ActivityStack stack, int position) {
121 if (position == POSITION_BOTTOM) {
122 position = 0;
123 } else if (position == POSITION_TOP) {
124 position = mStacks.size();
125 }
126 if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack
127 + " to displayId=" + mDisplayId + " position=" + position);
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700128 addStackReferenceIfNeeded(stack);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700129 positionChildAt(stack, position);
130 mSupervisor.mService.updateSleepIfNeededLocked();
131 }
132
133 void removeChild(ActivityStack stack) {
134 if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack
135 + " from displayId=" + mDisplayId);
136 mStacks.remove(stack);
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700137 removeStackReferenceIfNeeded(stack);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700138 mSupervisor.mService.updateSleepIfNeededLocked();
139 }
140
141 void positionChildAtTop(ActivityStack stack) {
142 positionChildAt(stack, mStacks.size());
143 }
144
145 void positionChildAtBottom(ActivityStack stack) {
146 positionChildAt(stack, 0);
147 }
148
149 private void positionChildAt(ActivityStack stack, int position) {
150 mStacks.remove(stack);
151 mStacks.add(getTopInsertPosition(stack, position), stack);
152 }
153
154 private int getTopInsertPosition(ActivityStack stack, int candidatePosition) {
155 int position = mStacks.size();
156 if (position > 0) {
157 final ActivityStack topStack = mStacks.get(position - 1);
158 if (topStack.getWindowConfiguration().isAlwaysOnTop() && topStack != stack) {
159 // If the top stack is always on top, we move this stack just below it.
160 position--;
161 }
162 }
163 return Math.min(position, candidatePosition);
164 }
165
166 <T extends ActivityStack> T getStack(int stackId) {
167 for (int i = mStacks.size() - 1; i >= 0; --i) {
168 final ActivityStack stack = mStacks.get(i);
169 if (stack.mStackId == stackId) {
170 return (T) stack;
171 }
172 }
173 return null;
174 }
175
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700176 /**
177 * @return the topmost stack on the display that is compatible with the input windowing mode and
178 * activity type. {@code null} means no compatible stack on the display.
179 * @see ConfigurationContainer#isCompatible(int, int)
180 */
181 <T extends ActivityStack> T getStack(int windowingMode, int activityType) {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700182 if (activityType == ACTIVITY_TYPE_HOME) {
183 return (T) mHomeStack;
184 } else if (activityType == ACTIVITY_TYPE_RECENTS) {
185 return (T) mRecentsStack;
186 }
187 if (windowingMode == WINDOWING_MODE_PINNED) {
188 return (T) mPinnedStack;
189 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
190 return (T) mSplitScreenPrimaryStack;
191 }
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700192
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700193 for (int i = mStacks.size() - 1; i >= 0; --i) {
194 final ActivityStack stack = mStacks.get(i);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700195 if (stack.isCompatible(windowingMode, activityType)) {
196 return (T) stack;
197 }
198 }
199 return null;
200 }
201
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700202 private boolean alwaysCreateStack(int windowingMode, int activityType) {
203 // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
204 // modes so that we can manage visual ordering and return types correctly.
205 return activityType == ACTIVITY_TYPE_STANDARD
206 && (windowingMode == WINDOWING_MODE_FULLSCREEN
207 || windowingMode == WINDOWING_MODE_FREEFORM
208 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
209 }
210
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700211 /**
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700212 * Returns an existing stack compatible with the windowing mode and activity type or creates one
213 * if a compatible stack doesn't exist.
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700214 * @see #getStack(int, int)
215 * @see #createStack(int, int, boolean)
216 */
217 <T extends ActivityStack> T getOrCreateStack(int windowingMode, int activityType,
218 boolean onTop) {
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700219 if (!alwaysCreateStack(windowingMode, activityType)) {
220 T stack = getStack(windowingMode, activityType);
221 if (stack != null) {
222 return stack;
223 }
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700224 }
225 return createStack(windowingMode, activityType, onTop);
226 }
227
Wale Ogunwale68278562017-09-23 17:13:55 -0700228 /**
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700229 * Returns an existing stack compatible with the input params or creates one
230 * if a compatible stack doesn't exist.
231 * @see #getOrCreateStack(int, int, boolean)
232 */
233 <T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r,
234 @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType,
235 boolean onTop) {
236 final int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType);
237 return getOrCreateStack(windowingMode, activityType, onTop);
238 }
239
Bryce Leed9cce2c2017-12-04 16:16:27 -0800240 private int getNextStackId() {
241 return sNextFreeStackId++;
242 }
243
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700244 /**
Wale Ogunwale68278562017-09-23 17:13:55 -0700245 * Creates a stack matching the input windowing mode and activity type on this display.
246 * @param windowingMode The windowing mode the stack should be created in. If
247 * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
248 * be created in {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}.
249 * @param activityType The activityType the stack should be created in. If
250 * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
251 * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
252 * @param onTop If true the stack will be created at the top of the display, else at the bottom.
253 * @return The newly created stack.
254 */
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700255 <T extends ActivityStack> T createStack(int windowingMode, int activityType, boolean onTop) {
256
Wale Ogunwale68278562017-09-23 17:13:55 -0700257 if (activityType == ACTIVITY_TYPE_UNDEFINED) {
258 // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
259 // anything else should be passing it in anyways...
260 activityType = ACTIVITY_TYPE_STANDARD;
261 }
262
263 if (activityType != ACTIVITY_TYPE_STANDARD) {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700264 // For now there can be only one stack of a particular non-standard activity type on a
265 // display. So, get that ignoring whatever windowing mode it is currently in.
266 T stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
267 if (stack != null) {
268 throw new IllegalArgumentException("Stack=" + stack + " of activityType="
269 + activityType + " already on display=" + this + ". Can't have multiple.");
270 }
271 }
272
273 final ActivityManagerService service = mSupervisor.mService;
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700274 if (!isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow,
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700275 service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement,
276 service.mSupportsPictureInPicture, activityType)) {
277 throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
278 + windowingMode);
279 }
280
281 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
282 // TODO: Should be okay to have stacks with with undefined windowing mode long term, but
283 // have to set them to something for now due to logic that depending on them.
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700284 windowingMode = getWindowingMode(); // Put in current display's windowing mode
285 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
286 // Else fullscreen for now...
287 windowingMode = WINDOWING_MODE_FULLSCREEN;
288 }
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700289 }
290
Bryce Leed9cce2c2017-12-04 16:16:27 -0800291 final int stackId = getNextStackId();
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700292 return createStackUnchecked(windowingMode, activityType, stackId, onTop);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700293 }
294
295 @VisibleForTesting
296 <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
297 int stackId, boolean onTop) {
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700298 if (windowingMode == WINDOWING_MODE_PINNED) {
299 return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700300 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800301 return (T) new ActivityStack(
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700302 this, stackId, mSupervisor, windowingMode, activityType, onTop);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700303 }
304
Wale Ogunwale68278562017-09-23 17:13:55 -0700305 /**
306 * Removes stacks in the input windowing modes from the system if they are of activity type
307 * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
308 */
309 void removeStacksInWindowingModes(int... windowingModes) {
310 if (windowingModes == null || windowingModes.length == 0) {
311 return;
312 }
313
314 for (int j = windowingModes.length - 1 ; j >= 0; --j) {
315 final int windowingMode = windowingModes[j];
316 for (int i = mStacks.size() - 1; i >= 0; --i) {
317 final ActivityStack stack = mStacks.get(i);
318 if (!stack.isActivityTypeStandardOrUndefined()) {
319 continue;
320 }
321 if (stack.getWindowingMode() != windowingMode) {
322 continue;
323 }
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700324 mSupervisor.removeStack(stack);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700325 }
326 }
327 }
328
Wale Ogunwale68278562017-09-23 17:13:55 -0700329 void removeStacksWithActivityTypes(int... activityTypes) {
330 if (activityTypes == null || activityTypes.length == 0) {
331 return;
332 }
333
334 for (int j = activityTypes.length - 1 ; j >= 0; --j) {
335 final int activityType = activityTypes[j];
336 for (int i = mStacks.size() - 1; i >= 0; --i) {
337 final ActivityStack stack = mStacks.get(i);
338 if (stack.getActivityType() == activityType) {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700339 mSupervisor.removeStack(stack);
Wale Ogunwale68278562017-09-23 17:13:55 -0700340 }
341 }
342 }
343 }
344
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700345 void onStackWindowingModeChanged(ActivityStack stack) {
346 removeStackReferenceIfNeeded(stack);
347 addStackReferenceIfNeeded(stack);
348 }
349
350 private void addStackReferenceIfNeeded(ActivityStack stack) {
351 final int activityType = stack.getActivityType();
352 final int windowingMode = stack.getWindowingMode();
353
354 if (activityType == ACTIVITY_TYPE_HOME) {
355 if (mHomeStack != null && mHomeStack != stack) {
356 throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
357 + mHomeStack + " already exist on display=" + this + " stack=" + stack);
358 }
359 mHomeStack = stack;
360 } else if (activityType == ACTIVITY_TYPE_RECENTS) {
361 if (mRecentsStack != null && mRecentsStack != stack) {
362 throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack="
363 + mRecentsStack + " already exist on display=" + this + " stack=" + stack);
364 }
365 mRecentsStack = stack;
366 }
367 if (windowingMode == WINDOWING_MODE_PINNED) {
368 if (mPinnedStack != null && mPinnedStack != stack) {
369 throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack="
370 + mPinnedStack + " already exist on display=" + this
371 + " stack=" + stack);
372 }
373 mPinnedStack = stack;
374 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
375 if (mSplitScreenPrimaryStack != null && mSplitScreenPrimaryStack != stack) {
376 throw new IllegalArgumentException("addStackReferenceIfNeeded:"
377 + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack
378 + " already exist on display=" + this + " stack=" + stack);
379 }
380 mSplitScreenPrimaryStack = stack;
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800381 onSplitScreenModeActivated();
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700382 }
383 }
384
385 private void removeStackReferenceIfNeeded(ActivityStack stack) {
386 if (stack == mHomeStack) {
387 mHomeStack = null;
388 } else if (stack == mRecentsStack) {
389 mRecentsStack = null;
390 } else if (stack == mPinnedStack) {
391 mPinnedStack = null;
392 } else if (stack == mSplitScreenPrimaryStack) {
393 mSplitScreenPrimaryStack = null;
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800394 // Inform the reset of the system that split-screen mode was dismissed so things like
395 // resizing all the other stacks can take place.
396 onSplitScreenModeDismissed();
397 }
398 }
399
400 private void onSplitScreenModeDismissed() {
401 mSupervisor.mWindowManager.deferSurfaceLayout();
402 try {
403 // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
404 for (int i = mStacks.size() - 1; i >= 0; --i) {
405 final ActivityStack otherStack = mStacks.get(i);
406 if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
407 continue;
408 }
409 otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
410 }
411 } finally {
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800412 if (mHomeStack != null && !isTopStack(mHomeStack)) {
413 // Whenever split-screen is dismissed we want the home stack directly behind the
414 // currently top stack so it shows up when the top stack is finished.
415 final ActivityStack topStack = getTopStack();
416 // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
417 // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
418 // once we have that.
419 mHomeStack.moveToFront("onSplitScreenModeDismissed");
420 topStack.moveToFront("onSplitScreenModeDismissed");
421 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800422 mSupervisor.mWindowManager.continueSurfaceLayout();
423 }
424 }
425
426 private void onSplitScreenModeActivated() {
427 mSupervisor.mWindowManager.deferSurfaceLayout();
428 try {
429 // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
430 for (int i = mStacks.size() - 1; i >= 0; --i) {
431 final ActivityStack otherStack = mStacks.get(i);
432 if (otherStack == mSplitScreenPrimaryStack
433 || !otherStack.affectedBySplitScreenResize()) {
434 continue;
435 }
Wale Ogunwaledf262f52017-12-07 18:17:12 -0800436 otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
437 false /* animate */, false /* showRecents */,
438 false /* sendNonResizeableNotification */);
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800439 }
440 } finally {
441 mSupervisor.mWindowManager.continueSurfaceLayout();
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700442 }
443 }
444
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700445 /**
446 * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
447 * @param windowingMode The windowing mode we are checking support for.
448 * @param supportsMultiWindow If we should consider support for multi-window mode in general.
449 * @param supportsSplitScreen If we should consider support for split-screen multi-window.
450 * @param supportsFreeform If we should consider support for freeform multi-window.
451 * @param supportsPip If we should consider support for picture-in-picture mutli-window.
452 * @param activityType The activity type under consideration.
453 * @return true if the windowing mode is supported.
454 */
455 private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
456 boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
457 int activityType) {
458
459 if (windowingMode == WINDOWING_MODE_UNDEFINED
460 || windowingMode == WINDOWING_MODE_FULLSCREEN) {
461 return true;
462 }
463 if (!supportsMultiWindow) {
464 return false;
465 }
466
467 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
468 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
Wale Ogunwale2b07da82017-11-08 14:52:40 -0800469 return supportsSplitScreen
470 && WindowConfiguration.supportSplitScreenWindowingMode(activityType);
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700471 }
472
473 if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
474 return false;
475 }
476
477 if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
478 return false;
479 }
480 return true;
481 }
482
483 int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
484 @Nullable TaskRecord task, int activityType) {
485
486 // First preference if the windowing mode in the activity options if set.
487 int windowingMode = (options != null)
488 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
489
490 // If windowing mode is unset, then next preference is the candidate task, then the
491 // activity record.
492 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
493 if (task != null) {
494 windowingMode = task.getWindowingMode();
495 }
496 if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
497 windowingMode = r.getWindowingMode();
498 }
499 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
500 // Use the display's windowing mode.
501 windowingMode = getWindowingMode();
502 }
503 }
504
505 // Make sure the windowing mode we are trying to use makes sense for what is supported.
506 final ActivityManagerService service = mSupervisor.mService;
507 boolean supportsMultiWindow = service.mSupportsMultiWindow;
508 boolean supportsSplitScreen = service.mSupportsSplitScreenMultiWindow;
509 boolean supportsFreeform = service.mSupportsFreeformWindowManagement;
510 boolean supportsPip = service.mSupportsPictureInPicture;
511 if (supportsMultiWindow) {
512 if (task != null) {
513 supportsMultiWindow = task.isResizeable();
514 supportsSplitScreen = task.supportsSplitScreenWindowingMode();
515 // TODO: Do we need to check for freeform and Pip support here?
516 } else if (r != null) {
517 supportsMultiWindow = r.isResizeable();
518 supportsSplitScreen = r.supportsSplitScreenWindowingMode();
519 supportsFreeform = r.supportsFreeform();
520 supportsPip = r.supportsPictureInPicture();
521 }
522 }
523
524 final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
525 if (!inSplitScreenMode
526 && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
527 // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
528 // trying to launch in split-screen secondary.
529 windowingMode = WINDOWING_MODE_FULLSCREEN;
530 } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
531 && supportsSplitScreen) {
532 windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
533 }
534
535 if (windowingMode != WINDOWING_MODE_UNDEFINED
536 && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
537 supportsFreeform, supportsPip, activityType)) {
538 return windowingMode;
539 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800540 // Try to use the display's windowing mode otherwise fallback to fullscreen.
541 windowingMode = getWindowingMode();
542 return windowingMode != WINDOWING_MODE_UNDEFINED
543 ? windowingMode : WINDOWING_MODE_FULLSCREEN;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700544 }
545
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700546 /**
547 * Get the topmost stack on the display. It may be different from focused stack, because
548 * focus may be on another display.
549 */
550 ActivityStack getTopStack() {
551 return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700552 }
553
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700554 boolean isTopStack(ActivityStack stack) {
555 return stack == getTopStack();
556 }
557
558 int getIndexOf(ActivityStack stack) {
559 return mStacks.indexOf(stack);
560 }
561
562 void onLockTaskPackagesUpdated() {
563 for (int i = mStacks.size() - 1; i >= 0; --i) {
564 mStacks.get(i).onLockTaskPackagesUpdated();
565 }
566 }
567
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700568 /** We are in the process of exiting split-screen mode. */
569 void onExitingSplitScreenMode() {
570 // Remove reference to the primary-split-screen stack so it no longer has any effect on the
571 // display. For example, we want to be able to create fullscreen stack for standard activity
572 // types when exiting split-screen mode.
573 mSplitScreenPrimaryStack = null;
574 }
575
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700576 ActivityStack getSplitScreenPrimaryStack() {
577 return mSplitScreenPrimaryStack;
578 }
579
580 boolean hasSplitScreenPrimaryStack() {
581 return mSplitScreenPrimaryStack != null;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700582 }
583
584 PinnedActivityStack getPinnedStack() {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700585 return (PinnedActivityStack) mPinnedStack;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700586 }
587
588 boolean hasPinnedStack() {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700589 return mPinnedStack != null;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700590 }
591
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700592 @Override
593 public String toString() {
594 return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
595 }
596
597 @Override
598 protected int getChildCount() {
599 return mStacks.size();
600 }
601
602 @Override
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700603 protected ActivityStack getChildAt(int index) {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700604 return mStacks.get(index);
605 }
606
607 @Override
608 protected ConfigurationContainer getParent() {
609 return mSupervisor;
610 }
611
612 boolean isPrivate() {
613 return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
614 }
615
616 boolean isUidPresent(int uid) {
617 for (ActivityStack stack : mStacks) {
618 if (stack.isUidPresent(uid)) {
619 return true;
620 }
621 }
622 return false;
623 }
624
625 /** Update and get all UIDs that are present on the display and have access to it. */
626 IntArray getPresentUIDs() {
627 mDisplayAccessUIDs.clear();
628 for (ActivityStack stack : mStacks) {
629 stack.getPresentUIDs(mDisplayAccessUIDs);
630 }
631 return mDisplayAccessUIDs;
632 }
633
634 boolean shouldDestroyContentOnRemove() {
635 return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
636 }
637
638 boolean shouldSleep() {
639 return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty())
640 && (mSupervisor.mService.mRunningVoice == null);
641 }
642
643 boolean isSleeping() {
644 return mSleeping;
645 }
646
647 void setIsSleeping(boolean asleep) {
648 mSleeping = asleep;
649 }
650
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700651 public void dump(PrintWriter pw, String prefix) {
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800652 pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size());
653 final String myPrefix = prefix + " ";
654 if (mHomeStack != null) {
655 pw.println(myPrefix + "mHomeStack=" + mHomeStack);
656 }
657 if (mRecentsStack != null) {
658 pw.println(myPrefix + "mRecentsStack=" + mRecentsStack);
659 }
660 if (mPinnedStack != null) {
661 pw.println(myPrefix + "mPinnedStack=" + mPinnedStack);
662 }
663 if (mSplitScreenPrimaryStack != null) {
664 pw.println(myPrefix + "mSplitScreenPrimaryStack=" + mSplitScreenPrimaryStack);
665 }
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700666 }
667
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700668 public void writeToProto(ProtoOutputStream proto, long fieldId) {
669 final long token = proto.start(fieldId);
Adrian Roos4921ccf2017-09-28 16:54:06 +0200670 super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700671 proto.write(ID, mDisplayId);
672 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
673 final ActivityStack stack = mStacks.get(stackNdx);
674 stack.writeToProto(proto, STACKS);
675 }
676 proto.end(token);
677 }
678}