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