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