WindowContainer.java revision 2f0567b00d22edba0b87c0d06766c3cacaa0e041
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(); 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.onParentResize(); 471 } 472 } 473 474 void onParentResize() { 475 // In the case this container has specified its own bounds, a parent resize will not 476 // affect its bounds. Any relevant changes will be propagated through changes to the 477 // Configuration override. 478 if (hasOverrideBounds()) { 479 return; 480 } 481 482 // Default implementation is to treat as resize on self. 483 onResize(); 484 } 485 486 void onMovedByResize() { 487 for (int i = mChildren.size() - 1; i >= 0; --i) { 488 final WindowContainer wc = mChildren.get(i); 489 wc.onMovedByResize(); 490 } 491 } 492 493 void resetDragResizingChangeReported() { 494 for (int i = mChildren.size() - 1; i >= 0; --i) { 495 final WindowContainer wc = mChildren.get(i); 496 wc.resetDragResizingChangeReported(); 497 } 498 } 499 500 void forceWindowsScaleableInTransaction(boolean force) { 501 for (int i = mChildren.size() - 1; i >= 0; --i) { 502 final WindowContainer wc = mChildren.get(i); 503 wc.forceWindowsScaleableInTransaction(force); 504 } 505 } 506 507 /** 508 * @return Whether our own container is running an animation or any child, no matter how deep in 509 * the hierarchy, is animating. 510 */ 511 boolean isSelfOrChildAnimating() { 512 if (isSelfAnimating()) { 513 return true; 514 } 515 for (int j = mChildren.size() - 1; j >= 0; j--) { 516 final WindowContainer wc = mChildren.get(j); 517 if (wc.isSelfOrChildAnimating()) { 518 return true; 519 } 520 } 521 return false; 522 } 523 524 /** 525 * @return Whether our own container is running an animation or our parent is animating. This 526 * doesn't consider whether children are animating. 527 */ 528 boolean isAnimating() { 529 530 // We are animating if we ourselves are animating or if our parent is animating. 531 return isSelfAnimating() || mParent != null && mParent.isAnimating(); 532 } 533 534 /** 535 * @return {@code true} if in this subtree of the hierarchy we have an {@link AppWindowToken} 536 * that is {@link #isSelfAnimating}; {@code false} otherwise. 537 */ 538 boolean isAppAnimating() { 539 for (int j = mChildren.size() - 1; j >= 0; j--) { 540 final WindowContainer wc = mChildren.get(j); 541 if (wc.isAppAnimating()) { 542 return true; 543 } 544 } 545 return false; 546 } 547 548 /** 549 * @return Whether our own container running an animation at the moment. 550 */ 551 boolean isSelfAnimating() { 552 return mSurfaceAnimator.isAnimating(); 553 } 554 555 void sendAppVisibilityToClients() { 556 for (int i = mChildren.size() - 1; i >= 0; --i) { 557 final WindowContainer wc = mChildren.get(i); 558 wc.sendAppVisibilityToClients(); 559 } 560 } 561 562 /** 563 * Returns true if the container or one of its children as some content it can display or wants 564 * to display (e.g. app views or saved surface). 565 * 566 * NOTE: While this method will return true if the there is some content to display, it doesn't 567 * mean the container is visible. Use {@link #isVisible()} to determine if the container is 568 * visible. 569 */ 570 boolean hasContentToDisplay() { 571 for (int i = mChildren.size() - 1; i >= 0; --i) { 572 final WindowContainer wc = mChildren.get(i); 573 if (wc.hasContentToDisplay()) { 574 return true; 575 } 576 } 577 return false; 578 } 579 580 /** 581 * Returns true if the container or one of its children is considered visible from the 582 * WindowManager perspective which usually means valid surface and some other internal state 583 * are true. 584 * 585 * NOTE: While this method will return true if the surface is visible, it doesn't mean the 586 * client has actually displayed any content. Use {@link #hasContentToDisplay()} to determine if 587 * the container has any content to display. 588 */ 589 boolean isVisible() { 590 // TODO: Will this be more correct if it checks the visibility of its parents? 591 // It depends...For example, Tasks and Stacks are only visible if there children are visible 592 // but, WindowState are not visible if there parent are not visible. Maybe have the 593 // container specify which direction to traverse for visibility? 594 for (int i = mChildren.size() - 1; i >= 0; --i) { 595 final WindowContainer wc = mChildren.get(i); 596 if (wc.isVisible()) { 597 return true; 598 } 599 } 600 return false; 601 } 602 603 /** 604 * @return Whether this child is on top of the window hierarchy. 605 */ 606 boolean isOnTop() { 607 return getParent().getTopChild() == this && getParent().isOnTop(); 608 } 609 610 /** Returns the top child container. */ 611 E getTopChild() { 612 return mChildren.peekLast(); 613 } 614 615 /** Returns true if there is still a removal being deferred */ 616 boolean checkCompleteDeferredRemoval() { 617 boolean stillDeferringRemoval = false; 618 619 for (int i = mChildren.size() - 1; i >= 0; --i) { 620 final WindowContainer wc = mChildren.get(i); 621 stillDeferringRemoval |= wc.checkCompleteDeferredRemoval(); 622 } 623 624 return stillDeferringRemoval; 625 } 626 627 /** Checks if all windows in an app are all drawn and shows them if needed. */ 628 void checkAppWindowsReadyToShow() { 629 for (int i = mChildren.size() - 1; i >= 0; --i) { 630 final WindowContainer wc = mChildren.get(i); 631 wc.checkAppWindowsReadyToShow(); 632 } 633 } 634 635 void onAppTransitionDone() { 636 for (int i = mChildren.size() - 1; i >= 0; --i) { 637 final WindowContainer wc = mChildren.get(i); 638 wc.onAppTransitionDone(); 639 } 640 } 641 642 void setOrientation(int orientation) { 643 mOrientation = orientation; 644 } 645 646 int getOrientation() { 647 return getOrientation(mOrientation); 648 } 649 650 /** 651 * Returns the specified orientation for this window container or one of its children is there 652 * is one set, or {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSET} if no 653 * specification is set. 654 * NOTE: {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} is a 655 * specification... 656 * 657 * @param candidate The current orientation candidate that will be returned if we don't find a 658 * better match. 659 * @return The orientation as specified by this branch or the window hierarchy. 660 */ 661 int getOrientation(int candidate) { 662 if (!fillsParent()) { 663 // Ignore containers that don't completely fill their parents. 664 return SCREEN_ORIENTATION_UNSET; 665 } 666 667 // The container fills its parent so we can use it orientation if it has one 668 // specified; otherwise we prefer to use the orientation of its topmost child that has one 669 // specified and fall back on this container's unset or unspecified value as a candidate 670 // if none of the children have a better candidate for the orientation. 671 if (mOrientation != SCREEN_ORIENTATION_UNSET 672 && mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { 673 return mOrientation; 674 } 675 676 for (int i = mChildren.size() - 1; i >= 0; --i) { 677 final WindowContainer wc = mChildren.get(i); 678 679 // TODO: Maybe mOrientation should default to SCREEN_ORIENTATION_UNSET vs. 680 // SCREEN_ORIENTATION_UNSPECIFIED? 681 final int orientation = wc.getOrientation(candidate == SCREEN_ORIENTATION_BEHIND 682 ? SCREEN_ORIENTATION_BEHIND : SCREEN_ORIENTATION_UNSET); 683 if (orientation == SCREEN_ORIENTATION_BEHIND) { 684 // container wants us to use the orientation of the container behind it. See if we 685 // can find one. Else return SCREEN_ORIENTATION_BEHIND so the caller can choose to 686 // look behind this container. 687 candidate = orientation; 688 continue; 689 } 690 691 if (orientation == SCREEN_ORIENTATION_UNSET) { 692 continue; 693 } 694 695 if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) { 696 // Use the orientation if the container fills its parent or requested an explicit 697 // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED. 698 return orientation; 699 } 700 } 701 702 return candidate; 703 } 704 705 /** 706 * Returns true if this container is opaque and fills all the space made available by its parent 707 * container. 708 * 709 * NOTE: It is possible for this container to occupy more space than the parent has (or less), 710 * this is just a signal from the client to window manager stating its intent, but not what it 711 * actually does. 712 */ 713 boolean fillsParent() { 714 return false; 715 } 716 717 // TODO: Users would have their own window containers under the display container? 718 void switchUser() { 719 for (int i = mChildren.size() - 1; i >= 0; --i) { 720 mChildren.get(i).switchUser(); 721 } 722 } 723 724 /** 725 * For all windows at or below this container call the callback. 726 * @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and 727 * stops the search if {@link ToBooleanFunction#apply} returns true. 728 * @param traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of 729 * z-order, else from bottom-to-top. 730 * @return True if the search ended before we reached the end of the hierarchy due to 731 * {@link ToBooleanFunction#apply} returning true. 732 */ 733 boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { 734 if (traverseTopToBottom) { 735 for (int i = mChildren.size() - 1; i >= 0; --i) { 736 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) { 737 return true; 738 } 739 } 740 } else { 741 final int count = mChildren.size(); 742 for (int i = 0; i < count; i++) { 743 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) { 744 return true; 745 } 746 } 747 } 748 return false; 749 } 750 751 void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) { 752 ForAllWindowsConsumerWrapper wrapper = obtainConsumerWrapper(callback); 753 forAllWindows(wrapper, traverseTopToBottom); 754 wrapper.release(); 755 } 756 757 /** 758 * For all tasks at or below this container call the callback. 759 * 760 * @param callback Callback to be called for every task. 761 */ 762 void forAllTasks(Consumer<Task> callback) { 763 for (int i = mChildren.size() - 1; i >= 0; --i) { 764 mChildren.get(i).forAllTasks(callback); 765 } 766 } 767 768 WindowState getWindow(Predicate<WindowState> callback) { 769 for (int i = mChildren.size() - 1; i >= 0; --i) { 770 final WindowState w = mChildren.get(i).getWindow(callback); 771 if (w != null) { 772 return w; 773 } 774 } 775 776 return null; 777 } 778 779 /** 780 * Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than 781 * the input container in terms of z-order. 782 */ 783 @Override 784 public int compareTo(WindowContainer other) { 785 if (this == other) { 786 return 0; 787 } 788 789 if (mParent != null && mParent == other.mParent) { 790 final WindowList<WindowContainer> list = mParent.mChildren; 791 return list.indexOf(this) > list.indexOf(other) ? 1 : -1; 792 } 793 794 final LinkedList<WindowContainer> thisParentChain = mTmpChain1; 795 final LinkedList<WindowContainer> otherParentChain = mTmpChain2; 796 try { 797 getParents(thisParentChain); 798 other.getParents(otherParentChain); 799 800 // Find the common ancestor of both containers. 801 WindowContainer commonAncestor = null; 802 WindowContainer thisTop = thisParentChain.peekLast(); 803 WindowContainer otherTop = otherParentChain.peekLast(); 804 while (thisTop != null && otherTop != null && thisTop == otherTop) { 805 commonAncestor = thisParentChain.removeLast(); 806 otherParentChain.removeLast(); 807 thisTop = thisParentChain.peekLast(); 808 otherTop = otherParentChain.peekLast(); 809 } 810 811 // Containers don't belong to the same hierarchy??? 812 if (commonAncestor == null) { 813 throw new IllegalArgumentException("No in the same hierarchy this=" 814 + thisParentChain + " other=" + otherParentChain); 815 } 816 817 // Children are always considered greater than their parents, so if one of the containers 818 // we are comparing it the parent of the other then whichever is the child is greater. 819 if (commonAncestor == this) { 820 return -1; 821 } else if (commonAncestor == other) { 822 return 1; 823 } 824 825 // The position of the first non-common ancestor in the common ancestor list determines 826 // which is greater the which. 827 final WindowList<WindowContainer> list = commonAncestor.mChildren; 828 return list.indexOf(thisParentChain.peekLast()) > list.indexOf(otherParentChain.peekLast()) 829 ? 1 : -1; 830 } finally { 831 mTmpChain1.clear(); 832 mTmpChain2.clear(); 833 } 834 } 835 836 private void getParents(LinkedList<WindowContainer> parents) { 837 parents.clear(); 838 WindowContainer current = this; 839 do { 840 parents.addLast(current); 841 current = current.mParent; 842 } while (current != null); 843 } 844 845 WindowContainerController getController() { 846 return mController; 847 } 848 849 void setController(WindowContainerController controller) { 850 if (mController != null && controller != null) { 851 throw new IllegalArgumentException("Can't set controller=" + mController 852 + " for container=" + this + " Already set to=" + mController); 853 } 854 if (controller != null) { 855 controller.setContainer(this); 856 } else if (mController != null) { 857 mController.setContainer(null); 858 } 859 mController = controller; 860 } 861 862 SurfaceControl.Builder makeSurface() { 863 final WindowContainer p = getParent(); 864 return p.makeChildSurface(this); 865 } 866 867 /** 868 * @param child The WindowContainer this child surface is for, or null if the Surface 869 * is not assosciated with a WindowContainer (e.g. a surface used for Dimming). 870 */ 871 SurfaceControl.Builder makeChildSurface(WindowContainer child) { 872 final WindowContainer p = getParent(); 873 // Give the parent a chance to set properties. In hierarchy v1 we rely 874 // on this to set full-screen dimensions on all our Surface-less Layers. 875 return p.makeChildSurface(child) 876 .setParent(mSurfaceControl); 877 } 878 879 @Override 880 public SurfaceControl getParentSurfaceControl() { 881 final WindowContainer parent = getParent(); 882 if (parent == null) { 883 return null; 884 } 885 return parent.getSurfaceControl(); 886 } 887 888 /** 889 * @return Whether this WindowContainer should be magnified by the accessibility magnifier. 890 */ 891 boolean shouldMagnify() { 892 for (int i = 0; i < mChildren.size(); i++) { 893 if (!mChildren.get(i).shouldMagnify()) { 894 return false; 895 } 896 } 897 return true; 898 } 899 900 SurfaceSession getSession() { 901 if (getParent() != null) { 902 return getParent().getSession(); 903 } 904 return null; 905 } 906 907 void assignLayer(Transaction t, int layer) { 908 final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null; 909 if (mSurfaceControl != null && changed) { 910 setLayer(t, layer); 911 mLastLayer = layer; 912 mLastRelativeToLayer = null; 913 } 914 } 915 916 void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { 917 final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo; 918 if (mSurfaceControl != null && changed) { 919 setRelativeLayer(t, relativeTo, layer); 920 mLastLayer = layer; 921 mLastRelativeToLayer = relativeTo; 922 } 923 } 924 925 protected void setLayer(Transaction t, int layer) { 926 927 // Route through surface animator to accommodate that our surface control might be 928 // attached to the leash, and leash is attached to parent container. 929 mSurfaceAnimator.setLayer(t, layer); 930 } 931 932 protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { 933 934 // Route through surface animator to accommodate that our surface control might be 935 // attached to the leash, and leash is attached to parent container. 936 mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer); 937 } 938 939 protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) { 940 mSurfaceAnimator.reparent(t, newParent); 941 } 942 943 void assignChildLayers(Transaction t) { 944 int layer = 0; 945 946 // We use two passes as a way to promote children which 947 // need Z-boosting to the end of the list. 948 for (int j = 0; j < mChildren.size(); ++j) { 949 final WindowContainer wc = mChildren.get(j); 950 wc.assignChildLayers(t); 951 if (!wc.needsZBoost()) { 952 wc.assignLayer(t, layer++); 953 } 954 } 955 for (int j = 0; j < mChildren.size(); ++j) { 956 final WindowContainer wc = mChildren.get(j); 957 if (wc.needsZBoost()) { 958 wc.assignLayer(t, layer++); 959 } 960 } 961 } 962 963 void assignChildLayers() { 964 assignChildLayers(getPendingTransaction()); 965 scheduleAnimation(); 966 } 967 968 boolean needsZBoost() { 969 for (int i = 0; i < mChildren.size(); i++) { 970 if (mChildren.get(i).needsZBoost()) { 971 return true; 972 } 973 } 974 return false; 975 } 976 977 /** 978 * Write to a protocol buffer output stream. Protocol buffer message definition is at 979 * {@link com.android.server.wm.proto.WindowContainerProto}. 980 * 981 * @param proto Stream to write the WindowContainer object to. 982 * @param fieldId Field Id of the WindowContainer as defined in the parent message. 983 * @param trim If true, reduce the amount of data written. 984 * @hide 985 */ 986 @CallSuper 987 @Override 988 public void writeToProto(ProtoOutputStream proto, long fieldId, boolean trim) { 989 final long token = proto.start(fieldId); 990 super.writeToProto(proto, CONFIGURATION_CONTAINER, trim); 991 proto.write(ORIENTATION, mOrientation); 992 proto.write(VISIBLE, isVisible()); 993 mSurfaceAnimator.writeToProto(proto, SURFACE_ANIMATOR); 994 proto.end(token); 995 } 996 997 private ForAllWindowsConsumerWrapper obtainConsumerWrapper(Consumer<WindowState> consumer) { 998 ForAllWindowsConsumerWrapper wrapper = mConsumerWrapperPool.acquire(); 999 if (wrapper == null) { 1000 wrapper = new ForAllWindowsConsumerWrapper(); 1001 } 1002 wrapper.setConsumer(consumer); 1003 return wrapper; 1004 } 1005 1006 private final class ForAllWindowsConsumerWrapper implements ToBooleanFunction<WindowState> { 1007 1008 private Consumer<WindowState> mConsumer; 1009 1010 void setConsumer(Consumer<WindowState> consumer) { 1011 mConsumer = consumer; 1012 } 1013 1014 @Override 1015 public boolean apply(WindowState w) { 1016 mConsumer.accept(w); 1017 return false; 1018 } 1019 1020 void release() { 1021 mConsumer = null; 1022 mConsumerWrapperPool.release(this); 1023 } 1024 } 1025 1026 // TODO(b/68336570): Should this really be on WindowContainer since it 1027 // can only be used on the top-level nodes that aren't animated? 1028 // (otherwise we would be fighting other callers of setMatrix). 1029 void applyMagnificationSpec(Transaction t, MagnificationSpec spec) { 1030 if (shouldMagnify()) { 1031 t.setMatrix(mSurfaceControl, spec.scale, 0, 0, spec.scale) 1032 .setPosition(mSurfaceControl, spec.offsetX, spec.offsetY); 1033 } else { 1034 for (int i = 0; i < mChildren.size(); i++) { 1035 mChildren.get(i).applyMagnificationSpec(t, spec); 1036 } 1037 } 1038 } 1039 1040 /** 1041 * TODO: Once we totally eliminate global transaction we will pass transaction in here 1042 * rather than merging to global. 1043 */ 1044 void prepareSurfaces() { 1045 SurfaceControl.mergeToGlobalTransaction(getPendingTransaction()); 1046 1047 // If a leash has been set when the transaction was committed, then the leash reparent has 1048 // been committed. 1049 mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash(); 1050 for (int i = 0; i < mChildren.size(); i++) { 1051 mChildren.get(i).prepareSurfaces(); 1052 } 1053 } 1054 1055 /** 1056 * @return true if the reparent to animation leash transaction has been committed, false 1057 * otherwise. 1058 */ 1059 boolean hasCommittedReparentToAnimationLeash() { 1060 return mCommittedReparentToAnimationLeash; 1061 } 1062 1063 /** 1064 * Trigger a call to prepareSurfaces from the animation thread, such that 1065 * mPendingTransaction will be applied. 1066 */ 1067 void scheduleAnimation() { 1068 if (mParent != null) { 1069 mParent.scheduleAnimation(); 1070 } 1071 } 1072 1073 @Override 1074 public SurfaceControl getSurfaceControl() { 1075 return mSurfaceControl; 1076 } 1077 1078 /** 1079 * Destroy a given surface after executing mPendingTransaction. This is 1080 * largely a workaround for destroy not being part of transactions 1081 * rather than an intentional design, so please take care when 1082 * expanding use. 1083 */ 1084 @Override 1085 public void destroyAfterPendingTransaction(SurfaceControl surface) { 1086 if (mParent != null) { 1087 mParent.destroyAfterPendingTransaction(surface); 1088 } 1089 } 1090 1091 @Override 1092 public Transaction getPendingTransaction() { 1093 return mPendingTransaction; 1094 } 1095 1096 /** 1097 * Starts an animation on the container. 1098 * 1099 * @param anim The animation to run. 1100 * @param hidden Whether our container is currently hidden. TODO This should use isVisible at 1101 * some point but the meaning is too weird to work for all containers. 1102 */ 1103 void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) { 1104 if (DEBUG_ANIM) Slog.v(TAG, "Starting animation on " + this + ": " + anim); 1105 1106 // TODO: This should use isVisible() but because isVisible has a really weird meaning at 1107 // the moment this doesn't work for all animatable window containers. 1108 mSurfaceAnimator.startAnimation(t, anim, hidden); 1109 } 1110 1111 void transferAnimation(WindowContainer from) { 1112 mSurfaceAnimator.transferAnimation(from.mSurfaceAnimator); 1113 } 1114 1115 void cancelAnimation() { 1116 mSurfaceAnimator.cancelAnimation(); 1117 } 1118 1119 @Override 1120 public Builder makeAnimationLeash() { 1121 return makeSurface(); 1122 } 1123 1124 @Override 1125 public SurfaceControl getAnimationLeashParent() { 1126 return getParentSurfaceControl(); 1127 } 1128 1129 /** 1130 * @return The layer on which all app animations are happening. 1131 */ 1132 SurfaceControl getAppAnimationLayer() { 1133 final WindowContainer parent = getParent(); 1134 if (parent != null) { 1135 return parent.getAppAnimationLayer(); 1136 } 1137 return null; 1138 } 1139 1140 @Override 1141 public void commitPendingTransaction() { 1142 scheduleAnimation(); 1143 } 1144 1145 private void reassignLayer(Transaction t) { 1146 final WindowContainer parent = getParent(); 1147 if (parent != null) { 1148 parent.assignChildLayers(t); 1149 } 1150 } 1151 1152 @Override 1153 public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { 1154 reassignLayer(t); 1155 } 1156 1157 @Override 1158 public void onAnimationLeashDestroyed(Transaction t) { 1159 reassignLayer(t); 1160 } 1161 1162 /** 1163 * Called when an animation has finished running. 1164 */ 1165 protected void onAnimationFinished() { 1166 } 1167 1168 /** 1169 * @return The currently running animation, if any, or {@code null} otherwise. 1170 */ 1171 AnimationAdapter getAnimation() { 1172 return mSurfaceAnimator.getAnimation(); 1173 } 1174 1175 /** 1176 * @see SurfaceAnimator#startDelayingAnimationStart 1177 */ 1178 void startDelayingAnimationStart() { 1179 mSurfaceAnimator.startDelayingAnimationStart(); 1180 } 1181 1182 /** 1183 * @see SurfaceAnimator#endDelayingAnimationStart 1184 */ 1185 void endDelayingAnimationStart() { 1186 mSurfaceAnimator.endDelayingAnimationStart(); 1187 } 1188 1189 @Override 1190 public int getSurfaceWidth() { 1191 return mSurfaceControl.getWidth(); 1192 } 1193 1194 @Override 1195 public int getSurfaceHeight() { 1196 return mSurfaceControl.getHeight(); 1197 } 1198 1199 @CallSuper 1200 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 1201 if (mSurfaceAnimator.isAnimating()) { 1202 pw.print(prefix); pw.println("ContainerAnimator:"); 1203 mSurfaceAnimator.dump(pw, prefix + " "); 1204 } 1205 } 1206 1207 void updateSurfacePosition() { 1208 if (mSurfaceControl == null) { 1209 return; 1210 } 1211 1212 getRelativePosition(mTmpPos); 1213 if (mTmpPos.equals(mLastSurfacePosition)) { 1214 return; 1215 } 1216 1217 getPendingTransaction().setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y); 1218 mLastSurfacePosition.set(mTmpPos.x, mTmpPos.y); 1219 } 1220 1221 void getRelativePosition(Point outPos) { 1222 final Rect bounds = getBounds(); 1223 outPos.set(bounds.left, bounds.top); 1224 final WindowContainer parent = getParent(); 1225 if (parent != null) { 1226 final Rect parentBounds = parent.getBounds(); 1227 outPos.offset(-parentBounds.left, -parentBounds.top); 1228 } 1229 } 1230 1231 Dimmer getDimmer() { 1232 if (mParent == null) { 1233 return null; 1234 } 1235 return mParent.getDimmer(); 1236 } 1237} 1238