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