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.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; 21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 22 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 23 import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; 24 import static android.content.pm.ActivityInfo.isFixedOrientationPortrait; 25 import static android.content.pm.ActivityInfo.reverseOrientation; 26 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 27 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 28 import static android.content.res.Configuration.ORIENTATION_UNDEFINED; 29 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; 30 import static android.os.UserHandle.USER_NULL; 31 import static android.view.SurfaceControl.Transaction; 32 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; 33 34 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; 35 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; 36 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; 37 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE; 38 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 39 import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION; 40 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; 41 import static com.android.server.wm.IdentifierProto.HASH_CODE; 42 import static com.android.server.wm.IdentifierProto.TITLE; 43 import static com.android.server.wm.IdentifierProto.USER_ID; 44 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; 45 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; 46 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; 47 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; 48 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; 49 import static com.android.server.wm.WindowContainerChildProto.WINDOW_CONTAINER; 50 import static com.android.server.wm.WindowContainerProto.CONFIGURATION_CONTAINER; 51 import static com.android.server.wm.WindowContainerProto.IDENTIFIER; 52 import static com.android.server.wm.WindowContainerProto.ORIENTATION; 53 import static com.android.server.wm.WindowContainerProto.SURFACE_ANIMATOR; 54 import static com.android.server.wm.WindowContainerProto.VISIBLE; 55 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 56 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 57 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 58 import static com.android.server.wm.WindowManagerService.logWithStack; 59 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM; 60 61 import android.annotation.CallSuper; 62 import android.annotation.IntDef; 63 import android.annotation.NonNull; 64 import android.annotation.Nullable; 65 import android.app.WindowConfiguration; 66 import android.content.pm.ActivityInfo; 67 import android.content.res.Configuration; 68 import android.graphics.Point; 69 import android.graphics.Rect; 70 import android.os.Debug; 71 import android.os.IBinder; 72 import android.os.Trace; 73 import android.util.ArraySet; 74 import android.util.Pair; 75 import android.util.Pools; 76 import android.util.Slog; 77 import android.util.proto.ProtoOutputStream; 78 import android.view.DisplayInfo; 79 import android.view.MagnificationSpec; 80 import android.view.RemoteAnimationDefinition; 81 import android.view.RemoteAnimationTarget; 82 import android.view.SurfaceControl; 83 import android.view.SurfaceControl.Builder; 84 import android.view.SurfaceSession; 85 import android.view.WindowManager; 86 import android.view.WindowManager.TransitionOldType; 87 import android.view.animation.Animation; 88 import android.window.IWindowContainerToken; 89 import android.window.WindowContainerToken; 90 91 import com.android.internal.annotations.VisibleForTesting; 92 import com.android.internal.protolog.common.ProtoLog; 93 import com.android.internal.util.ToBooleanFunction; 94 import com.android.server.wm.SurfaceAnimator.Animatable; 95 import com.android.server.wm.SurfaceAnimator.AnimationType; 96 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; 97 98 import java.io.PrintWriter; 99 import java.lang.ref.WeakReference; 100 import java.util.ArrayList; 101 import java.util.Comparator; 102 import java.util.LinkedList; 103 import java.util.List; 104 import java.util.function.BiFunction; 105 import java.util.function.Consumer; 106 import java.util.function.Function; 107 import java.util.function.Predicate; 108 109 /** 110 * Defines common functionality for classes that can hold windows directly or through their 111 * children in a hierarchy form. 112 * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime 113 * changes are made to this class. 114 */ 115 class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E> 116 implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable { 117 118 private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM; 119 120 /** Animation layer that happens above all animating {@link Task}s. */ 121 static final int ANIMATION_LAYER_STANDARD = 0; 122 123 /** Animation layer that happens above all {@link Task}s. */ 124 static final int ANIMATION_LAYER_BOOSTED = 1; 125 126 /** 127 * Animation layer that is reserved for {@link WindowConfiguration#ACTIVITY_TYPE_HOME} 128 * activities and all activities that are being controlled by the recents animation. This 129 * layer is generally below all {@link Task}s. 130 */ 131 static final int ANIMATION_LAYER_HOME = 2; 132 133 @IntDef(prefix = { "ANIMATION_LAYER_" }, value = { 134 ANIMATION_LAYER_STANDARD, 135 ANIMATION_LAYER_BOOSTED, 136 ANIMATION_LAYER_HOME, 137 }) 138 @interface AnimationLayer {} 139 140 static final int POSITION_TOP = Integer.MAX_VALUE; 141 static final int POSITION_BOTTOM = Integer.MIN_VALUE; 142 143 /** 144 * The parent of this window container. 145 * For removing or setting new parent {@link #setParent} should be used, because it also 146 * performs configuration updates based on new parent's settings. 147 */ 148 private WindowContainer<WindowContainer> mParent = null; 149 150 // Set to true when we are performing a reparenting operation so we only send one 151 // onParentChanged() notification. 152 boolean mReparenting; 153 154 // List of children for this window container. List is in z-order as the children appear on 155 // screen with the top-most window container at the tail of the list. 156 protected final WindowList<E> mChildren = new WindowList<E>(); 157 158 // The specified orientation for this window container. 159 @ActivityInfo.ScreenOrientation 160 protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED; 161 162 /** 163 * The window container which decides its orientation since the last time 164 * {@link #getOrientation(int) was called. 165 */ 166 protected WindowContainer mLastOrientationSource; 167 168 private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool = 169 new Pools.SynchronizedPool<>(3); 170 171 // The display this window container is on. 172 protected DisplayContent mDisplayContent; 173 174 protected SurfaceControl mSurfaceControl; 175 private int mLastLayer = 0; 176 private SurfaceControl mLastRelativeToLayer = null; 177 178 // TODO(b/132320879): Remove this from WindowContainers except DisplayContent. 179 private final Transaction mPendingTransaction; 180 181 /** 182 * Windows that clients are waiting to have drawn. 183 */ 184 final ArrayList<WindowState> mWaitingForDrawn = new ArrayList<>(); 185 186 /** 187 * Applied as part of the animation pass in "prepareSurfaces". 188 */ 189 protected final SurfaceAnimator mSurfaceAnimator; 190 private boolean mAnyParentAnimating; 191 192 final SurfaceFreezer mSurfaceFreezer; 193 protected final WindowManagerService mWmService; 194 195 /** 196 * Sources which triggered a surface animation on this container. An animation target can be 197 * promoted to higher level, for example, from a set of {@link ActivityRecord}s to 198 * {@link Task}. In this case, {@link ActivityRecord}s are set on this variable while 199 * the animation is running, and reset after finishing it. 200 */ 201 private final ArraySet<WindowContainer> mSurfaceAnimationSources = new ArraySet<>(); 202 203 private final Point mTmpPos = new Point(); 204 protected final Point mLastSurfacePosition = new Point(); 205 206 /** Total number of elements in this subtree, including our own hierarchy element. */ 207 private int mTreeWeight = 1; 208 209 /** 210 * Indicates whether we are animating and have committed the transaction to reparent our 211 * surface to the animation leash 212 */ 213 private boolean mCommittedReparentToAnimationLeash; 214 215 /** Interface for {@link #isAnimating} to check which cases for the container is animating. */ 216 public interface AnimationFlags { 217 /** 218 * A bit flag indicates that {@link #isAnimating} should also return {@code true} 219 * even though the container is not yet animating, but the window container or its 220 * relatives as specified by PARENTS or CHILDREN are part of an {@link AppTransition} 221 * that is pending so an animation starts soon. 222 */ 223 int TRANSITION = 1; 224 225 /** 226 * A bit flag indicates that {@link #isAnimating} should also check if one of the 227 * ancestors of the container are animating in addition to the container itself. 228 */ 229 int PARENTS = 2; 230 231 /** 232 * A bit flag indicates that {@link #isAnimating} should also check if one of the 233 * descendants of the container are animating in addition to the container itself. 234 */ 235 int CHILDREN = 4; 236 } 237 238 /** 239 * Callback which is triggered while changing the parent, after setting up the surface but 240 * before asking the parent to assign child layers. 241 */ 242 interface PreAssignChildLayersCallback { onPreAssignChildLayers()243 void onPreAssignChildLayers(); 244 } 245 246 /** 247 * True if this an AppWindowToken and the activity which created this was launched with 248 * ActivityOptions.setLaunchTaskBehind. 249 * 250 * TODO(b/142617871): We run a special animation when the activity was launched with that 251 * flag, but it's not necessary anymore. Keep the window invisible until the task is explicitly 252 * selected to suppress an animation, and remove this flag. 253 */ 254 boolean mLaunchTaskBehind; 255 256 /** 257 * If we are running an animation, this determines the transition type. 258 */ 259 @TransitionOldType int mTransit; 260 261 /** 262 * If we are running an animation, this determines the flags during this animation. Must be a 263 * bitwise combination of AppTransition.TRANSIT_FLAG_* constants. 264 */ 265 int mTransitFlags; 266 267 /** Whether this container should be boosted at the top of all its siblings. */ 268 @VisibleForTesting boolean mNeedsZBoost; 269 270 /** Layer used to constrain the animation to a container's stack bounds. */ 271 SurfaceControl mAnimationBoundsLayer; 272 273 /** Whether this container needs to create mAnimationBoundsLayer for cropping animations. */ 274 boolean mNeedsAnimationBoundsLayer; 275 276 /** 277 * This gets used during some open/close transitions as well as during a change transition 278 * where it represents the starting-state snapshot. 279 */ 280 WindowContainerThumbnail mThumbnail; 281 final Point mTmpPoint = new Point(); 282 protected final Rect mTmpRect = new Rect(); 283 final Rect mTmpPrevBounds = new Rect(); 284 285 private MagnificationSpec mLastMagnificationSpec; 286 287 private boolean mIsFocusable = true; 288 289 /** 290 * Used as a unique, cross-process identifier for this Container. It also serves a minimal 291 * interface to other processes. 292 */ 293 RemoteToken mRemoteToken = null; 294 295 /** This isn't participating in a sync. */ 296 public static final int SYNC_STATE_NONE = 0; 297 298 /** This is currently waiting for itself to finish drawing. */ 299 public static final int SYNC_STATE_WAITING_FOR_DRAW = 1; 300 301 /** This container is ready, but it might still have unfinished children. */ 302 public static final int SYNC_STATE_READY = 2; 303 304 @IntDef(prefix = { "SYNC_STATE_" }, value = { 305 SYNC_STATE_NONE, 306 SYNC_STATE_WAITING_FOR_DRAW, 307 SYNC_STATE_READY, 308 }) 309 @interface SyncState {} 310 311 /** 312 * If non-null, references the sync-group directly waiting on this container. Otherwise, this 313 * container is only being waited-on by its parents (if in a sync-group). This has implications 314 * on how this container is handled during parent changes. 315 */ 316 BLASTSyncEngine.SyncGroup mSyncGroup = null; 317 final SurfaceControl.Transaction mSyncTransaction; 318 @SyncState int mSyncState = SYNC_STATE_NONE; 319 320 private final List<WindowContainerListener> mListeners = new ArrayList<>(); 321 WindowContainer(WindowManagerService wms)322 WindowContainer(WindowManagerService wms) { 323 mWmService = wms; 324 mPendingTransaction = wms.mTransactionFactory.get(); 325 mSyncTransaction = wms.mTransactionFactory.get(); 326 mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms); 327 mSurfaceFreezer = new SurfaceFreezer(this, wms); 328 } 329 330 @Override getParent()331 final protected WindowContainer getParent() { 332 return mParent; 333 } 334 335 @Override getChildCount()336 protected int getChildCount() { 337 return mChildren.size(); 338 } 339 340 @Override getChildAt(int index)341 protected E getChildAt(int index) { 342 return mChildren.get(index); 343 } 344 345 @Override onConfigurationChanged(Configuration newParentConfig)346 public void onConfigurationChanged(Configuration newParentConfig) { 347 super.onConfigurationChanged(newParentConfig); 348 updateSurfacePositionNonOrganized(); 349 scheduleAnimation(); 350 } 351 reparent(WindowContainer newParent, int position)352 void reparent(WindowContainer newParent, int position) { 353 if (newParent == null) { 354 throw new IllegalArgumentException("reparent: can't reparent to null " + this); 355 } 356 357 final WindowContainer oldParent = mParent; 358 if (mParent == newParent) { 359 throw new IllegalArgumentException("WC=" + this + " already child of " + mParent); 360 } 361 362 // The display object before reparenting as that might lead to old parent getting removed 363 // from the display if it no longer has any child. 364 final DisplayContent prevDc = oldParent.getDisplayContent(); 365 final DisplayContent dc = newParent.getDisplayContent(); 366 367 mReparenting = true; 368 oldParent.removeChild(this); 369 newParent.addChild(this, position); 370 mReparenting = false; 371 372 // Relayout display(s) 373 dc.setLayoutNeeded(); 374 if (prevDc != dc) { 375 onDisplayChanged(dc); 376 prevDc.setLayoutNeeded(); 377 } 378 getDisplayContent().layoutAndAssignWindowLayersIfNeeded(); 379 380 // Send onParentChanged notification here is we disabled sending it in setParent for 381 // reparenting case. 382 onParentChanged(newParent, oldParent); 383 onSyncReparent(oldParent, newParent); 384 } 385 setParent(WindowContainer<WindowContainer> parent)386 final protected void setParent(WindowContainer<WindowContainer> parent) { 387 final WindowContainer oldParent = mParent; 388 mParent = parent; 389 390 if (mParent != null) { 391 mParent.onChildAdded(this); 392 } 393 if (!mReparenting) { 394 onSyncReparent(oldParent, mParent); 395 if (mParent != null && mParent.mDisplayContent != null 396 && mDisplayContent != mParent.mDisplayContent) { 397 onDisplayChanged(mParent.mDisplayContent); 398 } 399 onParentChanged(mParent, oldParent); 400 } 401 } 402 403 /** 404 * Callback that is triggered when @link WindowContainer#setParent(WindowContainer)} was called. 405 * Supposed to be overridden and contain actions that should be executed after parent was set. 406 */ 407 @Override onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent)408 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { 409 onParentChanged(newParent, oldParent, null); 410 } 411 onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent, PreAssignChildLayersCallback callback)412 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent, 413 PreAssignChildLayersCallback callback) { 414 super.onParentChanged(newParent, oldParent); 415 if (mParent == null) { 416 return; 417 } 418 419 if (mSurfaceControl == null) { 420 // If we don't yet have a surface, but we now have a parent, we should 421 // build a surface. 422 createSurfaceControl(false /*force*/); 423 } else { 424 // If we have a surface but a new parent, we just need to perform a reparent. Go through 425 // surface animator such that hierarchy is preserved when animating, i.e. 426 // mSurfaceControl stays attached to the leash and we just reparent the leash to the 427 // new parent. 428 reparentSurfaceControl(getSyncTransaction(), mParent.mSurfaceControl); 429 } 430 431 if (callback != null) { 432 callback.onPreAssignChildLayers(); 433 } 434 435 // Either way we need to ask the parent to assign us a Z-order. 436 mParent.assignChildLayers(); 437 scheduleAnimation(); 438 } 439 createSurfaceControl(boolean force)440 void createSurfaceControl(boolean force) { 441 setInitialSurfaceControlProperties(makeSurface()); 442 } 443 setInitialSurfaceControlProperties(SurfaceControl.Builder b)444 void setInitialSurfaceControlProperties(SurfaceControl.Builder b) { 445 setSurfaceControl(b.setCallsite("WindowContainer.setInitialSurfaceControlProperties").build()); 446 if (showSurfaceOnCreation()) { 447 getSyncTransaction().show(mSurfaceControl); 448 } 449 onSurfaceShown(getSyncTransaction()); 450 updateSurfacePositionNonOrganized(); 451 } 452 453 /** 454 * Create a new SurfaceControl for this WindowContainer and migrate all properties to the new 455 * SurfaceControl. Properties include: 456 * 1. Children 457 * 2. Position 458 * 3. Z order 459 * 460 * Remove the old SurfaceControl since it's no longer needed. 461 * 462 * This is used to revoke control of the SurfaceControl from a client process that was 463 * previously organizing this WindowContainer. 464 */ migrateToNewSurfaceControl(SurfaceControl.Transaction t)465 void migrateToNewSurfaceControl(SurfaceControl.Transaction t) { 466 t.remove(mSurfaceControl); 467 // Clear the last position so the new SurfaceControl will get correct position 468 mLastSurfacePosition.set(0, 0); 469 470 final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(null) 471 .setContainerLayer() 472 .setName(getName()); 473 474 setInitialSurfaceControlProperties(b); 475 476 // If parent is null, the layer should be placed offscreen so reparent to null. Otherwise, 477 // set to the available parent. 478 t.reparent(mSurfaceControl, mParent == null ? null : mParent.getSurfaceControl()); 479 480 if (mLastRelativeToLayer != null) { 481 t.setRelativeLayer(mSurfaceControl, mLastRelativeToLayer, mLastLayer); 482 } else { 483 t.setLayer(mSurfaceControl, mLastLayer); 484 } 485 486 for (int i = 0; i < mChildren.size(); i++) { 487 SurfaceControl sc = mChildren.get(i).getSurfaceControl(); 488 if (sc != null) { 489 t.reparent(sc, mSurfaceControl); 490 } 491 } 492 scheduleAnimation(); 493 } 494 495 /** 496 * Called when the surface is shown for the first time. 497 */ onSurfaceShown(Transaction t)498 void onSurfaceShown(Transaction t) { 499 // do nothing 500 } 501 502 // Temp. holders for a chain of containers we are currently processing. 503 private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList<>(); 504 private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList<>(); 505 506 /** 507 * Adds the input window container has a child of this container in order based on the input 508 * comparator. 509 * @param child The window container to add as a child of this window container. 510 * @param comparator Comparator to use in determining the position the child should be added to. 511 * If null, the child will be added to the top. 512 */ 513 @CallSuper addChild(E child, Comparator<E> comparator)514 protected void addChild(E child, Comparator<E> comparator) { 515 if (!child.mReparenting && child.getParent() != null) { 516 throw new IllegalArgumentException("addChild: container=" + child.getName() 517 + " is already a child of container=" + child.getParent().getName() 518 + " can't add to container=" + getName()); 519 } 520 521 int positionToAdd = -1; 522 if (comparator != null) { 523 final int count = mChildren.size(); 524 for (int i = 0; i < count; i++) { 525 if (comparator.compare(child, mChildren.get(i)) < 0) { 526 positionToAdd = i; 527 break; 528 } 529 } 530 } 531 532 if (positionToAdd == -1) { 533 mChildren.add(child); 534 } else { 535 mChildren.add(positionToAdd, child); 536 } 537 538 // Set the parent after we've actually added a child in case a subclass depends on this. 539 child.setParent(this); 540 } 541 542 /** Adds the input window container has a child of this container at the input index. */ 543 @CallSuper addChild(E child, int index)544 void addChild(E child, int index) { 545 if (!child.mReparenting && child.getParent() != null) { 546 throw new IllegalArgumentException("addChild: container=" + child.getName() 547 + " is already a child of container=" + child.getParent().getName() 548 + " can't add to container=" + getName() 549 + "\n callers=" + Debug.getCallers(15, "\n")); 550 } 551 552 if ((index < 0 && index != POSITION_BOTTOM) 553 || (index > mChildren.size() && index != POSITION_TOP)) { 554 throw new IllegalArgumentException("addChild: invalid position=" + index 555 + ", children number=" + mChildren.size()); 556 } 557 558 if (index == POSITION_TOP) { 559 index = mChildren.size(); 560 } else if (index == POSITION_BOTTOM) { 561 index = 0; 562 } 563 564 mChildren.add(index, child); 565 566 // Set the parent after we've actually added a child in case a subclass depends on this. 567 child.setParent(this); 568 } 569 onChildAdded(WindowContainer child)570 private void onChildAdded(WindowContainer child) { 571 mTreeWeight += child.mTreeWeight; 572 WindowContainer parent = getParent(); 573 while (parent != null) { 574 parent.mTreeWeight += child.mTreeWeight; 575 parent = parent.getParent(); 576 } 577 onChildPositionChanged(child); 578 } 579 580 /** 581 * Removes the input child container from this container which is its parent. 582 * 583 * @return True if the container did contain the input child and it was detached. 584 */ 585 @CallSuper removeChild(E child)586 void removeChild(E child) { 587 if (mChildren.remove(child)) { 588 onChildRemoved(child); 589 if (!child.mReparenting) { 590 child.setParent(null); 591 } 592 } else { 593 throw new IllegalArgumentException("removeChild: container=" + child.getName() 594 + " is not a child of container=" + getName()); 595 } 596 } 597 onChildRemoved(WindowContainer child)598 private void onChildRemoved(WindowContainer child) { 599 mTreeWeight -= child.mTreeWeight; 600 WindowContainer parent = getParent(); 601 while (parent != null) { 602 parent.mTreeWeight -= child.mTreeWeight; 603 parent = parent.getParent(); 604 } 605 onChildPositionChanged(child); 606 } 607 608 /** 609 * Removes this window container and its children with no regard for what else might be going on 610 * in the system. For example, the container will be removed during animation if this method is 611 * called which isn't desirable. For most cases you want to call {@link #removeIfPossible()} 612 * which allows the system to defer removal until a suitable time. 613 */ 614 @CallSuper removeImmediately()615 void removeImmediately() { 616 final DisplayContent dc = getDisplayContent(); 617 if (dc != null) { 618 mSurfaceFreezer.unfreeze(getSyncTransaction()); 619 dc.mChangingContainers.remove(this); 620 } 621 while (!mChildren.isEmpty()) { 622 final E child = mChildren.peekLast(); 623 child.removeImmediately(); 624 // Need to do this after calling remove on the child because the child might try to 625 // remove/detach itself from its parent which will cause an exception if we remove 626 // it before calling remove on the child. 627 if (mChildren.remove(child)) { 628 onChildRemoved(child); 629 } 630 } 631 632 if (mSurfaceControl != null) { 633 getSyncTransaction().remove(mSurfaceControl); 634 setSurfaceControl(null); 635 mLastSurfacePosition.set(0, 0); 636 scheduleAnimation(); 637 } 638 639 // This must happen after updating the surface so that sync transactions can be handled 640 // properly. 641 if (mParent != null) { 642 mParent.removeChild(this); 643 } 644 645 for (int i = mListeners.size() - 1; i >= 0; --i) { 646 mListeners.get(i).onRemoved(); 647 } 648 } 649 650 /** 651 * @return The index of this element in the hierarchy tree in prefix order. 652 */ getPrefixOrderIndex()653 int getPrefixOrderIndex() { 654 if (mParent == null) { 655 return 0; 656 } 657 return mParent.getPrefixOrderIndex(this); 658 } 659 getPrefixOrderIndex(WindowContainer child)660 private int getPrefixOrderIndex(WindowContainer child) { 661 int order = 0; 662 for (int i = 0; i < mChildren.size(); i++) { 663 final WindowContainer childI = mChildren.get(i); 664 if (child == childI) { 665 break; 666 } 667 order += childI.mTreeWeight; 668 } 669 if (mParent != null) { 670 order += mParent.getPrefixOrderIndex(this); 671 } 672 673 // We also need to count ourselves. 674 order++; 675 return order; 676 } 677 678 /** 679 * Removes this window container and its children taking care not to remove them during a 680 * critical stage in the system. For example, some containers will not be removed during 681 * animation if this method is called. 682 */ 683 // TODO: figure-out implementation that works best for this. 684 // E.g. when do we remove from parent list? maybe not... removeIfPossible()685 void removeIfPossible() { 686 for (int i = mChildren.size() - 1; i >= 0; --i) { 687 final WindowContainer wc = mChildren.get(i); 688 wc.removeIfPossible(); 689 } 690 } 691 692 /** Returns true if this window container has the input child. */ hasChild(E child)693 boolean hasChild(E child) { 694 for (int i = mChildren.size() - 1; i >= 0; --i) { 695 final E current = mChildren.get(i); 696 if (current == child || current.hasChild(child)) { 697 return true; 698 } 699 } 700 return false; 701 } 702 703 /** @return true if this window container is a descendant of the input container. */ isDescendantOf(WindowContainer ancestor)704 boolean isDescendantOf(WindowContainer ancestor) { 705 final WindowContainer parent = getParent(); 706 if (parent == ancestor) return true; 707 return (parent != null) && parent.isDescendantOf(ancestor); 708 } 709 710 /** 711 * Move a child from it's current place in siblings list to the specified position, 712 * with an option to move all its parents to top. 713 * @param position Target position to move the child to. 714 * @param child Child to move to selected position. 715 * @param includingParents Flag indicating whether we need to move the entire branch of the 716 * hierarchy when we're moving a child to {@link #POSITION_TOP} or 717 * {@link #POSITION_BOTTOM}. When moving to other intermediate positions 718 * this flag will do nothing. 719 */ 720 @CallSuper positionChildAt(int position, E child, boolean includingParents)721 void positionChildAt(int position, E child, boolean includingParents) { 722 if (child.getParent() != this) { 723 throw new IllegalArgumentException("positionChildAt: container=" + child.getName() 724 + " is not a child of container=" + getName() 725 + " current parent=" + child.getParent()); 726 } 727 728 if (position >= mChildren.size() - 1) { 729 position = POSITION_TOP; 730 } else if (position <= 0) { 731 position = POSITION_BOTTOM; 732 } 733 734 switch (position) { 735 case POSITION_TOP: 736 if (mChildren.peekLast() != child) { 737 mChildren.remove(child); 738 mChildren.add(child); 739 onChildPositionChanged(child); 740 } 741 if (includingParents && getParent() != null) { 742 getParent().positionChildAt(POSITION_TOP, this /* child */, 743 true /* includingParents */); 744 } 745 break; 746 case POSITION_BOTTOM: 747 if (mChildren.peekFirst() != child) { 748 mChildren.remove(child); 749 mChildren.addFirst(child); 750 onChildPositionChanged(child); 751 } 752 if (includingParents && getParent() != null) { 753 getParent().positionChildAt(POSITION_BOTTOM, this /* child */, 754 true /* includingParents */); 755 } 756 break; 757 default: 758 // TODO: Removing the child before reinserting requires the caller to provide a 759 // position that takes into account the removed child (if the index of the 760 // child < position, then the position should be adjusted). We should consider 761 // doing this adjustment here and remove any adjustments in the callers. 762 if (mChildren.indexOf(child) != position) { 763 mChildren.remove(child); 764 mChildren.add(position, child); 765 onChildPositionChanged(child); 766 } 767 } 768 } 769 770 /** 771 * Notify that a child's position has changed. Possible changes are adding or removing a child. 772 */ onChildPositionChanged(WindowContainer child)773 void onChildPositionChanged(WindowContainer child) { } 774 775 /** 776 * Update override configuration and recalculate full config. 777 * @see #mRequestedOverrideConfiguration 778 * @see #mFullConfiguration 779 */ 780 @Override onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration)781 public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) { 782 // We must diff before the configuration is applied so that we can capture the change 783 // against the existing bounds. 784 final int diff = diffRequestedOverrideBounds( 785 overrideConfiguration.windowConfiguration.getBounds()); 786 super.onRequestedOverrideConfigurationChanged(overrideConfiguration); 787 if (mParent != null) { 788 mParent.onDescendantOverrideConfigurationChanged(); 789 } 790 791 if (diff == BOUNDS_CHANGE_NONE) { 792 return; 793 } 794 795 if ((diff & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) { 796 onResize(); 797 } else { 798 onMovedByResize(); 799 } 800 } 801 802 /** 803 * Notify that a descendant's overrideConfiguration has changed. 804 */ onDescendantOverrideConfigurationChanged()805 void onDescendantOverrideConfigurationChanged() { 806 if (mParent != null) { 807 mParent.onDescendantOverrideConfigurationChanged(); 808 } 809 } 810 811 /** 812 * Notify that the display this container is on has changed. This could be either this container 813 * is moved to a new display, or some configurations on the display it is on changes. 814 * 815 * @param dc The display this container is on after changes. 816 */ onDisplayChanged(DisplayContent dc)817 void onDisplayChanged(DisplayContent dc) { 818 if (mDisplayContent != null && mDisplayContent.mChangingContainers.remove(this)) { 819 // Cancel any change transition queued-up for this container on the old display. 820 mSurfaceFreezer.unfreeze(getPendingTransaction()); 821 } 822 mDisplayContent = dc; 823 if (dc != null && dc != this) { 824 dc.getPendingTransaction().merge(mPendingTransaction); 825 } 826 for (int i = mChildren.size() - 1; i >= 0; --i) { 827 final WindowContainer child = mChildren.get(i); 828 child.onDisplayChanged(dc); 829 } 830 for (int i = mListeners.size() - 1; i >= 0; --i) { 831 mListeners.get(i).onDisplayChanged(dc); 832 } 833 } 834 getDisplayContent()835 DisplayContent getDisplayContent() { 836 return mDisplayContent; 837 } 838 839 /** Returns the first node of type {@link DisplayArea} above or at this node. */ 840 @Nullable getDisplayArea()841 DisplayArea getDisplayArea() { 842 WindowContainer parent = getParent(); 843 return parent != null ? parent.getDisplayArea() : null; 844 } 845 846 /** Returns the first node of type {@link RootDisplayArea} above or at this node. */ 847 @Nullable getRootDisplayArea()848 RootDisplayArea getRootDisplayArea() { 849 WindowContainer parent = getParent(); 850 return parent != null ? parent.getRootDisplayArea() : null; 851 } 852 isAttached()853 boolean isAttached() { 854 return getDisplayArea() != null; 855 } 856 setWaitingForDrawnIfResizingChanged()857 void setWaitingForDrawnIfResizingChanged() { 858 for (int i = mChildren.size() - 1; i >= 0; --i) { 859 final WindowContainer wc = mChildren.get(i); 860 wc.setWaitingForDrawnIfResizingChanged(); 861 } 862 } 863 onResize()864 void onResize() { 865 for (int i = mChildren.size() - 1; i >= 0; --i) { 866 final WindowContainer wc = mChildren.get(i); 867 wc.onParentResize(); 868 } 869 } 870 onParentResize()871 void onParentResize() { 872 // In the case this container has specified its own bounds, a parent resize will not 873 // affect its bounds. Any relevant changes will be propagated through changes to the 874 // Configuration override. 875 if (hasOverrideBounds()) { 876 return; 877 } 878 879 // Default implementation is to treat as resize on self. 880 onResize(); 881 } 882 onMovedByResize()883 void onMovedByResize() { 884 for (int i = mChildren.size() - 1; i >= 0; --i) { 885 final WindowContainer wc = mChildren.get(i); 886 wc.onMovedByResize(); 887 } 888 } 889 resetDragResizingChangeReported()890 void resetDragResizingChangeReported() { 891 for (int i = mChildren.size() - 1; i >= 0; --i) { 892 final WindowContainer wc = mChildren.get(i); 893 wc.resetDragResizingChangeReported(); 894 } 895 } 896 897 /** 898 * @return {@code true} when an application can override an app transition animation on this 899 * container. 900 */ canCustomizeAppTransition()901 boolean canCustomizeAppTransition() { 902 return !WindowManagerService.sDisableCustomTaskAnimationProperty; 903 } 904 905 /** 906 * @return {@code true} when this container or its related containers are running an 907 * animation, {@code false} otherwise. 908 * 909 * By default this predicate only checks if this container itself is actually running an 910 * animation, but you can extend the check target over its relatives, or relax the condition 911 * so that this can return {@code true} if an animation starts soon by giving a combination 912 * of {@link AnimationFlags}. 913 * 914 * Note that you can give a combination of bitmask flags to specify targets and condition for 915 * checking animating status. 916 * e.g. {@code isAnimating(TRANSITION | PARENT)} returns {@code true} if either this 917 * container itself or one of its parents is running an animation or waiting for an app 918 * transition. 919 * 920 * Note that TRANSITION propagates to parents and children as well. 921 * 922 * @param flags The combination of bitmask flags to specify targets and condition for 923 * checking animating status. 924 * @param typesToCheck The combination of bitmask {@link AnimationType} to compare when 925 * determining if animating. 926 * 927 * @see AnimationFlags#TRANSITION 928 * @see AnimationFlags#PARENTS 929 * @see AnimationFlags#CHILDREN 930 */ isAnimating(int flags, int typesToCheck)931 final boolean isAnimating(int flags, int typesToCheck) { 932 return getAnimatingContainer(flags, typesToCheck) != null; 933 } 934 935 /** 936 * Similar to {@link #isAnimating(int, int)} except provide a bitmask of 937 * {@link AnimationType} to exclude, rather than include 938 * @param flags The combination of bitmask flags to specify targets and condition for 939 * checking animating status. 940 * @param typesToExclude The combination of bitmask {@link AnimationType} to exclude when 941 * checking if animating. 942 * 943 * @deprecated Use {@link #isAnimating(int, int)} 944 */ 945 @Deprecated isAnimatingExcluding(int flags, int typesToExclude)946 final boolean isAnimatingExcluding(int flags, int typesToExclude) { 947 return isAnimating(flags, ANIMATION_TYPE_ALL & ~typesToExclude); 948 } 949 950 /** 951 * @deprecated Use {@link #isAnimating(int, int)} 952 * TODO (b/152333373): Migrate calls to use isAnimating with specified animation type 953 */ 954 @Deprecated isAnimating(int flags)955 final boolean isAnimating(int flags) { 956 return isAnimating(flags, ANIMATION_TYPE_ALL); 957 } 958 959 /** 960 * @return {@code true} when the container is waiting the app transition start, {@code false} 961 * otherwise. 962 */ isWaitingForTransitionStart()963 boolean isWaitingForTransitionStart() { 964 return false; 965 } 966 967 /** 968 * @return {@code true} if in this subtree of the hierarchy we have an 969 * {@code ActivityRecord#isAnimating(TRANSITION)}, {@code false} otherwise. 970 */ isAppTransitioning()971 boolean isAppTransitioning() { 972 return getActivity(app -> app.isAnimating(PARENTS | TRANSITION)) != null; 973 } 974 975 /** 976 * @return Whether our own container running an animation at the moment. 977 */ isAnimating()978 final boolean isAnimating() { 979 return isAnimating(0 /* self only */); 980 } 981 982 /** 983 * @return {@code true} if the container is in changing app transition. 984 */ isChangingAppTransition()985 boolean isChangingAppTransition() { 986 return mDisplayContent != null && mDisplayContent.mChangingContainers.contains(this); 987 } 988 sendAppVisibilityToClients()989 void sendAppVisibilityToClients() { 990 for (int i = mChildren.size() - 1; i >= 0; --i) { 991 final WindowContainer wc = mChildren.get(i); 992 wc.sendAppVisibilityToClients(); 993 } 994 } 995 996 /** 997 * Returns true if the container or one of its children as some content it can display or wants 998 * to display (e.g. app views or saved surface). 999 * 1000 * NOTE: While this method will return true if the there is some content to display, it doesn't 1001 * mean the container is visible. Use {@link #isVisible()} to determine if the container is 1002 * visible. 1003 */ hasContentToDisplay()1004 boolean hasContentToDisplay() { 1005 for (int i = mChildren.size() - 1; i >= 0; --i) { 1006 final WindowContainer wc = mChildren.get(i); 1007 if (wc.hasContentToDisplay()) { 1008 return true; 1009 } 1010 } 1011 return false; 1012 } 1013 1014 /** 1015 * Returns true if the container or one of its children is considered visible from the 1016 * WindowManager perspective which usually means valid surface and some other internal state 1017 * are true. 1018 * 1019 * NOTE: While this method will return true if the surface is visible, it doesn't mean the 1020 * client has actually displayed any content. Use {@link #hasContentToDisplay()} to determine if 1021 * the container has any content to display. 1022 */ isVisible()1023 boolean isVisible() { 1024 // TODO: Will this be more correct if it checks the visibility of its parents? 1025 // It depends...For example, Tasks and Stacks are only visible if there children are visible 1026 // but, WindowState are not visible if there parent are not visible. Maybe have the 1027 // container specify which direction to traverse for visibility? 1028 for (int i = mChildren.size() - 1; i >= 0; --i) { 1029 final WindowContainer wc = mChildren.get(i); 1030 if (wc.isVisible()) { 1031 return true; 1032 } 1033 } 1034 return false; 1035 } 1036 1037 /** 1038 * Is this window's surface needed? This is almost like isVisible, except when participating 1039 * in a transition, this will reflect the final visibility while isVisible won't change until 1040 * the transition is finished. 1041 */ isVisibleRequested()1042 boolean isVisibleRequested() { 1043 for (int i = mChildren.size() - 1; i >= 0; --i) { 1044 final WindowContainer child = mChildren.get(i); 1045 if (child.isVisibleRequested()) { 1046 return true; 1047 } 1048 } 1049 return false; 1050 } 1051 1052 /** 1053 * Called when the visibility of a child is asked to change. This is before visibility actually 1054 * changes (eg. a transition animation might play out first). 1055 */ onChildVisibilityRequested(boolean visible)1056 void onChildVisibilityRequested(boolean visible) { 1057 // If we are losing visibility, then a snapshot isn't necessary and we are no-longer 1058 // part of a change transition. 1059 if (!visible) { 1060 mSurfaceFreezer.unfreeze(getSyncTransaction()); 1061 if (mDisplayContent != null) { 1062 mDisplayContent.mChangingContainers.remove(this); 1063 } 1064 } 1065 WindowContainer parent = getParent(); 1066 if (parent != null) { 1067 parent.onChildVisibilityRequested(visible); 1068 } 1069 } 1070 writeIdentifierToProto(ProtoOutputStream proto, long fieldId)1071 void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { 1072 final long token = proto.start(fieldId); 1073 proto.write(HASH_CODE, System.identityHashCode(this)); 1074 proto.write(USER_ID, USER_NULL); 1075 proto.write(TITLE, "WindowContainer"); 1076 proto.end(token); 1077 } 1078 1079 /** 1080 * Returns {@code true} if this container is focusable. Generally, if a parent is not focusable, 1081 * this will not be focusable either. 1082 */ isFocusable()1083 boolean isFocusable() { 1084 final WindowContainer parent = getParent(); 1085 return (parent == null || parent.isFocusable()) && mIsFocusable; 1086 } 1087 1088 /** Set whether this container or its children can be focusable */ setFocusable(boolean focusable)1089 boolean setFocusable(boolean focusable) { 1090 if (mIsFocusable == focusable) { 1091 return false; 1092 } 1093 mIsFocusable = focusable; 1094 return true; 1095 } 1096 1097 /** 1098 * @return Whether this child is on top of the window hierarchy. 1099 */ isOnTop()1100 boolean isOnTop() { 1101 final WindowContainer parent = getParent(); 1102 return parent != null && parent.getTopChild() == this && parent.isOnTop(); 1103 } 1104 1105 /** Returns the top child container. */ getTopChild()1106 E getTopChild() { 1107 return mChildren.peekLast(); 1108 } 1109 1110 /** 1111 * Removes the containers which were deferred. 1112 * 1113 * @return {@code true} if there is still a removal being deferred. 1114 */ handleCompleteDeferredRemoval()1115 boolean handleCompleteDeferredRemoval() { 1116 boolean stillDeferringRemoval = false; 1117 1118 for (int i = mChildren.size() - 1; i >= 0; --i) { 1119 final WindowContainer wc = mChildren.get(i); 1120 stillDeferringRemoval |= wc.handleCompleteDeferredRemoval(); 1121 if (!hasChild()) { 1122 // All child containers of current level could be removed from a removal of 1123 // descendant. E.g. if a display is pending to be removed because it contains an 1124 // activity with {@link ActivityRecord#mIsExiting} is true, the display may be 1125 // removed when completing the removal of the last activity from 1126 // {@link ActivityRecord#handleCompleteDeferredRemoval}. 1127 return false; 1128 } 1129 } 1130 1131 return stillDeferringRemoval; 1132 } 1133 1134 /** Checks if all windows in an app are all drawn and shows them if needed. */ checkAppWindowsReadyToShow()1135 void checkAppWindowsReadyToShow() { 1136 for (int i = mChildren.size() - 1; i >= 0; --i) { 1137 final WindowContainer wc = mChildren.get(i); 1138 wc.checkAppWindowsReadyToShow(); 1139 } 1140 } 1141 onAppTransitionDone()1142 void onAppTransitionDone() { 1143 for (int i = mChildren.size() - 1; i >= 0; --i) { 1144 final WindowContainer wc = mChildren.get(i); 1145 wc.onAppTransitionDone(); 1146 } 1147 } 1148 1149 /** 1150 * Called when this container or one of its descendants changed its requested orientation, and 1151 * wants this container to handle it or pass it to its parent. 1152 * 1153 * @param requestingContainer the container which orientation request has changed 1154 * @return {@code true} if handled; {@code false} otherwise. 1155 */ onDescendantOrientationChanged(@ullable WindowContainer requestingContainer)1156 boolean onDescendantOrientationChanged(@Nullable WindowContainer requestingContainer) { 1157 final WindowContainer parent = getParent(); 1158 if (parent == null) { 1159 return false; 1160 } 1161 return parent.onDescendantOrientationChanged(requestingContainer); 1162 } 1163 1164 /** 1165 * Check if this container or its parent will handle orientation changes from descendants. It's 1166 * different from the return value of {@link #onDescendantOrientationChanged(WindowContainer)} 1167 * in the sense that the return value of this method tells if this container or its parent will 1168 * handle the request eventually, while the return value of the other method is if it handled 1169 * the request synchronously. 1170 * 1171 * @return {@code true} if it handles or will handle orientation change in the future; {@code 1172 * false} if it won't handle the change at anytime. 1173 */ handlesOrientationChangeFromDescendant()1174 boolean handlesOrientationChangeFromDescendant() { 1175 final WindowContainer parent = getParent(); 1176 return parent != null && parent.handlesOrientationChangeFromDescendant(); 1177 } 1178 1179 /** 1180 * Gets the configuration orientation by the requested screen orientation 1181 * ({@link ActivityInfo.ScreenOrientation}) of this activity. 1182 * 1183 * @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE}, 1184 * {@link Configuration#ORIENTATION_PORTRAIT}, 1185 * {@link Configuration#ORIENTATION_UNDEFINED}). 1186 */ getRequestedConfigurationOrientation()1187 int getRequestedConfigurationOrientation() { 1188 return getRequestedConfigurationOrientation(false /* forDisplay */); 1189 } 1190 1191 /** 1192 * Gets the configuration orientation by the requested screen orientation 1193 * ({@link ActivityInfo.ScreenOrientation}) of this activity. 1194 * 1195 * @param forDisplay whether it is the requested config orientation for display. 1196 * If {@code true}, we may reverse the requested orientation if the root is 1197 * different from the display, so that when the display rotates to the 1198 * reversed orientation, the requested app will be in the requested 1199 * orientation. 1200 * @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE}, 1201 * {@link Configuration#ORIENTATION_PORTRAIT}, 1202 * {@link Configuration#ORIENTATION_UNDEFINED}). 1203 */ getRequestedConfigurationOrientation(boolean forDisplay)1204 int getRequestedConfigurationOrientation(boolean forDisplay) { 1205 int requestedOrientation = mOrientation; 1206 final RootDisplayArea root = getRootDisplayArea(); 1207 if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) { 1208 // Reverse the requested orientation if the orientation of its root is different from 1209 // the display, so that when the display rotates to the reversed orientation, the 1210 // requested app will be in the requested orientation. 1211 // For example, if the display is 1200x900 (landscape), and the DAG is 600x900 1212 // (portrait). 1213 // When an app below the DAG is requesting landscape, it should actually request the 1214 // display to be portrait, so that the DAG and the app will be in landscape. 1215 requestedOrientation = reverseOrientation(mOrientation); 1216 } 1217 1218 if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { 1219 // NOSENSOR means the display's "natural" orientation, so return that. 1220 if (mDisplayContent != null) { 1221 return mDisplayContent.getNaturalOrientation(); 1222 } 1223 } else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { 1224 // LOCKED means the activity's orientation remains unchanged, so return existing value. 1225 return getConfiguration().orientation; 1226 } else if (isFixedOrientationLandscape(requestedOrientation)) { 1227 return ORIENTATION_LANDSCAPE; 1228 } else if (isFixedOrientationPortrait(requestedOrientation)) { 1229 return ORIENTATION_PORTRAIT; 1230 } 1231 return ORIENTATION_UNDEFINED; 1232 } 1233 1234 /** 1235 * Calls {@link #setOrientation(int, WindowContainer)} with {@code null} to the last 2 1236 * parameters. 1237 * 1238 * @param orientation the specified orientation. 1239 */ setOrientation(int orientation)1240 void setOrientation(int orientation) { 1241 setOrientation(orientation, null /* requestingContainer */); 1242 } 1243 1244 /** 1245 * Sets the specified orientation of this container. It percolates this change upward along the 1246 * hierarchy to let each level of the hierarchy a chance to respond to it. 1247 * 1248 * @param orientation the specified orientation. Needs to be one of {@link 1249 * android.content.pm.ActivityInfo.ScreenOrientation}. 1250 * @param requestingContainer the container which orientation request has changed. Mostly used 1251 * to ensure it gets correct configuration. 1252 */ setOrientation(int orientation, @Nullable WindowContainer requestingContainer)1253 void setOrientation(int orientation, @Nullable WindowContainer requestingContainer) { 1254 if (mOrientation == orientation) { 1255 return; 1256 } 1257 1258 mOrientation = orientation; 1259 final WindowContainer parent = getParent(); 1260 if (parent != null) { 1261 if (getConfiguration().orientation != getRequestedConfigurationOrientation() 1262 // Update configuration directly only if the change won't be dispatched from 1263 // ancestor. This prevents from computing intermediate configuration when the 1264 // parent also needs to be updated from the ancestor. E.g. the app requests 1265 // portrait but the task is still in landscape. While updating from display, 1266 // the task can be updated to portrait first so the configuration can be 1267 // computed in a consistent environment. 1268 && (inMultiWindowMode() || !handlesOrientationChangeFromDescendant())) { 1269 // Resolve the requested orientation. 1270 onConfigurationChanged(parent.getConfiguration()); 1271 } 1272 onDescendantOrientationChanged(requestingContainer); 1273 } 1274 } 1275 1276 @ActivityInfo.ScreenOrientation getOrientation()1277 int getOrientation() { 1278 return getOrientation(mOrientation); 1279 } 1280 1281 /** 1282 * Returns the specified orientation for this window container or one of its children is there 1283 * is one set, or {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSET} if no 1284 * specification is set. 1285 * NOTE: {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} is a 1286 * specification... 1287 * 1288 * @param candidate The current orientation candidate that will be returned if we don't find a 1289 * better match. 1290 * @return The orientation as specified by this branch or the window hierarchy. 1291 */ getOrientation(int candidate)1292 int getOrientation(int candidate) { 1293 mLastOrientationSource = null; 1294 if (!fillsParent()) { 1295 // Ignore containers that don't completely fill their parents. 1296 return SCREEN_ORIENTATION_UNSET; 1297 } 1298 1299 // The container fills its parent so we can use it orientation if it has one 1300 // specified; otherwise we prefer to use the orientation of its topmost child that has one 1301 // specified and fall back on this container's unset or unspecified value as a candidate 1302 // if none of the children have a better candidate for the orientation. 1303 if (mOrientation != SCREEN_ORIENTATION_UNSET 1304 && mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { 1305 mLastOrientationSource = this; 1306 return mOrientation; 1307 } 1308 1309 for (int i = mChildren.size() - 1; i >= 0; --i) { 1310 final WindowContainer wc = mChildren.get(i); 1311 1312 // TODO: Maybe mOrientation should default to SCREEN_ORIENTATION_UNSET vs. 1313 // SCREEN_ORIENTATION_UNSPECIFIED? 1314 final int orientation = wc.getOrientation(candidate == SCREEN_ORIENTATION_BEHIND 1315 ? SCREEN_ORIENTATION_BEHIND : SCREEN_ORIENTATION_UNSET); 1316 if (orientation == SCREEN_ORIENTATION_BEHIND) { 1317 // container wants us to use the orientation of the container behind it. See if we 1318 // can find one. Else return SCREEN_ORIENTATION_BEHIND so the caller can choose to 1319 // look behind this container. 1320 candidate = orientation; 1321 mLastOrientationSource = wc; 1322 continue; 1323 } 1324 1325 if (orientation == SCREEN_ORIENTATION_UNSET) { 1326 continue; 1327 } 1328 1329 if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) { 1330 // Use the orientation if the container fills its parent or requested an explicit 1331 // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED. 1332 ProtoLog.v(WM_DEBUG_ORIENTATION, "%s is requesting orientation %d (%s)", 1333 wc.toString(), orientation, 1334 ActivityInfo.screenOrientationToString(orientation)); 1335 mLastOrientationSource = wc; 1336 return orientation; 1337 } 1338 } 1339 1340 return candidate; 1341 } 1342 1343 /** 1344 * @return The deepest source which decides the orientation of this window container since the 1345 * last time {@link #getOrientation(int) was called. 1346 */ 1347 @Nullable getLastOrientationSource()1348 WindowContainer getLastOrientationSource() { 1349 final WindowContainer source = mLastOrientationSource; 1350 if (source != null && source != this) { 1351 final WindowContainer nextSource = source.getLastOrientationSource(); 1352 if (nextSource != null) { 1353 return nextSource; 1354 } 1355 } 1356 return source; 1357 } 1358 1359 /** 1360 * Returns true if this container is opaque and fills all the space made available by its parent 1361 * container. 1362 * 1363 * NOTE: It is possible for this container to occupy more space than the parent has (or less), 1364 * this is just a signal from the client to window manager stating its intent, but not what it 1365 * actually does. 1366 */ fillsParent()1367 boolean fillsParent() { 1368 return false; 1369 } 1370 1371 // TODO: Users would have their own window containers under the display container? switchUser(int userId)1372 void switchUser(int userId) { 1373 for (int i = mChildren.size() - 1; i >= 0; --i) { 1374 mChildren.get(i).switchUser(userId); 1375 } 1376 } 1377 showToCurrentUser()1378 boolean showToCurrentUser() { 1379 return true; 1380 } 1381 1382 /** 1383 * For all windows at or below this container call the callback. 1384 * @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and 1385 * stops the search if {@link ToBooleanFunction#apply} returns true. 1386 * @param traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of 1387 * z-order, else from bottom-to-top. 1388 * @return True if the search ended before we reached the end of the hierarchy due to 1389 * {@link ToBooleanFunction#apply} returning true. 1390 */ forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)1391 boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { 1392 if (traverseTopToBottom) { 1393 for (int i = mChildren.size() - 1; i >= 0; --i) { 1394 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) { 1395 return true; 1396 } 1397 } 1398 } else { 1399 final int count = mChildren.size(); 1400 for (int i = 0; i < count; i++) { 1401 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) { 1402 return true; 1403 } 1404 } 1405 } 1406 return false; 1407 } 1408 forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom)1409 void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) { 1410 ForAllWindowsConsumerWrapper wrapper = obtainConsumerWrapper(callback); 1411 forAllWindows(wrapper, traverseTopToBottom); 1412 wrapper.release(); 1413 } 1414 forAllActivities(Function<ActivityRecord, Boolean> callback)1415 boolean forAllActivities(Function<ActivityRecord, Boolean> callback) { 1416 return forAllActivities(callback, true /*traverseTopToBottom*/); 1417 } 1418 forAllActivities( Function<ActivityRecord, Boolean> callback, boolean traverseTopToBottom)1419 boolean forAllActivities( 1420 Function<ActivityRecord, Boolean> callback, boolean traverseTopToBottom) { 1421 if (traverseTopToBottom) { 1422 for (int i = mChildren.size() - 1; i >= 0; --i) { 1423 if (mChildren.get(i).forAllActivities(callback, traverseTopToBottom)) return true; 1424 } 1425 } else { 1426 final int count = mChildren.size(); 1427 for (int i = 0; i < count; i++) { 1428 if (mChildren.get(i).forAllActivities(callback, traverseTopToBottom)) return true; 1429 } 1430 } 1431 1432 return false; 1433 } 1434 forAllActivities(Consumer<ActivityRecord> callback)1435 void forAllActivities(Consumer<ActivityRecord> callback) { 1436 forAllActivities(callback, true /*traverseTopToBottom*/); 1437 } 1438 forAllActivities(Consumer<ActivityRecord> callback, boolean traverseTopToBottom)1439 void forAllActivities(Consumer<ActivityRecord> callback, boolean traverseTopToBottom) { 1440 if (traverseTopToBottom) { 1441 for (int i = mChildren.size() - 1; i >= 0; --i) { 1442 mChildren.get(i).forAllActivities(callback, traverseTopToBottom); 1443 } 1444 } else { 1445 final int count = mChildren.size(); 1446 for (int i = 0; i < count; i++) { 1447 mChildren.get(i).forAllActivities(callback, traverseTopToBottom); 1448 } 1449 } 1450 } 1451 1452 /** 1453 * Process all activities in this branch of the tree. 1454 * 1455 * @param callback Called for each activity found. 1456 * @param boundary We don't return activities via {@param callback} until we get to this node in 1457 * the tree. 1458 * @param includeBoundary If the boundary from be processed to return activities. 1459 * @param traverseTopToBottom direction to traverse the tree. 1460 * @return {@code true} if we ended the search before reaching the end of the tree. 1461 */ forAllActivities(Function<ActivityRecord, Boolean> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom)1462 final boolean forAllActivities(Function<ActivityRecord, Boolean> callback, 1463 WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom) { 1464 return forAllActivities( 1465 callback, boundary, includeBoundary, traverseTopToBottom, new boolean[1]); 1466 } 1467 forAllActivities(Function<ActivityRecord, Boolean> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound)1468 private boolean forAllActivities(Function<ActivityRecord, Boolean> callback, 1469 WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, 1470 boolean[] boundaryFound) { 1471 if (traverseTopToBottom) { 1472 for (int i = mChildren.size() - 1; i >= 0; --i) { 1473 if (processForAllActivitiesWithBoundary(callback, boundary, includeBoundary, 1474 traverseTopToBottom, boundaryFound, mChildren.get(i))) { 1475 return true; 1476 } 1477 } 1478 } else { 1479 final int count = mChildren.size(); 1480 for (int i = 0; i < count; i++) { 1481 if (processForAllActivitiesWithBoundary(callback, boundary, includeBoundary, 1482 traverseTopToBottom, boundaryFound, mChildren.get(i))) { 1483 return true; 1484 } 1485 } 1486 } 1487 1488 return false; 1489 } 1490 processForAllActivitiesWithBoundary(Function<ActivityRecord, Boolean> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound, WindowContainer wc)1491 private boolean processForAllActivitiesWithBoundary(Function<ActivityRecord, Boolean> callback, 1492 WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, 1493 boolean[] boundaryFound, WindowContainer wc) { 1494 if (wc == boundary) { 1495 boundaryFound[0] = true; 1496 if (!includeBoundary) return false; 1497 } 1498 1499 if (boundaryFound[0]) { 1500 return wc.forAllActivities(callback, traverseTopToBottom); 1501 } 1502 1503 return wc.forAllActivities( 1504 callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound); 1505 } 1506 1507 /** @return {@code true} if this node or any of its children contains an activity. */ hasActivity()1508 boolean hasActivity() { 1509 for (int i = mChildren.size() - 1; i >= 0; --i) { 1510 if (mChildren.get(i).hasActivity()) { 1511 return true; 1512 } 1513 } 1514 return false; 1515 } 1516 getActivity(Predicate<ActivityRecord> callback)1517 ActivityRecord getActivity(Predicate<ActivityRecord> callback) { 1518 return getActivity(callback, true /*traverseTopToBottom*/); 1519 } 1520 getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom)1521 ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom) { 1522 return getActivity(callback, traverseTopToBottom, null /*boundary*/); 1523 } 1524 getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom, ActivityRecord boundary)1525 ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom, 1526 ActivityRecord boundary) { 1527 if (traverseTopToBottom) { 1528 for (int i = mChildren.size() - 1; i >= 0; --i) { 1529 final WindowContainer wc = mChildren.get(i); 1530 // TODO(b/156986561): Improve the correctness of the boundary check. 1531 if (wc == boundary) return boundary; 1532 1533 final ActivityRecord r = wc.getActivity(callback, traverseTopToBottom, boundary); 1534 if (r != null) { 1535 return r; 1536 } 1537 } 1538 } else { 1539 final int count = mChildren.size(); 1540 for (int i = 0; i < count; i++) { 1541 final WindowContainer wc = mChildren.get(i); 1542 // TODO(b/156986561): Improve the correctness of the boundary check. 1543 if (wc == boundary) return boundary; 1544 1545 final ActivityRecord r = wc.getActivity(callback, traverseTopToBottom, boundary); 1546 if (r != null) { 1547 return r; 1548 } 1549 } 1550 } 1551 1552 return null; 1553 } 1554 1555 /** 1556 * Gets an activity in a branch of the tree. 1557 * 1558 * @param callback called to test if this is the activity that should be returned. 1559 * @param boundary We don't return activities via {@param callback} until we get to this node in 1560 * the tree. 1561 * @param includeBoundary If the boundary from be processed to return activities. 1562 * @param traverseTopToBottom direction to traverse the tree. 1563 * @return The activity if found or null. 1564 */ getActivity(Predicate<ActivityRecord> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom)1565 final ActivityRecord getActivity(Predicate<ActivityRecord> callback, 1566 WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom) { 1567 return getActivity( 1568 callback, boundary, includeBoundary, traverseTopToBottom, new boolean[1]); 1569 } 1570 getActivity(Predicate<ActivityRecord> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound)1571 private ActivityRecord getActivity(Predicate<ActivityRecord> callback, 1572 WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, 1573 boolean[] boundaryFound) { 1574 if (traverseTopToBottom) { 1575 for (int i = mChildren.size() - 1; i >= 0; --i) { 1576 final ActivityRecord r = processGetActivityWithBoundary(callback, boundary, 1577 includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i)); 1578 if (r != null) { 1579 return r; 1580 } 1581 } 1582 } else { 1583 final int count = mChildren.size(); 1584 for (int i = 0; i < count; i++) { 1585 final ActivityRecord r = processGetActivityWithBoundary(callback, boundary, 1586 includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i)); 1587 if (r != null) { 1588 return r; 1589 } 1590 } 1591 } 1592 1593 return null; 1594 } 1595 processGetActivityWithBoundary(Predicate<ActivityRecord> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound, WindowContainer wc)1596 private ActivityRecord processGetActivityWithBoundary(Predicate<ActivityRecord> callback, 1597 WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, 1598 boolean[] boundaryFound, WindowContainer wc) { 1599 if (wc == boundary || boundary == null) { 1600 boundaryFound[0] = true; 1601 if (!includeBoundary) return null; 1602 } 1603 1604 if (boundaryFound[0]) { 1605 return wc.getActivity(callback, traverseTopToBottom); 1606 } 1607 1608 return wc.getActivity( 1609 callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound); 1610 } 1611 getActivityAbove(ActivityRecord r)1612 ActivityRecord getActivityAbove(ActivityRecord r) { 1613 return getActivity((above) -> true, r, 1614 false /*includeBoundary*/, false /*traverseTopToBottom*/); 1615 } 1616 getActivityBelow(ActivityRecord r)1617 ActivityRecord getActivityBelow(ActivityRecord r) { 1618 return getActivity((below) -> true, r, 1619 false /*includeBoundary*/, true /*traverseTopToBottom*/); 1620 } 1621 getBottomMostActivity()1622 ActivityRecord getBottomMostActivity() { 1623 return getActivity((r) -> true, false /*traverseTopToBottom*/); 1624 } 1625 getTopMostActivity()1626 ActivityRecord getTopMostActivity() { 1627 return getActivity((r) -> true, true /*traverseTopToBottom*/); 1628 } 1629 getTopActivity(boolean includeFinishing, boolean includeOverlays)1630 ActivityRecord getTopActivity(boolean includeFinishing, boolean includeOverlays) { 1631 // Break down into 4 calls to avoid object creation due to capturing input params. 1632 if (includeFinishing) { 1633 if (includeOverlays) { 1634 return getActivity((r) -> true); 1635 } 1636 return getActivity((r) -> !r.isTaskOverlay()); 1637 } else if (includeOverlays) { 1638 return getActivity((r) -> !r.finishing); 1639 } 1640 1641 return getActivity((r) -> !r.finishing && !r.isTaskOverlay()); 1642 } 1643 forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback)1644 void forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback) { 1645 for (int i = mChildren.size() - 1; i >= 0; --i) { 1646 mChildren.get(i).forAllWallpaperWindows(callback); 1647 } 1648 } 1649 1650 /** 1651 * For all tasks at or below this container call the callback. 1652 * 1653 * @param callback Calls the {@link ToBooleanFunction#apply} method for each task found and 1654 * stops the search if {@link ToBooleanFunction#apply} returns {@code true}. 1655 */ forAllTasks(Function<Task, Boolean> callback)1656 boolean forAllTasks(Function<Task, Boolean> callback) { 1657 for (int i = mChildren.size() - 1; i >= 0; --i) { 1658 if (mChildren.get(i).forAllTasks(callback)) { 1659 return true; 1660 } 1661 } 1662 return false; 1663 } 1664 forAllLeafTasks(Function<Task, Boolean> callback)1665 boolean forAllLeafTasks(Function<Task, Boolean> callback) { 1666 for (int i = mChildren.size() - 1; i >= 0; --i) { 1667 if (mChildren.get(i).forAllLeafTasks(callback)) { 1668 return true; 1669 } 1670 } 1671 return false; 1672 } 1673 1674 /** 1675 * For all root tasks at or below this container call the callback. 1676 * 1677 * @param callback Calls the {@link ToBooleanFunction#apply} method for each root task found and 1678 * stops the search if {@link ToBooleanFunction#apply} returns {@code true}. 1679 */ forAllRootTasks(Function<Task, Boolean> callback)1680 boolean forAllRootTasks(Function<Task, Boolean> callback) { 1681 return forAllRootTasks(callback, true /* traverseTopToBottom */); 1682 } 1683 forAllRootTasks(Function<Task, Boolean> callback, boolean traverseTopToBottom)1684 boolean forAllRootTasks(Function<Task, Boolean> callback, boolean traverseTopToBottom) { 1685 int count = mChildren.size(); 1686 if (traverseTopToBottom) { 1687 for (int i = count - 1; i >= 0; --i) { 1688 if (mChildren.get(i).forAllRootTasks(callback, traverseTopToBottom)) { 1689 return true; 1690 } 1691 } 1692 } else { 1693 for (int i = 0; i < count; i++) { 1694 if (mChildren.get(i).forAllRootTasks(callback, traverseTopToBottom)) { 1695 return true; 1696 } 1697 // Root tasks may be removed from this display. Ensure each task will be processed 1698 // and the loop will end. 1699 int newCount = mChildren.size(); 1700 i -= count - newCount; 1701 count = newCount; 1702 } 1703 } 1704 return false; 1705 } 1706 1707 /** 1708 * For all tasks at or below this container call the callback. 1709 * 1710 * @param callback Callback to be called for every task. 1711 */ forAllTasks(Consumer<Task> callback)1712 void forAllTasks(Consumer<Task> callback) { 1713 forAllTasks(callback, true /*traverseTopToBottom*/); 1714 } 1715 forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom)1716 void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 1717 final int count = mChildren.size(); 1718 if (traverseTopToBottom) { 1719 for (int i = count - 1; i >= 0; --i) { 1720 mChildren.get(i).forAllTasks(callback, traverseTopToBottom); 1721 } 1722 } else { 1723 for (int i = 0; i < count; i++) { 1724 mChildren.get(i).forAllTasks(callback, traverseTopToBottom); 1725 } 1726 } 1727 } 1728 forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom)1729 void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 1730 final int count = mChildren.size(); 1731 if (traverseTopToBottom) { 1732 for (int i = count - 1; i >= 0; --i) { 1733 mChildren.get(i).forAllLeafTasks(callback, traverseTopToBottom); 1734 } 1735 } else { 1736 for (int i = 0; i < count; i++) { 1737 mChildren.get(i).forAllLeafTasks(callback, traverseTopToBottom); 1738 } 1739 } 1740 } 1741 1742 /** 1743 * For all root tasks at or below this container call the callback. 1744 * 1745 * @param callback Callback to be called for every root task. 1746 */ forAllRootTasks(Consumer<Task> callback)1747 void forAllRootTasks(Consumer<Task> callback) { 1748 forAllRootTasks(callback, true /* traverseTopToBottom */); 1749 } 1750 forAllRootTasks(Consumer<Task> callback, boolean traverseTopToBottom)1751 void forAllRootTasks(Consumer<Task> callback, boolean traverseTopToBottom) { 1752 int count = mChildren.size(); 1753 if (traverseTopToBottom) { 1754 for (int i = count - 1; i >= 0; --i) { 1755 mChildren.get(i).forAllRootTasks(callback, traverseTopToBottom); 1756 } 1757 } else { 1758 for (int i = 0; i < count; i++) { 1759 mChildren.get(i).forAllRootTasks(callback, traverseTopToBottom); 1760 // Root tasks may be removed from this display. Ensure each task will be processed 1761 // and the loop will end. 1762 int newCount = mChildren.size(); 1763 i -= count - newCount; 1764 count = newCount; 1765 } 1766 } 1767 } 1768 getTaskAbove(Task t)1769 Task getTaskAbove(Task t) { 1770 return getTask( 1771 (above) -> true, t, false /*includeBoundary*/, false /*traverseTopToBottom*/); 1772 } 1773 getTaskBelow(Task t)1774 Task getTaskBelow(Task t) { 1775 return getTask((below) -> true, t, false /*includeBoundary*/, true /*traverseTopToBottom*/); 1776 } 1777 getBottomMostTask()1778 Task getBottomMostTask() { 1779 return getTask((t) -> true, false /*traverseTopToBottom*/); 1780 } 1781 getTopMostTask()1782 Task getTopMostTask() { 1783 return getTask((t) -> true, true /*traverseTopToBottom*/); 1784 } 1785 getTask(Predicate<Task> callback)1786 Task getTask(Predicate<Task> callback) { 1787 return getTask(callback, true /*traverseTopToBottom*/); 1788 } 1789 getTask(Predicate<Task> callback, boolean traverseTopToBottom)1790 Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) { 1791 if (traverseTopToBottom) { 1792 for (int i = mChildren.size() - 1; i >= 0; --i) { 1793 final Task t = mChildren.get(i).getTask(callback, traverseTopToBottom); 1794 if (t != null) { 1795 return t; 1796 } 1797 } 1798 } else { 1799 final int count = mChildren.size(); 1800 for (int i = 0; i < count; i++) { 1801 final Task t = mChildren.get(i).getTask(callback, traverseTopToBottom); 1802 if (t != null) { 1803 return t; 1804 } 1805 } 1806 } 1807 1808 return null; 1809 } 1810 1811 /** 1812 * Gets an task in a branch of the tree. 1813 * 1814 * @param callback called to test if this is the task that should be returned. 1815 * @param boundary We don't return tasks via {@param callback} until we get to this node in 1816 * the tree. 1817 * @param includeBoundary If the boundary from be processed to return tasks. 1818 * @param traverseTopToBottom direction to traverse the tree. 1819 * @return The task if found or null. 1820 */ getTask(Predicate<Task> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom)1821 final Task getTask(Predicate<Task> callback, WindowContainer boundary, boolean includeBoundary, 1822 boolean traverseTopToBottom) { 1823 return getTask(callback, boundary, includeBoundary, traverseTopToBottom, new boolean[1]); 1824 } 1825 getTask(Predicate<Task> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound)1826 private Task getTask(Predicate<Task> callback, 1827 WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, 1828 boolean[] boundaryFound) { 1829 if (traverseTopToBottom) { 1830 for (int i = mChildren.size() - 1; i >= 0; --i) { 1831 final Task t = processGetTaskWithBoundary(callback, boundary, 1832 includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i)); 1833 if (t != null) { 1834 return t; 1835 } 1836 } 1837 } else { 1838 final int count = mChildren.size(); 1839 for (int i = 0; i < count; i++) { 1840 final Task t = processGetTaskWithBoundary(callback, boundary, 1841 includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i)); 1842 if (t != null) { 1843 return t; 1844 } 1845 } 1846 } 1847 1848 return null; 1849 } 1850 1851 /** 1852 * Gets a root task in a branch of the tree. 1853 * 1854 * @param callback called to test if this is the task that should be returned. 1855 * @return The root task if found or null. 1856 */ 1857 @Nullable getRootTask(Predicate<Task> callback)1858 Task getRootTask(Predicate<Task> callback) { 1859 return getRootTask(callback, true /*traverseTopToBottom*/); 1860 } 1861 1862 @Nullable getRootTask(Predicate<Task> callback, boolean traverseTopToBottom)1863 Task getRootTask(Predicate<Task> callback, boolean traverseTopToBottom) { 1864 int count = mChildren.size(); 1865 if (traverseTopToBottom) { 1866 for (int i = count - 1; i >= 0; --i) { 1867 final Task t = mChildren.get(i).getRootTask(callback, traverseTopToBottom); 1868 if (t != null) { 1869 return t; 1870 } 1871 } 1872 } else { 1873 for (int i = 0; i < count; i++) { 1874 final Task t = mChildren.get(i).getRootTask(callback, traverseTopToBottom); 1875 if (t != null) { 1876 return t; 1877 } 1878 // Root tasks may be removed from this display. Ensure each task will be processed 1879 // and the loop will end. 1880 int newCount = mChildren.size(); 1881 i -= count - newCount; 1882 count = newCount; 1883 } 1884 } 1885 1886 return null; 1887 } 1888 processGetTaskWithBoundary(Predicate<Task> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound, WindowContainer wc)1889 private Task processGetTaskWithBoundary(Predicate<Task> callback, 1890 WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, 1891 boolean[] boundaryFound, WindowContainer wc) { 1892 if (wc == boundary || boundary == null) { 1893 boundaryFound[0] = true; 1894 if (!includeBoundary) return null; 1895 } 1896 1897 if (boundaryFound[0]) { 1898 return wc.getTask(callback, traverseTopToBottom); 1899 } 1900 1901 return wc.getTask( 1902 callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound); 1903 } 1904 getWindow(Predicate<WindowState> callback)1905 WindowState getWindow(Predicate<WindowState> callback) { 1906 for (int i = mChildren.size() - 1; i >= 0; --i) { 1907 final WindowState w = mChildren.get(i).getWindow(callback); 1908 if (w != null) { 1909 return w; 1910 } 1911 } 1912 1913 return null; 1914 } 1915 forAllDisplayAreas(Consumer<DisplayArea> callback)1916 void forAllDisplayAreas(Consumer<DisplayArea> callback) { 1917 for (int i = mChildren.size() - 1; i >= 0; --i) { 1918 mChildren.get(i).forAllDisplayAreas(callback); 1919 } 1920 } 1921 1922 /** 1923 * For all {@link TaskDisplayArea} at or below this container call the callback. 1924 * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it 1925 * returns {@code true}. 1926 * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in 1927 * terms of z-order, else from bottom-to-top. 1928 * @return {@code true} if the search ended before we reached the end of the hierarchy due to 1929 * callback returning {@code true}. 1930 */ forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback, boolean traverseTopToBottom)1931 boolean forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback, 1932 boolean traverseTopToBottom) { 1933 int childCount = mChildren.size(); 1934 int i = traverseTopToBottom ? childCount - 1 : 0; 1935 while (i >= 0 && i < childCount) { 1936 if (mChildren.get(i).forAllTaskDisplayAreas(callback, traverseTopToBottom)) { 1937 return true; 1938 } 1939 i += traverseTopToBottom ? -1 : 1; 1940 } 1941 return false; 1942 } 1943 1944 /** 1945 * For all {@link TaskDisplayArea} at or below this container call the callback. Traverses from 1946 * top to bottom in terms of z-order. 1947 * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it 1948 * returns {@code true}. 1949 * @return {@code true} if the search ended before we reached the end of the hierarchy due to 1950 * callback returning {@code true}. 1951 */ forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback)1952 boolean forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback) { 1953 return forAllTaskDisplayAreas(callback, true /* traverseTopToBottom */); 1954 } 1955 1956 /** 1957 * For all {@link TaskDisplayArea} at or below this container call the callback. 1958 * @param callback Applies on each {@link TaskDisplayArea} found. 1959 * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in 1960 * terms of z-order, else from bottom-to-top. 1961 */ forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom)1962 void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom) { 1963 int childCount = mChildren.size(); 1964 int i = traverseTopToBottom ? childCount - 1 : 0; 1965 while (i >= 0 && i < childCount) { 1966 mChildren.get(i).forAllTaskDisplayAreas(callback, traverseTopToBottom); 1967 i += traverseTopToBottom ? -1 : 1; 1968 } 1969 } 1970 1971 /** 1972 * For all {@link TaskDisplayArea} at or below this container call the callback. Traverses from 1973 * top to bottom in terms of z-order. 1974 * @param callback Applies on each {@link TaskDisplayArea} found. 1975 */ forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback)1976 void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback) { 1977 forAllTaskDisplayAreas(callback, true /* traverseTopToBottom */); 1978 } 1979 1980 /** 1981 * Performs a reduction on all {@link TaskDisplayArea} at or below this container, using the 1982 * provided initial value and an accumulation function, and returns the reduced value. 1983 * @param accumulator Applies on each {@link TaskDisplayArea} found with the accumulative result 1984 * from the previous call. 1985 * @param initValue The initial value to pass to the accumulating function with the first 1986 * {@link TaskDisplayArea}. 1987 * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in 1988 * terms of z-order, else from bottom-to-top. 1989 * @return the accumulative result. 1990 */ 1991 @Nullable reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator, @Nullable R initValue, boolean traverseTopToBottom)1992 <R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator, 1993 @Nullable R initValue, boolean traverseTopToBottom) { 1994 int childCount = mChildren.size(); 1995 int i = traverseTopToBottom ? childCount - 1 : 0; 1996 R result = initValue; 1997 while (i >= 0 && i < childCount) { 1998 result = (R) mChildren.get(i) 1999 .reduceOnAllTaskDisplayAreas(accumulator, result, traverseTopToBottom); 2000 i += traverseTopToBottom ? -1 : 1; 2001 } 2002 return result; 2003 } 2004 2005 /** 2006 * Performs a reduction on all {@link TaskDisplayArea} at or below this container, using the 2007 * provided initial value and an accumulation function, and returns the reduced value. Traverses 2008 * from top to bottom in terms of z-order. 2009 * @param accumulator Applies on each {@link TaskDisplayArea} found with the accumulative result 2010 * from the previous call. 2011 * @param initValue The initial value to pass to the accumulating function with the first 2012 * {@link TaskDisplayArea}. 2013 * @return the accumulative result. 2014 */ 2015 @Nullable reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator, @Nullable R initValue)2016 <R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator, 2017 @Nullable R initValue) { 2018 return reduceOnAllTaskDisplayAreas(accumulator, initValue, true /* traverseTopToBottom */); 2019 } 2020 2021 /** 2022 * Finds the first non {@code null} return value from calling the callback on all 2023 * {@link DisplayArea} at or below this container. Traverses from top to bottom in terms of 2024 * z-order. 2025 * @param callback Applies on each {@link DisplayArea} found and stops the search if it 2026 * returns non {@code null}. 2027 * @return the first returned object that is not {@code null}. Returns {@code null} if not 2028 * found. 2029 */ 2030 @Nullable getItemFromDisplayAreas(Function<DisplayArea, R> callback)2031 <R> R getItemFromDisplayAreas(Function<DisplayArea, R> callback) { 2032 for (int i = mChildren.size() - 1; i >= 0; --i) { 2033 R result = (R) mChildren.get(i).getItemFromDisplayAreas(callback); 2034 if (result != null) { 2035 return result; 2036 } 2037 } 2038 return null; 2039 } 2040 2041 /** 2042 * Finds the first non {@code null} return value from calling the callback on all 2043 * {@link TaskDisplayArea} at or below this container. 2044 * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it 2045 * returns non {@code null}. 2046 * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in 2047 * terms of z-order, else from bottom-to-top. 2048 * @return the first returned object that is not {@code null}. Returns {@code null} if not 2049 * found. 2050 */ 2051 @Nullable getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback, boolean traverseTopToBottom)2052 <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback, 2053 boolean traverseTopToBottom) { 2054 int childCount = mChildren.size(); 2055 int i = traverseTopToBottom ? childCount - 1 : 0; 2056 while (i >= 0 && i < childCount) { 2057 R result = (R) mChildren.get(i) 2058 .getItemFromTaskDisplayAreas(callback, traverseTopToBottom); 2059 if (result != null) { 2060 return result; 2061 } 2062 i += traverseTopToBottom ? -1 : 1; 2063 } 2064 return null; 2065 } 2066 2067 /** 2068 * Finds the first non {@code null} return value from calling the callback on all 2069 * {@link TaskDisplayArea} at or below this container. Traverses from top to bottom in terms of 2070 * z-order. 2071 * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it 2072 * returns non {@code null}. 2073 * @return the first returned object that is not {@code null}. Returns {@code null} if not 2074 * found. 2075 */ 2076 @Nullable getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback)2077 <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback) { 2078 return getItemFromTaskDisplayAreas(callback, true /* traverseTopToBottom */); 2079 } 2080 2081 /** 2082 * Finds the first non {@code null} return value from calling the callback on all root 2083 * {@link Task} at or below this container. 2084 * @param callback Applies on each root {@link Task} found and stops the search if it 2085 * returns non {@code null}. 2086 * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in 2087 * terms of z-order, else from bottom-to-top. 2088 * @return the first returned object that is not {@code null}. Returns {@code null} if not 2089 * found. 2090 */ 2091 @Nullable getItemFromRootTasks(Function<Task, R> callback, boolean traverseTopToBottom)2092 <R> R getItemFromRootTasks(Function<Task, R> callback, boolean traverseTopToBottom) { 2093 int count = mChildren.size(); 2094 if (traverseTopToBottom) { 2095 for (int i = count - 1; i >= 0; --i) { 2096 R result = (R) mChildren.get(i).getItemFromRootTasks(callback, traverseTopToBottom); 2097 if (result != null) { 2098 return result; 2099 } 2100 } 2101 } else { 2102 for (int i = 0; i < count; i++) { 2103 R result = (R) mChildren.get(i).getItemFromRootTasks(callback, traverseTopToBottom); 2104 if (result != null) { 2105 return result; 2106 } 2107 // Root tasks may be removed from this display. Ensure each task will be processed 2108 // and the loop will end. 2109 int newCount = mChildren.size(); 2110 i -= count - newCount; 2111 count = newCount; 2112 } 2113 } 2114 return null; 2115 } 2116 2117 @Nullable getItemFromRootTasks(Function<Task, R> callback)2118 <R> R getItemFromRootTasks(Function<Task, R> callback) { 2119 return getItemFromRootTasks(callback, true /* traverseTopToBottom */); 2120 } 2121 2122 /** 2123 * Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than 2124 * the input container in terms of z-order. 2125 */ 2126 @Override compareTo(WindowContainer other)2127 public int compareTo(WindowContainer other) { 2128 if (this == other) { 2129 return 0; 2130 } 2131 2132 if (mParent != null && mParent == other.mParent) { 2133 final WindowList<WindowContainer> list = mParent.mChildren; 2134 return list.indexOf(this) > list.indexOf(other) ? 1 : -1; 2135 } 2136 2137 final LinkedList<WindowContainer> thisParentChain = mTmpChain1; 2138 final LinkedList<WindowContainer> otherParentChain = mTmpChain2; 2139 try { 2140 getParents(thisParentChain); 2141 other.getParents(otherParentChain); 2142 2143 // Find the common ancestor of both containers. 2144 WindowContainer commonAncestor = null; 2145 WindowContainer thisTop = thisParentChain.peekLast(); 2146 WindowContainer otherTop = otherParentChain.peekLast(); 2147 while (thisTop != null && otherTop != null && thisTop == otherTop) { 2148 commonAncestor = thisParentChain.removeLast(); 2149 otherParentChain.removeLast(); 2150 thisTop = thisParentChain.peekLast(); 2151 otherTop = otherParentChain.peekLast(); 2152 } 2153 2154 // Containers don't belong to the same hierarchy??? 2155 if (commonAncestor == null) { 2156 throw new IllegalArgumentException("No in the same hierarchy this=" 2157 + thisParentChain + " other=" + otherParentChain); 2158 } 2159 2160 // Children are always considered greater than their parents, so if one of the containers 2161 // we are comparing it the parent of the other then whichever is the child is greater. 2162 if (commonAncestor == this) { 2163 return -1; 2164 } else if (commonAncestor == other) { 2165 return 1; 2166 } 2167 2168 // The position of the first non-common ancestor in the common ancestor list determines 2169 // which is greater the which. 2170 final WindowList<WindowContainer> list = commonAncestor.mChildren; 2171 return list.indexOf(thisParentChain.peekLast()) > list.indexOf(otherParentChain.peekLast()) 2172 ? 1 : -1; 2173 } finally { 2174 mTmpChain1.clear(); 2175 mTmpChain2.clear(); 2176 } 2177 } 2178 getParents(LinkedList<WindowContainer> parents)2179 private void getParents(LinkedList<WindowContainer> parents) { 2180 parents.clear(); 2181 WindowContainer current = this; 2182 do { 2183 parents.addLast(current); 2184 current = current.mParent; 2185 } while (current != null); 2186 } 2187 makeSurface()2188 SurfaceControl.Builder makeSurface() { 2189 final WindowContainer p = getParent(); 2190 return p.makeChildSurface(this); 2191 } 2192 2193 /** 2194 * @param child The WindowContainer this child surface is for, or null if the Surface 2195 * is not assosciated with a WindowContainer (e.g. a surface used for Dimming). 2196 */ makeChildSurface(WindowContainer child)2197 SurfaceControl.Builder makeChildSurface(WindowContainer child) { 2198 final WindowContainer p = getParent(); 2199 // Give the parent a chance to set properties. In hierarchy v1 we rely 2200 // on this to set full-screen dimensions on all our Surface-less Layers. 2201 return p.makeChildSurface(child) 2202 .setParent(mSurfaceControl); 2203 } 2204 /* 2205 * @return The SurfaceControl parent for this containers SurfaceControl. 2206 * The SurfaceControl must be valid if non-null. 2207 */ 2208 @Override getParentSurfaceControl()2209 public SurfaceControl getParentSurfaceControl() { 2210 final WindowContainer parent = getParent(); 2211 if (parent == null) { 2212 return null; 2213 } 2214 return parent.getSurfaceControl(); 2215 } 2216 2217 /** 2218 * @return Whether this WindowContainer should be magnified by the accessibility magnifier. 2219 */ shouldMagnify()2220 boolean shouldMagnify() { 2221 if (mSurfaceControl == null) { 2222 return false; 2223 } 2224 2225 for (int i = 0; i < mChildren.size(); i++) { 2226 if (!mChildren.get(i).shouldMagnify()) { 2227 return false; 2228 } 2229 } 2230 return true; 2231 } 2232 getSession()2233 SurfaceSession getSession() { 2234 if (getParent() != null) { 2235 return getParent().getSession(); 2236 } 2237 return null; 2238 } 2239 assignLayer(Transaction t, int layer)2240 void assignLayer(Transaction t, int layer) { 2241 // Don't assign layers while a transition animation is playing 2242 // TODO(b/173528115): establish robust best-practices around z-order fighting. 2243 if (mWmService.mAtmService.getTransitionController().isPlaying()) return; 2244 final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null; 2245 if (mSurfaceControl != null && changed) { 2246 setLayer(t, layer); 2247 mLastLayer = layer; 2248 mLastRelativeToLayer = null; 2249 } 2250 } 2251 assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer, boolean forceUpdate)2252 void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer, 2253 boolean forceUpdate) { 2254 final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo; 2255 if (mSurfaceControl != null && (changed || forceUpdate)) { 2256 setRelativeLayer(t, relativeTo, layer); 2257 mLastLayer = layer; 2258 mLastRelativeToLayer = relativeTo; 2259 } 2260 } 2261 assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer)2262 void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { 2263 assignRelativeLayer(t, relativeTo, layer, false /* forceUpdate */); 2264 } 2265 setLayer(Transaction t, int layer)2266 protected void setLayer(Transaction t, int layer) { 2267 2268 // Route through surface animator to accommodate that our surface control might be 2269 // attached to the leash, and leash is attached to parent container. 2270 mSurfaceAnimator.setLayer(t, layer); 2271 } 2272 getLastLayer()2273 int getLastLayer() { 2274 return mLastLayer; 2275 } 2276 setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer)2277 protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { 2278 2279 // Route through surface animator to accommodate that our surface control might be 2280 // attached to the leash, and leash is attached to parent container. 2281 mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer); 2282 } 2283 reparentSurfaceControl(Transaction t, SurfaceControl newParent)2284 protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) { 2285 // Don't reparent active leashes since the animator won't know about the change. 2286 if (mSurfaceFreezer.hasLeash() || mSurfaceAnimator.hasLeash()) return; 2287 t.reparent(getSurfaceControl(), newParent); 2288 } 2289 assignChildLayers(Transaction t)2290 void assignChildLayers(Transaction t) { 2291 int layer = 0; 2292 2293 // We use two passes as a way to promote children which 2294 // need Z-boosting to the end of the list. 2295 for (int j = 0; j < mChildren.size(); ++j) { 2296 final WindowContainer wc = mChildren.get(j); 2297 wc.assignChildLayers(t); 2298 if (!wc.needsZBoost()) { 2299 wc.assignLayer(t, layer++); 2300 } 2301 } 2302 for (int j = 0; j < mChildren.size(); ++j) { 2303 final WindowContainer wc = mChildren.get(j); 2304 if (wc.needsZBoost()) { 2305 wc.assignLayer(t, layer++); 2306 } 2307 } 2308 } 2309 assignChildLayers()2310 void assignChildLayers() { 2311 assignChildLayers(getSyncTransaction()); 2312 scheduleAnimation(); 2313 } 2314 needsZBoost()2315 boolean needsZBoost() { 2316 if (mNeedsZBoost) return true; 2317 for (int i = 0; i < mChildren.size(); i++) { 2318 if (mChildren.get(i).needsZBoost()) { 2319 return true; 2320 } 2321 } 2322 return false; 2323 } 2324 2325 /** 2326 * Write to a protocol buffer output stream. Protocol buffer message definition is at 2327 * {@link com.android.server.wm.WindowContainerProto}. 2328 * 2329 * @param proto Stream to write the WindowContainer object to. 2330 * @param fieldId Field Id of the WindowContainer as defined in the parent message. 2331 * @param logLevel Determines the amount of data to be written to the Protobuf. 2332 * @hide 2333 */ 2334 @CallSuper 2335 @Override dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)2336 public void dumpDebug(ProtoOutputStream proto, long fieldId, 2337 @WindowTraceLogLevel int logLevel) { 2338 boolean isVisible = isVisible(); 2339 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible) { 2340 return; 2341 } 2342 2343 final long token = proto.start(fieldId); 2344 super.dumpDebug(proto, CONFIGURATION_CONTAINER, logLevel); 2345 proto.write(ORIENTATION, mOrientation); 2346 proto.write(VISIBLE, isVisible); 2347 writeIdentifierToProto(proto, IDENTIFIER); 2348 if (mSurfaceAnimator.isAnimating()) { 2349 mSurfaceAnimator.dumpDebug(proto, SURFACE_ANIMATOR); 2350 } 2351 2352 // add children to proto 2353 for (int i = 0; i < getChildCount(); i++) { 2354 final long childToken = proto.start(WindowContainerProto.CHILDREN); 2355 final E child = getChildAt(i); 2356 child.dumpDebug(proto, child.getProtoFieldId(), logLevel); 2357 proto.end(childToken); 2358 } 2359 proto.end(token); 2360 } 2361 2362 /** 2363 * @return a proto field id to identify where to add the derived class to the generic window 2364 * container proto. 2365 */ getProtoFieldId()2366 long getProtoFieldId() { 2367 return WINDOW_CONTAINER; 2368 } 2369 obtainConsumerWrapper(Consumer<WindowState> consumer)2370 private ForAllWindowsConsumerWrapper obtainConsumerWrapper(Consumer<WindowState> consumer) { 2371 ForAllWindowsConsumerWrapper wrapper = mConsumerWrapperPool.acquire(); 2372 if (wrapper == null) { 2373 wrapper = new ForAllWindowsConsumerWrapper(); 2374 } 2375 wrapper.setConsumer(consumer); 2376 return wrapper; 2377 } 2378 2379 private final class ForAllWindowsConsumerWrapper implements ToBooleanFunction<WindowState> { 2380 2381 private Consumer<WindowState> mConsumer; 2382 setConsumer(Consumer<WindowState> consumer)2383 void setConsumer(Consumer<WindowState> consumer) { 2384 mConsumer = consumer; 2385 } 2386 2387 @Override apply(WindowState w)2388 public boolean apply(WindowState w) { 2389 mConsumer.accept(w); 2390 return false; 2391 } 2392 release()2393 void release() { 2394 mConsumer = null; 2395 mConsumerWrapperPool.release(this); 2396 } 2397 } 2398 2399 // TODO(b/68336570): Should this really be on WindowContainer since it 2400 // can only be used on the top-level nodes that aren't animated? 2401 // (otherwise we would be fighting other callers of setMatrix). applyMagnificationSpec(Transaction t, MagnificationSpec spec)2402 void applyMagnificationSpec(Transaction t, MagnificationSpec spec) { 2403 if (shouldMagnify()) { 2404 t.setMatrix(mSurfaceControl, spec.scale, 0, 0, spec.scale) 2405 .setPosition(mSurfaceControl, spec.offsetX, spec.offsetY); 2406 mLastMagnificationSpec = spec; 2407 } else { 2408 clearMagnificationSpec(t); 2409 for (int i = 0; i < mChildren.size(); i++) { 2410 mChildren.get(i).applyMagnificationSpec(t, spec); 2411 } 2412 } 2413 } 2414 clearMagnificationSpec(Transaction t)2415 void clearMagnificationSpec(Transaction t) { 2416 if (mLastMagnificationSpec != null) { 2417 t.setMatrix(mSurfaceControl, 1, 0, 0, 1) 2418 .setPosition(mSurfaceControl, 0, 0); 2419 } 2420 mLastMagnificationSpec = null; 2421 for (int i = 0; i < mChildren.size(); i++) { 2422 mChildren.get(i).clearMagnificationSpec(t); 2423 } 2424 } 2425 prepareSurfaces()2426 void prepareSurfaces() { 2427 // If a leash has been set when the transaction was committed, then the leash reparent has 2428 // been committed. 2429 mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash(); 2430 for (int i = 0; i < mChildren.size(); i++) { 2431 mChildren.get(i).prepareSurfaces(); 2432 } 2433 } 2434 2435 /** 2436 * @return true if the reparent to animation leash transaction has been committed, false 2437 * otherwise. 2438 */ hasCommittedReparentToAnimationLeash()2439 boolean hasCommittedReparentToAnimationLeash() { 2440 return mCommittedReparentToAnimationLeash; 2441 } 2442 2443 /** 2444 * Trigger a call to prepareSurfaces from the animation thread, such that pending transactions 2445 * will be applied. 2446 */ scheduleAnimation()2447 void scheduleAnimation() { 2448 if (mParent != null) { 2449 mParent.scheduleAnimation(); 2450 } 2451 } 2452 2453 /** 2454 * @return The SurfaceControl for this container. 2455 * The SurfaceControl must be valid if non-null. 2456 */ 2457 @Override getSurfaceControl()2458 public SurfaceControl getSurfaceControl() { 2459 return mSurfaceControl; 2460 } 2461 2462 /** 2463 * Use this method instead of {@link #getPendingTransaction()} if the Transaction should be 2464 * synchronized with the client. 2465 * 2466 * @return {@link #mBLASTSyncTransaction} if available. Otherwise, returns 2467 * {@link #getPendingTransaction()} 2468 */ getSyncTransaction()2469 public Transaction getSyncTransaction() { 2470 if (mSyncState != SYNC_STATE_NONE) { 2471 return mSyncTransaction; 2472 } 2473 2474 return getPendingTransaction(); 2475 } 2476 2477 @Override getPendingTransaction()2478 public Transaction getPendingTransaction() { 2479 final DisplayContent displayContent = getDisplayContent(); 2480 if (displayContent != null && displayContent != this) { 2481 return displayContent.getPendingTransaction(); 2482 } 2483 // This WindowContainer has not attached to a display yet or this is a DisplayContent, so we 2484 // let the caller to save the surface operations within the local mPendingTransaction. 2485 // If this is not a DisplayContent, we will merge it to the pending transaction of its 2486 // display once it attaches to it. 2487 return mPendingTransaction; 2488 } 2489 2490 /** 2491 * Starts an animation on the container. 2492 * 2493 * @param anim The animation to run. 2494 * @param hidden Whether our container is currently hidden. TODO This should use isVisible at 2495 * some point but the meaning is too weird to work for all containers. 2496 * @param type The type of animation defined as {@link AnimationType}. 2497 * @param animationFinishedCallback The callback being triggered when the animation finishes. 2498 */ startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, @AnimationType int type, @Nullable OnAnimationFinishedCallback animationFinishedCallback)2499 void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, 2500 @AnimationType int type, 2501 @Nullable OnAnimationFinishedCallback animationFinishedCallback) { 2502 if (DEBUG_ANIM) { 2503 Slog.v(TAG, "Starting animation on " + this + ": type=" + type + ", anim=" + anim); 2504 } 2505 2506 // TODO: This should use isVisible() but because isVisible has a really weird meaning at 2507 // the moment this doesn't work for all animatable window containers. 2508 mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback, 2509 mSurfaceFreezer); 2510 } 2511 startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, @AnimationType int type)2512 void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, 2513 @AnimationType int type) { 2514 startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */); 2515 } 2516 transferAnimation(WindowContainer from)2517 void transferAnimation(WindowContainer from) { 2518 mSurfaceAnimator.transferAnimation(from.mSurfaceAnimator); 2519 } 2520 cancelAnimation()2521 void cancelAnimation() { 2522 doAnimationFinished(mSurfaceAnimator.getAnimationType(), mSurfaceAnimator.getAnimation()); 2523 mSurfaceAnimator.cancelAnimation(); 2524 mSurfaceFreezer.unfreeze(getPendingTransaction()); 2525 } 2526 getAnimationSources()2527 ArraySet<WindowContainer> getAnimationSources() { 2528 return mSurfaceAnimationSources; 2529 } 2530 2531 @Override getFreezeSnapshotTarget()2532 public SurfaceControl getFreezeSnapshotTarget() { 2533 return null; 2534 } 2535 2536 @Override makeAnimationLeash()2537 public Builder makeAnimationLeash() { 2538 return makeSurface().setContainerLayer(); 2539 } 2540 2541 @Override getAnimationLeashParent()2542 public SurfaceControl getAnimationLeashParent() { 2543 return getParentSurfaceControl(); 2544 } 2545 2546 /** 2547 * @return The layer on which all app animations are happening. 2548 */ getAppAnimationLayer(@nimationLayer int animationLayer)2549 SurfaceControl getAppAnimationLayer(@AnimationLayer int animationLayer) { 2550 final WindowContainer parent = getParent(); 2551 if (parent != null) { 2552 return parent.getAppAnimationLayer(animationLayer); 2553 } 2554 return null; 2555 } 2556 2557 // TODO: Remove this and use #getBounds() instead once we set an app transition animation 2558 // on TaskStack. getAnimationBounds(int appRootTaskClipMode)2559 Rect getAnimationBounds(int appRootTaskClipMode) { 2560 return getBounds(); 2561 } 2562 2563 /** Gets the position relative to parent for animation. */ getAnimationPosition(Point outPosition)2564 void getAnimationPosition(Point outPosition) { 2565 getRelativePosition(outPosition); 2566 } 2567 2568 /** 2569 * Applies the app transition animation according the given the layout properties in the 2570 * window hierarchy. 2571 * 2572 * @param lp The layout parameters of the window. 2573 * @param transit The app transition type indicates what kind of transition to be applied. 2574 * @param enter Whether the app transition is entering transition or not. 2575 * @param isVoiceInteraction Whether the container is participating in voice interaction or not. 2576 * @param sources {@link ActivityRecord}s which causes this app transition animation. 2577 * 2578 * @return {@code true} when the container applied the app transition, {@code false} if the 2579 * app transition is disabled or skipped. 2580 * 2581 * @see #getAnimationAdapter 2582 */ applyAnimation(WindowManager.LayoutParams lp, @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources)2583 boolean applyAnimation(WindowManager.LayoutParams lp, @TransitionOldType int transit, 2584 boolean enter, boolean isVoiceInteraction, 2585 @Nullable ArrayList<WindowContainer> sources) { 2586 if (mWmService.mDisableTransitionAnimation) { 2587 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, 2588 "applyAnimation: transition animation is disabled or skipped. " 2589 + "container=%s", this); 2590 cancelAnimation(); 2591 return false; 2592 } 2593 2594 // Only apply an animation if the display isn't frozen. If it is frozen, there is no reason 2595 // to animate and it can cause strange artifacts when we unfreeze the display if some 2596 // different animation is running. 2597 try { 2598 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation"); 2599 if (okToAnimate()) { 2600 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, 2601 "applyAnimation: transit=%s, enter=%b, wc=%s", 2602 AppTransition.appTransitionOldToString(transit), enter, this); 2603 applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources); 2604 } else { 2605 cancelAnimation(); 2606 } 2607 } finally { 2608 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 2609 } 2610 2611 return isAnimating(); 2612 } 2613 2614 /** 2615 * Gets the {@link AnimationAdapter} according the given window layout properties in the window 2616 * hierarchy. 2617 * 2618 * @return The return value will always contain two elements, one for normal animations and the 2619 * other for thumbnail animation, both can be {@code null}. 2620 * 2621 * @See com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord 2622 * @See LocalAnimationAdapter 2623 */ getAnimationAdapter(WindowManager.LayoutParams lp, @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction)2624 Pair<AnimationAdapter, AnimationAdapter> getAnimationAdapter(WindowManager.LayoutParams lp, 2625 @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction) { 2626 final Pair<AnimationAdapter, AnimationAdapter> resultAdapters; 2627 final int appRootTaskClipMode = getDisplayContent().mAppTransition.getAppRootTaskClipMode(); 2628 2629 // Separate position and size for use in animators. 2630 final Rect screenBounds = getAnimationBounds(appRootTaskClipMode); 2631 mTmpRect.set(screenBounds); 2632 getAnimationPosition(mTmpPoint); 2633 mTmpRect.offsetTo(0, 0); 2634 2635 final RemoteAnimationController controller = 2636 getDisplayContent().mAppTransition.getRemoteAnimationController(); 2637 final boolean isChanging = AppTransition.isChangeTransitOld(transit) && enter 2638 && isChangingAppTransition(); 2639 2640 // Delaying animation start isn't compatible with remote animations at all. 2641 if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) { 2642 final Rect localBounds = new Rect(mTmpRect); 2643 localBounds.offsetTo(mTmpPoint.x, mTmpPoint.y); 2644 final RemoteAnimationController.RemoteAnimationRecord adapters = 2645 controller.createRemoteAnimationRecord(this, mTmpPoint, localBounds, 2646 screenBounds, (isChanging ? mSurfaceFreezer.mFreezeBounds : null)); 2647 resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter); 2648 } else if (isChanging) { 2649 final float durationScale = mWmService.getTransitionAnimationScaleLocked(); 2650 final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo(); 2651 mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y); 2652 2653 final AnimationAdapter adapter = new LocalAnimationAdapter( 2654 new WindowChangeAnimationSpec(mSurfaceFreezer.mFreezeBounds, mTmpRect, 2655 displayInfo, durationScale, true /* isAppAnimation */, 2656 false /* isThumbnail */), 2657 getSurfaceAnimationRunner()); 2658 2659 final AnimationAdapter thumbnailAdapter = mSurfaceFreezer.mSnapshot != null 2660 ? new LocalAnimationAdapter(new WindowChangeAnimationSpec( 2661 mSurfaceFreezer.mFreezeBounds, mTmpRect, displayInfo, durationScale, 2662 true /* isAppAnimation */, true /* isThumbnail */), getSurfaceAnimationRunner()) 2663 : null; 2664 resultAdapters = new Pair<>(adapter, thumbnailAdapter); 2665 mTransit = transit; 2666 mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags(); 2667 } else { 2668 mNeedsAnimationBoundsLayer = (appRootTaskClipMode == ROOT_TASK_CLIP_AFTER_ANIM); 2669 final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction); 2670 2671 if (a != null) { 2672 // Only apply corner radius to animation if we're not in multi window mode. 2673 // We don't want rounded corners when in pip or split screen. 2674 final float windowCornerRadius = !inMultiWindowMode() 2675 ? getDisplayContent().getWindowCornerRadius() 2676 : 0; 2677 AnimationAdapter adapter = new LocalAnimationAdapter( 2678 new WindowAnimationSpec(a, mTmpPoint, mTmpRect, 2679 getDisplayContent().mAppTransition.canSkipFirstFrame(), 2680 appRootTaskClipMode, true /* isAppAnimation */, windowCornerRadius), 2681 getSurfaceAnimationRunner()); 2682 2683 resultAdapters = new Pair<>(adapter, null); 2684 mNeedsZBoost = a.getZAdjustment() == Animation.ZORDER_TOP 2685 || AppTransition.isClosingTransitOld(transit); 2686 mTransit = transit; 2687 mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags(); 2688 } else { 2689 resultAdapters = new Pair<>(null, null); 2690 } 2691 } 2692 return resultAdapters; 2693 } 2694 applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter, @TransitionOldType int transit, boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources)2695 protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter, 2696 @TransitionOldType int transit, boolean isVoiceInteraction, 2697 @Nullable ArrayList<WindowContainer> sources) { 2698 final Task task = asTask(); 2699 if (task != null && !enter && !task.isHomeOrRecentsRootTask()) { 2700 final InsetsControlTarget imeTarget = mDisplayContent.getImeTarget(IME_TARGET_LAYERING); 2701 final boolean isImeLayeringTarget = imeTarget != null && imeTarget.getWindow() != null 2702 && imeTarget.getWindow().getTask() == task; 2703 // Attach and show the IME screenshot when the task is the IME target and performing 2704 // task closing transition to the next task. 2705 if (isImeLayeringTarget && AppTransition.isTaskCloseTransitOld(transit)) { 2706 mDisplayContent.showImeScreenshot(); 2707 } 2708 } 2709 final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp, 2710 transit, enter, isVoiceInteraction); 2711 AnimationAdapter adapter = adapters.first; 2712 AnimationAdapter thumbnailAdapter = adapters.second; 2713 if (adapter != null) { 2714 if (sources != null) { 2715 mSurfaceAnimationSources.addAll(sources); 2716 } 2717 startAnimation(getPendingTransaction(), adapter, !isVisible(), 2718 ANIMATION_TYPE_APP_TRANSITION); 2719 if (adapter.getShowWallpaper()) { 2720 getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; 2721 } 2722 if (thumbnailAdapter != null) { 2723 mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(), 2724 thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION, (type, anim) -> { }); 2725 } 2726 } 2727 } 2728 getSurfaceAnimationRunner()2729 final SurfaceAnimationRunner getSurfaceAnimationRunner() { 2730 return mWmService.mSurfaceAnimationRunner; 2731 } 2732 loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction)2733 private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, 2734 boolean isVoiceInteraction) { 2735 if (isOrganized() 2736 // TODO(b/161711458): Clean-up when moved to shell. 2737 && getWindowingMode() != WINDOWING_MODE_FULLSCREEN) { 2738 return null; 2739 } 2740 2741 final DisplayContent displayContent = getDisplayContent(); 2742 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 2743 final int width = displayInfo.appWidth; 2744 final int height = displayInfo.appHeight; 2745 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: container=%s", this); 2746 2747 // Determine the visible rect to calculate the thumbnail clip with 2748 // getAnimationFrames. 2749 final Rect frame = new Rect(0, 0, width, height); 2750 final Rect displayFrame = new Rect(0, 0, 2751 displayInfo.logicalWidth, displayInfo.logicalHeight); 2752 final Rect insets = new Rect(); 2753 final Rect stableInsets = new Rect(); 2754 final Rect surfaceInsets = new Rect(); 2755 getAnimationFrames(frame, insets, stableInsets, surfaceInsets); 2756 2757 if (mLaunchTaskBehind) { 2758 // Differentiate the two animations. This one which is briefly on the screen 2759 // gets the !enter animation, and the other one which remains on the 2760 // screen gets the enter animation. Both appear in the mOpeningApps set. 2761 enter = false; 2762 } 2763 ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, 2764 "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s " 2765 + "surfaceInsets=%s", 2766 AppTransition.appTransitionOldToString(transit), enter, frame, insets, 2767 surfaceInsets); 2768 final Configuration displayConfig = displayContent.getConfiguration(); 2769 final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter, 2770 displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets, 2771 surfaceInsets, stableInsets, isVoiceInteraction, inFreeformWindowingMode(), this); 2772 if (a != null) { 2773 if (a != null) { 2774 // Setup the maximum app transition duration to prevent malicious app may set a long 2775 // animation duration or infinite repeat counts for the app transition through 2776 // ActivityOption#makeCustomAnimation or WindowManager#overridePendingTransition. 2777 a.restrictDuration(MAX_APP_TRANSITION_DURATION); 2778 } 2779 if (DEBUG_ANIM) { 2780 logWithStack(TAG, "Loaded animation " + a + " for " + this 2781 + ", duration: " + ((a != null) ? a.getDuration() : 0)); 2782 } 2783 final int containingWidth = frame.width(); 2784 final int containingHeight = frame.height(); 2785 a.initialize(containingWidth, containingHeight, width, height); 2786 a.scaleCurrentDuration(mWmService.getTransitionAnimationScaleLocked()); 2787 } 2788 return a; 2789 } 2790 createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record)2791 RemoteAnimationTarget createRemoteAnimationTarget( 2792 RemoteAnimationController.RemoteAnimationRecord record) { 2793 return null; 2794 } 2795 canCreateRemoteAnimationTarget()2796 boolean canCreateRemoteAnimationTarget() { 2797 return false; 2798 } 2799 okToDisplay()2800 boolean okToDisplay() { 2801 final DisplayContent dc = getDisplayContent(); 2802 return dc != null && dc.okToDisplay(); 2803 } 2804 okToAnimate()2805 boolean okToAnimate() { 2806 return okToAnimate(false /* ignoreFrozen */); 2807 } 2808 okToAnimate(boolean ignoreFrozen)2809 boolean okToAnimate(boolean ignoreFrozen) { 2810 final DisplayContent dc = getDisplayContent(); 2811 return dc != null && dc.okToAnimate(ignoreFrozen); 2812 } 2813 okToAnimate(boolean ignoreFrozen, boolean ignoreScreenOn)2814 boolean okToAnimate(boolean ignoreFrozen, boolean ignoreScreenOn) { 2815 final DisplayContent dc = getDisplayContent(); 2816 return dc != null && dc.okToAnimate(ignoreFrozen, ignoreScreenOn); 2817 } 2818 2819 @Override commitPendingTransaction()2820 public void commitPendingTransaction() { 2821 scheduleAnimation(); 2822 } 2823 reassignLayer(Transaction t)2824 void reassignLayer(Transaction t) { 2825 final WindowContainer parent = getParent(); 2826 if (parent != null) { 2827 parent.assignChildLayers(t); 2828 } 2829 } 2830 resetSurfacePositionForAnimationLeash(Transaction t)2831 void resetSurfacePositionForAnimationLeash(Transaction t) { 2832 t.setPosition(mSurfaceControl, 0, 0); 2833 mLastSurfacePosition.set(0, 0); 2834 } 2835 2836 @Override onAnimationLeashCreated(Transaction t, SurfaceControl leash)2837 public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { 2838 mLastLayer = -1; 2839 reassignLayer(t); 2840 2841 // Leash is now responsible for position, so set our position to 0. 2842 resetSurfacePositionForAnimationLeash(t); 2843 } 2844 2845 @Override onAnimationLeashLost(Transaction t)2846 public void onAnimationLeashLost(Transaction t) { 2847 mLastLayer = -1; 2848 mSurfaceFreezer.unfreeze(t); 2849 reassignLayer(t); 2850 updateSurfacePosition(t); 2851 } 2852 doAnimationFinished(@nimationType int type, AnimationAdapter anim)2853 private void doAnimationFinished(@AnimationType int type, AnimationAdapter anim) { 2854 for (int i = 0; i < mSurfaceAnimationSources.size(); ++i) { 2855 mSurfaceAnimationSources.valueAt(i).onAnimationFinished(type, anim); 2856 } 2857 mSurfaceAnimationSources.clear(); 2858 if (mDisplayContent != null) { 2859 mDisplayContent.onWindowAnimationFinished(this, type); 2860 } 2861 } 2862 2863 /** 2864 * Called when an animation has finished running. 2865 */ onAnimationFinished(@nimationType int type, AnimationAdapter anim)2866 protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) { 2867 doAnimationFinished(type, anim); 2868 mWmService.onAnimationFinished(); 2869 mNeedsZBoost = false; 2870 } 2871 2872 /** 2873 * @return The currently running animation, if any, or {@code null} otherwise. 2874 */ getAnimation()2875 AnimationAdapter getAnimation() { 2876 return mSurfaceAnimator.getAnimation(); 2877 } 2878 2879 /** 2880 * @return The {@link WindowContainer} which is running an animation. 2881 * 2882 * By default this only checks if this container itself is actually running an animation, but 2883 * you can extend the check target over its relatives, or relax the condition so that this can 2884 * return {@code WindowContainer} if an animation starts soon by giving a combination 2885 * of {@link AnimationFlags}. 2886 * 2887 * Note that you can give a combination of bitmask flags to specify targets and condition for 2888 * checking animating status. 2889 * e.g. {@code isAnimating(TRANSITION | PARENT)} returns {@code true} if either this 2890 * container itself or one of its parents is running an animation or waiting for an app 2891 * transition. 2892 * 2893 * Note that TRANSITION propagates to parents and children as well. 2894 * 2895 * @param flags The combination of bitmask flags to specify targets and condition for 2896 * checking animating status. 2897 * @param typesToCheck The combination of bitmask {@link AnimationType} to compare when 2898 * determining if animating. 2899 * 2900 * @see AnimationFlags#TRANSITION 2901 * @see AnimationFlags#PARENTS 2902 * @see AnimationFlags#CHILDREN 2903 */ 2904 @Nullable getAnimatingContainer(int flags, int typesToCheck)2905 WindowContainer getAnimatingContainer(int flags, int typesToCheck) { 2906 if (isSelfAnimating(flags, typesToCheck)) { 2907 return this; 2908 } 2909 if ((flags & PARENTS) != 0) { 2910 WindowContainer parent = getParent(); 2911 while (parent != null) { 2912 if (parent.isSelfAnimating(flags, typesToCheck)) { 2913 return parent; 2914 } 2915 parent = parent.getParent(); 2916 } 2917 } 2918 if ((flags & CHILDREN) != 0) { 2919 for (int i = 0; i < mChildren.size(); ++i) { 2920 final WindowContainer wc = mChildren.get(i).getAnimatingContainer( 2921 flags & ~PARENTS, typesToCheck); 2922 if (wc != null) { 2923 return wc; 2924 } 2925 } 2926 } 2927 return null; 2928 } 2929 2930 /** 2931 * Internal method only to be used during {@link #getAnimatingContainer(int, int)}.DO NOT CALL 2932 * FROM OUTSIDE. 2933 */ isSelfAnimating(int flags, int typesToCheck)2934 protected boolean isSelfAnimating(int flags, int typesToCheck) { 2935 if (mSurfaceAnimator.isAnimating() 2936 && (mSurfaceAnimator.getAnimationType() & typesToCheck) > 0) { 2937 return true; 2938 } 2939 if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) { 2940 return true; 2941 } 2942 return false; 2943 } 2944 2945 /** 2946 * @deprecated Use {@link #getAnimatingContainer(int, int)} instead. 2947 */ 2948 @Nullable 2949 @Deprecated getAnimatingContainer()2950 final WindowContainer getAnimatingContainer() { 2951 return getAnimatingContainer(PARENTS, ANIMATION_TYPE_ALL); 2952 } 2953 2954 /** 2955 * @see SurfaceAnimator#startDelayingAnimationStart 2956 */ startDelayingAnimationStart()2957 void startDelayingAnimationStart() { 2958 mSurfaceAnimator.startDelayingAnimationStart(); 2959 } 2960 2961 /** 2962 * @see SurfaceAnimator#endDelayingAnimationStart 2963 */ endDelayingAnimationStart()2964 void endDelayingAnimationStart() { 2965 mSurfaceAnimator.endDelayingAnimationStart(); 2966 } 2967 2968 @Override getSurfaceWidth()2969 public int getSurfaceWidth() { 2970 return mSurfaceControl.getWidth(); 2971 } 2972 2973 @Override getSurfaceHeight()2974 public int getSurfaceHeight() { 2975 return mSurfaceControl.getHeight(); 2976 } 2977 2978 @CallSuper dump(PrintWriter pw, String prefix, boolean dumpAll)2979 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 2980 if (mSurfaceAnimator.isAnimating()) { 2981 pw.print(prefix); pw.println("ContainerAnimator:"); 2982 mSurfaceAnimator.dump(pw, prefix + " "); 2983 } 2984 if (mLastOrientationSource != null && this == mDisplayContent) { 2985 pw.println(prefix + "mLastOrientationSource=" + mLastOrientationSource); 2986 pw.println(prefix + "deepestLastOrientationSource=" + getLastOrientationSource()); 2987 } 2988 } 2989 updateSurfacePositionNonOrganized()2990 final void updateSurfacePositionNonOrganized() { 2991 // Avoid fighting with the organizer over Surface position. 2992 if (isOrganized()) return; 2993 updateSurfacePosition(getSyncTransaction()); 2994 } 2995 2996 /** 2997 * Only for use internally (see PROTECTED annotation). This should only be used over 2998 * {@link #updateSurfacePositionNonOrganized} when the surface position needs to be 2999 * updated even if organized (eg. while changing to organized). 3000 */ 3001 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) updateSurfacePosition(Transaction t)3002 void updateSurfacePosition(Transaction t) { 3003 if (mSurfaceControl == null || mSurfaceAnimator.hasLeash()) { 3004 return; 3005 } 3006 3007 getRelativePosition(mTmpPos); 3008 if (mTmpPos.equals(mLastSurfacePosition)) { 3009 return; 3010 } 3011 3012 t.setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y); 3013 mLastSurfacePosition.set(mTmpPos.x, mTmpPos.y); 3014 } 3015 3016 @VisibleForTesting getLastSurfacePosition()3017 Point getLastSurfacePosition() { 3018 return mLastSurfacePosition; 3019 } 3020 3021 /** 3022 * The {@code outFrame} retrieved by this method specifies where the animation will finish 3023 * the entrance animation, as the next frame will display the window at these coordinates. In 3024 * case of exit animation, this is where the animation will start, as the frame before the 3025 * animation is displaying the window at these bounds. 3026 * 3027 * @param outFrame The bounds where entrance animation finishes or exit animation starts. 3028 * @param outInsets Insets that are covered by system windows. 3029 * @param outStableInsets Insets that determine the area covered by the stable system windows. 3030 * @param outSurfaceInsets Positive insets between the drawing surface and window content. 3031 */ getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, Rect outSurfaceInsets)3032 void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, 3033 Rect outSurfaceInsets) { 3034 final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo(); 3035 outFrame.set(0, 0, displayInfo.appWidth, displayInfo.appHeight); 3036 outInsets.setEmpty(); 3037 outStableInsets.setEmpty(); 3038 outSurfaceInsets.setEmpty(); 3039 } 3040 getRelativePosition(Point outPos)3041 void getRelativePosition(Point outPos) { 3042 final Rect dispBounds = getBounds(); 3043 outPos.set(dispBounds.left, dispBounds.top); 3044 final WindowContainer parent = getParent(); 3045 if (parent != null) { 3046 final Rect parentBounds = parent.getBounds(); 3047 outPos.offset(-parentBounds.left, -parentBounds.top); 3048 } 3049 } 3050 waitForAllWindowsDrawn()3051 void waitForAllWindowsDrawn() { 3052 forAllWindows(w -> { 3053 w.requestDrawIfNeeded(mWaitingForDrawn); 3054 }, true /* traverseTopToBottom */); 3055 } 3056 getDimmer()3057 Dimmer getDimmer() { 3058 if (mParent == null) { 3059 return null; 3060 } 3061 return mParent.getDimmer(); 3062 } 3063 setSurfaceControl(SurfaceControl sc)3064 void setSurfaceControl(SurfaceControl sc) { 3065 mSurfaceControl = sc; 3066 } 3067 getRemoteAnimationDefinition()3068 RemoteAnimationDefinition getRemoteAnimationDefinition() { 3069 return null; 3070 } 3071 3072 /** Cheap way of doing cast and instanceof. */ asTask()3073 Task asTask() { 3074 return null; 3075 } 3076 3077 /** Cheap way of doing cast and instanceof. */ asWindowToken()3078 WindowToken asWindowToken() { 3079 return null; 3080 } 3081 3082 /** Cheap way of doing cast and instanceof. */ asActivityRecord()3083 ActivityRecord asActivityRecord() { 3084 return null; 3085 } 3086 3087 /** Cheap way of doing cast and instanceof. */ asWallpaperToken()3088 WallpaperWindowToken asWallpaperToken() { 3089 return null; 3090 } 3091 3092 /** Cheap way of doing cast and instanceof. */ asDisplayArea()3093 DisplayArea asDisplayArea() { 3094 return null; 3095 } 3096 3097 /** Cheap way of doing cast and instanceof. */ asRootDisplayArea()3098 RootDisplayArea asRootDisplayArea() { 3099 return null; 3100 } 3101 3102 /** Cheap way of doing cast and instanceof. */ asTaskDisplayArea()3103 TaskDisplayArea asTaskDisplayArea() { 3104 return null; 3105 } 3106 3107 /** Cheap way of doing cast and instanceof. */ asDisplayContent()3108 DisplayContent asDisplayContent() { 3109 return null; 3110 } 3111 3112 /** 3113 * @return {@code true} if window container is manage by a 3114 * {@link android.window.WindowOrganizer} 3115 */ isOrganized()3116 boolean isOrganized() { 3117 return false; 3118 } 3119 3120 /** 3121 * @return {@code true} if this container's surface should be shown when it is created. 3122 */ showSurfaceOnCreation()3123 boolean showSurfaceOnCreation() { 3124 return true; 3125 } 3126 3127 /** @return {@code true} if the wallpaper is visible behind this container. */ showWallpaper()3128 boolean showWallpaper() { 3129 if (!isVisibleRequested() 3130 // in multi-window mode, wallpaper is always visible at the back and not tied to 3131 // the app (there is no wallpaper target). 3132 || inMultiWindowMode()) { 3133 return false; 3134 } 3135 for (int i = mChildren.size() - 1; i >= 0; --i) { 3136 final WindowContainer child = mChildren.get(i); 3137 if (child.showWallpaper()) { 3138 return true; 3139 } 3140 } 3141 return false; 3142 } 3143 3144 @Nullable fromBinder(IBinder binder)3145 static WindowContainer fromBinder(IBinder binder) { 3146 return RemoteToken.fromBinder(binder).getContainer(); 3147 } 3148 3149 static class RemoteToken extends IWindowContainerToken.Stub { 3150 3151 final WeakReference<WindowContainer> mWeakRef; 3152 private WindowContainerToken mWindowContainerToken; 3153 RemoteToken(WindowContainer container)3154 RemoteToken(WindowContainer container) { 3155 mWeakRef = new WeakReference<>(container); 3156 } 3157 3158 @Nullable getContainer()3159 WindowContainer getContainer() { 3160 return mWeakRef.get(); 3161 } 3162 fromBinder(IBinder binder)3163 static RemoteToken fromBinder(IBinder binder) { 3164 return (RemoteToken) binder; 3165 } 3166 toWindowContainerToken()3167 WindowContainerToken toWindowContainerToken() { 3168 if (mWindowContainerToken == null) { 3169 mWindowContainerToken = new WindowContainerToken(this); 3170 } 3171 return mWindowContainerToken; 3172 } 3173 3174 @Override toString()3175 public String toString() { 3176 StringBuilder sb = new StringBuilder(128); 3177 sb.append("RemoteToken{"); 3178 sb.append(Integer.toHexString(System.identityHashCode(this))); 3179 sb.append(' '); 3180 sb.append(mWeakRef.get()); 3181 sb.append('}'); 3182 return sb.toString(); 3183 } 3184 } 3185 3186 /** 3187 * Call this when this container finishes drawing content. 3188 * 3189 * @return {@code true} if consumed (this container is part of a sync group). 3190 */ onSyncFinishedDrawing()3191 boolean onSyncFinishedDrawing() { 3192 if (mSyncState == SYNC_STATE_NONE) return false; 3193 mSyncState = SYNC_STATE_READY; 3194 mWmService.mWindowPlacerLocked.requestTraversal(); 3195 ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "onSyncFinishedDrawing %s", this); 3196 return true; 3197 } 3198 setSyncGroup(@onNull BLASTSyncEngine.SyncGroup group)3199 void setSyncGroup(@NonNull BLASTSyncEngine.SyncGroup group) { 3200 ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "setSyncGroup #%d on %s", group.mSyncId, this); 3201 if (group != null) { 3202 if (mSyncGroup != null && mSyncGroup != group) { 3203 throw new IllegalStateException("Can't sync on 2 engines simultaneously"); 3204 } 3205 } 3206 mSyncGroup = group; 3207 } 3208 3209 /** 3210 * Prepares this container for participation in a sync-group. This includes preparing all its 3211 * children. 3212 * 3213 * @return {@code true} if something changed (eg. this wasn't already in the sync group). 3214 */ prepareSync()3215 boolean prepareSync() { 3216 if (mSyncState != SYNC_STATE_NONE) { 3217 // Already part of sync 3218 return false; 3219 } 3220 for (int i = getChildCount() - 1; i >= 0; --i) { 3221 final WindowContainer child = getChildAt(i); 3222 child.prepareSync(); 3223 } 3224 mSyncState = SYNC_STATE_READY; 3225 return true; 3226 } 3227 useBLASTSync()3228 boolean useBLASTSync() { 3229 return mSyncState != SYNC_STATE_NONE; 3230 } 3231 3232 /** 3233 * Recursively finishes/cleans-up sync state of this subtree and collects all the sync 3234 * transactions into `outMergedTransaction`. 3235 * @param outMergedTransaction A transaction to merge all the recorded sync operations into. 3236 * @param cancel If true, this is being finished because it is leaving the sync group rather 3237 * than due to the sync group completing. 3238 */ finishSync(Transaction outMergedTransaction, boolean cancel)3239 void finishSync(Transaction outMergedTransaction, boolean cancel) { 3240 if (mSyncState == SYNC_STATE_NONE) return; 3241 ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "finishSync cancel=%b for %s", cancel, this); 3242 outMergedTransaction.merge(mSyncTransaction); 3243 for (int i = mChildren.size() - 1; i >= 0; --i) { 3244 mChildren.get(i).finishSync(outMergedTransaction, cancel); 3245 } 3246 mSyncState = SYNC_STATE_NONE; 3247 if (cancel && mSyncGroup != null) mSyncGroup.onCancelSync(this); 3248 mSyncGroup = null; 3249 } 3250 3251 /** 3252 * Checks if the subtree rooted at this container is finished syncing (everything is ready or 3253 * not visible). NOTE, this is not const: it will cancel/prepare itself depending on its state 3254 * in the hierarchy. 3255 * 3256 * @return {@code true} if this subtree is finished waiting for sync participants. 3257 */ isSyncFinished()3258 boolean isSyncFinished() { 3259 if (!isVisibleRequested()) { 3260 return true; 3261 } 3262 if (mSyncState == SYNC_STATE_NONE) { 3263 prepareSync(); 3264 } 3265 if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW) { 3266 return false; 3267 } 3268 // READY 3269 // Loop from top-down. 3270 for (int i = mChildren.size() - 1; i >= 0; --i) { 3271 final WindowContainer child = mChildren.get(i); 3272 final boolean childFinished = child.isSyncFinished(); 3273 if (childFinished && child.isVisibleRequested() && child.fillsParent()) { 3274 // Any lower children will be covered-up, so we can consider this finished. 3275 return true; 3276 } 3277 if (!childFinished) { 3278 return false; 3279 } 3280 } 3281 return true; 3282 } 3283 3284 /** 3285 * Called during reparent to handle sync state when the hierarchy changes. 3286 * If this is in a sync group and gets reparented out, it will cancel syncing. 3287 * If this is not in a sync group and gets parented into one, it will prepare itself. 3288 * If its moving around within a sync-group, it needs to restart its syncing since a 3289 * hierarchy change implies a configuration change. 3290 */ onSyncReparent(WindowContainer oldParent, WindowContainer newParent)3291 private void onSyncReparent(WindowContainer oldParent, WindowContainer newParent) { 3292 if (newParent == null || newParent.mSyncState == SYNC_STATE_NONE) { 3293 if (mSyncState == SYNC_STATE_NONE) { 3294 return; 3295 } 3296 if (newParent == null) { 3297 // This is getting removed. 3298 if (oldParent.mSyncState != SYNC_STATE_NONE) { 3299 // In order to keep the transaction in sync, merge it into the parent. 3300 finishSync(oldParent.mSyncTransaction, true /* cancel */); 3301 } else if (mSyncGroup != null) { 3302 // This is watched directly by the sync-group, so merge this transaction into 3303 // into the sync-group so it isn't lost 3304 finishSync(mSyncGroup.getOrphanTransaction(), true /* cancel */); 3305 } else { 3306 throw new IllegalStateException("This container is in sync mode without a sync" 3307 + " group: " + this); 3308 } 3309 return; 3310 } else if (mSyncGroup == null) { 3311 // This is being reparented out of the sync-group. To prevent ordering issues on 3312 // this container, immediately apply/cancel sync on it. 3313 finishSync(getPendingTransaction(), true /* cancel */); 3314 return; 3315 } 3316 // Otherwise this is the "root" of a synced subtree, so continue on to preparation. 3317 } 3318 // This container's situation has changed so we need to restart its sync. 3319 mSyncState = SYNC_STATE_NONE; 3320 prepareSync(); 3321 } 3322 registerWindowContainerListener(WindowContainerListener listener)3323 void registerWindowContainerListener(WindowContainerListener listener) { 3324 if (mListeners.contains(listener)) { 3325 return; 3326 } 3327 mListeners.add(listener); 3328 // Also register to ConfigurationChangeListener to receive configuration changes. 3329 registerConfigurationChangeListener(listener); 3330 listener.onDisplayChanged(getDisplayContent()); 3331 } 3332 unregisterWindowContainerListener(WindowContainerListener listener)3333 void unregisterWindowContainerListener(WindowContainerListener listener) { 3334 mListeners.remove(listener); 3335 unregisterConfigurationChangeListener(listener); 3336 } 3337 3338 /** 3339 * Returns the {@link WindowManager.LayoutParams.WindowType}. 3340 */ getWindowType()3341 @WindowManager.LayoutParams.WindowType int getWindowType() { 3342 return INVALID_WINDOW_TYPE; 3343 } 3344 setCanScreenshot(boolean canScreenshot)3345 boolean setCanScreenshot(boolean canScreenshot) { 3346 if (mSurfaceControl == null) { 3347 return false; 3348 } 3349 getPendingTransaction().setSecure(mSurfaceControl, !canScreenshot); 3350 return true; 3351 } 3352 } 3353