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