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