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