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