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