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