WindowContainer.java revision 619c9f7c5cd2a19912f9a4f2dbfe1a32d944a75b
1/*
2 * Copyright (C) 2016 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.wm;
18
19import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
20import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
21import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
22import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
23import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
24import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
25import static com.android.server.wm.proto.WindowContainerProto.CONFIGURATION_CONTAINER;
26import static com.android.server.wm.proto.WindowContainerProto.ORIENTATION;
27import static com.android.server.wm.proto.WindowContainerProto.VISIBLE;
28import static android.view.SurfaceControl.Transaction;
29
30import android.annotation.CallSuper;
31import android.content.res.Configuration;
32import android.graphics.Point;
33import android.graphics.Rect;
34import android.util.Slog;
35import android.view.MagnificationSpec;
36import android.view.SurfaceControl;
37import android.view.SurfaceControl.Builder;
38import android.view.SurfaceSession;
39import android.util.Pools;
40
41import android.util.proto.ProtoOutputStream;
42
43import com.android.internal.util.ToBooleanFunction;
44import com.android.server.wm.SurfaceAnimator.Animatable;
45
46import java.io.PrintWriter;
47import java.util.Comparator;
48import java.util.LinkedList;
49import java.util.function.Consumer;
50import java.util.function.Predicate;
51
52/**
53 * Defines common functionality for classes that can hold windows directly or through their
54 * children in a hierarchy form.
55 * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
56 * changes are made to this class.
57 */
58class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
59        implements Comparable<WindowContainer>, Animatable {
60
61    private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM;
62
63    static final int POSITION_TOP = Integer.MAX_VALUE;
64    static final int POSITION_BOTTOM = Integer.MIN_VALUE;
65
66    /**
67     * The parent of this window container.
68     * For removing or setting new parent {@link #setParent} should be used, because it also
69     * performs configuration updates based on new parent's settings.
70     */
71    private WindowContainer<WindowContainer> mParent = null;
72
73    // List of children for this window container. List is in z-order as the children appear on
74    // screen with the top-most window container at the tail of the list.
75    protected final WindowList<E> mChildren = new WindowList<E>();
76
77    // The specified orientation for this window container.
78    protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
79
80    private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool =
81            new Pools.SynchronizedPool<>(3);
82
83    // The owner/creator for this container. No controller if null.
84    WindowContainerController mController;
85
86    protected SurfaceControl mSurfaceControl;
87    private int mLastLayer = 0;
88    private SurfaceControl mLastRelativeToLayer = null;
89
90    /**
91     * Applied as part of the animation pass in "prepareSurfaces".
92     */
93    protected final Transaction mPendingTransaction;
94    protected final SurfaceAnimator mSurfaceAnimator;
95    protected final WindowManagerService mService;
96
97    private final Point mTmpPos = new Point();
98
99    /** Total number of elements in this subtree, including our own hierarchy element. */
100    private int mTreeWeight = 1;
101
102    WindowContainer(WindowManagerService service) {
103        mService = service;
104        mPendingTransaction = service.mTransactionFactory.make();
105        mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
106    }
107
108    @Override
109    final protected WindowContainer getParent() {
110        return mParent;
111    }
112
113    @Override
114    protected int getChildCount() {
115        return mChildren.size();
116    }
117
118    @Override
119    protected E getChildAt(int index) {
120        return mChildren.get(index);
121    }
122
123    @Override
124    public void onConfigurationChanged(Configuration newParentConfig) {
125        super.onConfigurationChanged(newParentConfig);
126        updateSurfacePosition(getPendingTransaction());
127        scheduleAnimation();
128    }
129
130    final protected void setParent(WindowContainer<WindowContainer> parent) {
131        mParent = parent;
132        // Removing parent usually means that we've detached this entity to destroy it or to attach
133        // to another parent. In both cases we don't need to update the configuration now.
134        if (mParent != null) {
135            // Update full configuration of this container and all its children.
136            onConfigurationChanged(mParent.getConfiguration());
137            // Update merged override configuration of this container and all its children.
138            onMergedOverrideConfigurationChanged();
139        }
140
141        onParentSet();
142    }
143
144    /**
145     * Callback that is triggered when @link WindowContainer#setParent(WindowContainer)} was called.
146     * Supposed to be overridden and contain actions that should be executed after parent was set.
147     */
148    void onParentSet() {
149        if (mParent == null) {
150            return;
151        }
152
153        if (mSurfaceControl == null) {
154            // If we don't yet have a surface, but we now have a parent, we should
155            // build a surface.
156            mSurfaceControl = makeSurface().build();
157            getPendingTransaction().show(mSurfaceControl);
158        } else {
159            // If we have a surface but a new parent, we just need to perform a reparent. Go through
160            // surface animator such that hierarchy is preserved when animating, i.e.
161            // mSurfaceControl stays attached to the leash and we just reparent the leash to the
162            // new parent.
163            reparentSurfaceControl(getPendingTransaction(), mParent.mSurfaceControl);
164        }
165
166        // Either way we need to ask the parent to assign us a Z-order.
167        mParent.assignChildLayers();
168        scheduleAnimation();
169    }
170
171    // Temp. holders for a chain of containers we are currently processing.
172    private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList<>();
173    private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList<>();
174
175    /**
176     * Adds the input window container has a child of this container in order based on the input
177     * comparator.
178     * @param child The window container to add as a child of this window container.
179     * @param comparator Comparator to use in determining the position the child should be added to.
180     *                   If null, the child will be added to the top.
181     */
182    @CallSuper
183    protected void addChild(E child, Comparator<E> comparator) {
184        if (child.getParent() != null) {
185            throw new IllegalArgumentException("addChild: container=" + child.getName()
186                    + " is already a child of container=" + child.getParent().getName()
187                    + " can't add to container=" + getName());
188        }
189
190        int positionToAdd = -1;
191        if (comparator != null) {
192            final int count = mChildren.size();
193            for (int i = 0; i < count; i++) {
194                if (comparator.compare(child, mChildren.get(i)) < 0) {
195                    positionToAdd = i;
196                    break;
197                }
198            }
199        }
200
201        if (positionToAdd == -1) {
202            mChildren.add(child);
203        } else {
204            mChildren.add(positionToAdd, child);
205        }
206        onChildAdded(child);
207
208        // Set the parent after we've actually added a child in case a subclass depends on this.
209        child.setParent(this);
210    }
211
212    /** Adds the input window container has a child of this container at the input index. */
213    @CallSuper
214    void addChild(E child, int index) {
215        if (child.getParent() != null) {
216            throw new IllegalArgumentException("addChild: container=" + child.getName()
217                    + " is already a child of container=" + child.getParent().getName()
218                    + " can't add to container=" + getName());
219        }
220        mChildren.add(index, child);
221        onChildAdded(child);
222
223        // Set the parent after we've actually added a child in case a subclass depends on this.
224        child.setParent(this);
225    }
226
227    private void onChildAdded(WindowContainer child) {
228        mTreeWeight += child.mTreeWeight;
229        WindowContainer parent = getParent();
230        while (parent != null) {
231            parent.mTreeWeight += child.mTreeWeight;
232            parent = parent.getParent();
233        }
234    }
235
236    /**
237     * Removes the input child container from this container which is its parent.
238     *
239     * @return True if the container did contain the input child and it was detached.
240     */
241    @CallSuper
242    void removeChild(E child) {
243        if (mChildren.remove(child)) {
244            onChildRemoved(child);
245            child.setParent(null);
246        } else {
247            throw new IllegalArgumentException("removeChild: container=" + child.getName()
248                    + " is not a child of container=" + getName());
249        }
250    }
251
252    private void onChildRemoved(WindowContainer child) {
253        mTreeWeight -= child.mTreeWeight;
254        WindowContainer parent = getParent();
255        while (parent != null) {
256            parent.mTreeWeight -= child.mTreeWeight;
257            parent = parent.getParent();
258        }
259    }
260
261    /**
262     * Removes this window container and its children with no regard for what else might be going on
263     * in the system. For example, the container will be removed during animation if this method is
264     * called which isn't desirable. For most cases you want to call {@link #removeIfPossible()}
265     * which allows the system to defer removal until a suitable time.
266     */
267    @CallSuper
268    void removeImmediately() {
269        while (!mChildren.isEmpty()) {
270            final E child = mChildren.peekLast();
271            child.removeImmediately();
272            // Need to do this after calling remove on the child because the child might try to
273            // remove/detach itself from its parent which will cause an exception if we remove
274            // it before calling remove on the child.
275            if (mChildren.remove(child)) {
276                onChildRemoved(child);
277            }
278        }
279
280        if (mSurfaceControl != null) {
281            destroyAfterPendingTransaction(mSurfaceControl);
282            mSurfaceControl = null;
283        }
284
285        if (mParent != null) {
286            mParent.removeChild(this);
287        }
288
289        if (mController != null) {
290            setController(null);
291        }
292
293    }
294
295    /**
296     * @return The index of this element in the hierarchy tree in prefix order.
297     */
298    int getPrefixOrderIndex() {
299        if (mParent == null) {
300            return 0;
301        }
302        return mParent.getPrefixOrderIndex(this);
303    }
304
305    private int getPrefixOrderIndex(WindowContainer child) {
306        int order = 0;
307        for (int i = 0; i < mChildren.size(); i++) {
308            final WindowContainer childI = mChildren.get(i);
309            if (child == childI) {
310                break;
311            }
312            order += childI.mTreeWeight;
313        }
314        if (mParent != null) {
315            order += mParent.getPrefixOrderIndex(this);
316        }
317
318        // We also need to count ourselves.
319        order++;
320        return order;
321    }
322
323    /**
324     * Removes this window container and its children taking care not to remove them during a
325     * critical stage in the system. For example, some containers will not be removed during
326     * animation if this method is called.
327     */
328    // TODO: figure-out implementation that works best for this.
329    // E.g. when do we remove from parent list? maybe not...
330    void removeIfPossible() {
331        for (int i = mChildren.size() - 1; i >= 0; --i) {
332            final WindowContainer wc = mChildren.get(i);
333            wc.removeIfPossible();
334        }
335    }
336
337    /** Returns true if this window container has the input child. */
338    boolean hasChild(WindowContainer child) {
339        for (int i = mChildren.size() - 1; i >= 0; --i) {
340            final WindowContainer current = mChildren.get(i);
341            if (current == child || current.hasChild(child)) {
342                return true;
343            }
344        }
345        return false;
346    }
347
348    /**
349     * Move a child from it's current place in siblings list to the specified position,
350     * with an option to move all its parents to top.
351     * @param position Target position to move the child to.
352     * @param child Child to move to selected position.
353     * @param includingParents Flag indicating whether we need to move the entire branch of the
354     *                         hierarchy when we're moving a child to {@link #POSITION_TOP} or
355     *                         {@link #POSITION_BOTTOM}. When moving to other intermediate positions
356     *                         this flag will do nothing.
357     */
358    @CallSuper
359    void positionChildAt(int position, E child, boolean includingParents) {
360
361        if (child.getParent() != this) {
362            throw new IllegalArgumentException("removeChild: container=" + child.getName()
363                    + " is not a child of container=" + getName()
364                    + " current parent=" + child.getParent());
365        }
366
367        if ((position < 0 && position != POSITION_BOTTOM)
368                || (position > mChildren.size() && position != POSITION_TOP)) {
369            throw new IllegalArgumentException("positionAt: invalid position=" + position
370                    + ", children number=" + mChildren.size());
371        }
372
373        if (position >= mChildren.size() - 1) {
374            position = POSITION_TOP;
375        } else if (position == 0) {
376            position = POSITION_BOTTOM;
377        }
378
379        switch (position) {
380            case POSITION_TOP:
381                if (mChildren.peekLast() != child) {
382                    mChildren.remove(child);
383                    mChildren.add(child);
384                }
385                if (includingParents && getParent() != null) {
386                    getParent().positionChildAt(POSITION_TOP, this /* child */,
387                            true /* includingParents */);
388                }
389                break;
390            case POSITION_BOTTOM:
391                if (mChildren.peekFirst() != child) {
392                    mChildren.remove(child);
393                    mChildren.addFirst(child);
394                }
395                if (includingParents && getParent() != null) {
396                    getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
397                            true /* includingParents */);
398                }
399                break;
400            default:
401                mChildren.remove(child);
402                mChildren.add(position, child);
403        }
404    }
405
406    /**
407     * Update override configuration and recalculate full config.
408     * @see #mOverrideConfiguration
409     * @see #mFullConfiguration
410     */
411    @Override
412    public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
413        // We must diff before the configuration is applied so that we can capture the change
414        // against the existing bounds.
415        final int diff = diffOverrideBounds(overrideConfiguration.windowConfiguration.getBounds());
416        super.onOverrideConfigurationChanged(overrideConfiguration);
417        if (mParent != null) {
418            mParent.onDescendantOverrideConfigurationChanged();
419        }
420
421        if (diff == BOUNDS_CHANGE_NONE) {
422            return;
423        }
424
425        if ((diff & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
426            onResize();
427        } else {
428            onMovedByResize();
429        }
430    }
431
432    /**
433     * Notify that a descendant's overrideConfiguration has changed.
434     */
435    void onDescendantOverrideConfigurationChanged() {
436        if (mParent != null) {
437            mParent.onDescendantOverrideConfigurationChanged();
438        }
439    }
440
441    /**
442     * Notify that the display this container is on has changed.
443     * @param dc The new display this container is on.
444     */
445    void onDisplayChanged(DisplayContent dc) {
446        for (int i = mChildren.size() - 1; i >= 0; --i) {
447            final WindowContainer child = mChildren.get(i);
448            child.onDisplayChanged(dc);
449        }
450    }
451
452    void setWaitingForDrawnIfResizingChanged() {
453        for (int i = mChildren.size() - 1; i >= 0; --i) {
454            final WindowContainer wc = mChildren.get(i);
455            wc.setWaitingForDrawnIfResizingChanged();
456        }
457    }
458
459    void onResize() {
460        for (int i = mChildren.size() - 1; i >= 0; --i) {
461            final WindowContainer wc = mChildren.get(i);
462            wc.onResize();
463        }
464    }
465
466    void onMovedByResize() {
467        for (int i = mChildren.size() - 1; i >= 0; --i) {
468            final WindowContainer wc = mChildren.get(i);
469            wc.onMovedByResize();
470        }
471    }
472
473    void resetDragResizingChangeReported() {
474        for (int i = mChildren.size() - 1; i >= 0; --i) {
475            final WindowContainer wc = mChildren.get(i);
476            wc.resetDragResizingChangeReported();
477        }
478    }
479
480    void forceWindowsScaleableInTransaction(boolean force) {
481        for (int i = mChildren.size() - 1; i >= 0; --i) {
482            final WindowContainer wc = mChildren.get(i);
483            wc.forceWindowsScaleableInTransaction(force);
484        }
485    }
486
487    /**
488     * @return Whether our own container is running an animation or any child, no matter how deep in
489     *         the hierarchy, is animating.
490     */
491    boolean isSelfOrChildAnimating() {
492        if (isSelfAnimating()) {
493            return true;
494        }
495        for (int j = mChildren.size() - 1; j >= 0; j--) {
496            final WindowContainer wc = mChildren.get(j);
497            if (wc.isSelfOrChildAnimating()) {
498                return true;
499            }
500        }
501        return false;
502    }
503
504    /**
505     * @return Whether our own container is running an animation or our parent is animating. This
506     *         doesn't consider whether children are animating.
507     */
508    boolean isAnimating() {
509
510        // We are animating if we ourselves are animating or if our parent is animating.
511        return isSelfAnimating() || mParent != null && mParent.isAnimating();
512    }
513
514    /**
515     * @return {@code true} if in this subtree of the hierarchy we have an {@link AppWindowToken}
516     *         that is {@link #isSelfAnimating}; {@code false} otherwise.
517     */
518    boolean isAppAnimating() {
519        for (int j = mChildren.size() - 1; j >= 0; j--) {
520            final WindowContainer wc = mChildren.get(j);
521            if (wc.isAppAnimating()) {
522                return true;
523            }
524        }
525        return false;
526    }
527
528    /**
529     * @return Whether our own container running an animation at the moment.
530     */
531    boolean isSelfAnimating() {
532        return mSurfaceAnimator.isAnimating();
533    }
534
535    void sendAppVisibilityToClients() {
536        for (int i = mChildren.size() - 1; i >= 0; --i) {
537            final WindowContainer wc = mChildren.get(i);
538            wc.sendAppVisibilityToClients();
539        }
540    }
541
542    /**
543     * Returns true if the container or one of its children as some content it can display or wants
544     * to display (e.g. app views or saved surface).
545     *
546     * NOTE: While this method will return true if the there is some content to display, it doesn't
547     * mean the container is visible. Use {@link #isVisible()} to determine if the container is
548     * visible.
549     */
550    boolean hasContentToDisplay() {
551        for (int i = mChildren.size() - 1; i >= 0; --i) {
552            final WindowContainer wc = mChildren.get(i);
553            if (wc.hasContentToDisplay()) {
554                return true;
555            }
556        }
557        return false;
558    }
559
560    /**
561     * Returns true if the container or one of its children is considered visible from the
562     * WindowManager perspective which usually means valid surface and some other internal state
563     * are true.
564     *
565     * NOTE: While this method will return true if the surface is visible, it doesn't mean the
566     * client has actually displayed any content. Use {@link #hasContentToDisplay()} to determine if
567     * the container has any content to display.
568     */
569    boolean isVisible() {
570        // TODO: Will this be more correct if it checks the visibility of its parents?
571        // It depends...For example, Tasks and Stacks are only visible if there children are visible
572        // but, WindowState are not visible if there parent are not visible. Maybe have the
573        // container specify which direction to traverse for visibility?
574        for (int i = mChildren.size() - 1; i >= 0; --i) {
575            final WindowContainer wc = mChildren.get(i);
576            if (wc.isVisible()) {
577                return true;
578            }
579        }
580        return false;
581    }
582
583    /**
584     * @return Whether this child is on top of the window hierarchy.
585     */
586    boolean isOnTop() {
587        return getParent().getTopChild() == this && getParent().isOnTop();
588    }
589
590    /** Returns the top child container. */
591    E getTopChild() {
592        return mChildren.peekLast();
593    }
594
595    /** Returns true if there is still a removal being deferred */
596    boolean checkCompleteDeferredRemoval() {
597        boolean stillDeferringRemoval = false;
598
599        for (int i = mChildren.size() - 1; i >= 0; --i) {
600            final WindowContainer wc = mChildren.get(i);
601            stillDeferringRemoval |= wc.checkCompleteDeferredRemoval();
602        }
603
604        return stillDeferringRemoval;
605    }
606
607    /** Checks if all windows in an app are all drawn and shows them if needed. */
608    void checkAppWindowsReadyToShow() {
609        for (int i = mChildren.size() - 1; i >= 0; --i) {
610            final WindowContainer wc = mChildren.get(i);
611            wc.checkAppWindowsReadyToShow();
612        }
613    }
614
615    void onAppTransitionDone() {
616        for (int i = mChildren.size() - 1; i >= 0; --i) {
617            final WindowContainer wc = mChildren.get(i);
618            wc.onAppTransitionDone();
619        }
620    }
621
622    void setOrientation(int orientation) {
623        mOrientation = orientation;
624    }
625
626    int getOrientation() {
627        return getOrientation(mOrientation);
628    }
629
630    /**
631     * Returns the specified orientation for this window container or one of its children is there
632     * is one set, or {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSET} if no
633     * specification is set.
634     * NOTE: {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} is a
635     * specification...
636     *
637     * @param candidate The current orientation candidate that will be returned if we don't find a
638     *                  better match.
639     * @return The orientation as specified by this branch or the window hierarchy.
640     */
641    int getOrientation(int candidate) {
642        if (!fillsParent()) {
643            // Ignore containers that don't completely fill their parents.
644            return SCREEN_ORIENTATION_UNSET;
645        }
646
647        // The container fills its parent so we can use it orientation if it has one
648        // specified; otherwise we prefer to use the orientation of its topmost child that has one
649        // specified and fall back on this container's unset or unspecified value as a candidate
650        // if none of the children have a better candidate for the orientation.
651        if (mOrientation != SCREEN_ORIENTATION_UNSET
652                && mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
653            return mOrientation;
654        }
655
656        for (int i = mChildren.size() - 1; i >= 0; --i) {
657            final WindowContainer wc = mChildren.get(i);
658
659            // TODO: Maybe mOrientation should default to SCREEN_ORIENTATION_UNSET vs.
660            // SCREEN_ORIENTATION_UNSPECIFIED?
661            final int orientation = wc.getOrientation(candidate == SCREEN_ORIENTATION_BEHIND
662                    ? SCREEN_ORIENTATION_BEHIND : SCREEN_ORIENTATION_UNSET);
663            if (orientation == SCREEN_ORIENTATION_BEHIND) {
664                // container wants us to use the orientation of the container behind it. See if we
665                // can find one. Else return SCREEN_ORIENTATION_BEHIND so the caller can choose to
666                // look behind this container.
667                candidate = orientation;
668                continue;
669            }
670
671            if (orientation == SCREEN_ORIENTATION_UNSET) {
672                continue;
673            }
674
675            if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
676                // Use the orientation if the container fills its parent or requested an explicit
677                // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED.
678                return orientation;
679            }
680        }
681
682        return candidate;
683    }
684
685    /**
686     * Returns true if this container is opaque and fills all the space made available by its parent
687     * container.
688     *
689     * NOTE: It is possible for this container to occupy more space than the parent has (or less),
690     * this is just a signal from the client to window manager stating its intent, but not what it
691     * actually does.
692     */
693    boolean fillsParent() {
694        return false;
695    }
696
697    // TODO: Users would have their own window containers under the display container?
698    void switchUser() {
699        for (int i = mChildren.size() - 1; i >= 0; --i) {
700            mChildren.get(i).switchUser();
701        }
702    }
703
704    /**
705     * For all windows at or below this container call the callback.
706     * @param   callback Calls the {@link ToBooleanFunction#apply} method for each window found and
707     *                   stops the search if {@link ToBooleanFunction#apply} returns true.
708     * @param   traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of
709     *                              z-order, else from bottom-to-top.
710     * @return  True if the search ended before we reached the end of the hierarchy due to
711     *          {@link ToBooleanFunction#apply} returning true.
712     */
713    boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
714        if (traverseTopToBottom) {
715            for (int i = mChildren.size() - 1; i >= 0; --i) {
716                if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
717                    return true;
718                }
719            }
720        } else {
721            final int count = mChildren.size();
722            for (int i = 0; i < count; i++) {
723                if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
724                    return true;
725                }
726            }
727        }
728        return false;
729    }
730
731    void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) {
732        ForAllWindowsConsumerWrapper wrapper = obtainConsumerWrapper(callback);
733        forAllWindows(wrapper, traverseTopToBottom);
734        wrapper.release();
735    }
736
737    /**
738     * For all tasks at or below this container call the callback.
739     *
740     * @param callback Callback to be called for every task.
741     */
742    void forAllTasks(Consumer<Task> callback) {
743        for (int i = mChildren.size() - 1; i >= 0; --i) {
744            mChildren.get(i).forAllTasks(callback);
745        }
746    }
747
748    WindowState getWindow(Predicate<WindowState> callback) {
749        for (int i = mChildren.size() - 1; i >= 0; --i) {
750            final WindowState w = mChildren.get(i).getWindow(callback);
751            if (w != null) {
752                return w;
753            }
754        }
755
756        return null;
757    }
758
759    /**
760     * Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than
761     * the input container in terms of z-order.
762     */
763    @Override
764    public int compareTo(WindowContainer other) {
765        if (this == other) {
766            return 0;
767        }
768
769        if (mParent != null && mParent == other.mParent) {
770            final WindowList<WindowContainer> list = mParent.mChildren;
771            return list.indexOf(this) > list.indexOf(other) ? 1 : -1;
772        }
773
774        final LinkedList<WindowContainer> thisParentChain = mTmpChain1;
775        final LinkedList<WindowContainer> otherParentChain = mTmpChain2;
776        try {
777            getParents(thisParentChain);
778            other.getParents(otherParentChain);
779
780            // Find the common ancestor of both containers.
781            WindowContainer commonAncestor = null;
782            WindowContainer thisTop = thisParentChain.peekLast();
783            WindowContainer otherTop = otherParentChain.peekLast();
784            while (thisTop != null && otherTop != null && thisTop == otherTop) {
785                commonAncestor = thisParentChain.removeLast();
786                otherParentChain.removeLast();
787                thisTop = thisParentChain.peekLast();
788                otherTop = otherParentChain.peekLast();
789            }
790
791            // Containers don't belong to the same hierarchy???
792            if (commonAncestor == null) {
793                throw new IllegalArgumentException("No in the same hierarchy this="
794                        + thisParentChain + " other=" + otherParentChain);
795            }
796
797            // Children are always considered greater than their parents, so if one of the containers
798            // we are comparing it the parent of the other then whichever is the child is greater.
799            if (commonAncestor == this) {
800                return -1;
801            } else if (commonAncestor == other) {
802                return 1;
803            }
804
805            // The position of the first non-common ancestor in the common ancestor list determines
806            // which is greater the which.
807            final WindowList<WindowContainer> list = commonAncestor.mChildren;
808            return list.indexOf(thisParentChain.peekLast()) > list.indexOf(otherParentChain.peekLast())
809                    ? 1 : -1;
810        } finally {
811            mTmpChain1.clear();
812            mTmpChain2.clear();
813        }
814    }
815
816    private void getParents(LinkedList<WindowContainer> parents) {
817        parents.clear();
818        WindowContainer current = this;
819        do {
820            parents.addLast(current);
821            current = current.mParent;
822        } while (current != null);
823    }
824
825    WindowContainerController getController() {
826        return mController;
827    }
828
829    void setController(WindowContainerController controller) {
830        if (mController != null && controller != null) {
831            throw new IllegalArgumentException("Can't set controller=" + mController
832                    + " for container=" + this + " Already set to=" + mController);
833        }
834        if (controller != null) {
835            controller.setContainer(this);
836        } else if (mController != null) {
837            mController.setContainer(null);
838        }
839        mController = controller;
840    }
841
842    SurfaceControl.Builder makeSurface() {
843        final WindowContainer p = getParent();
844        return p.makeChildSurface(this);
845    }
846
847    /**
848     * @param child The WindowContainer this child surface is for, or null if the Surface
849     *              is not assosciated with a WindowContainer (e.g. a surface used for Dimming).
850     */
851    SurfaceControl.Builder makeChildSurface(WindowContainer child) {
852        final WindowContainer p = getParent();
853        // Give the parent a chance to set properties. In hierarchy v1 we rely
854        // on this to set full-screen dimensions on all our Surface-less Layers.
855        return p.makeChildSurface(child)
856                .setParent(mSurfaceControl);
857    }
858
859    @Override
860    public SurfaceControl getParentSurfaceControl() {
861        final WindowContainer parent = getParent();
862        if (parent == null) {
863            return null;
864        }
865        return parent.getSurfaceControl();
866    }
867
868    /**
869     * @return Whether this WindowContainer should be magnified by the accessibility magnifier.
870     */
871    boolean shouldMagnify() {
872        for (int i = 0; i < mChildren.size(); i++) {
873            if (!mChildren.get(i).shouldMagnify()) {
874                return false;
875            }
876        }
877        return true;
878    }
879
880    SurfaceSession getSession() {
881        if (getParent() != null) {
882            return getParent().getSession();
883        }
884        return null;
885    }
886
887    void assignLayer(Transaction t, int layer) {
888        final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
889        if (mSurfaceControl != null && changed) {
890            setLayer(t, layer);
891            mLastLayer = layer;
892            mLastRelativeToLayer = null;
893        }
894    }
895
896    void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
897        final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
898        if (mSurfaceControl != null && changed) {
899            setRelativeLayer(t, relativeTo, layer);
900            mLastLayer = layer;
901            mLastRelativeToLayer = relativeTo;
902        }
903    }
904
905    protected void setLayer(Transaction t, int layer) {
906
907        // Route through surface animator to accommodate that our surface control might be
908        // attached to the leash, and leash is attached to parent container.
909        mSurfaceAnimator.setLayer(t, layer);
910    }
911
912    protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
913
914        // Route through surface animator to accommodate that our surface control might be
915        // attached to the leash, and leash is attached to parent container.
916        mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer);
917    }
918
919    protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
920        mSurfaceAnimator.reparent(t, newParent);
921    }
922
923    void assignChildLayers(Transaction t) {
924        int layer = 0;
925
926        // We use two passes as a way to promote children which
927        // need Z-boosting to the end of the list.
928        for (int j = 0; j < mChildren.size(); ++j) {
929            final WindowContainer wc = mChildren.get(j);
930            wc.assignChildLayers(t);
931            if (!wc.needsZBoost()) {
932                wc.assignLayer(t, layer++);
933            }
934        }
935        for (int j = 0; j < mChildren.size(); ++j) {
936            final WindowContainer wc = mChildren.get(j);
937            if (wc.needsZBoost()) {
938                wc.assignLayer(t, layer++);
939            }
940        }
941    }
942
943    void assignChildLayers() {
944        assignChildLayers(getPendingTransaction());
945        scheduleAnimation();
946    }
947
948    boolean needsZBoost() {
949        for (int i = 0; i < mChildren.size(); i++) {
950            if (mChildren.get(i).needsZBoost()) {
951                return true;
952            }
953        }
954        return false;
955    }
956
957    /**
958     * Write to a protocol buffer output stream. Protocol buffer message definition is at
959     * {@link com.android.server.wm.proto.WindowContainerProto}.
960     *
961     * @param proto     Stream to write the WindowContainer object to.
962     * @param fieldId   Field Id of the WindowContainer as defined in the parent message.
963     * @param trim      If true, reduce the amount of data written.
964     * @hide
965     */
966    @CallSuper
967    @Override
968    public void writeToProto(ProtoOutputStream proto, long fieldId, boolean trim) {
969        final long token = proto.start(fieldId);
970        super.writeToProto(proto, CONFIGURATION_CONTAINER, trim);
971        proto.write(ORIENTATION, mOrientation);
972        proto.write(VISIBLE, isVisible());
973        proto.end(token);
974    }
975
976    private ForAllWindowsConsumerWrapper obtainConsumerWrapper(Consumer<WindowState> consumer) {
977        ForAllWindowsConsumerWrapper wrapper = mConsumerWrapperPool.acquire();
978        if (wrapper == null) {
979            wrapper = new ForAllWindowsConsumerWrapper();
980        }
981        wrapper.setConsumer(consumer);
982        return wrapper;
983    }
984
985    private final class ForAllWindowsConsumerWrapper implements ToBooleanFunction<WindowState> {
986
987        private Consumer<WindowState> mConsumer;
988
989        void setConsumer(Consumer<WindowState> consumer) {
990            mConsumer = consumer;
991        }
992
993        @Override
994        public boolean apply(WindowState w) {
995            mConsumer.accept(w);
996            return false;
997        }
998
999        void release() {
1000            mConsumer = null;
1001            mConsumerWrapperPool.release(this);
1002        }
1003    }
1004
1005    // TODO(b/68336570): Should this really be on WindowContainer since it
1006    // can only be used on the top-level nodes that aren't animated?
1007    // (otherwise we would be fighting other callers of setMatrix).
1008    void applyMagnificationSpec(Transaction t, MagnificationSpec spec) {
1009        if (shouldMagnify()) {
1010            t.setMatrix(mSurfaceControl, spec.scale, 0, 0, spec.scale)
1011                    .setPosition(mSurfaceControl, spec.offsetX, spec.offsetY);
1012        } else {
1013            for (int i = 0; i < mChildren.size(); i++) {
1014                mChildren.get(i).applyMagnificationSpec(t, spec);
1015            }
1016        }
1017    }
1018
1019    /**
1020     * TODO: Once we totally eliminate global transaction we will pass transaction in here
1021     * rather than merging to global.
1022     */
1023    void prepareSurfaces() {
1024        SurfaceControl.mergeToGlobalTransaction(getPendingTransaction());
1025        for (int i = 0; i < mChildren.size(); i++) {
1026            mChildren.get(i).prepareSurfaces();
1027        }
1028    }
1029
1030    /**
1031     * Trigger a call to prepareSurfaces from the animation thread, such that
1032     * mPendingTransaction will be applied.
1033     */
1034    void scheduleAnimation() {
1035        if (mParent != null) {
1036            mParent.scheduleAnimation();
1037        }
1038    }
1039
1040    @Override
1041    public SurfaceControl getSurfaceControl() {
1042        return mSurfaceControl;
1043    }
1044
1045    /**
1046     * Destroy a given surface after executing mPendingTransaction. This is
1047     * largely a workaround for destroy not being part of transactions
1048     * rather than an intentional design, so please take care when
1049     * expanding use.
1050     */
1051    @Override
1052    public void destroyAfterPendingTransaction(SurfaceControl surface) {
1053        if (mParent != null) {
1054            mParent.destroyAfterPendingTransaction(surface);
1055        }
1056    }
1057
1058    @Override
1059    public Transaction getPendingTransaction() {
1060        return mPendingTransaction;
1061    }
1062
1063    /**
1064     * Starts an animation on the container.
1065     *
1066     * @param anim The animation to run.
1067     * @param hidden Whether our container is currently hidden. TODO This should use isVisible at
1068     *               some point but the meaning is too weird to work for all containers.
1069     */
1070    void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
1071        if (DEBUG_ANIM) Slog.v(TAG, "Starting animation on " + this + ": " + anim);
1072
1073        // TODO: This should use isVisible() but because isVisible has a really weird meaning at
1074        // the moment this doesn't work for all animatable window containers.
1075        mSurfaceAnimator.startAnimation(t, anim, hidden);
1076    }
1077
1078    void transferAnimation(WindowContainer from) {
1079        mSurfaceAnimator.transferAnimation(from.mSurfaceAnimator);
1080    }
1081
1082    void cancelAnimation() {
1083        mSurfaceAnimator.cancelAnimation();
1084    }
1085
1086    @Override
1087    public Builder makeAnimationLeash() {
1088        return makeSurface();
1089    }
1090
1091    /**
1092     * @return The layer on which all app animations are happening.
1093     */
1094    SurfaceControl getAppAnimationLayer() {
1095        final WindowContainer parent = getParent();
1096        if (parent != null) {
1097            return parent.getAppAnimationLayer();
1098        }
1099        return null;
1100    }
1101
1102    @Override
1103    public void commitPendingTransaction() {
1104        scheduleAnimation();
1105    }
1106
1107    private void reassignLayer(Transaction t) {
1108        final WindowContainer parent = getParent();
1109        if (parent != null) {
1110            parent.assignChildLayers(t);
1111        }
1112    }
1113
1114    @Override
1115    public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
1116        reassignLayer(t);
1117    }
1118
1119    @Override
1120    public void onAnimationLeashDestroyed(Transaction t) {
1121        reassignLayer(t);
1122    }
1123
1124    /**
1125     * Called when an animation has finished running.
1126     */
1127    protected void onAnimationFinished() {
1128    }
1129
1130    /**
1131     * @return The currently running animation, if any, or {@code null} otherwise.
1132     */
1133    AnimationAdapter getAnimation() {
1134        return mSurfaceAnimator.getAnimation();
1135    }
1136
1137    /**
1138     * @see SurfaceAnimator#startDelayingAnimationStart
1139     */
1140    void startDelayingAnimationStart() {
1141        mSurfaceAnimator.startDelayingAnimationStart();
1142    }
1143
1144    /**
1145     * @see SurfaceAnimator#endDelayingAnimationStart
1146     */
1147    void endDelayingAnimationStart() {
1148        mSurfaceAnimator.endDelayingAnimationStart();
1149    }
1150
1151    @Override
1152    public int getSurfaceWidth() {
1153        return mSurfaceControl.getWidth();
1154    }
1155
1156    @Override
1157    public int getSurfaceHeight() {
1158        return mSurfaceControl.getHeight();
1159    }
1160
1161    @CallSuper
1162    void dump(PrintWriter pw, String prefix, boolean dumpAll) {
1163        if (mSurfaceAnimator.isAnimating()) {
1164            pw.print(prefix); pw.println("ContainerAnimator:");
1165            mSurfaceAnimator.dump(pw, prefix + "  ");
1166        }
1167    }
1168
1169    void updateSurfacePosition(SurfaceControl.Transaction transaction) {
1170        if (mSurfaceControl == null) {
1171            return;
1172        }
1173
1174        getRelativePosition(mTmpPos);
1175        transaction.setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y);
1176
1177        for (int i = mChildren.size() - 1; i >= 0; i--) {
1178            mChildren.get(i).updateSurfacePosition(transaction);
1179        }
1180    }
1181
1182    void getRelativePosition(Point outPos) {
1183        final Rect bounds = getBounds();
1184        outPos.set(bounds.left, bounds.top);
1185        final WindowContainer parent = getParent();
1186        if (parent != null) {
1187            final Rect parentBounds = parent.getBounds();
1188            outPos.offset(-parentBounds.left, -parentBounds.top);
1189        }
1190    }
1191}
1192