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
17package com.android.server.am;
18
19import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
20import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
21import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
22import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
23import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
24import 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;
31import 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.ActivityDisplayProto.CONFIGURATION_CONTAINER;
38import static com.android.server.am.ActivityDisplayProto.STACKS;
39import static com.android.server.am.ActivityDisplayProto.ID;
40
41import android.annotation.Nullable;
42import android.app.ActivityManagerInternal;
43import android.app.ActivityOptions;
44import android.app.WindowConfiguration;
45import android.graphics.Point;
46import android.util.IntArray;
47import android.util.Slog;
48import android.util.proto.ProtoOutputStream;
49import android.view.Display;
50import com.android.internal.annotations.VisibleForTesting;
51import com.android.server.wm.ConfigurationContainer;
52import com.android.server.wm.DisplayWindowController;
53
54import com.android.server.wm.WindowContainerListener;
55import java.io.PrintWriter;
56import 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 */
62class 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
112    ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
113        this(supervisor, supervisor.mDisplayManager.getDisplay(displayId));
114    }
115
116    ActivityDisplay(ActivityStackSupervisor supervisor, Display display) {
117        mSupervisor = supervisor;
118        mDisplayId = display.getDisplayId();
119        mDisplay = display;
120        mWindowContainerController = createWindowContainerController();
121        updateBounds();
122    }
123
124    protected DisplayWindowController createWindowContainerController() {
125        return new DisplayWindowController(mDisplay, this);
126    }
127
128    void updateBounds() {
129        mDisplay.getSize(mTmpDisplaySize);
130        setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
131    }
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);
141        addStackReferenceIfNeeded(stack);
142        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);
150        removeStackReferenceIfNeeded(stack);
151        mSupervisor.mService.updateSleepIfNeededLocked();
152        onStackOrderChanged();
153    }
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) {
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
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
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     */
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
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     */
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     */
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
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     */
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
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     */
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
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
365    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;
401            onSplitScreenModeActivated();
402        }
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;
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
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
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     */
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
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     */
573    ActivityStack getTopStack() {
574        return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1);
575    }
576
577    boolean isTopStack(ActivityStack stack) {
578        return stack == getTopStack();
579    }
580
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
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
601    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
611    /** 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
619    ActivityStack getSplitScreenPrimaryStack() {
620        return mSplitScreenPrimaryStack;
621    }
622
623    boolean hasSplitScreenPrimaryStack() {
624        return mSplitScreenPrimaryStack != null;
625    }
626
627    PinnedActivityStack getPinnedStack() {
628        return (PinnedActivityStack) mPinnedStack;
629    }
630
631    boolean hasPinnedStack() {
632        return mPinnedStack != null;
633    }
634
635    @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
646    protected ActivityStack getChildAt(int index) {
647        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
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. */
693    IntArray getPresentUIDs() {
694        mDisplayAccessUIDs.clear();
695        for (ActivityStack stack : mStacks) {
696            stack.getPresentUIDs(mDisplayAccessUIDs);
697        }
698        return mDisplayAccessUIDs;
699    }
700
701    private boolean shouldDestroyContentOnRemove() {
702        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
710    /**
711     * @return the stack currently above the {@param stack}.  Can be null if the {@param stack} is
712     *         already top-most.
713     */
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     */
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     */
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
771    boolean isSleeping() {
772        return mSleeping;
773    }
774
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     */
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
803    /**
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
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
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
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 {
858        void onStackOrderChanged();
859    }
860}
861