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