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