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