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