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