blob: bf79dfa15ea59f3bfe0b36865b8637bc965a8d86 [file] [log] [blame]
Wale Ogunwaled63594a2016-07-18 07:48:30 -07001/*
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
Jorim Jaggi612bb882017-05-16 17:11:18 +020019import 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.content.res.Configuration.EMPTY;
23
Wale Ogunwaled63594a2016-07-18 07:48:30 -070024import android.annotation.CallSuper;
Andrii Kulian441e4492016-09-29 15:25:00 -070025import android.content.res.Configuration;
Wale Ogunwaleee41d4a2016-11-21 08:41:10 -080026import android.util.Pools;
27
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -080028import com.android.internal.util.ToBooleanFunction;
Wale Ogunwaled63594a2016-07-18 07:48:30 -070029
30import java.util.Comparator;
31import java.util.LinkedList;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070032import java.util.function.Consumer;
Wale Ogunwaled1880962016-11-08 10:31:59 -080033import java.util.function.Predicate;
Wale Ogunwaled63594a2016-07-18 07:48:30 -070034
35/**
36 * Defines common functionality for classes that can hold windows directly or through their
Wale Ogunwale51362492016-09-08 17:49:17 -070037 * children in a hierarchy form.
Wale Ogunwaled63594a2016-07-18 07:48:30 -070038 * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
39 * changes are made to this class.
40 */
Wale Ogunwale98d62312017-07-12 09:24:56 -070041class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
42 implements Comparable<WindowContainer> {
Wale Ogunwaled63594a2016-07-18 07:48:30 -070043
Andrii Kuliand2765632016-12-12 22:26:34 -080044 static final int POSITION_TOP = Integer.MAX_VALUE;
45 static final int POSITION_BOTTOM = Integer.MIN_VALUE;
46
Andrii Kulian441e4492016-09-29 15:25:00 -070047 /**
48 * The parent of this window container.
49 * For removing or setting new parent {@link #setParent} should be used, because it also
50 * performs configuration updates based on new parent's settings.
51 */
52 private WindowContainer mParent = null;
Wale Ogunwaled63594a2016-07-18 07:48:30 -070053
54 // List of children for this window container. List is in z-order as the children appear on
55 // screen with the top-most window container at the tail of the list.
Jorim Jaggi612bb882017-05-16 17:11:18 +020056 protected final WindowList<E> mChildren = new WindowList<E>();
Wale Ogunwaled63594a2016-07-18 07:48:30 -070057
Wale Ogunwale51362492016-09-08 17:49:17 -070058 // The specified orientation for this window container.
59 protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
60
Wale Ogunwaleee41d4a2016-11-21 08:41:10 -080061 private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool =
62 new Pools.SynchronizedPool<>(3);
63
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080064 // The owner/creator for this container. No controller if null.
65 private WindowContainerController mController;
66
Wale Ogunwale98d62312017-07-12 09:24:56 -070067 @Override
Wale Ogunwale51362492016-09-08 17:49:17 -070068 final protected WindowContainer getParent() {
Wale Ogunwaled63594a2016-07-18 07:48:30 -070069 return mParent;
70 }
71
Wale Ogunwale98d62312017-07-12 09:24:56 -070072
73 @Override
74 final protected int getChildCount() {
75 return mChildren.size();
76 }
77
78 @Override
79 final protected E getChildAt(int index) {
80 return mChildren.get(index);
81 }
82
Andrii Kulian441e4492016-09-29 15:25:00 -070083 final protected void setParent(WindowContainer parent) {
84 mParent = parent;
Andrii Kulianb94292e2016-10-19 13:30:58 -070085 // Removing parent usually means that we've detached this entity to destroy it or to attach
86 // to another parent. In both cases we don't need to update the configuration now.
87 if (mParent != null) {
88 // Update full configuration of this container and all its children.
Wale Ogunwale98d62312017-07-12 09:24:56 -070089 onConfigurationChanged(mParent.getConfiguration());
Andrii Kulianb94292e2016-10-19 13:30:58 -070090 // Update merged override configuration of this container and all its children.
91 onMergedOverrideConfigurationChanged();
92 }
Andrii Kuliand2765632016-12-12 22:26:34 -080093
94 onParentSet();
95 }
96
97 /**
98 * Callback that is triggered when @link WindowContainer#setParent(WindowContainer)} was called.
99 * Supposed to be overridden and contain actions that should be executed after parent was set.
100 */
101 void onParentSet() {
102 // Do nothing by default.
Andrii Kulian441e4492016-09-29 15:25:00 -0700103 }
104
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700105 // Temp. holders for a chain of containers we are currently processing.
106 private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList();
107 private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList();
108
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700109 /**
110 * Adds the input window container has a child of this container in order based on the input
111 * comparator.
112 * @param child The window container to add as a child of this window container.
113 * @param comparator Comparator to use in determining the position the child should be added to.
114 * If null, the child will be added to the top.
115 */
116 @CallSuper
Wale Ogunwaled90546a2016-09-09 23:28:03 -0700117 protected void addChild(E child, Comparator<E> comparator) {
Andrii Kulian441e4492016-09-29 15:25:00 -0700118 if (child.getParent() != null) {
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700119 throw new IllegalArgumentException("addChild: container=" + child.getName()
Andrii Kulian441e4492016-09-29 15:25:00 -0700120 + " is already a child of container=" + child.getParent().getName()
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700121 + " can't add to container=" + getName());
Wale Ogunwalef6192862016-09-10 13:42:30 -0700122 }
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700123
Andrii Kulianb94292e2016-10-19 13:30:58 -0700124 int positionToAdd = -1;
125 if (comparator != null) {
126 final int count = mChildren.size();
127 for (int i = 0; i < count; i++) {
128 if (comparator.compare(child, mChildren.get(i)) < 0) {
129 positionToAdd = i;
130 break;
131 }
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700132 }
133 }
134
Andrii Kulianb94292e2016-10-19 13:30:58 -0700135 if (positionToAdd == -1) {
136 mChildren.add(child);
137 } else {
138 mChildren.add(positionToAdd, child);
139 }
140 // Set the parent after we've actually added a child in case a subclass depends on this.
141 child.setParent(this);
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700142 }
143
Wale Ogunwalef6192862016-09-10 13:42:30 -0700144 /** Adds the input window container has a child of this container at the input index. */
145 @CallSuper
Wale Ogunwale72919d22016-12-08 18:58:50 -0800146 void addChild(E child, int index) {
Andrii Kulian441e4492016-09-29 15:25:00 -0700147 if (child.getParent() != null) {
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700148 throw new IllegalArgumentException("addChild: container=" + child.getName()
Andrii Kulian441e4492016-09-29 15:25:00 -0700149 + " is already a child of container=" + child.getParent().getName()
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700150 + " can't add to container=" + getName());
Wale Ogunwalef6192862016-09-10 13:42:30 -0700151 }
Wale Ogunwalef6192862016-09-10 13:42:30 -0700152 mChildren.add(index, child);
Andrii Kulianb94292e2016-10-19 13:30:58 -0700153 // Set the parent after we've actually added a child in case a subclass depends on this.
154 child.setParent(this);
Wale Ogunwalef6192862016-09-10 13:42:30 -0700155 }
156
157 /**
158 * Removes the input child container from this container which is its parent.
159 *
160 * @return True if the container did contain the input child and it was detached.
161 */
162 @CallSuper
163 void removeChild(E child) {
164 if (mChildren.remove(child)) {
Andrii Kulian441e4492016-09-29 15:25:00 -0700165 child.setParent(null);
Wale Ogunwalef6192862016-09-10 13:42:30 -0700166 } else {
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700167 throw new IllegalArgumentException("removeChild: container=" + child.getName()
168 + " is not a child of container=" + getName());
Wale Ogunwalef6192862016-09-10 13:42:30 -0700169 }
170 }
171
Wale Ogunwale571771c2016-08-26 13:18:50 -0700172 /**
173 * Removes this window container and its children with no regard for what else might be going on
174 * in the system. For example, the container will be removed during animation if this method is
175 * called which isn't desirable. For most cases you want to call {@link #removeIfPossible()}
176 * which allows the system to defer removal until a suitable time.
177 */
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700178 @CallSuper
Wale Ogunwale571771c2016-08-26 13:18:50 -0700179 void removeImmediately() {
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700180 while (!mChildren.isEmpty()) {
Wale Ogunwale571771c2016-08-26 13:18:50 -0700181 final WindowContainer child = mChildren.peekLast();
182 child.removeImmediately();
183 // Need to do this after calling remove on the child because the child might try to
184 // remove/detach itself from its parent which will cause an exception if we remove
185 // it before calling remove on the child.
186 mChildren.remove(child);
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700187 }
188
189 if (mParent != null) {
Wale Ogunwalef6192862016-09-10 13:42:30 -0700190 mParent.removeChild(this);
Wale Ogunwale571771c2016-08-26 13:18:50 -0700191 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800192
193 if (mController != null) {
194 setController(null);
195 }
Wale Ogunwale571771c2016-08-26 13:18:50 -0700196 }
197
198 /**
199 * Removes this window container and its children taking care not to remove them during a
200 * critical stage in the system. For example, some containers will not be removed during
201 * animation if this method is called.
202 */
203 // TODO: figure-out implementation that works best for this.
204 // E.g. when do we remove from parent list? maybe not...
205 void removeIfPossible() {
206 for (int i = mChildren.size() - 1; i >= 0; --i) {
207 final WindowContainer wc = mChildren.get(i);
208 wc.removeIfPossible();
209 }
210 }
211
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700212 /** Returns true if this window container has the input child. */
213 boolean hasChild(WindowContainer child) {
214 for (int i = mChildren.size() - 1; i >= 0; --i) {
215 final WindowContainer current = mChildren.get(i);
216 if (current == child || current.hasChild(child)) {
217 return true;
218 }
219 }
220 return false;
221 }
Wale Ogunwale9bc47732016-08-10 14:44:22 -0700222
Andrii Kulian441e4492016-09-29 15:25:00 -0700223 /**
Andrii Kuliand2765632016-12-12 22:26:34 -0800224 * Move a child from it's current place in siblings list to the specified position,
225 * with an option to move all its parents to top.
226 * @param position Target position to move the child to.
227 * @param child Child to move to selected position.
228 * @param includingParents Flag indicating whether we need to move the entire branch of the
229 * hierarchy when we're moving a child to {@link #POSITION_TOP} or
230 * {@link #POSITION_BOTTOM}. When moving to other intermediate positions
231 * this flag will do nothing.
232 */
233 @CallSuper
234 void positionChildAt(int position, E child, boolean includingParents) {
Wale Ogunwalec5cc3012017-01-13 13:26:16 -0800235
236 if (child.getParent() != this) {
237 throw new IllegalArgumentException("removeChild: container=" + child.getName()
238 + " is not a child of container=" + getName()
239 + " current parent=" + child.getParent());
240 }
241
Andrii Kuliand2765632016-12-12 22:26:34 -0800242 if ((position < 0 && position != POSITION_BOTTOM)
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800243 || (position > mChildren.size() && position != POSITION_TOP)) {
Andrii Kuliand2765632016-12-12 22:26:34 -0800244 throw new IllegalArgumentException("positionAt: invalid position=" + position
245 + ", children number=" + mChildren.size());
246 }
247
Wale Ogunwalec5cc3012017-01-13 13:26:16 -0800248 if (position >= mChildren.size() - 1) {
Andrii Kuliand2765632016-12-12 22:26:34 -0800249 position = POSITION_TOP;
250 } else if (position == 0) {
251 position = POSITION_BOTTOM;
252 }
253
254 switch (position) {
255 case POSITION_TOP:
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800256 if (mChildren.peekLast() != child) {
Andrii Kuliand2765632016-12-12 22:26:34 -0800257 mChildren.remove(child);
Jorim Jaggi612bb882017-05-16 17:11:18 +0200258 mChildren.add(child);
Andrii Kuliand2765632016-12-12 22:26:34 -0800259 }
260 if (includingParents && getParent() != null) {
261 getParent().positionChildAt(POSITION_TOP, this /* child */,
262 true /* includingParents */);
263 }
264 break;
265 case POSITION_BOTTOM:
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800266 if (mChildren.peekFirst() != child) {
Andrii Kuliand2765632016-12-12 22:26:34 -0800267 mChildren.remove(child);
268 mChildren.addFirst(child);
269 }
270 if (includingParents && getParent() != null) {
271 getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
272 true /* includingParents */);
273 }
274 break;
275 default:
276 mChildren.remove(child);
277 mChildren.add(position, child);
278 }
279 }
280
281 /**
Andrii Kulian441e4492016-09-29 15:25:00 -0700282 * Update override configuration and recalculate full config.
283 * @see #mOverrideConfiguration
284 * @see #mFullConfiguration
285 */
Wale Ogunwale98d62312017-07-12 09:24:56 -0700286 @Override
287 final public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
288 super.onOverrideConfigurationChanged(overrideConfiguration);
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700289 if (mParent != null) {
290 mParent.onDescendantOverrideConfigurationChanged();
291 }
292 }
293
294 /**
295 * Notify that a descendant's overrideConfiguration has changed.
296 */
297 void onDescendantOverrideConfigurationChanged() {
298 if (mParent != null) {
299 mParent.onDescendantOverrideConfigurationChanged();
300 }
Andrii Kulian441e4492016-09-29 15:25:00 -0700301 }
302
303 /**
Wale Ogunwale02319a62016-09-26 15:21:22 -0700304 * Notify that the display this container is on has changed.
305 * @param dc The new display this container is on.
306 */
307 void onDisplayChanged(DisplayContent dc) {
308 for (int i = mChildren.size() - 1; i >= 0; --i) {
309 final WindowContainer child = mChildren.get(i);
310 child.onDisplayChanged(dc);
311 }
312 }
313
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700314 void setWaitingForDrawnIfResizingChanged() {
315 for (int i = mChildren.size() - 1; i >= 0; --i) {
316 final WindowContainer wc = mChildren.get(i);
317 wc.setWaitingForDrawnIfResizingChanged();
318 }
319 }
320
321 void onResize() {
322 for (int i = mChildren.size() - 1; i >= 0; --i) {
323 final WindowContainer wc = mChildren.get(i);
324 wc.onResize();
325 }
326 }
327
328 void onMovedByResize() {
329 for (int i = mChildren.size() - 1; i >= 0; --i) {
330 final WindowContainer wc = mChildren.get(i);
331 wc.onMovedByResize();
332 }
333 }
334
335 void resetDragResizingChangeReported() {
336 for (int i = mChildren.size() - 1; i >= 0; --i) {
337 final WindowContainer wc = mChildren.get(i);
338 wc.resetDragResizingChangeReported();
339 }
340 }
341
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700342 void forceWindowsScaleableInTransaction(boolean force) {
343 for (int i = mChildren.size() - 1; i >= 0; --i) {
344 final WindowContainer wc = mChildren.get(i);
345 wc.forceWindowsScaleableInTransaction(force);
346 }
347 }
348
349 boolean isAnimating() {
350 for (int j = mChildren.size() - 1; j >= 0; j--) {
351 final WindowContainer wc = mChildren.get(j);
352 if (wc.isAnimating()) {
353 return true;
354 }
355 }
356 return false;
357 }
358
359 void sendAppVisibilityToClients() {
360 for (int i = mChildren.size() - 1; i >= 0; --i) {
361 final WindowContainer wc = mChildren.get(i);
362 wc.sendAppVisibilityToClients();
363 }
364 }
365
366 void setVisibleBeforeClientHidden() {
367 for (int i = mChildren.size() - 1; i >= 0; --i) {
368 final WindowContainer wc = mChildren.get(i);
369 wc.setVisibleBeforeClientHidden();
370 }
371 }
372
Wale Ogunwale44f21802016-09-02 12:49:48 -0700373 /**
374 * Returns true if the container or one of its children as some content it can display or wants
375 * to display (e.g. app views or saved surface).
376 *
377 * NOTE: While this method will return true if the there is some content to display, it doesn't
378 * mean the container is visible. Use {@link #isVisible()} to determine if the container is
379 * visible.
380 */
381 boolean hasContentToDisplay() {
382 for (int i = mChildren.size() - 1; i >= 0; --i) {
383 final WindowContainer wc = mChildren.get(i);
384 if (wc.hasContentToDisplay()) {
385 return true;
386 }
387 }
388 return false;
389 }
390
391 /**
392 * Returns true if the container or one of its children is considered visible from the
393 * WindowManager perspective which usually means valid surface and some other internal state
394 * are true.
395 *
396 * NOTE: While this method will return true if the surface is visible, it doesn't mean the
397 * client has actually displayed any content. Use {@link #hasContentToDisplay()} to determine if
398 * the container has any content to display.
399 */
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700400 boolean isVisible() {
Wale Ogunwalef6192862016-09-10 13:42:30 -0700401 // TODO: Will this be more correct if it checks the visibility of its parents?
402 // It depends...For example, Tasks and Stacks are only visible if there children are visible
403 // but, WindowState are not visible if there parent are not visible. Maybe have the
Andrii Kuliancd5dcb8b2017-01-03 17:09:45 -0800404 // container specify which direction to traverse for visibility?
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700405 for (int i = mChildren.size() - 1; i >= 0; --i) {
406 final WindowContainer wc = mChildren.get(i);
407 if (wc.isVisible()) {
408 return true;
409 }
410 }
411 return false;
412 }
413
Bryce Lee00d586d2017-07-28 20:48:43 -0700414 /**
415a * Returns whether this child is on top of the window hierarchy.
416 */
417 boolean isOnTop() {
418 return getParent().getTopChild() == this && getParent().isOnTop();
419 }
420
Jorim Jaggi10abe2f2017-01-03 16:44:46 +0100421 /** Returns the top child container. */
422 E getTopChild() {
423 return mChildren.peekLast();
Wale Ogunwale9bc47732016-08-10 14:44:22 -0700424 }
Wale Ogunwale51362492016-09-08 17:49:17 -0700425
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700426 /** Returns true if there is still a removal being deferred */
427 boolean checkCompleteDeferredRemoval() {
428 boolean stillDeferringRemoval = false;
429
430 for (int i = mChildren.size() - 1; i >= 0; --i) {
431 final WindowContainer wc = mChildren.get(i);
432 stillDeferringRemoval |= wc.checkCompleteDeferredRemoval();
433 }
434
435 return stillDeferringRemoval;
436 }
437
438 /** Checks if all windows in an app are all drawn and shows them if needed. */
Wale Ogunwaleb0f3b832016-10-17 10:13:07 -0700439 void checkAppWindowsReadyToShow() {
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700440 for (int i = mChildren.size() - 1; i >= 0; --i) {
441 final WindowContainer wc = mChildren.get(i);
Wale Ogunwaleb0f3b832016-10-17 10:13:07 -0700442 wc.checkAppWindowsReadyToShow();
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700443 }
444 }
445
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700446 /** Step currently ongoing animation for App window containers. */
Wale Ogunwaleb0f3b832016-10-17 10:13:07 -0700447 void stepAppWindowsAnimation(long currentTime) {
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700448 for (int i = mChildren.size() - 1; i >= 0; --i) {
449 final WindowContainer wc = mChildren.get(i);
Wale Ogunwaleb0f3b832016-10-17 10:13:07 -0700450 wc.stepAppWindowsAnimation(currentTime);
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700451 }
452 }
453
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700454 void onAppTransitionDone() {
455 for (int i = mChildren.size() - 1; i >= 0; --i) {
456 final WindowContainer wc = mChildren.get(i);
457 wc.onAppTransitionDone();
458 }
459 }
460
Wale Ogunwale51362492016-09-08 17:49:17 -0700461 void setOrientation(int orientation) {
462 mOrientation = orientation;
463 }
464
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700465 int getOrientation() {
466 return getOrientation(mOrientation);
467 }
468
Wale Ogunwale51362492016-09-08 17:49:17 -0700469 /**
470 * Returns the specified orientation for this window container or one of its children is there
471 * is one set, or {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSET} if no
472 * specification is set.
473 * NOTE: {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} is a
474 * specification...
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700475 *
476 * @param candidate The current orientation candidate that will be returned if we don't find a
477 * better match.
478 * @return The orientation as specified by this branch or the window hierarchy.
Wale Ogunwale51362492016-09-08 17:49:17 -0700479 */
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700480 int getOrientation(int candidate) {
Bryce Leea163b762017-01-24 11:05:01 -0800481 if (!fillsParent()) {
482 // Ignore containers that don't completely fill their parents.
Wale Ogunwale51362492016-09-08 17:49:17 -0700483 return SCREEN_ORIENTATION_UNSET;
484 }
485
Bryce Leea163b762017-01-24 11:05:01 -0800486 // The container fills its parent so we can use it orientation if it has one
487 // specified; otherwise we prefer to use the orientation of its topmost child that has one
Wale Ogunwale51362492016-09-08 17:49:17 -0700488 // specified and fall back on this container's unset or unspecified value as a candidate
489 // if none of the children have a better candidate for the orientation.
490 if (mOrientation != SCREEN_ORIENTATION_UNSET
491 && mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
492 return mOrientation;
493 }
Wale Ogunwale51362492016-09-08 17:49:17 -0700494
495 for (int i = mChildren.size() - 1; i >= 0; --i) {
496 final WindowContainer wc = mChildren.get(i);
497
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700498 // TODO: Maybe mOrientation should default to SCREEN_ORIENTATION_UNSET vs.
499 // SCREEN_ORIENTATION_UNSPECIFIED?
500 final int orientation = wc.getOrientation(candidate == SCREEN_ORIENTATION_BEHIND
501 ? SCREEN_ORIENTATION_BEHIND : SCREEN_ORIENTATION_UNSET);
Wale Ogunwale51362492016-09-08 17:49:17 -0700502 if (orientation == SCREEN_ORIENTATION_BEHIND) {
503 // container wants us to use the orientation of the container behind it. See if we
504 // can find one. Else return SCREEN_ORIENTATION_BEHIND so the caller can choose to
505 // look behind this container.
506 candidate = orientation;
507 continue;
508 }
509
510 if (orientation == SCREEN_ORIENTATION_UNSET) {
511 continue;
512 }
513
514 if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
515 // Use the orientation if the container fills its parent or requested an explicit
516 // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED.
517 return orientation;
518 }
519 }
520
521 return candidate;
522 }
523
524 /**
525 * Returns true if this container is opaque and fills all the space made available by its parent
526 * container.
527 *
528 * NOTE: It is possible for this container to occupy more space than the parent has (or less),
529 * this is just a signal from the client to window manager stating its intent, but not what it
530 * actually does.
531 */
532 boolean fillsParent() {
533 return false;
534 }
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700535
Wale Ogunwale6213caa2016-12-02 16:47:15 +0000536 // TODO: Users would have their own window containers under the display container?
537 void switchUser() {
538 for (int i = mChildren.size() - 1; i >= 0; --i) {
539 mChildren.get(i).switchUser();
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700540 }
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700541 }
542
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800543 /**
544 * For all windows at or below this container call the callback.
545 * @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and
546 * stops the search if {@link ToBooleanFunction#apply} returns true.
547 * @param traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of
548 * z-order, else from bottom-to-top.
549 * @return True if the search ended before we reached the end of the hierarchy due to
Wale Ogunwale1e129a42016-11-21 13:03:47 -0800550 * {@link ToBooleanFunction#apply} returning true.
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800551 */
552 boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700553 if (traverseTopToBottom) {
554 for (int i = mChildren.size() - 1; i >= 0; --i) {
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800555 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
556 return true;
557 }
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700558 }
559 } else {
560 final int count = mChildren.size();
561 for (int i = 0; i < count; i++) {
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800562 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
563 return true;
564 }
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700565 }
566 }
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800567 return false;
568 }
569
570 void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) {
Wale Ogunwaleee41d4a2016-11-21 08:41:10 -0800571 ForAllWindowsConsumerWrapper wrapper = obtainConsumerWrapper(callback);
572 forAllWindows(wrapper, traverseTopToBottom);
573 wrapper.release();
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700574 }
575
Jorim Jaggi51304d72017-05-17 17:25:32 +0200576 /**
577 * For all tasks at or below this container call the callback.
578 *
579 * @param callback Callback to be called for every task.
580 */
581 void forAllTasks(Consumer<Task> callback) {
582 for (int i = mChildren.size() - 1; i >= 0; --i) {
583 mChildren.get(i).forAllTasks(callback);
584 }
585 }
586
Wale Ogunwaled1880962016-11-08 10:31:59 -0800587 WindowState getWindow(Predicate<WindowState> callback) {
588 for (int i = mChildren.size() - 1; i >= 0; --i) {
589 final WindowState w = mChildren.get(i).getWindow(callback);
590 if (w != null) {
591 return w;
592 }
593 }
594
595 return null;
596 }
597
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700598 /**
Wale Ogunwalef6192862016-09-10 13:42:30 -0700599 * Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than
600 * the input container in terms of z-order.
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700601 */
602 @Override
603 public int compareTo(WindowContainer other) {
604 if (this == other) {
605 return 0;
606 }
607
608 if (mParent != null && mParent == other.mParent) {
Jorim Jaggi612bb882017-05-16 17:11:18 +0200609 final WindowList<WindowContainer> list = mParent.mChildren;
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700610 return list.indexOf(this) > list.indexOf(other) ? 1 : -1;
611 }
612
613 final LinkedList<WindowContainer> thisParentChain = mTmpChain1;
614 final LinkedList<WindowContainer> otherParentChain = mTmpChain2;
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200615 try {
616 getParents(thisParentChain);
617 other.getParents(otherParentChain);
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700618
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200619 // Find the common ancestor of both containers.
620 WindowContainer commonAncestor = null;
621 WindowContainer thisTop = thisParentChain.peekLast();
622 WindowContainer otherTop = otherParentChain.peekLast();
623 while (thisTop != null && otherTop != null && thisTop == otherTop) {
624 commonAncestor = thisParentChain.removeLast();
625 otherParentChain.removeLast();
626 thisTop = thisParentChain.peekLast();
627 otherTop = otherParentChain.peekLast();
628 }
629
630 // Containers don't belong to the same hierarchy???
631 if (commonAncestor == null) {
632 throw new IllegalArgumentException("No in the same hierarchy this="
633 + thisParentChain + " other=" + otherParentChain);
634 }
635
636 // Children are always considered greater than their parents, so if one of the containers
637 // we are comparing it the parent of the other then whichever is the child is greater.
638 if (commonAncestor == this) {
639 return -1;
640 } else if (commonAncestor == other) {
641 return 1;
642 }
643
644 // The position of the first non-common ancestor in the common ancestor list determines
645 // which is greater the which.
646 final WindowList<WindowContainer> list = commonAncestor.mChildren;
647 return list.indexOf(thisParentChain.peekLast()) > list.indexOf(otherParentChain.peekLast())
648 ? 1 : -1;
649 } finally {
650 mTmpChain1.clear();
651 mTmpChain2.clear();
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700652 }
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700653 }
654
655 private void getParents(LinkedList<WindowContainer> parents) {
656 parents.clear();
657 WindowContainer current = this;
658 do {
659 parents.addLast(current);
660 current = current.mParent;
661 } while (current != null);
662 }
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700663
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800664 WindowContainerController getController() {
665 return mController;
666 }
667
668 void setController(WindowContainerController controller) {
669 if (mController != null && controller != null) {
670 throw new IllegalArgumentException("Can't set controller=" + mController
671 + " for container=" + this + " Already set to=" + mController);
672 }
673 if (controller != null) {
674 controller.setContainer(this);
675 } else if (mController != null) {
676 mController.setContainer(null);
677 }
678 mController = controller;
679 }
680
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700681 /**
682 * Dumps the names of this container children in the input print writer indenting each
683 * level with the input prefix.
684 */
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700685 void dumpChildrenNames(StringBuilder out, String prefix) {
686 final String childPrefix = prefix + " ";
687 out.append(getName() + "\n");
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700688 for (int i = mChildren.size() - 1; i >= 0; --i) {
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700689 final WindowContainer wc = mChildren.get(i);
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700690 out.append(childPrefix + "#" + i + " ");
691 wc.dumpChildrenNames(out, childPrefix);
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700692 }
693 }
694
695 String getName() {
696 return toString();
697 }
698
Wale Ogunwaleee41d4a2016-11-21 08:41:10 -0800699 private ForAllWindowsConsumerWrapper obtainConsumerWrapper(Consumer<WindowState> consumer) {
700 ForAllWindowsConsumerWrapper wrapper = mConsumerWrapperPool.acquire();
701 if (wrapper == null) {
702 wrapper = new ForAllWindowsConsumerWrapper();
703 }
704 wrapper.setConsumer(consumer);
705 return wrapper;
706 }
707
708 private final class ForAllWindowsConsumerWrapper implements ToBooleanFunction<WindowState> {
709
710 private Consumer<WindowState> mConsumer;
711
712 void setConsumer(Consumer<WindowState> consumer) {
713 mConsumer = consumer;
714 }
715
716 @Override
717 public boolean apply(WindowState w) {
718 mConsumer.accept(w);
719 return false;
720 }
721
722 void release() {
723 mConsumer = null;
724 mConsumerWrapperPool.release(this);
725 }
726 }
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700727}