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