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