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