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