blob: 3df73d7c627a96f11f49b69fd6ef55c202dc73f9 [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 Ogunwaled90546a2016-09-09 23:28:03 -070041class WindowContainer<E extends WindowContainer> implements Comparable<WindowContainer> {
Wale Ogunwaled63594a2016-07-18 07:48:30 -070042
Andrii Kuliand2765632016-12-12 22:26:34 -080043 static final int POSITION_TOP = Integer.MAX_VALUE;
44 static final int POSITION_BOTTOM = Integer.MIN_VALUE;
45
Andrii Kulian441e4492016-09-29 15:25:00 -070046 /**
47 * The parent of this window container.
48 * For removing or setting new parent {@link #setParent} should be used, because it also
49 * performs configuration updates based on new parent's settings.
50 */
51 private WindowContainer mParent = null;
Wale Ogunwaled63594a2016-07-18 07:48:30 -070052
53 // List of children for this window container. List is in z-order as the children appear on
54 // screen with the top-most window container at the tail of the list.
Jorim Jaggi612bb882017-05-16 17:11:18 +020055 protected final WindowList<E> mChildren = new WindowList<E>();
Wale Ogunwaled63594a2016-07-18 07:48:30 -070056
Andrii Kulian441e4492016-09-29 15:25:00 -070057 /** Contains override configuration settings applied to this window container. */
58 private Configuration mOverrideConfiguration = new Configuration();
59
60 /**
61 * Contains full configuration applied to this window container. Corresponds to full parent's
62 * config with applied {@link #mOverrideConfiguration}.
63 */
64 private Configuration mFullConfiguration = new Configuration();
65
66 /**
67 * Contains merged override configuration settings from the top of the hierarchy down to this
68 * particular instance. It is different from {@link #mFullConfiguration} because it starts from
69 * topmost container's override config instead of global config.
70 */
71 private Configuration mMergedOverrideConfiguration = new Configuration();
72
Wale Ogunwale51362492016-09-08 17:49:17 -070073 // The specified orientation for this window container.
74 protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
75
Wale Ogunwaleee41d4a2016-11-21 08:41:10 -080076 private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool =
77 new Pools.SynchronizedPool<>(3);
78
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080079 // The owner/creator for this container. No controller if null.
80 private WindowContainerController mController;
81
Wale Ogunwale51362492016-09-08 17:49:17 -070082 final protected WindowContainer getParent() {
Wale Ogunwaled63594a2016-07-18 07:48:30 -070083 return mParent;
84 }
85
Andrii Kulian441e4492016-09-29 15:25:00 -070086 final protected void setParent(WindowContainer parent) {
87 mParent = parent;
Andrii Kulianb94292e2016-10-19 13:30:58 -070088 // Removing parent usually means that we've detached this entity to destroy it or to attach
89 // to another parent. In both cases we don't need to update the configuration now.
90 if (mParent != null) {
91 // Update full configuration of this container and all its children.
92 onConfigurationChanged(mParent.mFullConfiguration);
93 // Update merged override configuration of this container and all its children.
94 onMergedOverrideConfigurationChanged();
95 }
Andrii Kuliand2765632016-12-12 22:26:34 -080096
97 onParentSet();
98 }
99
100 /**
101 * Callback that is triggered when @link WindowContainer#setParent(WindowContainer)} was called.
102 * Supposed to be overridden and contain actions that should be executed after parent was set.
103 */
104 void onParentSet() {
105 // Do nothing by default.
Andrii Kulian441e4492016-09-29 15:25:00 -0700106 }
107
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700108 // Temp. holders for a chain of containers we are currently processing.
109 private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList();
110 private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList();
111
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700112 /**
113 * Adds the input window container has a child of this container in order based on the input
114 * comparator.
115 * @param child The window container to add as a child of this window container.
116 * @param comparator Comparator to use in determining the position the child should be added to.
117 * If null, the child will be added to the top.
118 */
119 @CallSuper
Wale Ogunwaled90546a2016-09-09 23:28:03 -0700120 protected void addChild(E child, Comparator<E> comparator) {
Andrii Kulian441e4492016-09-29 15:25:00 -0700121 if (child.getParent() != null) {
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700122 throw new IllegalArgumentException("addChild: container=" + child.getName()
Andrii Kulian441e4492016-09-29 15:25:00 -0700123 + " is already a child of container=" + child.getParent().getName()
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700124 + " can't add to container=" + getName());
Wale Ogunwalef6192862016-09-10 13:42:30 -0700125 }
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700126
Andrii Kulianb94292e2016-10-19 13:30:58 -0700127 int positionToAdd = -1;
128 if (comparator != null) {
129 final int count = mChildren.size();
130 for (int i = 0; i < count; i++) {
131 if (comparator.compare(child, mChildren.get(i)) < 0) {
132 positionToAdd = i;
133 break;
134 }
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700135 }
136 }
137
Andrii Kulianb94292e2016-10-19 13:30:58 -0700138 if (positionToAdd == -1) {
139 mChildren.add(child);
140 } else {
141 mChildren.add(positionToAdd, child);
142 }
143 // Set the parent after we've actually added a child in case a subclass depends on this.
144 child.setParent(this);
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700145 }
146
Wale Ogunwalef6192862016-09-10 13:42:30 -0700147 /** Adds the input window container has a child of this container at the input index. */
148 @CallSuper
Wale Ogunwale72919d22016-12-08 18:58:50 -0800149 void addChild(E child, int index) {
Andrii Kulian441e4492016-09-29 15:25:00 -0700150 if (child.getParent() != null) {
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700151 throw new IllegalArgumentException("addChild: container=" + child.getName()
Andrii Kulian441e4492016-09-29 15:25:00 -0700152 + " is already a child of container=" + child.getParent().getName()
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700153 + " can't add to container=" + getName());
Wale Ogunwalef6192862016-09-10 13:42:30 -0700154 }
Wale Ogunwalef6192862016-09-10 13:42:30 -0700155 mChildren.add(index, child);
Andrii Kulianb94292e2016-10-19 13:30:58 -0700156 // Set the parent after we've actually added a child in case a subclass depends on this.
157 child.setParent(this);
Wale Ogunwalef6192862016-09-10 13:42:30 -0700158 }
159
160 /**
161 * Removes the input child container from this container which is its parent.
162 *
163 * @return True if the container did contain the input child and it was detached.
164 */
165 @CallSuper
166 void removeChild(E child) {
167 if (mChildren.remove(child)) {
Andrii Kulian441e4492016-09-29 15:25:00 -0700168 child.setParent(null);
Wale Ogunwalef6192862016-09-10 13:42:30 -0700169 } else {
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700170 throw new IllegalArgumentException("removeChild: container=" + child.getName()
171 + " is not a child of container=" + getName());
Wale Ogunwalef6192862016-09-10 13:42:30 -0700172 }
173 }
174
Wale Ogunwale571771c2016-08-26 13:18:50 -0700175 /**
176 * Removes this window container and its children with no regard for what else might be going on
177 * in the system. For example, the container will be removed during animation if this method is
178 * called which isn't desirable. For most cases you want to call {@link #removeIfPossible()}
179 * which allows the system to defer removal until a suitable time.
180 */
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700181 @CallSuper
Wale Ogunwale571771c2016-08-26 13:18:50 -0700182 void removeImmediately() {
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700183 while (!mChildren.isEmpty()) {
Wale Ogunwale571771c2016-08-26 13:18:50 -0700184 final WindowContainer child = mChildren.peekLast();
185 child.removeImmediately();
186 // Need to do this after calling remove on the child because the child might try to
187 // remove/detach itself from its parent which will cause an exception if we remove
188 // it before calling remove on the child.
189 mChildren.remove(child);
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700190 }
191
192 if (mParent != null) {
Wale Ogunwalef6192862016-09-10 13:42:30 -0700193 mParent.removeChild(this);
Wale Ogunwale571771c2016-08-26 13:18:50 -0700194 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800195
196 if (mController != null) {
197 setController(null);
198 }
Wale Ogunwale571771c2016-08-26 13:18:50 -0700199 }
200
201 /**
202 * Removes this window container and its children taking care not to remove them during a
203 * critical stage in the system. For example, some containers will not be removed during
204 * animation if this method is called.
205 */
206 // TODO: figure-out implementation that works best for this.
207 // E.g. when do we remove from parent list? maybe not...
208 void removeIfPossible() {
209 for (int i = mChildren.size() - 1; i >= 0; --i) {
210 final WindowContainer wc = mChildren.get(i);
211 wc.removeIfPossible();
212 }
213 }
214
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700215 /** Returns true if this window container has the input child. */
216 boolean hasChild(WindowContainer child) {
217 for (int i = mChildren.size() - 1; i >= 0; --i) {
218 final WindowContainer current = mChildren.get(i);
219 if (current == child || current.hasChild(child)) {
220 return true;
221 }
222 }
223 return false;
224 }
Wale Ogunwale9bc47732016-08-10 14:44:22 -0700225
Andrii Kulian441e4492016-09-29 15:25:00 -0700226 /**
Andrii Kuliand2765632016-12-12 22:26:34 -0800227 * Move a child from it's current place in siblings list to the specified position,
228 * with an option to move all its parents to top.
229 * @param position Target position to move the child to.
230 * @param child Child to move to selected position.
231 * @param includingParents Flag indicating whether we need to move the entire branch of the
232 * hierarchy when we're moving a child to {@link #POSITION_TOP} or
233 * {@link #POSITION_BOTTOM}. When moving to other intermediate positions
234 * this flag will do nothing.
235 */
236 @CallSuper
237 void positionChildAt(int position, E child, boolean includingParents) {
Wale Ogunwalec5cc3012017-01-13 13:26:16 -0800238
239 if (child.getParent() != this) {
240 throw new IllegalArgumentException("removeChild: container=" + child.getName()
241 + " is not a child of container=" + getName()
242 + " current parent=" + child.getParent());
243 }
244
Andrii Kuliand2765632016-12-12 22:26:34 -0800245 if ((position < 0 && position != POSITION_BOTTOM)
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800246 || (position > mChildren.size() && position != POSITION_TOP)) {
Andrii Kuliand2765632016-12-12 22:26:34 -0800247 throw new IllegalArgumentException("positionAt: invalid position=" + position
248 + ", children number=" + mChildren.size());
249 }
250
Wale Ogunwalec5cc3012017-01-13 13:26:16 -0800251 if (position >= mChildren.size() - 1) {
Andrii Kuliand2765632016-12-12 22:26:34 -0800252 position = POSITION_TOP;
253 } else if (position == 0) {
254 position = POSITION_BOTTOM;
255 }
256
257 switch (position) {
258 case POSITION_TOP:
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800259 if (mChildren.peekLast() != child) {
Andrii Kuliand2765632016-12-12 22:26:34 -0800260 mChildren.remove(child);
Jorim Jaggi612bb882017-05-16 17:11:18 +0200261 mChildren.add(child);
Andrii Kuliand2765632016-12-12 22:26:34 -0800262 }
263 if (includingParents && getParent() != null) {
264 getParent().positionChildAt(POSITION_TOP, this /* child */,
265 true /* includingParents */);
266 }
267 break;
268 case POSITION_BOTTOM:
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800269 if (mChildren.peekFirst() != child) {
Andrii Kuliand2765632016-12-12 22:26:34 -0800270 mChildren.remove(child);
271 mChildren.addFirst(child);
272 }
273 if (includingParents && getParent() != null) {
274 getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
275 true /* includingParents */);
276 }
277 break;
278 default:
279 mChildren.remove(child);
280 mChildren.add(position, child);
281 }
282 }
283
284 /**
Andrii Kulian441e4492016-09-29 15:25:00 -0700285 * Returns full configuration applied to this window container.
286 * This method should be used for getting settings applied in each particular level of the
287 * hierarchy.
288 */
289 Configuration getConfiguration() {
290 return mFullConfiguration;
291 }
292
293 /**
294 * Notify that parent config changed and we need to update full configuration.
295 * @see #mFullConfiguration
296 */
297 void onConfigurationChanged(Configuration newParentConfig) {
298 mFullConfiguration.setTo(newParentConfig);
299 mFullConfiguration.updateFrom(mOverrideConfiguration);
300 for (int i = mChildren.size() - 1; i >= 0; --i) {
301 final WindowContainer child = mChildren.get(i);
302 child.onConfigurationChanged(mFullConfiguration);
303 }
304 }
305
306 /** Returns override configuration applied to this window container. */
307 Configuration getOverrideConfiguration() {
308 return mOverrideConfiguration;
309 }
310
311 /**
312 * Update override configuration and recalculate full config.
313 * @see #mOverrideConfiguration
314 * @see #mFullConfiguration
315 */
316 void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
317 mOverrideConfiguration.setTo(overrideConfiguration);
318 // Update full configuration of this container and all its children.
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700319 onConfigurationChanged(mParent != null ? mParent.getConfiguration() : EMPTY);
Andrii Kulian441e4492016-09-29 15:25:00 -0700320 // Update merged override config of this container and all its children.
321 onMergedOverrideConfigurationChanged();
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700322
323 if (mParent != null) {
324 mParent.onDescendantOverrideConfigurationChanged();
325 }
326 }
327
328 /**
329 * Notify that a descendant's overrideConfiguration has changed.
330 */
331 void onDescendantOverrideConfigurationChanged() {
332 if (mParent != null) {
333 mParent.onDescendantOverrideConfigurationChanged();
334 }
Andrii Kulian441e4492016-09-29 15:25:00 -0700335 }
336
337 /**
338 * Get merged override configuration from the top of the hierarchy down to this
339 * particular instance. This should be reported to client as override config.
340 */
341 Configuration getMergedOverrideConfiguration() {
342 return mMergedOverrideConfiguration;
343 }
344
345 /**
346 * Update merged override configuration based on corresponding parent's config and notify all
347 * its children. If there is no parent, merged override configuration will set equal to current
348 * override config.
349 * @see #mMergedOverrideConfiguration
350 */
351 private void onMergedOverrideConfigurationChanged() {
352 if (mParent != null) {
353 mMergedOverrideConfiguration.setTo(mParent.getMergedOverrideConfiguration());
354 mMergedOverrideConfiguration.updateFrom(mOverrideConfiguration);
355 } else {
356 mMergedOverrideConfiguration.setTo(mOverrideConfiguration);
357 }
358 for (int i = mChildren.size() - 1; i >= 0; --i) {
359 final WindowContainer child = mChildren.get(i);
360 child.onMergedOverrideConfigurationChanged();
361 }
362 }
363
Wale Ogunwale02319a62016-09-26 15:21:22 -0700364 /**
365 * Notify that the display this container is on has changed.
366 * @param dc The new display this container is on.
367 */
368 void onDisplayChanged(DisplayContent dc) {
369 for (int i = mChildren.size() - 1; i >= 0; --i) {
370 final WindowContainer child = mChildren.get(i);
371 child.onDisplayChanged(dc);
372 }
373 }
374
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700375 void setWaitingForDrawnIfResizingChanged() {
376 for (int i = mChildren.size() - 1; i >= 0; --i) {
377 final WindowContainer wc = mChildren.get(i);
378 wc.setWaitingForDrawnIfResizingChanged();
379 }
380 }
381
382 void onResize() {
383 for (int i = mChildren.size() - 1; i >= 0; --i) {
384 final WindowContainer wc = mChildren.get(i);
385 wc.onResize();
386 }
387 }
388
389 void onMovedByResize() {
390 for (int i = mChildren.size() - 1; i >= 0; --i) {
391 final WindowContainer wc = mChildren.get(i);
392 wc.onMovedByResize();
393 }
394 }
395
396 void resetDragResizingChangeReported() {
397 for (int i = mChildren.size() - 1; i >= 0; --i) {
398 final WindowContainer wc = mChildren.get(i);
399 wc.resetDragResizingChangeReported();
400 }
401 }
402
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700403 void forceWindowsScaleableInTransaction(boolean force) {
404 for (int i = mChildren.size() - 1; i >= 0; --i) {
405 final WindowContainer wc = mChildren.get(i);
406 wc.forceWindowsScaleableInTransaction(force);
407 }
408 }
409
410 boolean isAnimating() {
411 for (int j = mChildren.size() - 1; j >= 0; j--) {
412 final WindowContainer wc = mChildren.get(j);
413 if (wc.isAnimating()) {
414 return true;
415 }
416 }
417 return false;
418 }
419
420 void sendAppVisibilityToClients() {
421 for (int i = mChildren.size() - 1; i >= 0; --i) {
422 final WindowContainer wc = mChildren.get(i);
423 wc.sendAppVisibilityToClients();
424 }
425 }
426
427 void setVisibleBeforeClientHidden() {
428 for (int i = mChildren.size() - 1; i >= 0; --i) {
429 final WindowContainer wc = mChildren.get(i);
430 wc.setVisibleBeforeClientHidden();
431 }
432 }
433
Wale Ogunwale44f21802016-09-02 12:49:48 -0700434 /**
435 * Returns true if the container or one of its children as some content it can display or wants
436 * to display (e.g. app views or saved surface).
437 *
438 * NOTE: While this method will return true if the there is some content to display, it doesn't
439 * mean the container is visible. Use {@link #isVisible()} to determine if the container is
440 * visible.
441 */
442 boolean hasContentToDisplay() {
443 for (int i = mChildren.size() - 1; i >= 0; --i) {
444 final WindowContainer wc = mChildren.get(i);
445 if (wc.hasContentToDisplay()) {
446 return true;
447 }
448 }
449 return false;
450 }
451
452 /**
453 * Returns true if the container or one of its children is considered visible from the
454 * WindowManager perspective which usually means valid surface and some other internal state
455 * are true.
456 *
457 * NOTE: While this method will return true if the surface is visible, it doesn't mean the
458 * client has actually displayed any content. Use {@link #hasContentToDisplay()} to determine if
459 * the container has any content to display.
460 */
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700461 boolean isVisible() {
Wale Ogunwalef6192862016-09-10 13:42:30 -0700462 // TODO: Will this be more correct if it checks the visibility of its parents?
463 // It depends...For example, Tasks and Stacks are only visible if there children are visible
464 // but, WindowState are not visible if there parent are not visible. Maybe have the
Andrii Kuliancd5dcb8b2017-01-03 17:09:45 -0800465 // container specify which direction to traverse for visibility?
Wale Ogunwaled1c37912016-08-16 03:19:39 -0700466 for (int i = mChildren.size() - 1; i >= 0; --i) {
467 final WindowContainer wc = mChildren.get(i);
468 if (wc.isVisible()) {
469 return true;
470 }
471 }
472 return false;
473 }
474
Bryce Lee00d586d2017-07-28 20:48:43 -0700475 /**
476a * Returns whether this child is on top of the window hierarchy.
477 */
478 boolean isOnTop() {
479 return getParent().getTopChild() == this && getParent().isOnTop();
480 }
481
Jorim Jaggi10abe2f2017-01-03 16:44:46 +0100482 /** Returns the top child container. */
483 E getTopChild() {
484 return mChildren.peekLast();
Wale Ogunwale9bc47732016-08-10 14:44:22 -0700485 }
Wale Ogunwale51362492016-09-08 17:49:17 -0700486
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700487 /** Returns true if there is still a removal being deferred */
488 boolean checkCompleteDeferredRemoval() {
489 boolean stillDeferringRemoval = false;
490
491 for (int i = mChildren.size() - 1; i >= 0; --i) {
492 final WindowContainer wc = mChildren.get(i);
493 stillDeferringRemoval |= wc.checkCompleteDeferredRemoval();
494 }
495
496 return stillDeferringRemoval;
497 }
498
499 /** Checks if all windows in an app are all drawn and shows them if needed. */
Wale Ogunwaleb0f3b832016-10-17 10:13:07 -0700500 void checkAppWindowsReadyToShow() {
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700501 for (int i = mChildren.size() - 1; i >= 0; --i) {
502 final WindowContainer wc = mChildren.get(i);
Wale Ogunwaleb0f3b832016-10-17 10:13:07 -0700503 wc.checkAppWindowsReadyToShow();
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700504 }
505 }
506
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700507 /** Step currently ongoing animation for App window containers. */
Wale Ogunwaleb0f3b832016-10-17 10:13:07 -0700508 void stepAppWindowsAnimation(long currentTime) {
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700509 for (int i = mChildren.size() - 1; i >= 0; --i) {
510 final WindowContainer wc = mChildren.get(i);
Wale Ogunwaleb0f3b832016-10-17 10:13:07 -0700511 wc.stepAppWindowsAnimation(currentTime);
Wale Ogunwale3f4433d2016-08-18 20:42:42 -0700512 }
513 }
514
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700515 void onAppTransitionDone() {
516 for (int i = mChildren.size() - 1; i >= 0; --i) {
517 final WindowContainer wc = mChildren.get(i);
518 wc.onAppTransitionDone();
519 }
520 }
521
Wale Ogunwale51362492016-09-08 17:49:17 -0700522 void setOrientation(int orientation) {
523 mOrientation = orientation;
524 }
525
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700526 int getOrientation() {
527 return getOrientation(mOrientation);
528 }
529
Wale Ogunwale51362492016-09-08 17:49:17 -0700530 /**
531 * Returns the specified orientation for this window container or one of its children is there
532 * is one set, or {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSET} if no
533 * specification is set.
534 * NOTE: {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} is a
535 * specification...
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700536 *
537 * @param candidate The current orientation candidate that will be returned if we don't find a
538 * better match.
539 * @return The orientation as specified by this branch or the window hierarchy.
Wale Ogunwale51362492016-09-08 17:49:17 -0700540 */
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700541 int getOrientation(int candidate) {
Bryce Leea163b762017-01-24 11:05:01 -0800542 if (!fillsParent()) {
543 // Ignore containers that don't completely fill their parents.
Wale Ogunwale51362492016-09-08 17:49:17 -0700544 return SCREEN_ORIENTATION_UNSET;
545 }
546
Bryce Leea163b762017-01-24 11:05:01 -0800547 // The container fills its parent so we can use it orientation if it has one
548 // specified; otherwise we prefer to use the orientation of its topmost child that has one
Wale Ogunwale51362492016-09-08 17:49:17 -0700549 // specified and fall back on this container's unset or unspecified value as a candidate
550 // if none of the children have a better candidate for the orientation.
551 if (mOrientation != SCREEN_ORIENTATION_UNSET
552 && mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
553 return mOrientation;
554 }
Wale Ogunwale51362492016-09-08 17:49:17 -0700555
556 for (int i = mChildren.size() - 1; i >= 0; --i) {
557 final WindowContainer wc = mChildren.get(i);
558
Wale Ogunwale5e5a68d2017-03-24 17:36:38 -0700559 // TODO: Maybe mOrientation should default to SCREEN_ORIENTATION_UNSET vs.
560 // SCREEN_ORIENTATION_UNSPECIFIED?
561 final int orientation = wc.getOrientation(candidate == SCREEN_ORIENTATION_BEHIND
562 ? SCREEN_ORIENTATION_BEHIND : SCREEN_ORIENTATION_UNSET);
Wale Ogunwale51362492016-09-08 17:49:17 -0700563 if (orientation == SCREEN_ORIENTATION_BEHIND) {
564 // container wants us to use the orientation of the container behind it. See if we
565 // can find one. Else return SCREEN_ORIENTATION_BEHIND so the caller can choose to
566 // look behind this container.
567 candidate = orientation;
568 continue;
569 }
570
571 if (orientation == SCREEN_ORIENTATION_UNSET) {
572 continue;
573 }
574
575 if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
576 // Use the orientation if the container fills its parent or requested an explicit
577 // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED.
578 return orientation;
579 }
580 }
581
582 return candidate;
583 }
584
585 /**
586 * Returns true if this container is opaque and fills all the space made available by its parent
587 * container.
588 *
589 * NOTE: It is possible for this container to occupy more space than the parent has (or less),
590 * this is just a signal from the client to window manager stating its intent, but not what it
591 * actually does.
592 */
593 boolean fillsParent() {
594 return false;
595 }
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700596
Wale Ogunwale6213caa2016-12-02 16:47:15 +0000597 // TODO: Users would have their own window containers under the display container?
598 void switchUser() {
599 for (int i = mChildren.size() - 1; i >= 0; --i) {
600 mChildren.get(i).switchUser();
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700601 }
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700602 }
603
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800604 /**
605 * For all windows at or below this container call the callback.
606 * @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and
607 * stops the search if {@link ToBooleanFunction#apply} returns true.
608 * @param traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of
609 * z-order, else from bottom-to-top.
610 * @return True if the search ended before we reached the end of the hierarchy due to
Wale Ogunwale1e129a42016-11-21 13:03:47 -0800611 * {@link ToBooleanFunction#apply} returning true.
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800612 */
613 boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700614 if (traverseTopToBottom) {
615 for (int i = mChildren.size() - 1; i >= 0; --i) {
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800616 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
617 return true;
618 }
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700619 }
620 } else {
621 final int count = mChildren.size();
622 for (int i = 0; i < count; i++) {
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800623 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
624 return true;
625 }
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700626 }
627 }
Wale Ogunwalef4ebe2e2016-11-09 13:24:43 -0800628 return false;
629 }
630
631 void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) {
Wale Ogunwaleee41d4a2016-11-21 08:41:10 -0800632 ForAllWindowsConsumerWrapper wrapper = obtainConsumerWrapper(callback);
633 forAllWindows(wrapper, traverseTopToBottom);
634 wrapper.release();
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700635 }
636
Jorim Jaggi51304d72017-05-17 17:25:32 +0200637 /**
638 * For all tasks at or below this container call the callback.
639 *
640 * @param callback Callback to be called for every task.
641 */
642 void forAllTasks(Consumer<Task> callback) {
643 for (int i = mChildren.size() - 1; i >= 0; --i) {
644 mChildren.get(i).forAllTasks(callback);
645 }
646 }
647
Wale Ogunwaled1880962016-11-08 10:31:59 -0800648 WindowState getWindow(Predicate<WindowState> callback) {
649 for (int i = mChildren.size() - 1; i >= 0; --i) {
650 final WindowState w = mChildren.get(i).getWindow(callback);
651 if (w != null) {
652 return w;
653 }
654 }
655
656 return null;
657 }
658
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700659 /**
Wale Ogunwalef6192862016-09-10 13:42:30 -0700660 * Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than
661 * the input container in terms of z-order.
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700662 */
663 @Override
664 public int compareTo(WindowContainer other) {
665 if (this == other) {
666 return 0;
667 }
668
669 if (mParent != null && mParent == other.mParent) {
Jorim Jaggi612bb882017-05-16 17:11:18 +0200670 final WindowList<WindowContainer> list = mParent.mChildren;
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700671 return list.indexOf(this) > list.indexOf(other) ? 1 : -1;
672 }
673
674 final LinkedList<WindowContainer> thisParentChain = mTmpChain1;
675 final LinkedList<WindowContainer> otherParentChain = mTmpChain2;
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200676 try {
677 getParents(thisParentChain);
678 other.getParents(otherParentChain);
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700679
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200680 // Find the common ancestor of both containers.
681 WindowContainer commonAncestor = null;
682 WindowContainer thisTop = thisParentChain.peekLast();
683 WindowContainer otherTop = otherParentChain.peekLast();
684 while (thisTop != null && otherTop != null && thisTop == otherTop) {
685 commonAncestor = thisParentChain.removeLast();
686 otherParentChain.removeLast();
687 thisTop = thisParentChain.peekLast();
688 otherTop = otherParentChain.peekLast();
689 }
690
691 // Containers don't belong to the same hierarchy???
692 if (commonAncestor == null) {
693 throw new IllegalArgumentException("No in the same hierarchy this="
694 + thisParentChain + " other=" + otherParentChain);
695 }
696
697 // Children are always considered greater than their parents, so if one of the containers
698 // we are comparing it the parent of the other then whichever is the child is greater.
699 if (commonAncestor == this) {
700 return -1;
701 } else if (commonAncestor == other) {
702 return 1;
703 }
704
705 // The position of the first non-common ancestor in the common ancestor list determines
706 // which is greater the which.
707 final WindowList<WindowContainer> list = commonAncestor.mChildren;
708 return list.indexOf(thisParentChain.peekLast()) > list.indexOf(otherParentChain.peekLast())
709 ? 1 : -1;
710 } finally {
711 mTmpChain1.clear();
712 mTmpChain2.clear();
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700713 }
Wale Ogunwale63d4ecc2016-09-08 18:48:26 -0700714 }
715
716 private void getParents(LinkedList<WindowContainer> parents) {
717 parents.clear();
718 WindowContainer current = this;
719 do {
720 parents.addLast(current);
721 current = current.mParent;
722 } while (current != null);
723 }
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700724
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800725 WindowContainerController getController() {
726 return mController;
727 }
728
729 void setController(WindowContainerController controller) {
730 if (mController != null && controller != null) {
731 throw new IllegalArgumentException("Can't set controller=" + mController
732 + " for container=" + this + " Already set to=" + mController);
733 }
734 if (controller != null) {
735 controller.setContainer(this);
736 } else if (mController != null) {
737 mController.setContainer(null);
738 }
739 mController = controller;
740 }
741
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700742 /**
743 * Dumps the names of this container children in the input print writer indenting each
744 * level with the input prefix.
745 */
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700746 void dumpChildrenNames(StringBuilder out, String prefix) {
747 final String childPrefix = prefix + " ";
748 out.append(getName() + "\n");
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700749 for (int i = mChildren.size() - 1; i >= 0; --i) {
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700750 final WindowContainer wc = mChildren.get(i);
Wale Ogunwaleba51ca22016-09-23 06:06:54 -0700751 out.append(childPrefix + "#" + i + " ");
752 wc.dumpChildrenNames(out, childPrefix);
Wale Ogunwale9adfe572016-09-08 20:43:58 -0700753 }
754 }
755
756 String getName() {
757 return toString();
758 }
759
Wale Ogunwaleee41d4a2016-11-21 08:41:10 -0800760 private ForAllWindowsConsumerWrapper obtainConsumerWrapper(Consumer<WindowState> consumer) {
761 ForAllWindowsConsumerWrapper wrapper = mConsumerWrapperPool.acquire();
762 if (wrapper == null) {
763 wrapper = new ForAllWindowsConsumerWrapper();
764 }
765 wrapper.setConsumer(consumer);
766 return wrapper;
767 }
768
769 private final class ForAllWindowsConsumerWrapper implements ToBooleanFunction<WindowState> {
770
771 private Consumer<WindowState> mConsumer;
772
773 void setConsumer(Consumer<WindowState> consumer) {
774 mConsumer = consumer;
775 }
776
777 @Override
778 public boolean apply(WindowState w) {
779 mConsumer.accept(w);
780 return false;
781 }
782
783 void release() {
784 mConsumer = null;
785 mConsumerWrapperPool.release(this);
786 }
787 }
Wale Ogunwaled63594a2016-07-18 07:48:30 -0700788}