blob: 698b6f7d99f2dcac8f49681e54dfcd61cd53ee5e [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
Winson Chung0f7ec962018-05-03 18:03:15 -070081 /**
82 * All of the stacks on this display. Order matters, topmost stack is in front of all other
83 * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
84 * changing the list should also call {@link #onStackOrderChanged()}.
85 */
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070086 private final ArrayList<ActivityStack> mStacks = new ArrayList<>();
Winson Chung0f7ec962018-05-03 18:03:15 -070087 private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070088
89 /** Array of all UIDs that are present on the display. */
90 private IntArray mDisplayAccessUIDs = new IntArray();
91
92 /** All tokens used to put activities on this stack to sleep (including mOffToken) */
93 final ArrayList<ActivityManagerInternal.SleepToken> mAllSleepTokens = new ArrayList<>();
94 /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */
95 ActivityManagerInternal.SleepToken mOffToken;
96
97 private boolean mSleeping;
98
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070099 // Cached reference to some special stacks we tend to get a lot so we don't need to loop
100 // through the list to find them.
101 private ActivityStack mHomeStack = null;
102 private ActivityStack mRecentsStack = null;
103 private ActivityStack mPinnedStack = null;
104 private ActivityStack mSplitScreenPrimaryStack = null;
105
Bryce Leef3c6a472017-11-14 14:53:06 -0800106 // Used in updating the display size
107 private Point mTmpDisplaySize = new Point();
108
Winson Chung59a47ded2018-01-25 17:46:06 +0000109 private DisplayWindowController mWindowContainerController;
110
Wale Ogunwale45477b52018-03-06 12:24:19 -0800111 @VisibleForTesting
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700112 ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
Wale Ogunwale45477b52018-03-06 12:24:19 -0800113 this(supervisor, supervisor.mDisplayManager.getDisplay(displayId));
114 }
115
116 ActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700117 mSupervisor = supervisor;
Wale Ogunwale45477b52018-03-06 12:24:19 -0800118 mDisplayId = display.getDisplayId();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700119 mDisplay = display;
Winson Chung59a47ded2018-01-25 17:46:06 +0000120 mWindowContainerController = createWindowContainerController();
Bryce Leef3c6a472017-11-14 14:53:06 -0800121 updateBounds();
122 }
123
Winson Chung59a47ded2018-01-25 17:46:06 +0000124 protected DisplayWindowController createWindowContainerController() {
Wale Ogunwale45477b52018-03-06 12:24:19 -0800125 return new DisplayWindowController(mDisplay, this);
Winson Chung59a47ded2018-01-25 17:46:06 +0000126 }
127
Bryce Leef3c6a472017-11-14 14:53:06 -0800128 void updateBounds() {
129 mDisplay.getSize(mTmpDisplaySize);
130 setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700131 }
132
133 void addChild(ActivityStack stack, int position) {
134 if (position == POSITION_BOTTOM) {
135 position = 0;
136 } else if (position == POSITION_TOP) {
137 position = mStacks.size();
138 }
139 if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack
140 + " to displayId=" + mDisplayId + " position=" + position);
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700141 addStackReferenceIfNeeded(stack);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700142 positionChildAt(stack, position);
143 mSupervisor.mService.updateSleepIfNeededLocked();
144 }
145
146 void removeChild(ActivityStack stack) {
147 if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack
148 + " from displayId=" + mDisplayId);
149 mStacks.remove(stack);
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700150 removeStackReferenceIfNeeded(stack);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700151 mSupervisor.mService.updateSleepIfNeededLocked();
Winson Chung0f7ec962018-05-03 18:03:15 -0700152 onStackOrderChanged();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700153 }
154
155 void positionChildAtTop(ActivityStack stack) {
156 positionChildAt(stack, mStacks.size());
157 }
158
159 void positionChildAtBottom(ActivityStack stack) {
160 positionChildAt(stack, 0);
161 }
162
163 private void positionChildAt(ActivityStack stack, int position) {
Winson Chung123e07a2018-02-27 11:47:16 -0800164 // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
165 // the position internally, also update the logic here
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700166 mStacks.remove(stack);
Winson Chung59a47ded2018-01-25 17:46:06 +0000167 final int insertPosition = getTopInsertPosition(stack, position);
168 mStacks.add(insertPosition, stack);
169 mWindowContainerController.positionChildAt(stack.getWindowContainerController(),
170 insertPosition);
Winson Chung0f7ec962018-05-03 18:03:15 -0700171 onStackOrderChanged();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700172 }
173
174 private int getTopInsertPosition(ActivityStack stack, int candidatePosition) {
175 int position = mStacks.size();
176 if (position > 0) {
177 final ActivityStack topStack = mStacks.get(position - 1);
178 if (topStack.getWindowConfiguration().isAlwaysOnTop() && topStack != stack) {
179 // If the top stack is always on top, we move this stack just below it.
180 position--;
181 }
182 }
183 return Math.min(position, candidatePosition);
184 }
185
186 <T extends ActivityStack> T getStack(int stackId) {
187 for (int i = mStacks.size() - 1; i >= 0; --i) {
188 final ActivityStack stack = mStacks.get(i);
189 if (stack.mStackId == stackId) {
190 return (T) stack;
191 }
192 }
193 return null;
194 }
195
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700196 /**
197 * @return the topmost stack on the display that is compatible with the input windowing mode and
198 * activity type. {@code null} means no compatible stack on the display.
199 * @see ConfigurationContainer#isCompatible(int, int)
200 */
201 <T extends ActivityStack> T getStack(int windowingMode, int activityType) {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700202 if (activityType == ACTIVITY_TYPE_HOME) {
203 return (T) mHomeStack;
204 } else if (activityType == ACTIVITY_TYPE_RECENTS) {
205 return (T) mRecentsStack;
206 }
207 if (windowingMode == WINDOWING_MODE_PINNED) {
208 return (T) mPinnedStack;
209 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
210 return (T) mSplitScreenPrimaryStack;
211 }
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700212
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700213 for (int i = mStacks.size() - 1; i >= 0; --i) {
214 final ActivityStack stack = mStacks.get(i);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700215 if (stack.isCompatible(windowingMode, activityType)) {
216 return (T) stack;
217 }
218 }
219 return null;
220 }
221
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700222 private boolean alwaysCreateStack(int windowingMode, int activityType) {
223 // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
224 // modes so that we can manage visual ordering and return types correctly.
225 return activityType == ACTIVITY_TYPE_STANDARD
226 && (windowingMode == WINDOWING_MODE_FULLSCREEN
227 || windowingMode == WINDOWING_MODE_FREEFORM
228 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
229 }
230
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700231 /**
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700232 * Returns an existing stack compatible with the windowing mode and activity type or creates one
233 * if a compatible stack doesn't exist.
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700234 * @see #getStack(int, int)
235 * @see #createStack(int, int, boolean)
236 */
237 <T extends ActivityStack> T getOrCreateStack(int windowingMode, int activityType,
238 boolean onTop) {
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700239 if (!alwaysCreateStack(windowingMode, activityType)) {
240 T stack = getStack(windowingMode, activityType);
241 if (stack != null) {
242 return stack;
243 }
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700244 }
245 return createStack(windowingMode, activityType, onTop);
246 }
247
Wale Ogunwale68278562017-09-23 17:13:55 -0700248 /**
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700249 * Returns an existing stack compatible with the input params or creates one
250 * if a compatible stack doesn't exist.
251 * @see #getOrCreateStack(int, int, boolean)
252 */
253 <T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r,
254 @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType,
255 boolean onTop) {
256 final int windowingMode = resolveWindowingMode(r, options, candidateTask, activityType);
257 return getOrCreateStack(windowingMode, activityType, onTop);
258 }
259
Bryce Leed9cce2c2017-12-04 16:16:27 -0800260 private int getNextStackId() {
261 return sNextFreeStackId++;
262 }
263
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700264 /**
Wale Ogunwale68278562017-09-23 17:13:55 -0700265 * Creates a stack matching the input windowing mode and activity type on this display.
266 * @param windowingMode The windowing mode the stack should be created in. If
267 * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
268 * be created in {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}.
269 * @param activityType The activityType the stack should be created in. If
270 * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
271 * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
272 * @param onTop If true the stack will be created at the top of the display, else at the bottom.
273 * @return The newly created stack.
274 */
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700275 <T extends ActivityStack> T createStack(int windowingMode, int activityType, boolean onTop) {
276
Wale Ogunwale68278562017-09-23 17:13:55 -0700277 if (activityType == ACTIVITY_TYPE_UNDEFINED) {
278 // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
279 // anything else should be passing it in anyways...
280 activityType = ACTIVITY_TYPE_STANDARD;
281 }
282
283 if (activityType != ACTIVITY_TYPE_STANDARD) {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700284 // For now there can be only one stack of a particular non-standard activity type on a
285 // display. So, get that ignoring whatever windowing mode it is currently in.
286 T stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
287 if (stack != null) {
288 throw new IllegalArgumentException("Stack=" + stack + " of activityType="
289 + activityType + " already on display=" + this + ". Can't have multiple.");
290 }
291 }
292
293 final ActivityManagerService service = mSupervisor.mService;
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700294 if (!isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow,
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700295 service.mSupportsSplitScreenMultiWindow, service.mSupportsFreeformWindowManagement,
296 service.mSupportsPictureInPicture, activityType)) {
297 throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
298 + windowingMode);
299 }
300
301 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
302 // TODO: Should be okay to have stacks with with undefined windowing mode long term, but
303 // have to set them to something for now due to logic that depending on them.
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700304 windowingMode = getWindowingMode(); // Put in current display's windowing mode
305 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
306 // Else fullscreen for now...
307 windowingMode = WINDOWING_MODE_FULLSCREEN;
308 }
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700309 }
310
Bryce Leed9cce2c2017-12-04 16:16:27 -0800311 final int stackId = getNextStackId();
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700312 return createStackUnchecked(windowingMode, activityType, stackId, onTop);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700313 }
314
315 @VisibleForTesting
316 <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
317 int stackId, boolean onTop) {
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700318 if (windowingMode == WINDOWING_MODE_PINNED) {
319 return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700320 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800321 return (T) new ActivityStack(
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700322 this, stackId, mSupervisor, windowingMode, activityType, onTop);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700323 }
324
Wale Ogunwale68278562017-09-23 17:13:55 -0700325 /**
326 * Removes stacks in the input windowing modes from the system if they are of activity type
327 * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
328 */
329 void removeStacksInWindowingModes(int... windowingModes) {
330 if (windowingModes == null || windowingModes.length == 0) {
331 return;
332 }
333
334 for (int j = windowingModes.length - 1 ; j >= 0; --j) {
335 final int windowingMode = windowingModes[j];
336 for (int i = mStacks.size() - 1; i >= 0; --i) {
337 final ActivityStack stack = mStacks.get(i);
338 if (!stack.isActivityTypeStandardOrUndefined()) {
339 continue;
340 }
341 if (stack.getWindowingMode() != windowingMode) {
342 continue;
343 }
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700344 mSupervisor.removeStack(stack);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700345 }
346 }
347 }
348
Wale Ogunwale68278562017-09-23 17:13:55 -0700349 void removeStacksWithActivityTypes(int... activityTypes) {
350 if (activityTypes == null || activityTypes.length == 0) {
351 return;
352 }
353
354 for (int j = activityTypes.length - 1 ; j >= 0; --j) {
355 final int activityType = activityTypes[j];
356 for (int i = mStacks.size() - 1; i >= 0; --i) {
357 final ActivityStack stack = mStacks.get(i);
358 if (stack.getActivityType() == activityType) {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700359 mSupervisor.removeStack(stack);
Wale Ogunwale68278562017-09-23 17:13:55 -0700360 }
361 }
362 }
363 }
364
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700365 void onStackWindowingModeChanged(ActivityStack stack) {
366 removeStackReferenceIfNeeded(stack);
367 addStackReferenceIfNeeded(stack);
368 }
369
370 private void addStackReferenceIfNeeded(ActivityStack stack) {
371 final int activityType = stack.getActivityType();
372 final int windowingMode = stack.getWindowingMode();
373
374 if (activityType == ACTIVITY_TYPE_HOME) {
375 if (mHomeStack != null && mHomeStack != stack) {
376 throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
377 + mHomeStack + " already exist on display=" + this + " stack=" + stack);
378 }
379 mHomeStack = stack;
380 } else if (activityType == ACTIVITY_TYPE_RECENTS) {
381 if (mRecentsStack != null && mRecentsStack != stack) {
382 throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack="
383 + mRecentsStack + " already exist on display=" + this + " stack=" + stack);
384 }
385 mRecentsStack = stack;
386 }
387 if (windowingMode == WINDOWING_MODE_PINNED) {
388 if (mPinnedStack != null && mPinnedStack != stack) {
389 throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack="
390 + mPinnedStack + " already exist on display=" + this
391 + " stack=" + stack);
392 }
393 mPinnedStack = stack;
394 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
395 if (mSplitScreenPrimaryStack != null && mSplitScreenPrimaryStack != stack) {
396 throw new IllegalArgumentException("addStackReferenceIfNeeded:"
397 + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack
398 + " already exist on display=" + this + " stack=" + stack);
399 }
400 mSplitScreenPrimaryStack = stack;
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800401 onSplitScreenModeActivated();
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700402 }
403 }
404
405 private void removeStackReferenceIfNeeded(ActivityStack stack) {
406 if (stack == mHomeStack) {
407 mHomeStack = null;
408 } else if (stack == mRecentsStack) {
409 mRecentsStack = null;
410 } else if (stack == mPinnedStack) {
411 mPinnedStack = null;
412 } else if (stack == mSplitScreenPrimaryStack) {
413 mSplitScreenPrimaryStack = null;
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800414 // Inform the reset of the system that split-screen mode was dismissed so things like
415 // resizing all the other stacks can take place.
416 onSplitScreenModeDismissed();
417 }
418 }
419
420 private void onSplitScreenModeDismissed() {
421 mSupervisor.mWindowManager.deferSurfaceLayout();
422 try {
423 // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
424 for (int i = mStacks.size() - 1; i >= 0; --i) {
425 final ActivityStack otherStack = mStacks.get(i);
426 if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
427 continue;
428 }
Andrii Kulian9da138a2018-04-24 17:12:44 -0700429 otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN, false /* animate */,
430 false /* showRecents */, false /* enteringSplitScreenMode */,
431 true /* deferEnsuringVisibility */);
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800432 }
433 } finally {
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800434 final ActivityStack topFullscreenStack =
Wale Ogunwalef3257852018-01-24 08:52:28 -0800435 getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800436 if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) {
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800437 // Whenever split-screen is dismissed we want the home stack directly behind the
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800438 // current top fullscreen stack so it shows up when the top stack is finished.
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800439 // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
440 // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
441 // once we have that.
442 mHomeStack.moveToFront("onSplitScreenModeDismissed");
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800443 topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800444 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800445 mSupervisor.mWindowManager.continueSurfaceLayout();
446 }
447 }
448
449 private void onSplitScreenModeActivated() {
450 mSupervisor.mWindowManager.deferSurfaceLayout();
451 try {
452 // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
453 for (int i = mStacks.size() - 1; i >= 0; --i) {
454 final ActivityStack otherStack = mStacks.get(i);
455 if (otherStack == mSplitScreenPrimaryStack
456 || !otherStack.affectedBySplitScreenResize()) {
457 continue;
458 }
Wale Ogunwaledf262f52017-12-07 18:17:12 -0800459 otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
460 false /* animate */, false /* showRecents */,
Andrii Kulian9da138a2018-04-24 17:12:44 -0700461 true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */);
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800462 }
463 } finally {
464 mSupervisor.mWindowManager.continueSurfaceLayout();
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700465 }
466 }
467
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700468 /**
469 * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
470 * @param windowingMode The windowing mode we are checking support for.
471 * @param supportsMultiWindow If we should consider support for multi-window mode in general.
472 * @param supportsSplitScreen If we should consider support for split-screen multi-window.
473 * @param supportsFreeform If we should consider support for freeform multi-window.
474 * @param supportsPip If we should consider support for picture-in-picture mutli-window.
475 * @param activityType The activity type under consideration.
476 * @return true if the windowing mode is supported.
477 */
478 private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
479 boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
480 int activityType) {
481
482 if (windowingMode == WINDOWING_MODE_UNDEFINED
483 || windowingMode == WINDOWING_MODE_FULLSCREEN) {
484 return true;
485 }
486 if (!supportsMultiWindow) {
487 return false;
488 }
489
490 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
491 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
Wale Ogunwale2b07da82017-11-08 14:52:40 -0800492 return supportsSplitScreen
493 && WindowConfiguration.supportSplitScreenWindowingMode(activityType);
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700494 }
495
496 if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
497 return false;
498 }
499
500 if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
501 return false;
502 }
503 return true;
504 }
505
506 int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
507 @Nullable TaskRecord task, int activityType) {
508
509 // First preference if the windowing mode in the activity options if set.
510 int windowingMode = (options != null)
511 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
512
513 // If windowing mode is unset, then next preference is the candidate task, then the
514 // activity record.
515 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
516 if (task != null) {
517 windowingMode = task.getWindowingMode();
518 }
519 if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
520 windowingMode = r.getWindowingMode();
521 }
522 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
523 // Use the display's windowing mode.
524 windowingMode = getWindowingMode();
525 }
526 }
527
528 // Make sure the windowing mode we are trying to use makes sense for what is supported.
529 final ActivityManagerService service = mSupervisor.mService;
530 boolean supportsMultiWindow = service.mSupportsMultiWindow;
531 boolean supportsSplitScreen = service.mSupportsSplitScreenMultiWindow;
532 boolean supportsFreeform = service.mSupportsFreeformWindowManagement;
533 boolean supportsPip = service.mSupportsPictureInPicture;
534 if (supportsMultiWindow) {
535 if (task != null) {
536 supportsMultiWindow = task.isResizeable();
537 supportsSplitScreen = task.supportsSplitScreenWindowingMode();
538 // TODO: Do we need to check for freeform and Pip support here?
539 } else if (r != null) {
540 supportsMultiWindow = r.isResizeable();
541 supportsSplitScreen = r.supportsSplitScreenWindowingMode();
542 supportsFreeform = r.supportsFreeform();
543 supportsPip = r.supportsPictureInPicture();
544 }
545 }
546
547 final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
548 if (!inSplitScreenMode
549 && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
550 // Switch to fullscreen windowing mode if we are not in split-screen mode and we are
551 // trying to launch in split-screen secondary.
552 windowingMode = WINDOWING_MODE_FULLSCREEN;
553 } else if (inSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
554 && supportsSplitScreen) {
555 windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
556 }
557
558 if (windowingMode != WINDOWING_MODE_UNDEFINED
559 && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
560 supportsFreeform, supportsPip, activityType)) {
561 return windowingMode;
562 }
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800563 // Try to use the display's windowing mode otherwise fallback to fullscreen.
564 windowingMode = getWindowingMode();
565 return windowingMode != WINDOWING_MODE_UNDEFINED
566 ? windowingMode : WINDOWING_MODE_FULLSCREEN;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700567 }
568
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700569 /**
570 * Get the topmost stack on the display. It may be different from focused stack, because
571 * focus may be on another display.
572 */
573 ActivityStack getTopStack() {
574 return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700575 }
576
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700577 boolean isTopStack(ActivityStack stack) {
578 return stack == getTopStack();
579 }
580
chaviw2c500982018-01-04 17:05:05 -0800581 boolean isTopNotPinnedStack(ActivityStack stack) {
Wale Ogunwale2cca8622017-12-11 08:40:13 -0800582 for (int i = mStacks.size() - 1; i >= 0; --i) {
583 final ActivityStack current = mStacks.get(i);
chaviw2c500982018-01-04 17:05:05 -0800584 if (!current.inPinnedWindowingMode()) {
Wale Ogunwale2cca8622017-12-11 08:40:13 -0800585 return current == stack;
586 }
587 }
588 return false;
589 }
590
Wale Ogunwalef3257852018-01-24 08:52:28 -0800591 ActivityStack getTopStackInWindowingMode(int windowingMode) {
592 for (int i = mStacks.size() - 1; i >= 0; --i) {
593 final ActivityStack current = mStacks.get(i);
594 if (windowingMode == current.getWindowingMode()) {
595 return current;
596 }
597 }
598 return null;
599 }
600
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700601 int getIndexOf(ActivityStack stack) {
602 return mStacks.indexOf(stack);
603 }
604
605 void onLockTaskPackagesUpdated() {
606 for (int i = mStacks.size() - 1; i >= 0; --i) {
607 mStacks.get(i).onLockTaskPackagesUpdated();
608 }
609 }
610
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700611 /** We are in the process of exiting split-screen mode. */
612 void onExitingSplitScreenMode() {
613 // Remove reference to the primary-split-screen stack so it no longer has any effect on the
614 // display. For example, we want to be able to create fullscreen stack for standard activity
615 // types when exiting split-screen mode.
616 mSplitScreenPrimaryStack = null;
617 }
618
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700619 ActivityStack getSplitScreenPrimaryStack() {
620 return mSplitScreenPrimaryStack;
621 }
622
623 boolean hasSplitScreenPrimaryStack() {
624 return mSplitScreenPrimaryStack != null;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700625 }
626
627 PinnedActivityStack getPinnedStack() {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700628 return (PinnedActivityStack) mPinnedStack;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700629 }
630
631 boolean hasPinnedStack() {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700632 return mPinnedStack != null;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700633 }
634
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700635 @Override
636 public String toString() {
637 return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
638 }
639
640 @Override
641 protected int getChildCount() {
642 return mStacks.size();
643 }
644
645 @Override
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700646 protected ActivityStack getChildAt(int index) {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700647 return mStacks.get(index);
648 }
649
650 @Override
651 protected ConfigurationContainer getParent() {
652 return mSupervisor;
653 }
654
655 boolean isPrivate() {
656 return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
657 }
658
659 boolean isUidPresent(int uid) {
660 for (ActivityStack stack : mStacks) {
661 if (stack.isUidPresent(uid)) {
662 return true;
663 }
664 }
665 return false;
666 }
667
Bryce Leef19cbe22018-02-02 15:09:21 -0800668 void remove() {
669 final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
670 while (getChildCount() > 0) {
671 final ActivityStack stack = getChildAt(0);
672 if (destroyContentOnRemoval) {
Andrii Kulian823af6e2018-02-28 18:51:36 -0800673 // Override the stack configuration to make it equal to the current applied one, so
674 // that we don't accidentally report configuration change to activities that are
675 // going to be finished.
676 stack.onOverrideConfigurationChanged(stack.getConfiguration());
Bryce Leef19cbe22018-02-02 15:09:21 -0800677 mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY,
678 false /* onTop */);
679 stack.finishAllActivitiesLocked(true /* immediately */);
680 } else {
681 // Moving all tasks to fullscreen stack, because it's guaranteed to be
682 // a valid launch stack for all activities. This way the task history from
683 // external display will be preserved on primary after move.
684 mSupervisor.moveTasksToFullscreenStackLocked(stack, true /* onTop */);
685 }
686 }
687
688 mWindowContainerController.removeContainer();
689 mWindowContainerController = null;
690 }
691
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700692 /** Update and get all UIDs that are present on the display and have access to it. */
693 IntArray getPresentUIDs() {
694 mDisplayAccessUIDs.clear();
695 for (ActivityStack stack : mStacks) {
696 stack.getPresentUIDs(mDisplayAccessUIDs);
697 }
698 return mDisplayAccessUIDs;
699 }
700
Bryce Leef19cbe22018-02-02 15:09:21 -0800701 private boolean shouldDestroyContentOnRemove() {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700702 return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
703 }
704
705 boolean shouldSleep() {
706 return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty())
707 && (mSupervisor.mService.mRunningVoice == null);
708 }
709
Winson Chunge2d72172018-01-25 17:46:20 +0000710 /**
Winson Chung3e2980e2018-03-29 17:28:57 -0700711 * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
712 * already top-most.
Winson Chunge2d72172018-01-25 17:46:20 +0000713 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700714 ActivityStack getStackAbove(ActivityStack stack) {
715 final int stackIndex = mStacks.indexOf(stack) + 1;
Winson Chunge2d72172018-01-25 17:46:20 +0000716 return (stackIndex < mStacks.size()) ? mStacks.get(stackIndex) : null;
717 }
718
719 /**
Winson Chung3e2980e2018-03-29 17:28:57 -0700720 * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
721 * Generally used in conjunction with {@link #moveStackBehindStack}.
Winson Chunge2d72172018-01-25 17:46:20 +0000722 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700723 void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
724 if (stack.shouldBeVisible(null)) {
725 // Skip if the stack is already visible
Winson Chunge2d72172018-01-25 17:46:20 +0000726 return;
727 }
728
Winson Chung3e2980e2018-03-29 17:28:57 -0700729 // Move the stack to the bottom to not affect the following visibility checks
730 positionChildAtBottom(stack);
Winson Chunge2d72172018-01-25 17:46:20 +0000731
Winson Chung3e2980e2018-03-29 17:28:57 -0700732 // Find the next position where the stack should be placed
Winson Chunge2d72172018-01-25 17:46:20 +0000733 final int numStacks = mStacks.size();
734 for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700735 final ActivityStack s = mStacks.get(stackNdx);
736 if (s == stack) {
Winson Chunge2d72172018-01-25 17:46:20 +0000737 continue;
738 }
Winson Chung3e2980e2018-03-29 17:28:57 -0700739 final int winMode = s.getWindowingMode();
Winson Chunge2d72172018-01-25 17:46:20 +0000740 final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN ||
741 winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Winson Chung3e2980e2018-03-29 17:28:57 -0700742 if (s.shouldBeVisible(null) && isValidWindowingMode) {
743 // Move the provided stack to behind this stack
744 positionChildAt(stack, Math.max(0, stackNdx - 1));
Winson Chunge2d72172018-01-25 17:46:20 +0000745 break;
746 }
747 }
748 }
749
750 /**
Winson Chung3e2980e2018-03-29 17:28:57 -0700751 * Moves the {@param stack} behind the given {@param behindStack} if possible. If
752 * {@param behindStack} is not currently in the display, then then the stack is moved to the
753 * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
Winson Chunge2d72172018-01-25 17:46:20 +0000754 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700755 void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
756 if (behindStack == null || behindStack == stack) {
Winson Chunge2d72172018-01-25 17:46:20 +0000757 return;
758 }
759
Winson Chung123e07a2018-02-27 11:47:16 -0800760 // Note that positionChildAt will first remove the given stack before inserting into the
761 // list, so we need to adjust the insertion index to account for the removed index
762 // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
763 // position internally
Winson Chung3e2980e2018-03-29 17:28:57 -0700764 final int stackIndex = mStacks.indexOf(stack);
Winson Chung123e07a2018-02-27 11:47:16 -0800765 final int behindStackIndex = mStacks.indexOf(behindStack);
Winson Chung3e2980e2018-03-29 17:28:57 -0700766 final int insertIndex = stackIndex <= behindStackIndex
Winson Chung123e07a2018-02-27 11:47:16 -0800767 ? behindStackIndex - 1 : behindStackIndex;
Winson Chung3e2980e2018-03-29 17:28:57 -0700768 positionChildAt(stack, Math.max(0, insertIndex));
Winson Chunge2d72172018-01-25 17:46:20 +0000769 }
770
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700771 boolean isSleeping() {
772 return mSleeping;
773 }
774
775 void setIsSleeping(boolean asleep) {
776 mSleeping = asleep;
777 }
778
Winson Chung0f7ec962018-05-03 18:03:15 -0700779 /**
780 * Adds a listener to be notified whenever the stack order in the display changes. Currently
781 * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
782 * current animation when the system state changes.
783 */
784 void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
785 if (!mStackOrderChangedCallbacks.contains(listener)) {
786 mStackOrderChangedCallbacks.add(listener);
787 }
788 }
789
790 /**
791 * Removes a previously registered stack order change listener.
792 */
793 void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
794 mStackOrderChangedCallbacks.remove(listener);
795 }
796
797 private void onStackOrderChanged() {
798 for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
799 mStackOrderChangedCallbacks.get(i).onStackOrderChanged();
800 }
801 }
802
Chavi Weingarten3a748552018-05-14 17:32:42 +0000803 /**
804 * See {@link DisplayWindowController#deferUpdateImeTarget()}
805 */
806 public void deferUpdateImeTarget() {
807 mWindowContainerController.deferUpdateImeTarget();
808 }
809
810 /**
811 * See {@link DisplayWindowController#deferUpdateImeTarget()}
812 */
813 public void continueUpdateImeTarget() {
814 mWindowContainerController.continueUpdateImeTarget();
815 }
816
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700817 public void dump(PrintWriter pw, String prefix) {
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800818 pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size());
819 final String myPrefix = prefix + " ";
820 if (mHomeStack != null) {
821 pw.println(myPrefix + "mHomeStack=" + mHomeStack);
822 }
823 if (mRecentsStack != null) {
824 pw.println(myPrefix + "mRecentsStack=" + mRecentsStack);
825 }
826 if (mPinnedStack != null) {
827 pw.println(myPrefix + "mPinnedStack=" + mPinnedStack);
828 }
829 if (mSplitScreenPrimaryStack != null) {
830 pw.println(myPrefix + "mSplitScreenPrimaryStack=" + mSplitScreenPrimaryStack);
831 }
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700832 }
833
Bryce Lee77a7dd62018-01-22 15:47:09 -0800834 public void dumpStacks(PrintWriter pw) {
835 for (int i = mStacks.size() - 1; i >= 0; --i) {
836 pw.print(mStacks.get(i).mStackId);
837 if (i > 0) {
838 pw.print(",");
839 }
840 }
841 }
842
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700843 public void writeToProto(ProtoOutputStream proto, long fieldId) {
844 final long token = proto.start(fieldId);
Adrian Roos4921ccf2017-09-28 16:54:06 +0200845 super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700846 proto.write(ID, mDisplayId);
847 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
848 final ActivityStack stack = mStacks.get(stackNdx);
849 stack.writeToProto(proto, STACKS);
850 }
851 proto.end(token);
852 }
Winson Chung0f7ec962018-05-03 18:03:15 -0700853
854 /**
855 * Callback for when the order of the stacks in the display changes.
856 */
857 interface OnStackOrderChangedListener {
858 void onStackOrderChanged();
859 }
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700860}