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