1 /*
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 
17 package com.android.server.am;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
25 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
26 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
27 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
28 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
29 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
30 import static android.view.Display.DEFAULT_DISPLAY;
31 import static android.view.Display.FLAG_PRIVATE;
32 import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
33 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
34 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
35 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
36 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
37 import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER;
38 import static com.android.server.am.ActivityDisplayProto.STACKS;
39 import static com.android.server.am.ActivityDisplayProto.ID;
40 
41 import android.annotation.Nullable;
42 import android.app.ActivityManagerInternal;
43 import android.app.ActivityOptions;
44 import android.app.WindowConfiguration;
45 import android.graphics.Point;
46 import android.util.IntArray;
47 import android.util.Slog;
48 import android.util.proto.ProtoOutputStream;
49 import android.view.Display;
50 import com.android.internal.annotations.VisibleForTesting;
51 import com.android.server.wm.ConfigurationContainer;
52 import com.android.server.wm.DisplayWindowController;
53 
54 import com.android.server.wm.WindowContainerListener;
55 import java.io.PrintWriter;
56 import 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  */
62 class ActivityDisplay extends ConfigurationContainer<ActivityStack>
63         implements WindowContainerListener {
64     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 
70 
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 
76     private ActivityStackSupervisor mSupervisor;
77     /** Actual Display this object tracks. */
78     int mDisplayId;
79     Display mDisplay;
80 
81     /**
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      */
86     private final ArrayList<ActivityStack> mStacks = new ArrayList<>();
87     private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
88 
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 
99     // 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 
106     // Used in updating the display size
107     private Point mTmpDisplaySize = new Point();
108 
109     private DisplayWindowController mWindowContainerController;
110 
111     @VisibleForTesting
ActivityDisplay(ActivityStackSupervisor supervisor, int displayId)112     ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
113         this(supervisor, supervisor.mDisplayManager.getDisplay(displayId));
114     }
115 
ActivityDisplay(ActivityStackSupervisor supervisor, Display display)116     ActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
117         mSupervisor = supervisor;
118         mDisplayId = display.getDisplayId();
119         mDisplay = display;
120         mWindowContainerController = createWindowContainerController();
121         updateBounds();
122     }
123 
createWindowContainerController()124     protected DisplayWindowController createWindowContainerController() {
125         return new DisplayWindowController(mDisplay, this);
126     }
127 
updateBounds()128     void updateBounds() {
129         mDisplay.getSize(mTmpDisplaySize);
130         setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
131     }
132 
addChild(ActivityStack stack, int position)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);
141         addStackReferenceIfNeeded(stack);
142         positionChildAt(stack, position);
143         mSupervisor.mService.updateSleepIfNeededLocked();
144     }
145 
removeChild(ActivityStack stack)146     void removeChild(ActivityStack stack) {
147         if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack
148                 + " from displayId=" + mDisplayId);
149         mStacks.remove(stack);
150         removeStackReferenceIfNeeded(stack);
151         mSupervisor.mService.updateSleepIfNeededLocked();
152         onStackOrderChanged();
153     }
154 
positionChildAtTop(ActivityStack stack)155     void positionChildAtTop(ActivityStack stack) {
156         positionChildAt(stack, mStacks.size());
157     }
158 
positionChildAtBottom(ActivityStack stack)159     void positionChildAtBottom(ActivityStack stack) {
160         positionChildAt(stack, 0);
161     }
162 
positionChildAt(ActivityStack stack, int position)163     private void positionChildAt(ActivityStack stack, int position) {
164         // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
165         //       the position internally, also update the logic here
166         mStacks.remove(stack);
167         final int insertPosition = getTopInsertPosition(stack, position);
168         mStacks.add(insertPosition, stack);
169         mWindowContainerController.positionChildAt(stack.getWindowContainerController(),
170                 insertPosition);
171         onStackOrderChanged();
172     }
173 
getTopInsertPosition(ActivityStack stack, int candidatePosition)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 
getStack(int stackId)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 
196     /**
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      */
getStack(int windowingMode, int activityType)201     <T extends ActivityStack> T getStack(int windowingMode, int activityType) {
202         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         }
212 
213         for (int i = mStacks.size() - 1; i >= 0; --i) {
214             final ActivityStack stack = mStacks.get(i);
215             if (stack.isCompatible(windowingMode, activityType)) {
216                 return (T) stack;
217             }
218         }
219         return null;
220     }
221 
alwaysCreateStack(int windowingMode, int activityType)222     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 
231     /**
232      * Returns an existing stack compatible with the windowing mode and activity type or creates one
233      * if a compatible stack doesn't exist.
234      * @see #getStack(int, int)
235      * @see #createStack(int, int, boolean)
236      */
getOrCreateStack(int windowingMode, int activityType, boolean onTop)237     <T extends ActivityStack> T getOrCreateStack(int windowingMode, int activityType,
238             boolean onTop) {
239         if (!alwaysCreateStack(windowingMode, activityType)) {
240             T stack = getStack(windowingMode, activityType);
241             if (stack != null) {
242                 return stack;
243             }
244         }
245         return createStack(windowingMode, activityType, onTop);
246     }
247 
248     /**
249      * 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      */
getOrCreateStack(@ullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType, boolean onTop)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 
getNextStackId()260     private int getNextStackId() {
261         return sNextFreeStackId++;
262     }
263 
264     /**
265      * 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      */
createStack(int windowingMode, int activityType, boolean onTop)275     <T extends ActivityStack> T createStack(int windowingMode, int activityType, boolean onTop) {
276 
277         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) {
284             // 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;
294         if (!isWindowingModeSupported(windowingMode, service.mSupportsMultiWindow,
295                 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.
304             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             }
309         }
310 
311         final int stackId = getNextStackId();
312         return createStackUnchecked(windowingMode, activityType, stackId, onTop);
313     }
314 
315     @VisibleForTesting
createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop)316     <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
317             int stackId, boolean onTop) {
318         if (windowingMode == WINDOWING_MODE_PINNED) {
319             return (T) new PinnedActivityStack(this, stackId, mSupervisor, onTop);
320         }
321         return (T) new ActivityStack(
322                         this, stackId, mSupervisor, windowingMode, activityType, onTop);
323     }
324 
325     /**
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      */
removeStacksInWindowingModes(int... windowingModes)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                 }
344                 mSupervisor.removeStack(stack);
345             }
346         }
347     }
348 
removeStacksWithActivityTypes(int... activityTypes)349     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) {
359                     mSupervisor.removeStack(stack);
360                 }
361             }
362         }
363     }
364 
onStackWindowingModeChanged(ActivityStack stack)365     void onStackWindowingModeChanged(ActivityStack stack) {
366         removeStackReferenceIfNeeded(stack);
367         addStackReferenceIfNeeded(stack);
368     }
369 
addStackReferenceIfNeeded(ActivityStack stack)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;
401             onSplitScreenModeActivated();
402         }
403     }
404 
removeStackReferenceIfNeeded(ActivityStack stack)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;
414             // 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 
onSplitScreenModeDismissed()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                 }
429                 otherStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN, false /* animate */,
430                         false /* showRecents */, false /* enteringSplitScreenMode */,
431                         true /* deferEnsuringVisibility */);
432             }
433         } finally {
434             final ActivityStack topFullscreenStack =
435                     getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
436             if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) {
437                 // Whenever split-screen is dismissed we want the home stack directly behind the
438                 // current top fullscreen stack so it shows up when the top stack is finished.
439                 // 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");
443                 topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
444             }
445             mSupervisor.mWindowManager.continueSurfaceLayout();
446         }
447     }
448 
onSplitScreenModeActivated()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                 }
459                 otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
460                         false /* animate */, false /* showRecents */,
461                         true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */);
462             }
463         } finally {
464             mSupervisor.mWindowManager.continueSurfaceLayout();
465         }
466     }
467 
468     /**
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      */
isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow, boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip, int activityType)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) {
492             return supportsSplitScreen
493                     && WindowConfiguration.supportSplitScreenWindowingMode(activityType);
494         }
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 
resolveWindowingMode(@ullable ActivityRecord r, @Nullable ActivityOptions options, @Nullable TaskRecord task, int activityType)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         }
563         // 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;
567     }
568 
569     /**
570      * Get the topmost stack on the display. It may be different from focused stack, because
571      * focus may be on another display.
572      */
getTopStack()573     ActivityStack getTopStack() {
574         return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1);
575     }
576 
isTopStack(ActivityStack stack)577     boolean isTopStack(ActivityStack stack) {
578         return stack == getTopStack();
579     }
580 
isTopNotPinnedStack(ActivityStack stack)581     boolean isTopNotPinnedStack(ActivityStack stack) {
582         for (int i = mStacks.size() - 1; i >= 0; --i) {
583             final ActivityStack current = mStacks.get(i);
584             if (!current.inPinnedWindowingMode()) {
585                 return current == stack;
586             }
587         }
588         return false;
589     }
590 
getTopStackInWindowingMode(int windowingMode)591     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 
getIndexOf(ActivityStack stack)601     int getIndexOf(ActivityStack stack) {
602         return mStacks.indexOf(stack);
603     }
604 
onLockTaskPackagesUpdated()605     void onLockTaskPackagesUpdated() {
606         for (int i = mStacks.size() - 1; i >= 0; --i) {
607             mStacks.get(i).onLockTaskPackagesUpdated();
608         }
609     }
610 
611     /** We are in the process of exiting split-screen mode. */
onExitingSplitScreenMode()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 
getSplitScreenPrimaryStack()619     ActivityStack getSplitScreenPrimaryStack() {
620         return mSplitScreenPrimaryStack;
621     }
622 
hasSplitScreenPrimaryStack()623     boolean hasSplitScreenPrimaryStack() {
624         return mSplitScreenPrimaryStack != null;
625     }
626 
getPinnedStack()627     PinnedActivityStack getPinnedStack() {
628         return (PinnedActivityStack) mPinnedStack;
629     }
630 
hasPinnedStack()631     boolean hasPinnedStack() {
632         return mPinnedStack != null;
633     }
634 
635     @Override
toString()636     public String toString() {
637         return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
638     }
639 
640     @Override
getChildCount()641     protected int getChildCount() {
642         return mStacks.size();
643     }
644 
645     @Override
getChildAt(int index)646     protected ActivityStack getChildAt(int index) {
647         return mStacks.get(index);
648     }
649 
650     @Override
getParent()651     protected ConfigurationContainer getParent() {
652         return mSupervisor;
653     }
654 
isPrivate()655     boolean isPrivate() {
656         return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
657     }
658 
isUidPresent(int uid)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 
remove()668     void remove() {
669         final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
670         while (getChildCount() > 0) {
671             final ActivityStack stack = getChildAt(0);
672             if (destroyContentOnRemoval) {
673                 // 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());
677                 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 
692     /** Update and get all UIDs that are present on the display and have access to it. */
getPresentUIDs()693     IntArray getPresentUIDs() {
694         mDisplayAccessUIDs.clear();
695         for (ActivityStack stack : mStacks) {
696             stack.getPresentUIDs(mDisplayAccessUIDs);
697         }
698         return mDisplayAccessUIDs;
699     }
700 
shouldDestroyContentOnRemove()701     private boolean shouldDestroyContentOnRemove() {
702         return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
703     }
704 
shouldSleep()705     boolean shouldSleep() {
706         return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty())
707                 && (mSupervisor.mService.mRunningVoice == null);
708     }
709 
710     /**
711      * @return the stack currently above the {@param stack}.  Can be null if the {@param stack} is
712      *         already top-most.
713      */
getStackAbove(ActivityStack stack)714     ActivityStack getStackAbove(ActivityStack stack) {
715         final int stackIndex = mStacks.indexOf(stack) + 1;
716         return (stackIndex < mStacks.size()) ? mStacks.get(stackIndex) : null;
717     }
718 
719     /**
720      * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
721      * Generally used in conjunction with {@link #moveStackBehindStack}.
722      */
moveStackBehindBottomMostVisibleStack(ActivityStack stack)723     void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
724         if (stack.shouldBeVisible(null)) {
725             // Skip if the stack is already visible
726             return;
727         }
728 
729         // Move the stack to the bottom to not affect the following visibility checks
730         positionChildAtBottom(stack);
731 
732         // Find the next position where the stack should be placed
733         final int numStacks = mStacks.size();
734         for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
735             final ActivityStack s = mStacks.get(stackNdx);
736             if (s == stack) {
737                 continue;
738             }
739             final int winMode = s.getWindowingMode();
740             final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN ||
741                     winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
742             if (s.shouldBeVisible(null) && isValidWindowingMode) {
743                 // Move the provided stack to behind this stack
744                 positionChildAt(stack, Math.max(0, stackNdx - 1));
745                 break;
746             }
747         }
748     }
749 
750     /**
751      * 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}.
754      */
moveStackBehindStack(ActivityStack stack, ActivityStack behindStack)755     void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
756         if (behindStack == null || behindStack == stack) {
757             return;
758         }
759 
760         // 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
764         final int stackIndex = mStacks.indexOf(stack);
765         final int behindStackIndex = mStacks.indexOf(behindStack);
766         final int insertIndex = stackIndex <= behindStackIndex
767                 ? behindStackIndex - 1 : behindStackIndex;
768         positionChildAt(stack, Math.max(0, insertIndex));
769     }
770 
isSleeping()771     boolean isSleeping() {
772         return mSleeping;
773     }
774 
setIsSleeping(boolean asleep)775     void setIsSleeping(boolean asleep) {
776         mSleeping = asleep;
777     }
778 
779     /**
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      */
registerStackOrderChangedListener(OnStackOrderChangedListener listener)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      */
unregisterStackOrderChangedListener(OnStackOrderChangedListener listener)793     void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
794         mStackOrderChangedCallbacks.remove(listener);
795     }
796 
onStackOrderChanged()797     private void onStackOrderChanged() {
798         for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
799             mStackOrderChangedCallbacks.get(i).onStackOrderChanged();
800         }
801     }
802 
803     /**
804      * See {@link DisplayWindowController#deferUpdateImeTarget()}
805      */
deferUpdateImeTarget()806     public void deferUpdateImeTarget() {
807         mWindowContainerController.deferUpdateImeTarget();
808     }
809 
810     /**
811      * See {@link DisplayWindowController#deferUpdateImeTarget()}
812      */
continueUpdateImeTarget()813     public void continueUpdateImeTarget() {
814         mWindowContainerController.continueUpdateImeTarget();
815     }
816 
dump(PrintWriter pw, String prefix)817     public void dump(PrintWriter pw, String prefix) {
818         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         }
832     }
833 
dumpStacks(PrintWriter pw)834     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 
writeToProto(ProtoOutputStream proto, long fieldId)843     public void writeToProto(ProtoOutputStream proto, long fieldId) {
844         final long token = proto.start(fieldId);
845         super.writeToProto(proto, CONFIGURATION_CONTAINER, false /* trim */);
846         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     }
853 
854     /**
855      * Callback for when the order of the stacks in the display changes.
856      */
857     interface OnStackOrderChangedListener {
onStackOrderChanged()858         void onStackOrderChanged();
859     }
860 }
861