WindowContainer.java revision 571771c3fc912e63f83b75693c0f3c85ec9622da
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 android.annotation.CallSuper;
20
21import java.util.Comparator;
22import java.util.LinkedList;
23
24/**
25 * Defines common functionality for classes that can hold windows directly or through their
26 * children.
27 * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
28 * changes are made to this class.
29 */
30class WindowContainer {
31
32    // The parent of this window container.
33    private WindowContainer mParent = null;
34
35    // List of children for this window container. List is in z-order as the children appear on
36    // screen with the top-most window container at the tail of the list.
37    protected final LinkedList<WindowContainer> mChildren = new LinkedList();
38
39    protected WindowContainer getParent() {
40        return mParent;
41    }
42
43    /**
44     * Adds the input window container has a child of this container in order based on the input
45     * comparator.
46     * @param child The window container to add as a child of this window container.
47     * @param comparator Comparator to use in determining the position the child should be added to.
48     *                   If null, the child will be added to the top.
49     */
50    @CallSuper
51    protected void addChild(WindowContainer child, Comparator<WindowContainer> comparator) {
52        child.mParent = this;
53
54        if (mChildren.isEmpty() || comparator == null) {
55            mChildren.add(child);
56            return;
57        }
58
59        final int count = mChildren.size();
60        for (int i = 0; i < count; i++) {
61            if (comparator.compare(child, mChildren.get(i)) < 0) {
62                mChildren.add(i, child);
63                return;
64            }
65        }
66
67        mChildren.add(child);
68    }
69
70    /**
71     * Removes this window container and its children with no regard for what else might be going on
72     * in the system. For example, the container will be removed during animation if this method is
73     * called which isn't desirable. For most cases you want to call {@link #removeIfPossible()}
74     * which allows the system to defer removal until a suitable time.
75     */
76    @CallSuper
77    void removeImmediately() {
78        while (!mChildren.isEmpty()) {
79            final WindowContainer child = mChildren.peekLast();
80            child.removeImmediately();
81            // Need to do this after calling remove on the child because the child might try to
82            // remove/detach itself from its parent which will cause an exception if we remove
83            // it before calling remove on the child.
84            mChildren.remove(child);
85        }
86
87        if (mParent != null) {
88            mParent.detachChild(this);
89        }
90    }
91
92    /**
93     * Removes this window container and its children taking care not to remove them during a
94     * critical stage in the system. For example, some containers will not be removed during
95     * animation if this method is called.
96     */
97    // TODO: figure-out implementation that works best for this.
98    // E.g. when do we remove from parent list? maybe not...
99    void removeIfPossible() {
100        for (int i = mChildren.size() - 1; i >= 0; --i) {
101            final WindowContainer wc = mChildren.get(i);
102            wc.removeIfPossible();
103        }
104    }
105
106    /** Detaches the input child container from this container which is its parent. */
107    @CallSuper
108    void detachChild(WindowContainer child) {
109        if (mChildren.remove(child)) {
110            child.mParent = null;
111        } else {
112            throw new IllegalArgumentException("detachChild: container=" + child
113                    + " is not a child of container=" + this);
114        }
115    }
116
117    /** Returns true if this window container has the input child. */
118    boolean hasChild(WindowContainer child) {
119        for (int i = mChildren.size() - 1; i >= 0; --i) {
120            final WindowContainer current = mChildren.get(i);
121            if (current == child || current.hasChild(child)) {
122                return true;
123            }
124        }
125        return false;
126    }
127
128    void setWaitingForDrawnIfResizingChanged() {
129        for (int i = mChildren.size() - 1; i >= 0; --i) {
130            final WindowContainer wc = mChildren.get(i);
131            wc.setWaitingForDrawnIfResizingChanged();
132        }
133    }
134
135    void onResize() {
136        for (int i = mChildren.size() - 1; i >= 0; --i) {
137            final WindowContainer wc = mChildren.get(i);
138            wc.onResize();
139        }
140    }
141
142    void onMovedByResize() {
143        for (int i = mChildren.size() - 1; i >= 0; --i) {
144            final WindowContainer wc = mChildren.get(i);
145            wc.onMovedByResize();
146        }
147    }
148
149    void resetDragResizingChangeReported() {
150        for (int i = mChildren.size() - 1; i >= 0; --i) {
151            final WindowContainer wc = mChildren.get(i);
152            wc.resetDragResizingChangeReported();
153        }
154    }
155
156    boolean detachFromDisplay() {
157        boolean didSomething = false;
158        for (int i = mChildren.size() - 1; i >= 0; --i) {
159            final WindowContainer wc = mChildren.get(i);
160            didSomething |= wc.detachFromDisplay();
161        }
162        return didSomething;
163    }
164
165    void forceWindowsScaleableInTransaction(boolean force) {
166        for (int i = mChildren.size() - 1; i >= 0; --i) {
167            final WindowContainer wc = mChildren.get(i);
168            wc.forceWindowsScaleableInTransaction(force);
169        }
170    }
171
172    boolean isAnimating() {
173        for (int j = mChildren.size() - 1; j >= 0; j--) {
174            final WindowContainer wc = mChildren.get(j);
175            if (wc.isAnimating()) {
176                return true;
177            }
178        }
179        return false;
180    }
181
182    void sendAppVisibilityToClients() {
183        for (int i = mChildren.size() - 1; i >= 0; --i) {
184            final WindowContainer wc = mChildren.get(i);
185            wc.sendAppVisibilityToClients();
186        }
187    }
188
189    void setVisibleBeforeClientHidden() {
190        for (int i = mChildren.size() - 1; i >= 0; --i) {
191            final WindowContainer wc = mChildren.get(i);
192            wc.setVisibleBeforeClientHidden();
193        }
194    }
195
196    boolean isVisible() {
197        for (int i = mChildren.size() - 1; i >= 0; --i) {
198            final WindowContainer wc = mChildren.get(i);
199            if (wc.isVisible()) {
200                return true;
201            }
202        }
203        return false;
204    }
205
206    /** Returns the top child container or this container if there are no children. */
207    WindowContainer getTop() {
208        return mChildren.isEmpty() ? this : mChildren.peekLast();
209    }
210}
211