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