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.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
22 import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
23 import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
24 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
25 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
26 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
27 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
28 import static android.os.UserHandle.USER_NULL;
29 import static android.view.SurfaceControl.Transaction;
30 
31 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
32 import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION;
33 import static com.android.server.wm.IdentifierProto.HASH_CODE;
34 import static com.android.server.wm.IdentifierProto.TITLE;
35 import static com.android.server.wm.IdentifierProto.USER_ID;
36 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
37 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
38 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
39 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
40 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
41 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
42 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
43 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
44 import static com.android.server.wm.WindowContainerChildProto.WINDOW_CONTAINER;
45 import static com.android.server.wm.WindowContainerProto.CONFIGURATION_CONTAINER;
46 import static com.android.server.wm.WindowContainerProto.ORIENTATION;
47 import static com.android.server.wm.WindowContainerProto.SURFACE_ANIMATOR;
48 import static com.android.server.wm.WindowContainerProto.VISIBLE;
49 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
50 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
51 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
52 import static com.android.server.wm.WindowManagerService.logWithStack;
53 import static com.android.server.wm.WindowManagerService.sHierarchicalAnimations;
54 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
55 
56 import android.annotation.CallSuper;
57 import android.annotation.IntDef;
58 import android.annotation.Nullable;
59 import android.app.WindowConfiguration;
60 import android.content.pm.ActivityInfo;
61 import android.content.res.Configuration;
62 import android.graphics.Point;
63 import android.graphics.Rect;
64 import android.os.Debug;
65 import android.os.IBinder;
66 import android.os.Trace;
67 import android.util.ArraySet;
68 import android.util.Pair;
69 import android.util.Pools;
70 import android.util.Slog;
71 import android.util.proto.ProtoOutputStream;
72 import android.view.DisplayInfo;
73 import android.view.MagnificationSpec;
74 import android.view.RemoteAnimationDefinition;
75 import android.view.RemoteAnimationTarget;
76 import android.view.SurfaceControl;
77 import android.view.SurfaceControl.Builder;
78 import android.view.SurfaceSession;
79 import android.view.WindowManager;
80 import android.view.animation.Animation;
81 import android.window.IWindowContainerToken;
82 import android.window.WindowContainerToken;
83 
84 import com.android.internal.annotations.VisibleForTesting;
85 import com.android.internal.util.ToBooleanFunction;
86 import com.android.server.protolog.common.ProtoLog;
87 import com.android.server.wm.SurfaceAnimator.Animatable;
88 import com.android.server.wm.SurfaceAnimator.AnimationType;
89 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
90 
91 import java.io.PrintWriter;
92 import java.lang.ref.WeakReference;
93 import java.util.ArrayList;
94 import java.util.Comparator;
95 import java.util.LinkedList;
96 import java.util.Set;
97 import java.util.function.Consumer;
98 import java.util.function.Function;
99 import java.util.function.Predicate;
100 
101 /**
102  * Defines common functionality for classes that can hold windows directly or through their
103  * children in a hierarchy form.
104  * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
105  * changes are made to this class.
106  */
107 class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
108         implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable,
109                    BLASTSyncEngine.TransactionReadyListener {
110 
111     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM;
112 
113     /** Animation layer that happens above all animating {@link ActivityStack}s. */
114     static final int ANIMATION_LAYER_STANDARD = 0;
115 
116     /** Animation layer that happens above all {@link ActivityStack}s. */
117     static final int ANIMATION_LAYER_BOOSTED = 1;
118 
119     /**
120      * Animation layer that is reserved for {@link WindowConfiguration#ACTIVITY_TYPE_HOME}
121      * activities and all activities that are being controlled by the recents animation. This
122      * layer is generally below all {@link ActivityStack}s.
123      */
124     static final int ANIMATION_LAYER_HOME = 2;
125 
126     @IntDef(prefix = { "ANIMATION_LAYER_" }, value = {
127             ANIMATION_LAYER_STANDARD,
128             ANIMATION_LAYER_BOOSTED,
129             ANIMATION_LAYER_HOME,
130     })
131     @interface AnimationLayer {}
132 
133     static final int POSITION_TOP = Integer.MAX_VALUE;
134     static final int POSITION_BOTTOM = Integer.MIN_VALUE;
135 
136     /**
137      * The parent of this window container.
138      * For removing or setting new parent {@link #setParent} should be used, because it also
139      * performs configuration updates based on new parent's settings.
140      */
141     private WindowContainer<WindowContainer> mParent = null;
142 
143     // Set to true when we are performing a reparenting operation so we only send one
144     // onParentChanged() notification.
145     boolean mReparenting;
146 
147     // List of children for this window container. List is in z-order as the children appear on
148     // screen with the top-most window container at the tail of the list.
149     protected final WindowList<E> mChildren = new WindowList<E>();
150 
151     // The specified orientation for this window container.
152     @ActivityInfo.ScreenOrientation
153     protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
154 
155     /**
156      * The window container which decides its orientation since the last time
157      * {@link #getOrientation(int) was called.
158      */
159     protected WindowContainer mLastOrientationSource;
160 
161     private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool =
162             new Pools.SynchronizedPool<>(3);
163 
164     // The display this window container is on.
165     protected DisplayContent mDisplayContent;
166 
167     protected SurfaceControl mSurfaceControl;
168     private int mLastLayer = 0;
169     private SurfaceControl mLastRelativeToLayer = null;
170 
171     // TODO(b/132320879): Remove this from WindowContainers except DisplayContent.
172     private final Transaction mPendingTransaction;
173 
174     /**
175      * Windows that clients are waiting to have drawn.
176      */
177     final ArrayList<WindowState> mWaitingForDrawn = new ArrayList<>();
178 
179     /**
180      * Applied as part of the animation pass in "prepareSurfaces".
181      */
182     protected final SurfaceAnimator mSurfaceAnimator;
183     private boolean mAnyParentAnimating;
184 
185     final SurfaceFreezer mSurfaceFreezer;
186     protected final WindowManagerService mWmService;
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 ActivityStack}. 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. Must be one of
251      * {@link AppTransition#TransitionFlags}.
252      */
253     int mTransit;
254 
255     /**
256      * If we are running an animation, this determines the flags during this animation. Must be a
257      * bitwise combination of AppTransition.TRANSIT_FLAG_* constants.
258      */
259     int mTransitFlags;
260 
261     /** Whether this container should be boosted at the top of all its siblings. */
262     @VisibleForTesting boolean mNeedsZBoost;
263 
264     /** Layer used to constrain the animation to a container's stack bounds. */
265     SurfaceControl mAnimationBoundsLayer;
266 
267     /** Whether this container needs to create mAnimationBoundsLayer for cropping animations. */
268     boolean mNeedsAnimationBoundsLayer;
269 
270     /**
271      * This gets used during some open/close transitions as well as during a change transition
272      * where it represents the starting-state snapshot.
273      */
274     WindowContainerThumbnail mThumbnail;
275     final Point mTmpPoint = new Point();
276     protected final Rect mTmpRect = new Rect();
277     final Rect mTmpPrevBounds = new Rect();
278 
279     private MagnificationSpec mLastMagnificationSpec;
280 
281     private boolean mIsFocusable = true;
282 
283     /**
284      * Used as a unique, cross-process identifier for this Container. It also serves a minimal
285      * interface to other processes.
286      */
287     RemoteToken mRemoteToken = null;
288 
289     BLASTSyncEngine mBLASTSyncEngine = new BLASTSyncEngine();
290     SurfaceControl.Transaction mBLASTSyncTransaction;
291     boolean mUsingBLASTSyncTransaction = false;
292     BLASTSyncEngine.TransactionReadyListener mWaitingListener;
293     int mWaitingSyncId;
294 
WindowContainer(WindowManagerService wms)295     WindowContainer(WindowManagerService wms) {
296         mWmService = wms;
297         mPendingTransaction = wms.mTransactionFactory.get();
298         mBLASTSyncTransaction = wms.mTransactionFactory.get();
299         mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms);
300         mSurfaceFreezer = new SurfaceFreezer(this, wms);
301     }
302 
303     @Override
getParent()304     final protected WindowContainer getParent() {
305         return mParent;
306     }
307 
308     @Override
getChildCount()309     protected int getChildCount() {
310         return mChildren.size();
311     }
312 
313     @Override
getChildAt(int index)314     protected E getChildAt(int index) {
315         return mChildren.get(index);
316     }
317 
318     @Override
onConfigurationChanged(Configuration newParentConfig)319     public void onConfigurationChanged(Configuration newParentConfig) {
320         super.onConfigurationChanged(newParentConfig);
321         updateSurfacePosition();
322         scheduleAnimation();
323     }
324 
reparent(WindowContainer newParent, int position)325     void reparent(WindowContainer newParent, int position) {
326         if (newParent == null) {
327             throw new IllegalArgumentException("reparent: can't reparent to null " + this);
328         }
329 
330         final WindowContainer oldParent = mParent;
331         if (mParent == newParent) {
332             throw new IllegalArgumentException("WC=" + this + " already child of " + mParent);
333         }
334 
335         // The display object before reparenting as that might lead to old parent getting removed
336         // from the display if it no longer has any child.
337         final DisplayContent prevDc = oldParent.getDisplayContent();
338         final DisplayContent dc = newParent.getDisplayContent();
339 
340         mReparenting = true;
341         oldParent.removeChild(this);
342         newParent.addChild(this, position);
343         mReparenting = false;
344 
345         // Relayout display(s)
346         dc.setLayoutNeeded();
347         if (prevDc != dc) {
348             onDisplayChanged(dc);
349             prevDc.setLayoutNeeded();
350         }
351         getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
352 
353         // Send onParentChanged notification here is we disabled sending it in setParent for
354         // reparenting case.
355         onParentChanged(newParent, oldParent);
356     }
357 
setParent(WindowContainer<WindowContainer> parent)358     final protected void setParent(WindowContainer<WindowContainer> parent) {
359         final WindowContainer oldParent = mParent;
360         mParent = parent;
361 
362         if (mParent != null) {
363             mParent.onChildAdded(this);
364         }
365         if (!mReparenting) {
366             if (mParent != null && mParent.mDisplayContent != null
367                     && mDisplayContent != mParent.mDisplayContent) {
368                 onDisplayChanged(mParent.mDisplayContent);
369             }
370             onParentChanged(mParent, oldParent);
371         }
372     }
373 
374     /**
375      * Callback that is triggered when @link WindowContainer#setParent(WindowContainer)} was called.
376      * Supposed to be overridden and contain actions that should be executed after parent was set.
377      */
378     @Override
onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent)379     void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
380         onParentChanged(newParent, oldParent, null);
381     }
382 
onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent, PreAssignChildLayersCallback callback)383     void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent,
384             PreAssignChildLayersCallback callback) {
385         super.onParentChanged(newParent, oldParent);
386         if (mParent == null) {
387             return;
388         }
389 
390         if (mSurfaceControl == null) {
391             // If we don't yet have a surface, but we now have a parent, we should
392             // build a surface.
393             createSurfaceControl(false /*force*/);
394         } else {
395             // If we have a surface but a new parent, we just need to perform a reparent. Go through
396             // surface animator such that hierarchy is preserved when animating, i.e.
397             // mSurfaceControl stays attached to the leash and we just reparent the leash to the
398             // new parent.
399             reparentSurfaceControl(getSyncTransaction(), mParent.mSurfaceControl);
400         }
401 
402         if (callback != null) {
403             callback.onPreAssignChildLayers();
404         }
405 
406         // Either way we need to ask the parent to assign us a Z-order.
407         mParent.assignChildLayers();
408         scheduleAnimation();
409     }
410 
createSurfaceControl(boolean force)411     void createSurfaceControl(boolean force) {
412         setInitialSurfaceControlProperties(makeSurface());
413     }
414 
setInitialSurfaceControlProperties(SurfaceControl.Builder b)415     void setInitialSurfaceControlProperties(SurfaceControl.Builder b) {
416         setSurfaceControl(b.setCallsite("WindowContainer.setInitialSurfaceControlProperties").build());
417         getSyncTransaction().show(mSurfaceControl);
418         onSurfaceShown(getSyncTransaction());
419         updateSurfacePosition();
420     }
421 
422     /**
423      * Create a new SurfaceControl for this WindowContainer and migrate all properties to the new
424      * SurfaceControl. Properties include:
425      * 1. Children
426      * 2. Position
427      * 3. Z order
428      *
429      * Remove the old SurfaceControl since it's no longer needed.
430      *
431      * This is used to revoke control of the SurfaceControl from a client process that was
432      * previously organizing this WindowContainer.
433      */
migrateToNewSurfaceControl()434     void migrateToNewSurfaceControl() {
435         SurfaceControl.Transaction t = getPendingTransaction();
436         t.remove(mSurfaceControl);
437         // Clear the last position so the new SurfaceControl will get correct position
438         mLastSurfacePosition.set(0, 0);
439 
440         final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(null)
441                 .setContainerLayer()
442                 .setName(getName());
443 
444         setInitialSurfaceControlProperties(b);
445 
446         // If parent is null, the layer should be placed offscreen so reparent to null. Otherwise,
447         // set to the available parent.
448         t.reparent(mSurfaceControl, mParent == null ? null : mParent.getSurfaceControl());
449 
450         if (mLastRelativeToLayer != null) {
451             t.setRelativeLayer(mSurfaceControl, mLastRelativeToLayer, mLastLayer);
452         } else {
453             t.setLayer(mSurfaceControl, mLastLayer);
454         }
455 
456         for (int i = 0; i < mChildren.size(); i++)  {
457             SurfaceControl sc = mChildren.get(i).getSurfaceControl();
458             if (sc != null) {
459                 t.reparent(sc, mSurfaceControl);
460             }
461         }
462         scheduleAnimation();
463     }
464 
465     /**
466      * Called when the surface is shown for the first time.
467      */
onSurfaceShown(Transaction t)468     void onSurfaceShown(Transaction t) {
469         // do nothing
470     }
471 
472     // Temp. holders for a chain of containers we are currently processing.
473     private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList<>();
474     private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList<>();
475 
476     /**
477      * Adds the input window container has a child of this container in order based on the input
478      * comparator.
479      * @param child The window container to add as a child of this window container.
480      * @param comparator Comparator to use in determining the position the child should be added to.
481      *                   If null, the child will be added to the top.
482      */
483     @CallSuper
addChild(E child, Comparator<E> comparator)484     protected void addChild(E child, Comparator<E> comparator) {
485         if (!child.mReparenting && child.getParent() != null) {
486             throw new IllegalArgumentException("addChild: container=" + child.getName()
487                     + " is already a child of container=" + child.getParent().getName()
488                     + " can't add to container=" + getName());
489         }
490 
491         int positionToAdd = -1;
492         if (comparator != null) {
493             final int count = mChildren.size();
494             for (int i = 0; i < count; i++) {
495                 if (comparator.compare(child, mChildren.get(i)) < 0) {
496                     positionToAdd = i;
497                     break;
498                 }
499             }
500         }
501 
502         if (positionToAdd == -1) {
503             mChildren.add(child);
504         } else {
505             mChildren.add(positionToAdd, child);
506         }
507 
508         // Set the parent after we've actually added a child in case a subclass depends on this.
509         child.setParent(this);
510     }
511 
512     /** Adds the input window container has a child of this container at the input index. */
513     @CallSuper
addChild(E child, int index)514     void addChild(E child, int index) {
515         if (!child.mReparenting && child.getParent() != null) {
516             throw new IllegalArgumentException("addChild: container=" + child.getName()
517                     + " is already a child of container=" + child.getParent().getName()
518                     + " can't add to container=" + getName()
519                     + "\n callers=" + Debug.getCallers(15, "\n"));
520         }
521 
522         if ((index < 0 && index != POSITION_BOTTOM)
523                 || (index > mChildren.size() && index != POSITION_TOP)) {
524             throw new IllegalArgumentException("addChild: invalid position=" + index
525                     + ", children number=" + mChildren.size());
526         }
527 
528         if (index == POSITION_TOP) {
529             index = mChildren.size();
530         } else if (index == POSITION_BOTTOM) {
531             index = 0;
532         }
533 
534         mChildren.add(index, child);
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 
onChildAdded(WindowContainer child)540     private void onChildAdded(WindowContainer child) {
541         mTreeWeight += child.mTreeWeight;
542         WindowContainer parent = getParent();
543         while (parent != null) {
544             parent.mTreeWeight += child.mTreeWeight;
545             parent = parent.getParent();
546         }
547         onChildPositionChanged(child);
548     }
549 
550     /**
551      * Removes the input child container from this container which is its parent.
552      *
553      * @return True if the container did contain the input child and it was detached.
554      */
555     @CallSuper
removeChild(E child)556     void removeChild(E child) {
557         if (mChildren.remove(child)) {
558             onChildRemoved(child);
559             if (!child.mReparenting) {
560                 child.setParent(null);
561             }
562         } else {
563             throw new IllegalArgumentException("removeChild: container=" + child.getName()
564                     + " is not a child of container=" + getName());
565         }
566     }
567 
onChildRemoved(WindowContainer child)568     private void onChildRemoved(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 this window container and its children with no regard for what else might be going on
580      * in the system. For example, the container will be removed during animation if this method is
581      * called which isn't desirable. For most cases you want to call {@link #removeIfPossible()}
582      * which allows the system to defer removal until a suitable time.
583      */
584     @CallSuper
removeImmediately()585     void removeImmediately() {
586         final DisplayContent dc = getDisplayContent();
587         if (dc != null) {
588             mSurfaceFreezer.unfreeze(getSyncTransaction());
589             dc.mChangingContainers.remove(this);
590         }
591         while (!mChildren.isEmpty()) {
592             final E child = mChildren.peekLast();
593             child.removeImmediately();
594             // Need to do this after calling remove on the child because the child might try to
595             // remove/detach itself from its parent which will cause an exception if we remove
596             // it before calling remove on the child.
597             if (mChildren.remove(child)) {
598                 onChildRemoved(child);
599             }
600         }
601 
602         if (mSurfaceControl != null) {
603             getSyncTransaction().remove(mSurfaceControl);
604             setSurfaceControl(null);
605             mLastSurfacePosition.set(0, 0);
606             scheduleAnimation();
607         }
608 
609         if (mParent != null) {
610             mParent.removeChild(this);
611         }
612     }
613 
614     /**
615      * @return The index of this element in the hierarchy tree in prefix order.
616      */
getPrefixOrderIndex()617     int getPrefixOrderIndex() {
618         if (mParent == null) {
619             return 0;
620         }
621         return mParent.getPrefixOrderIndex(this);
622     }
623 
getPrefixOrderIndex(WindowContainer child)624     private int getPrefixOrderIndex(WindowContainer child) {
625         int order = 0;
626         for (int i = 0; i < mChildren.size(); i++) {
627             final WindowContainer childI = mChildren.get(i);
628             if (child == childI) {
629                 break;
630             }
631             order += childI.mTreeWeight;
632         }
633         if (mParent != null) {
634             order += mParent.getPrefixOrderIndex(this);
635         }
636 
637         // We also need to count ourselves.
638         order++;
639         return order;
640     }
641 
642     /**
643      * Removes this window container and its children taking care not to remove them during a
644      * critical stage in the system. For example, some containers will not be removed during
645      * animation if this method is called.
646      */
647     // TODO: figure-out implementation that works best for this.
648     // E.g. when do we remove from parent list? maybe not...
removeIfPossible()649     void removeIfPossible() {
650         for (int i = mChildren.size() - 1; i >= 0; --i) {
651             final WindowContainer wc = mChildren.get(i);
652             wc.removeIfPossible();
653         }
654     }
655 
656     /** Returns true if this window container has the input child. */
hasChild(E child)657     boolean hasChild(E child) {
658         for (int i = mChildren.size() - 1; i >= 0; --i) {
659             final E current = mChildren.get(i);
660             if (current == child || current.hasChild(child)) {
661                 return true;
662             }
663         }
664         return false;
665     }
666 
667     /** @return true if this window container is a descendant of the input container. */
isDescendantOf(WindowContainer ancestor)668     boolean isDescendantOf(WindowContainer ancestor) {
669         final WindowContainer parent = getParent();
670         if (parent == ancestor) return true;
671         return (parent != null) && parent.isDescendantOf(ancestor);
672     }
673 
674     /**
675      * Move a child from it's current place in siblings list to the specified position,
676      * with an option to move all its parents to top.
677      * @param position Target position to move the child to.
678      * @param child Child to move to selected position.
679      * @param includingParents Flag indicating whether we need to move the entire branch of the
680      *                         hierarchy when we're moving a child to {@link #POSITION_TOP} or
681      *                         {@link #POSITION_BOTTOM}. When moving to other intermediate positions
682      *                         this flag will do nothing.
683      */
684     @CallSuper
positionChildAt(int position, E child, boolean includingParents)685     void positionChildAt(int position, E child, boolean includingParents) {
686 
687         if (child.getParent() != this) {
688             throw new IllegalArgumentException("positionChildAt: container=" + child.getName()
689                     + " is not a child of container=" + getName()
690                     + " current parent=" + child.getParent());
691         }
692 
693         if (position >= mChildren.size() - 1) {
694             position = POSITION_TOP;
695         } else if (position <= 0) {
696             position = POSITION_BOTTOM;
697         }
698 
699         switch (position) {
700             case POSITION_TOP:
701                 if (mChildren.peekLast() != child) {
702                     mChildren.remove(child);
703                     mChildren.add(child);
704                     onChildPositionChanged(child);
705                 }
706                 if (includingParents && getParent() != null) {
707                     getParent().positionChildAt(POSITION_TOP, this /* child */,
708                             true /* includingParents */);
709                 }
710                 break;
711             case POSITION_BOTTOM:
712                 if (mChildren.peekFirst() != child) {
713                     mChildren.remove(child);
714                     mChildren.addFirst(child);
715                     onChildPositionChanged(child);
716                 }
717                 if (includingParents && getParent() != null) {
718                     getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
719                             true /* includingParents */);
720                 }
721                 break;
722             default:
723                 // TODO: Removing the child before reinserting requires the caller to provide a
724                 //       position that takes into account the removed child (if the index of the
725                 //       child < position, then the position should be adjusted). We should consider
726                 //       doing this adjustment here and remove any adjustments in the callers.
727                 if (mChildren.indexOf(child) != position) {
728                     mChildren.remove(child);
729                     mChildren.add(position, child);
730                     onChildPositionChanged(child);
731                 }
732         }
733     }
734 
735     /**
736      * Notify that a child's position has changed. Possible changes are adding or removing a child.
737      */
onChildPositionChanged(WindowContainer child)738     void onChildPositionChanged(WindowContainer child) { }
739 
740     /**
741      * Update override configuration and recalculate full config.
742      * @see #mRequestedOverrideConfiguration
743      * @see #mFullConfiguration
744      */
745     @Override
onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration)746     public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
747         // We must diff before the configuration is applied so that we can capture the change
748         // against the existing bounds.
749         final int diff = diffRequestedOverrideBounds(
750                 overrideConfiguration.windowConfiguration.getBounds());
751         super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
752         if (mParent != null) {
753             mParent.onDescendantOverrideConfigurationChanged();
754         }
755 
756         if (diff == BOUNDS_CHANGE_NONE) {
757             return;
758         }
759 
760         if ((diff & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
761             onResize();
762         } else {
763             onMovedByResize();
764         }
765     }
766 
767     /**
768      * Notify that a descendant's overrideConfiguration has changed.
769      */
onDescendantOverrideConfigurationChanged()770     void onDescendantOverrideConfigurationChanged() {
771         if (mParent != null) {
772             mParent.onDescendantOverrideConfigurationChanged();
773         }
774     }
775 
776     /**
777      * Notify that the display this container is on has changed. This could be either this container
778      * is moved to a new display, or some configurations on the display it is on changes.
779      *
780      * @param dc The display this container is on after changes.
781      */
onDisplayChanged(DisplayContent dc)782     void onDisplayChanged(DisplayContent dc) {
783         if (mDisplayContent != null && mDisplayContent.mChangingContainers.remove(this)) {
784             // Cancel any change transition queued-up for this container on the old display.
785             mSurfaceFreezer.unfreeze(getPendingTransaction());
786         }
787         mDisplayContent = dc;
788         if (dc != null && dc != this) {
789             dc.getPendingTransaction().merge(mPendingTransaction);
790         }
791         for (int i = mChildren.size() - 1; i >= 0; --i) {
792             final WindowContainer child = mChildren.get(i);
793             child.onDisplayChanged(dc);
794         }
795     }
796 
getDisplayContent()797     DisplayContent getDisplayContent() {
798         return mDisplayContent;
799     }
800 
801     /** Get the first node of type {@link DisplayArea} above or at this node. */
802     @Nullable
getDisplayArea()803     DisplayArea getDisplayArea() {
804         WindowContainer parent = getParent();
805         return parent != null ? parent.getDisplayArea() : null;
806     }
807 
isAttached()808     boolean isAttached() {
809         return getDisplayArea() != null;
810     }
811 
setWaitingForDrawnIfResizingChanged()812     void setWaitingForDrawnIfResizingChanged() {
813         for (int i = mChildren.size() - 1; i >= 0; --i) {
814             final WindowContainer wc = mChildren.get(i);
815             wc.setWaitingForDrawnIfResizingChanged();
816         }
817     }
818 
onResize()819     void onResize() {
820         for (int i = mChildren.size() - 1; i >= 0; --i) {
821             final WindowContainer wc = mChildren.get(i);
822             wc.onParentResize();
823         }
824     }
825 
onParentResize()826     void onParentResize() {
827         // In the case this container has specified its own bounds, a parent resize will not
828         // affect its bounds. Any relevant changes will be propagated through changes to the
829         // Configuration override.
830         if (hasOverrideBounds()) {
831             return;
832         }
833 
834         // Default implementation is to treat as resize on self.
835         onResize();
836     }
837 
onMovedByResize()838     void onMovedByResize() {
839         for (int i = mChildren.size() - 1; i >= 0; --i) {
840             final WindowContainer wc = mChildren.get(i);
841             wc.onMovedByResize();
842         }
843     }
844 
resetDragResizingChangeReported()845     void resetDragResizingChangeReported() {
846         for (int i = mChildren.size() - 1; i >= 0; --i) {
847             final WindowContainer wc = mChildren.get(i);
848             wc.resetDragResizingChangeReported();
849         }
850     }
851 
forceWindowsScaleableInTransaction(boolean force)852     void forceWindowsScaleableInTransaction(boolean force) {
853         for (int i = mChildren.size() - 1; i >= 0; --i) {
854             final WindowContainer wc = mChildren.get(i);
855             wc.forceWindowsScaleableInTransaction(force);
856         }
857     }
858 
859     /**
860      * @return {@code true} when this container or its related containers are running an
861      * animation, {@code false} otherwise.
862      *
863      * By default this predicate only checks if this container itself is actually running an
864      * animation, but you can extend the check target over its relatives, or relax the condition
865      * so that this can return {@code true} if an animation starts soon by giving a combination
866      * of {@link AnimationFlags}.
867      *
868      * Note that you can give a combination of bitmask flags to specify targets and condition for
869      * checking animating status.
870      * e.g. {@code isAnimating(TRANSITION | PARENT)} returns {@code true} if either this
871      * container itself or one of its parents is running an animation or waiting for an app
872      * transition.
873      *
874      * Note that TRANSITION propagates to parents and children as well.
875      *
876      * @param flags The combination of bitmask flags to specify targets and condition for
877      *              checking animating status.
878      * @param typesToCheck The combination of bitmask {@link AnimationType} to compare when
879      *                     determining if animating.
880      *
881      * @see AnimationFlags#TRANSITION
882      * @see AnimationFlags#PARENTS
883      * @see AnimationFlags#CHILDREN
884      */
isAnimating(int flags, int typesToCheck)885     final boolean isAnimating(int flags, int typesToCheck) {
886         return getAnimatingContainer(flags, typesToCheck) != null;
887     }
888 
889     /**
890      * Similar to {@link #isAnimating(int, int)} except provide a bitmask of
891      * {@link AnimationType} to exclude, rather than include
892      * @param flags The combination of bitmask flags to specify targets and condition for
893      *              checking animating status.
894      * @param typesToExclude The combination of bitmask {@link AnimationType} to exclude when
895      *                     checking if animating.
896      *
897      * @deprecated Use {@link #isAnimating(int, int)}
898      */
899     @Deprecated
isAnimatingExcluding(int flags, int typesToExclude)900     final boolean isAnimatingExcluding(int flags, int typesToExclude) {
901         return isAnimating(flags, ANIMATION_TYPE_ALL & ~typesToExclude);
902     }
903 
904     /**
905      * @deprecated Use {@link #isAnimating(int, int)}
906      * TODO (b/152333373): Migrate calls to use isAnimating with specified animation type
907      */
908     @Deprecated
isAnimating(int flags)909     final boolean isAnimating(int flags) {
910         return isAnimating(flags, ANIMATION_TYPE_ALL);
911     }
912 
913     /**
914      * @return {@code true} when the container is waiting the app transition start, {@code false}
915      *         otherwise.
916      */
isWaitingForTransitionStart()917     boolean isWaitingForTransitionStart() {
918         return false;
919     }
920 
921     /**
922      * @return {@code true} if in this subtree of the hierarchy we have an
923      *         {@code ActivityRecord#isAnimating(TRANSITION)}, {@code false} otherwise.
924      */
isAppTransitioning()925     boolean isAppTransitioning() {
926         return getActivity(app -> app.isAnimating(PARENTS | TRANSITION)) != null;
927     }
928 
929     /**
930      * @return Whether our own container running an animation at the moment.
931      */
isAnimating()932     final boolean isAnimating() {
933         return isAnimating(0 /* self only */);
934     }
935 
936     /**
937      * @return {@code true} if the container is in changing app transition.
938      */
isChangingAppTransition()939     boolean isChangingAppTransition() {
940         return mDisplayContent != null && mDisplayContent.mChangingContainers.contains(this);
941     }
942 
sendAppVisibilityToClients()943     void sendAppVisibilityToClients() {
944         for (int i = mChildren.size() - 1; i >= 0; --i) {
945             final WindowContainer wc = mChildren.get(i);
946             wc.sendAppVisibilityToClients();
947         }
948     }
949 
950     /**
951      * Returns true if the container or one of its children as some content it can display or wants
952      * to display (e.g. app views or saved surface).
953      *
954      * NOTE: While this method will return true if the there is some content to display, it doesn't
955      * mean the container is visible. Use {@link #isVisible()} to determine if the container is
956      * visible.
957      */
hasContentToDisplay()958     boolean hasContentToDisplay() {
959         for (int i = mChildren.size() - 1; i >= 0; --i) {
960             final WindowContainer wc = mChildren.get(i);
961             if (wc.hasContentToDisplay()) {
962                 return true;
963             }
964         }
965         return false;
966     }
967 
968     /**
969      * Returns true if the container or one of its children is considered visible from the
970      * WindowManager perspective which usually means valid surface and some other internal state
971      * are true.
972      *
973      * NOTE: While this method will return true if the surface is visible, it doesn't mean the
974      * client has actually displayed any content. Use {@link #hasContentToDisplay()} to determine if
975      * the container has any content to display.
976      */
isVisible()977     boolean isVisible() {
978         // TODO: Will this be more correct if it checks the visibility of its parents?
979         // It depends...For example, Tasks and Stacks are only visible if there children are visible
980         // but, WindowState are not visible if there parent are not visible. Maybe have the
981         // container specify which direction to traverse for visibility?
982         for (int i = mChildren.size() - 1; i >= 0; --i) {
983             final WindowContainer wc = mChildren.get(i);
984             if (wc.isVisible()) {
985                 return true;
986             }
987         }
988         return false;
989     }
990 
991     /**
992      * Called when the visibility of a child is asked to change. This is before visibility actually
993      * changes (eg. a transition animation might play out first).
994      */
onChildVisibilityRequested(boolean visible)995     void onChildVisibilityRequested(boolean visible) {
996         // If we are changing visibility, then a snapshot isn't necessary and we are no-longer
997         // part of a change transition.
998         mSurfaceFreezer.unfreeze(getSyncTransaction());
999         if (mDisplayContent != null) {
1000             mDisplayContent.mChangingContainers.remove(this);
1001         }
1002         WindowContainer parent = getParent();
1003         if (parent != null) {
1004             parent.onChildVisibilityRequested(visible);
1005         }
1006     }
1007 
writeIdentifierToProto(ProtoOutputStream proto, long fieldId)1008     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
1009         final long token = proto.start(fieldId);
1010         proto.write(HASH_CODE, System.identityHashCode(this));
1011         proto.write(USER_ID, USER_NULL);
1012         proto.write(TITLE, "WindowContainer");
1013         proto.end(token);
1014     }
1015 
1016     /**
1017      * Returns {@code true} if this container is focusable. Generally, if a parent is not focusable,
1018      * this will not be focusable either.
1019      */
isFocusable()1020     boolean isFocusable() {
1021         final WindowContainer parent = getParent();
1022         return (parent == null || parent.isFocusable()) && mIsFocusable;
1023     }
1024 
1025     /** Set whether this container or its children can be focusable */
setFocusable(boolean focusable)1026     boolean setFocusable(boolean focusable) {
1027         if (mIsFocusable == focusable) {
1028             return false;
1029         }
1030         mIsFocusable = focusable;
1031         return true;
1032     }
1033 
1034     /**
1035      * @return Whether this child is on top of the window hierarchy.
1036      */
isOnTop()1037     boolean isOnTop() {
1038         final WindowContainer parent = getParent();
1039         return parent != null && parent.getTopChild() == this && parent.isOnTop();
1040     }
1041 
1042     /** Returns the top child container. */
getTopChild()1043     E getTopChild() {
1044         return mChildren.peekLast();
1045     }
1046 
1047     /**
1048      * Removes the containers which were deferred.
1049      *
1050      * @return {@code true} if there is still a removal being deferred.
1051      */
handleCompleteDeferredRemoval()1052     boolean handleCompleteDeferredRemoval() {
1053         boolean stillDeferringRemoval = false;
1054 
1055         for (int i = mChildren.size() - 1; i >= 0; --i) {
1056             final WindowContainer wc = mChildren.get(i);
1057             stillDeferringRemoval |= wc.handleCompleteDeferredRemoval();
1058             if (!hasChild()) {
1059                 // All child containers of current level could be removed from a removal of
1060                 // descendant. E.g. if a display is pending to be removed because it contains an
1061                 // activity with {@link ActivityRecord#mIsExiting} is true, the display may be
1062                 // removed when completing the removal of the last activity from
1063                 // {@link ActivityRecord#checkCompleteDeferredRemoval}.
1064                 return false;
1065             }
1066         }
1067 
1068         return stillDeferringRemoval;
1069     }
1070 
1071     /** Checks if all windows in an app are all drawn and shows them if needed. */
checkAppWindowsReadyToShow()1072     void checkAppWindowsReadyToShow() {
1073         for (int i = mChildren.size() - 1; i >= 0; --i) {
1074             final WindowContainer wc = mChildren.get(i);
1075             wc.checkAppWindowsReadyToShow();
1076         }
1077     }
1078 
onAppTransitionDone()1079     void onAppTransitionDone() {
1080         for (int i = mChildren.size() - 1; i >= 0; --i) {
1081             final WindowContainer wc = mChildren.get(i);
1082             wc.onAppTransitionDone();
1083         }
1084     }
1085 
1086     /**
1087      * Called when this container or one of its descendants changed its requested orientation, and
1088      * wants this container to handle it or pass it to its parent.
1089      *
1090      * @param freezeDisplayToken freeze this app window token if display needs to freeze
1091      * @param requestingContainer the container which orientation request has changed
1092      * @return {@code true} if handled; {@code false} otherwise.
1093      */
onDescendantOrientationChanged(@ullable IBinder freezeDisplayToken, @Nullable ConfigurationContainer requestingContainer)1094     boolean onDescendantOrientationChanged(@Nullable IBinder freezeDisplayToken,
1095             @Nullable ConfigurationContainer requestingContainer) {
1096         final WindowContainer parent = getParent();
1097         if (parent == null) {
1098             return false;
1099         }
1100         return parent.onDescendantOrientationChanged(freezeDisplayToken,
1101                 requestingContainer);
1102     }
1103 
1104     /**
1105      * Check if this container or its parent will handle orientation changes from descendants. It's
1106      * different from the return value of {@link #onDescendantOrientationChanged(IBinder,
1107      * ConfigurationContainer)} in the sense that the return value of this method tells if this
1108      * container or its parent will handle the request eventually, while the return value of the
1109      * other method is if it handled the request synchronously.
1110      *
1111      * @return {@code true} if it handles or will handle orientation change in the future; {@code
1112      *         false} if it won't handle the change at anytime.
1113      */
handlesOrientationChangeFromDescendant()1114     boolean handlesOrientationChangeFromDescendant() {
1115         final WindowContainer parent = getParent();
1116         return parent != null && parent.handlesOrientationChangeFromDescendant();
1117     }
1118 
1119     /**
1120      * Get the configuration orientation by the requested screen orientation
1121      * ({@link ActivityInfo.ScreenOrientation}) of this activity.
1122      *
1123      * @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE},
1124      *         {@link Configuration#ORIENTATION_PORTRAIT},
1125      *         {@link Configuration#ORIENTATION_UNDEFINED}).
1126      */
getRequestedConfigurationOrientation()1127     int getRequestedConfigurationOrientation() {
1128         if (mOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
1129             // NOSENSOR means the display's "natural" orientation, so return that.
1130             if (mDisplayContent != null) {
1131                 return mDisplayContent.getNaturalOrientation();
1132             }
1133         } else if (mOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
1134             // LOCKED means the activity's orientation remains unchanged, so return existing value.
1135             return getConfiguration().orientation;
1136         } else if (isFixedOrientationLandscape(mOrientation)) {
1137             return ORIENTATION_LANDSCAPE;
1138         } else if (isFixedOrientationPortrait(mOrientation)) {
1139             return ORIENTATION_PORTRAIT;
1140         }
1141         return ORIENTATION_UNDEFINED;
1142     }
1143 
1144     /**
1145      * Calls {@link #setOrientation(int, IBinder, ActivityRecord)} with {@code null} to the last 2
1146      * parameters.
1147      *
1148      * @param orientation the specified orientation.
1149      */
setOrientation(int orientation)1150     void setOrientation(int orientation) {
1151         setOrientation(orientation, null /* freezeDisplayToken */,
1152                 null /* ActivityRecord */);
1153     }
1154 
1155     /**
1156      * Sets the specified orientation of this container. It percolates this change upward along the
1157      * hierarchy to let each level of the hierarchy a chance to respond to it.
1158      *
1159      * @param orientation the specified orientation. Needs to be one of {@link
1160      *      android.content.pm.ActivityInfo.ScreenOrientation}.
1161      * @param freezeDisplayToken uses this token to freeze display if orientation change is not
1162      *                           done. Display will not be frozen if this is {@code null}, which
1163      *                           should only happen in tests.
1164      * @param requestingContainer the container which orientation request has changed. Mostly used
1165      *                            to ensure it gets correct configuration.
1166      */
setOrientation(int orientation, @Nullable IBinder freezeDisplayToken, @Nullable ConfigurationContainer requestingContainer)1167     void setOrientation(int orientation, @Nullable IBinder freezeDisplayToken,
1168             @Nullable ConfigurationContainer requestingContainer) {
1169         if (mOrientation == orientation) {
1170             return;
1171         }
1172 
1173         mOrientation = orientation;
1174         final WindowContainer parent = getParent();
1175         if (parent != null) {
1176             if (getConfiguration().orientation != getRequestedConfigurationOrientation()) {
1177                 // Resolve the requested orientation.
1178                 onConfigurationChanged(parent.getConfiguration());
1179             }
1180             onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
1181         }
1182     }
1183 
1184     @ActivityInfo.ScreenOrientation
getOrientation()1185     int getOrientation() {
1186         return getOrientation(mOrientation);
1187     }
1188 
1189     /**
1190      * Returns the specified orientation for this window container or one of its children is there
1191      * is one set, or {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSET} if no
1192      * specification is set.
1193      * NOTE: {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} is a
1194      * specification...
1195      *
1196      * @param candidate The current orientation candidate that will be returned if we don't find a
1197      *                  better match.
1198      * @return The orientation as specified by this branch or the window hierarchy.
1199      */
getOrientation(int candidate)1200     int getOrientation(int candidate) {
1201         mLastOrientationSource = null;
1202         if (!fillsParent()) {
1203             // Ignore containers that don't completely fill their parents.
1204             return SCREEN_ORIENTATION_UNSET;
1205         }
1206 
1207         // The container fills its parent so we can use it orientation if it has one
1208         // specified; otherwise we prefer to use the orientation of its topmost child that has one
1209         // specified and fall back on this container's unset or unspecified value as a candidate
1210         // if none of the children have a better candidate for the orientation.
1211         if (mOrientation != SCREEN_ORIENTATION_UNSET
1212                 && mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
1213             mLastOrientationSource = this;
1214             return mOrientation;
1215         }
1216 
1217         for (int i = mChildren.size() - 1; i >= 0; --i) {
1218             final WindowContainer wc = mChildren.get(i);
1219 
1220             // TODO: Maybe mOrientation should default to SCREEN_ORIENTATION_UNSET vs.
1221             // SCREEN_ORIENTATION_UNSPECIFIED?
1222             final int orientation = wc.getOrientation(candidate == SCREEN_ORIENTATION_BEHIND
1223                     ? SCREEN_ORIENTATION_BEHIND : SCREEN_ORIENTATION_UNSET);
1224             if (orientation == SCREEN_ORIENTATION_BEHIND) {
1225                 // container wants us to use the orientation of the container behind it. See if we
1226                 // can find one. Else return SCREEN_ORIENTATION_BEHIND so the caller can choose to
1227                 // look behind this container.
1228                 candidate = orientation;
1229                 mLastOrientationSource = wc;
1230                 continue;
1231             }
1232 
1233             if (orientation == SCREEN_ORIENTATION_UNSET) {
1234                 continue;
1235             }
1236 
1237             if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
1238                 // Use the orientation if the container fills its parent or requested an explicit
1239                 // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED.
1240                 ProtoLog.v(WM_DEBUG_ORIENTATION, "%s is requesting orientation %d (%s)",
1241                         wc.toString(), orientation,
1242                         ActivityInfo.screenOrientationToString(orientation));
1243                 mLastOrientationSource = wc;
1244                 return orientation;
1245             }
1246         }
1247 
1248         return candidate;
1249     }
1250 
1251     /**
1252      * @return The deepest source which decides the orientation of this window container since the
1253      *         last time {@link #getOrientation(int) was called.
1254      */
1255     @Nullable
getLastOrientationSource()1256     WindowContainer getLastOrientationSource() {
1257         final WindowContainer source = mLastOrientationSource;
1258         if (source != null && source != this) {
1259             final WindowContainer nextSource = source.getLastOrientationSource();
1260             if (nextSource != null) {
1261                 return nextSource;
1262             }
1263         }
1264         return source;
1265     }
1266 
1267     /**
1268      * Returns true if this container is opaque and fills all the space made available by its parent
1269      * container.
1270      *
1271      * NOTE: It is possible for this container to occupy more space than the parent has (or less),
1272      * this is just a signal from the client to window manager stating its intent, but not what it
1273      * actually does.
1274      */
fillsParent()1275     boolean fillsParent() {
1276         return false;
1277     }
1278 
1279     // TODO: Users would have their own window containers under the display container?
switchUser(int userId)1280     void switchUser(int userId) {
1281         for (int i = mChildren.size() - 1; i >= 0; --i) {
1282             mChildren.get(i).switchUser(userId);
1283         }
1284     }
1285 
showToCurrentUser()1286     boolean showToCurrentUser() {
1287         return true;
1288     }
1289 
1290     /**
1291      * For all windows at or below this container call the callback.
1292      * @param   callback Calls the {@link ToBooleanFunction#apply} method for each window found and
1293      *                   stops the search if {@link ToBooleanFunction#apply} returns true.
1294      * @param   traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of
1295      *                              z-order, else from bottom-to-top.
1296      * @return  True if the search ended before we reached the end of the hierarchy due to
1297      *          {@link ToBooleanFunction#apply} returning true.
1298      */
forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)1299     boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
1300         if (traverseTopToBottom) {
1301             for (int i = mChildren.size() - 1; i >= 0; --i) {
1302                 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
1303                     return true;
1304                 }
1305             }
1306         } else {
1307             final int count = mChildren.size();
1308             for (int i = 0; i < count; i++) {
1309                 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
1310                     return true;
1311                 }
1312             }
1313         }
1314         return false;
1315     }
1316 
forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom)1317     void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) {
1318         ForAllWindowsConsumerWrapper wrapper = obtainConsumerWrapper(callback);
1319         forAllWindows(wrapper, traverseTopToBottom);
1320         wrapper.release();
1321     }
1322 
forAllActivities(Function<ActivityRecord, Boolean> callback)1323     boolean forAllActivities(Function<ActivityRecord, Boolean> callback) {
1324         return forAllActivities(callback, true /*traverseTopToBottom*/);
1325     }
1326 
forAllActivities( Function<ActivityRecord, Boolean> callback, boolean traverseTopToBottom)1327     boolean forAllActivities(
1328             Function<ActivityRecord, Boolean> callback, boolean traverseTopToBottom) {
1329         if (traverseTopToBottom) {
1330             for (int i = mChildren.size() - 1; i >= 0; --i) {
1331                 if (mChildren.get(i).forAllActivities(callback, traverseTopToBottom)) return true;
1332             }
1333         } else {
1334             final int count = mChildren.size();
1335             for (int i = 0; i < count; i++) {
1336                 if (mChildren.get(i).forAllActivities(callback, traverseTopToBottom)) return true;
1337             }
1338         }
1339 
1340         return false;
1341     }
1342 
forAllActivities(Consumer<ActivityRecord> callback)1343     void forAllActivities(Consumer<ActivityRecord> callback) {
1344         forAllActivities(callback, true /*traverseTopToBottom*/);
1345     }
1346 
forAllActivities(Consumer<ActivityRecord> callback, boolean traverseTopToBottom)1347     void forAllActivities(Consumer<ActivityRecord> callback, boolean traverseTopToBottom) {
1348         if (traverseTopToBottom) {
1349             for (int i = mChildren.size() - 1; i >= 0; --i) {
1350                 mChildren.get(i).forAllActivities(callback, traverseTopToBottom);
1351             }
1352         } else {
1353             final int count = mChildren.size();
1354             for (int i = 0; i < count; i++) {
1355                 mChildren.get(i).forAllActivities(callback, traverseTopToBottom);
1356             }
1357         }
1358     }
1359 
1360     /**
1361      * Process all activities in this branch of the tree.
1362      *
1363      * @param callback Called for each activity found.
1364      * @param boundary We don't return activities via {@param callback} until we get to this node in
1365      *                 the tree.
1366      * @param includeBoundary If the boundary from be processed to return activities.
1367      * @param traverseTopToBottom direction to traverse the tree.
1368      * @return {@code true} if we ended the search before reaching the end of the tree.
1369      */
forAllActivities(Function<ActivityRecord, Boolean> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom)1370     final boolean forAllActivities(Function<ActivityRecord, Boolean> callback,
1371             WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom) {
1372         return forAllActivities(
1373                 callback, boundary, includeBoundary, traverseTopToBottom, new boolean[1]);
1374     }
1375 
forAllActivities(Function<ActivityRecord, Boolean> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound)1376     private boolean forAllActivities(Function<ActivityRecord, Boolean> callback,
1377             WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
1378             boolean[] boundaryFound) {
1379         if (traverseTopToBottom) {
1380             for (int i = mChildren.size() - 1; i >= 0; --i) {
1381                 if (processForAllActivitiesWithBoundary(callback, boundary, includeBoundary,
1382                         traverseTopToBottom, boundaryFound, mChildren.get(i))) {
1383                     return true;
1384                 }
1385             }
1386         } else {
1387             final int count = mChildren.size();
1388             for (int i = 0; i < count; i++) {
1389                 if (processForAllActivitiesWithBoundary(callback, boundary, includeBoundary,
1390                         traverseTopToBottom, boundaryFound, mChildren.get(i))) {
1391                     return true;
1392                 }
1393             }
1394         }
1395 
1396         return false;
1397     }
1398 
processForAllActivitiesWithBoundary(Function<ActivityRecord, Boolean> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound, WindowContainer wc)1399     private boolean processForAllActivitiesWithBoundary(Function<ActivityRecord, Boolean> callback,
1400             WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
1401             boolean[] boundaryFound, WindowContainer wc) {
1402         if (wc == boundary) {
1403             boundaryFound[0] = true;
1404             if (!includeBoundary) return false;
1405         }
1406 
1407         if (boundaryFound[0]) {
1408             return wc.forAllActivities(callback, traverseTopToBottom);
1409         }
1410 
1411         return wc.forAllActivities(
1412                 callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound);
1413     }
1414 
1415     /** @return {@code true} if this node or any of its children contains an activity. */
hasActivity()1416     boolean hasActivity() {
1417         for (int i = mChildren.size() - 1; i >= 0; --i) {
1418             if (mChildren.get(i).hasActivity()) {
1419                 return true;
1420             }
1421         }
1422         return false;
1423     }
1424 
getActivity(Predicate<ActivityRecord> callback)1425     ActivityRecord getActivity(Predicate<ActivityRecord> callback) {
1426         return getActivity(callback, true /*traverseTopToBottom*/);
1427     }
1428 
getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom)1429     ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom) {
1430         return getActivity(callback, traverseTopToBottom, null /*boundary*/);
1431     }
1432 
getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom, ActivityRecord boundary)1433     ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom,
1434             ActivityRecord boundary) {
1435         if (traverseTopToBottom) {
1436             for (int i = mChildren.size() - 1; i >= 0; --i) {
1437                 final WindowContainer wc = mChildren.get(i);
1438                 // TODO(b/156986561): Improve the correctness of the boundary check.
1439                 if (wc == boundary) return boundary;
1440 
1441                 final ActivityRecord r = wc.getActivity(callback, traverseTopToBottom, boundary);
1442                 if (r != null) {
1443                     return r;
1444                 }
1445             }
1446         } else {
1447             final int count = mChildren.size();
1448             for (int i = 0; i < count; i++) {
1449                 final WindowContainer wc = mChildren.get(i);
1450                 // TODO(b/156986561): Improve the correctness of the boundary check.
1451                 if (wc == boundary) return boundary;
1452 
1453                 final ActivityRecord r = wc.getActivity(callback, traverseTopToBottom, boundary);
1454                 if (r != null) {
1455                     return r;
1456                 }
1457             }
1458         }
1459 
1460         return null;
1461     }
1462 
1463     /**
1464      * Gets an activity in a branch of the tree.
1465      *
1466      * @param callback called to test if this is the activity that should be returned.
1467      * @param boundary We don't return activities via {@param callback} until we get to this node in
1468      *                 the tree.
1469      * @param includeBoundary If the boundary from be processed to return activities.
1470      * @param traverseTopToBottom direction to traverse the tree.
1471      * @return The activity if found or null.
1472      */
getActivity(Predicate<ActivityRecord> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom)1473     final ActivityRecord getActivity(Predicate<ActivityRecord> callback,
1474             WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom) {
1475         return getActivity(
1476                 callback, boundary, includeBoundary, traverseTopToBottom, new boolean[1]);
1477     }
1478 
getActivity(Predicate<ActivityRecord> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound)1479     private ActivityRecord getActivity(Predicate<ActivityRecord> callback,
1480             WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
1481             boolean[] boundaryFound) {
1482         if (traverseTopToBottom) {
1483             for (int i = mChildren.size() - 1; i >= 0; --i) {
1484                 final ActivityRecord r = processGetActivityWithBoundary(callback, boundary,
1485                         includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i));
1486                 if (r != null) {
1487                     return r;
1488                 }
1489             }
1490         } else {
1491             final int count = mChildren.size();
1492             for (int i = 0; i < count; i++) {
1493                 final ActivityRecord r = processGetActivityWithBoundary(callback, boundary,
1494                         includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i));
1495                 if (r != null) {
1496                     return r;
1497                 }
1498             }
1499         }
1500 
1501         return null;
1502     }
1503 
processGetActivityWithBoundary(Predicate<ActivityRecord> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound, WindowContainer wc)1504     private ActivityRecord processGetActivityWithBoundary(Predicate<ActivityRecord> callback,
1505             WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
1506             boolean[] boundaryFound, WindowContainer wc) {
1507         if (wc == boundary || boundary == null) {
1508             boundaryFound[0] = true;
1509             if (!includeBoundary) return null;
1510         }
1511 
1512         if (boundaryFound[0]) {
1513             return wc.getActivity(callback, traverseTopToBottom);
1514         }
1515 
1516         return wc.getActivity(
1517                 callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound);
1518     }
1519 
getActivityAbove(ActivityRecord r)1520     ActivityRecord getActivityAbove(ActivityRecord r) {
1521         return getActivity((above) -> true, r,
1522                 false /*includeBoundary*/, false /*traverseTopToBottom*/);
1523     }
1524 
getActivityBelow(ActivityRecord r)1525     ActivityRecord getActivityBelow(ActivityRecord r) {
1526         return getActivity((below) -> true, r,
1527                 false /*includeBoundary*/, true /*traverseTopToBottom*/);
1528     }
1529 
getBottomMostActivity()1530     ActivityRecord getBottomMostActivity() {
1531         return getActivity((r) -> true, false /*traverseTopToBottom*/);
1532     }
1533 
getTopMostActivity()1534     ActivityRecord getTopMostActivity() {
1535         return getActivity((r) -> true, true /*traverseTopToBottom*/);
1536     }
1537 
getTopActivity(boolean includeFinishing, boolean includeOverlays)1538     ActivityRecord getTopActivity(boolean includeFinishing, boolean includeOverlays) {
1539         // Break down into 4 calls to avoid object creation due to capturing input params.
1540         if (includeFinishing) {
1541             if (includeOverlays) {
1542                 return getActivity((r) -> true);
1543             }
1544             return getActivity((r) -> !r.isTaskOverlay());
1545         } else if (includeOverlays) {
1546             return getActivity((r) -> !r.finishing);
1547         }
1548 
1549         return getActivity((r) -> !r.finishing && !r.isTaskOverlay());
1550     }
1551 
forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback)1552     void forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback) {
1553         for (int i = mChildren.size() - 1; i >= 0; --i) {
1554             mChildren.get(i).forAllWallpaperWindows(callback);
1555         }
1556     }
1557 
1558     /**
1559      * For all tasks at or below this container call the callback.
1560      *
1561      * @param callback Calls the {@link ToBooleanFunction#apply} method for each task found and
1562      *                 stops the search if {@link ToBooleanFunction#apply} returns {@code true}.
1563      */
forAllTasks(Function<Task, Boolean> callback)1564     boolean forAllTasks(Function<Task, Boolean> callback) {
1565         for (int i = mChildren.size() - 1; i >= 0; --i) {
1566             if (mChildren.get(i).forAllTasks(callback)) {
1567                 return true;
1568             }
1569         }
1570         return false;
1571     }
1572 
forAllLeafTasks(Function<Task, Boolean> callback)1573     boolean forAllLeafTasks(Function<Task, Boolean> callback) {
1574         for (int i = mChildren.size() - 1; i >= 0; --i) {
1575             if (mChildren.get(i).forAllLeafTasks(callback)) {
1576                 return true;
1577             }
1578         }
1579         return false;
1580     }
1581 
1582     /**
1583      * For all tasks at or below this container call the callback.
1584      *
1585      * @param callback Callback to be called for every task.
1586      */
forAllTasks(Consumer<Task> callback)1587     void forAllTasks(Consumer<Task> callback) {
1588         forAllTasks(callback, true /*traverseTopToBottom*/);
1589     }
1590 
forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom)1591     void forAllTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
1592         final int count = mChildren.size();
1593         if (traverseTopToBottom) {
1594             for (int i = count - 1; i >= 0; --i) {
1595                 mChildren.get(i).forAllTasks(callback, traverseTopToBottom);
1596             }
1597         } else {
1598             for (int i = 0; i < count; i++) {
1599                 mChildren.get(i).forAllTasks(callback, traverseTopToBottom);
1600             }
1601         }
1602     }
1603 
forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom)1604     void forAllLeafTasks(Consumer<Task> callback, boolean traverseTopToBottom) {
1605         final int count = mChildren.size();
1606         if (traverseTopToBottom) {
1607             for (int i = count - 1; i >= 0; --i) {
1608                 mChildren.get(i).forAllLeafTasks(callback, traverseTopToBottom);
1609             }
1610         } else {
1611             for (int i = 0; i < count; i++) {
1612                 mChildren.get(i).forAllLeafTasks(callback, traverseTopToBottom);
1613             }
1614         }
1615     }
1616 
getTaskAbove(Task t)1617     Task getTaskAbove(Task t) {
1618         return getTask(
1619                 (above) -> true, t, false /*includeBoundary*/, false /*traverseTopToBottom*/);
1620     }
1621 
getTaskBelow(Task t)1622     Task getTaskBelow(Task t) {
1623         return getTask((below) -> true, t, false /*includeBoundary*/, true /*traverseTopToBottom*/);
1624     }
1625 
getBottomMostTask()1626     Task getBottomMostTask() {
1627         return getTask((t) -> true, false /*traverseTopToBottom*/);
1628     }
1629 
getTopMostTask()1630     Task getTopMostTask() {
1631         return getTask((t) -> true, true /*traverseTopToBottom*/);
1632     }
1633 
getTask(Predicate<Task> callback)1634     Task getTask(Predicate<Task> callback) {
1635         return getTask(callback, true /*traverseTopToBottom*/);
1636     }
1637 
getTask(Predicate<Task> callback, boolean traverseTopToBottom)1638     Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) {
1639         if (traverseTopToBottom) {
1640             for (int i = mChildren.size() - 1; i >= 0; --i) {
1641                 final Task t = mChildren.get(i).getTask(callback, traverseTopToBottom);
1642                 if (t != null) {
1643                     return t;
1644                 }
1645             }
1646         } else {
1647             final int count = mChildren.size();
1648             for (int i = 0; i < count; i++) {
1649                 final Task t = mChildren.get(i).getTask(callback, traverseTopToBottom);
1650                 if (t != null) {
1651                     return t;
1652                 }
1653             }
1654         }
1655 
1656         return null;
1657     }
1658 
1659     /**
1660      * Gets an task in a branch of the tree.
1661      *
1662      * @param callback called to test if this is the task that should be returned.
1663      * @param boundary We don't return tasks via {@param callback} until we get to this node in
1664      *                 the tree.
1665      * @param includeBoundary If the boundary from be processed to return tasks.
1666      * @param traverseTopToBottom direction to traverse the tree.
1667      * @return The task if found or null.
1668      */
getTask(Predicate<Task> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom)1669     final Task getTask(Predicate<Task> callback, WindowContainer boundary, boolean includeBoundary,
1670             boolean traverseTopToBottom) {
1671         return getTask(callback, boundary, includeBoundary, traverseTopToBottom, new boolean[1]);
1672     }
1673 
getTask(Predicate<Task> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound)1674     private Task getTask(Predicate<Task> callback,
1675             WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
1676             boolean[] boundaryFound) {
1677         if (traverseTopToBottom) {
1678             for (int i = mChildren.size() - 1; i >= 0; --i) {
1679                 final Task t = processGetTaskWithBoundary(callback, boundary,
1680                         includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i));
1681                 if (t != null) {
1682                     return t;
1683                 }
1684             }
1685         } else {
1686             final int count = mChildren.size();
1687             for (int i = 0; i < count; i++) {
1688                 final Task t = processGetTaskWithBoundary(callback, boundary,
1689                         includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i));
1690                 if (t != null) {
1691                     return t;
1692                 }
1693             }
1694         }
1695 
1696         return null;
1697     }
1698 
processGetTaskWithBoundary(Predicate<Task> callback, WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom, boolean[] boundaryFound, WindowContainer wc)1699     private Task processGetTaskWithBoundary(Predicate<Task> callback,
1700             WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
1701             boolean[] boundaryFound, WindowContainer wc) {
1702         if (wc == boundary || boundary == null) {
1703             boundaryFound[0] = true;
1704             if (!includeBoundary) return null;
1705         }
1706 
1707         if (boundaryFound[0]) {
1708             return wc.getTask(callback, traverseTopToBottom);
1709         }
1710 
1711         return wc.getTask(
1712                 callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound);
1713     }
1714 
getWindow(Predicate<WindowState> callback)1715     WindowState getWindow(Predicate<WindowState> callback) {
1716         for (int i = mChildren.size() - 1; i >= 0; --i) {
1717             final WindowState w = mChildren.get(i).getWindow(callback);
1718             if (w != null) {
1719                 return w;
1720             }
1721         }
1722 
1723         return null;
1724     }
1725 
forAllDisplayAreas(Consumer<DisplayArea> callback)1726     void forAllDisplayAreas(Consumer<DisplayArea> callback) {
1727         for (int i = mChildren.size() - 1; i >= 0; --i) {
1728             mChildren.get(i).forAllDisplayAreas(callback);
1729         }
1730     }
1731 
1732     /**
1733      * Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than
1734      * the input container in terms of z-order.
1735      */
1736     @Override
compareTo(WindowContainer other)1737     public int compareTo(WindowContainer other) {
1738         if (this == other) {
1739             return 0;
1740         }
1741 
1742         if (mParent != null && mParent == other.mParent) {
1743             final WindowList<WindowContainer> list = mParent.mChildren;
1744             return list.indexOf(this) > list.indexOf(other) ? 1 : -1;
1745         }
1746 
1747         final LinkedList<WindowContainer> thisParentChain = mTmpChain1;
1748         final LinkedList<WindowContainer> otherParentChain = mTmpChain2;
1749         try {
1750             getParents(thisParentChain);
1751             other.getParents(otherParentChain);
1752 
1753             // Find the common ancestor of both containers.
1754             WindowContainer commonAncestor = null;
1755             WindowContainer thisTop = thisParentChain.peekLast();
1756             WindowContainer otherTop = otherParentChain.peekLast();
1757             while (thisTop != null && otherTop != null && thisTop == otherTop) {
1758                 commonAncestor = thisParentChain.removeLast();
1759                 otherParentChain.removeLast();
1760                 thisTop = thisParentChain.peekLast();
1761                 otherTop = otherParentChain.peekLast();
1762             }
1763 
1764             // Containers don't belong to the same hierarchy???
1765             if (commonAncestor == null) {
1766                 throw new IllegalArgumentException("No in the same hierarchy this="
1767                         + thisParentChain + " other=" + otherParentChain);
1768             }
1769 
1770             // Children are always considered greater than their parents, so if one of the containers
1771             // we are comparing it the parent of the other then whichever is the child is greater.
1772             if (commonAncestor == this) {
1773                 return -1;
1774             } else if (commonAncestor == other) {
1775                 return 1;
1776             }
1777 
1778             // The position of the first non-common ancestor in the common ancestor list determines
1779             // which is greater the which.
1780             final WindowList<WindowContainer> list = commonAncestor.mChildren;
1781             return list.indexOf(thisParentChain.peekLast()) > list.indexOf(otherParentChain.peekLast())
1782                     ? 1 : -1;
1783         } finally {
1784             mTmpChain1.clear();
1785             mTmpChain2.clear();
1786         }
1787     }
1788 
getParents(LinkedList<WindowContainer> parents)1789     private void getParents(LinkedList<WindowContainer> parents) {
1790         parents.clear();
1791         WindowContainer current = this;
1792         do {
1793             parents.addLast(current);
1794             current = current.mParent;
1795         } while (current != null);
1796     }
1797 
makeSurface()1798     SurfaceControl.Builder makeSurface() {
1799         final WindowContainer p = getParent();
1800         return p.makeChildSurface(this);
1801     }
1802 
1803     /**
1804      * @param child The WindowContainer this child surface is for, or null if the Surface
1805      *              is not assosciated with a WindowContainer (e.g. a surface used for Dimming).
1806      */
makeChildSurface(WindowContainer child)1807     SurfaceControl.Builder makeChildSurface(WindowContainer child) {
1808         final WindowContainer p = getParent();
1809         // Give the parent a chance to set properties. In hierarchy v1 we rely
1810         // on this to set full-screen dimensions on all our Surface-less Layers.
1811         return p.makeChildSurface(child)
1812                 .setParent(mSurfaceControl);
1813     }
1814     /*
1815      * @return The SurfaceControl parent for this containers SurfaceControl.
1816      *         The SurfaceControl must be valid if non-null.
1817      */
1818     @Override
getParentSurfaceControl()1819     public SurfaceControl getParentSurfaceControl() {
1820         final WindowContainer parent = getParent();
1821         if (parent == null) {
1822             return null;
1823         }
1824         return parent.getSurfaceControl();
1825     }
1826 
1827     /**
1828      * @return Whether this WindowContainer should be magnified by the accessibility magnifier.
1829      */
shouldMagnify()1830     boolean shouldMagnify() {
1831         if (mSurfaceControl == null) {
1832             return false;
1833         }
1834 
1835         for (int i = 0; i < mChildren.size(); i++) {
1836             if (!mChildren.get(i).shouldMagnify()) {
1837                 return false;
1838             }
1839         }
1840         return true;
1841     }
1842 
getSession()1843     SurfaceSession getSession() {
1844         if (getParent() != null) {
1845             return getParent().getSession();
1846         }
1847         return null;
1848     }
1849 
assignLayer(Transaction t, int layer)1850     void assignLayer(Transaction t, int layer) {
1851         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
1852         if (mSurfaceControl != null && changed) {
1853             setLayer(t, layer);
1854             mLastLayer = layer;
1855             mLastRelativeToLayer = null;
1856         }
1857     }
1858 
assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer)1859     void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
1860         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
1861         if (mSurfaceControl != null && changed) {
1862             setRelativeLayer(t, relativeTo, layer);
1863             mLastLayer = layer;
1864             mLastRelativeToLayer = relativeTo;
1865         }
1866     }
1867 
setLayer(Transaction t, int layer)1868     protected void setLayer(Transaction t, int layer) {
1869 
1870         // Route through surface animator to accommodate that our surface control might be
1871         // attached to the leash, and leash is attached to parent container.
1872         mSurfaceAnimator.setLayer(t, layer);
1873     }
1874 
setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer)1875     protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
1876 
1877         // Route through surface animator to accommodate that our surface control might be
1878         // attached to the leash, and leash is attached to parent container.
1879         mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer);
1880     }
1881 
reparentSurfaceControl(Transaction t, SurfaceControl newParent)1882     protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
1883         mSurfaceAnimator.reparent(t, newParent);
1884     }
1885 
assignChildLayers(Transaction t)1886     void assignChildLayers(Transaction t) {
1887         int layer = 0;
1888 
1889         // We use two passes as a way to promote children which
1890         // need Z-boosting to the end of the list.
1891         for (int j = 0; j < mChildren.size(); ++j) {
1892             final WindowContainer wc = mChildren.get(j);
1893             wc.assignChildLayers(t);
1894             if (!wc.needsZBoost()) {
1895                 wc.assignLayer(t, layer++);
1896             }
1897         }
1898         for (int j = 0; j < mChildren.size(); ++j) {
1899             final WindowContainer wc = mChildren.get(j);
1900             if (wc.needsZBoost()) {
1901                 wc.assignLayer(t, layer++);
1902             }
1903         }
1904     }
1905 
assignChildLayers()1906     void assignChildLayers() {
1907         assignChildLayers(getSyncTransaction());
1908         scheduleAnimation();
1909     }
1910 
needsZBoost()1911     boolean needsZBoost() {
1912         if (mNeedsZBoost) return true;
1913         for (int i = 0; i < mChildren.size(); i++) {
1914             if (mChildren.get(i).needsZBoost()) {
1915                 return true;
1916             }
1917         }
1918         return false;
1919     }
1920 
1921     /**
1922      * Write to a protocol buffer output stream. Protocol buffer message definition is at
1923      * {@link com.android.server.wm.WindowContainerProto}.
1924      *
1925      * @param proto     Stream to write the WindowContainer object to.
1926      * @param fieldId   Field Id of the WindowContainer as defined in the parent message.
1927      * @param logLevel  Determines the amount of data to be written to the Protobuf.
1928      * @hide
1929      */
1930     @CallSuper
1931     @Override
dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)1932     public void dumpDebug(ProtoOutputStream proto, long fieldId,
1933             @WindowTraceLogLevel int logLevel) {
1934         boolean isVisible = isVisible();
1935         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible) {
1936             return;
1937         }
1938 
1939         final long token = proto.start(fieldId);
1940         super.dumpDebug(proto, CONFIGURATION_CONTAINER, logLevel);
1941         proto.write(ORIENTATION, mOrientation);
1942         proto.write(VISIBLE, isVisible);
1943         if (mSurfaceAnimator.isAnimating()) {
1944             mSurfaceAnimator.dumpDebug(proto, SURFACE_ANIMATOR);
1945         }
1946 
1947         // add children to proto
1948         for (int i = 0; i < getChildCount(); i++) {
1949             final long childToken = proto.start(WindowContainerProto.CHILDREN);
1950             final E child = getChildAt(i);
1951             child.dumpDebug(proto, child.getProtoFieldId(), logLevel);
1952             proto.end(childToken);
1953         }
1954         proto.end(token);
1955     }
1956 
1957     /**
1958      * @return a proto field id to identify where to add the derived class to the generic window
1959      * container proto.
1960      */
getProtoFieldId()1961     long getProtoFieldId() {
1962         return WINDOW_CONTAINER;
1963     }
1964 
obtainConsumerWrapper(Consumer<WindowState> consumer)1965     private ForAllWindowsConsumerWrapper obtainConsumerWrapper(Consumer<WindowState> consumer) {
1966         ForAllWindowsConsumerWrapper wrapper = mConsumerWrapperPool.acquire();
1967         if (wrapper == null) {
1968             wrapper = new ForAllWindowsConsumerWrapper();
1969         }
1970         wrapper.setConsumer(consumer);
1971         return wrapper;
1972     }
1973 
1974     private final class ForAllWindowsConsumerWrapper implements ToBooleanFunction<WindowState> {
1975 
1976         private Consumer<WindowState> mConsumer;
1977 
setConsumer(Consumer<WindowState> consumer)1978         void setConsumer(Consumer<WindowState> consumer) {
1979             mConsumer = consumer;
1980         }
1981 
1982         @Override
apply(WindowState w)1983         public boolean apply(WindowState w) {
1984             mConsumer.accept(w);
1985             return false;
1986         }
1987 
release()1988         void release() {
1989             mConsumer = null;
1990             mConsumerWrapperPool.release(this);
1991         }
1992     }
1993 
1994     // TODO(b/68336570): Should this really be on WindowContainer since it
1995     // can only be used on the top-level nodes that aren't animated?
1996     // (otherwise we would be fighting other callers of setMatrix).
applyMagnificationSpec(Transaction t, MagnificationSpec spec)1997     void applyMagnificationSpec(Transaction t, MagnificationSpec spec) {
1998         if (shouldMagnify()) {
1999             t.setMatrix(mSurfaceControl, spec.scale, 0, 0, spec.scale)
2000                     .setPosition(mSurfaceControl, spec.offsetX, spec.offsetY);
2001             mLastMagnificationSpec = spec;
2002         } else {
2003             clearMagnificationSpec(t);
2004             for (int i = 0; i < mChildren.size(); i++) {
2005                 mChildren.get(i).applyMagnificationSpec(t, spec);
2006             }
2007         }
2008     }
2009 
clearMagnificationSpec(Transaction t)2010     void clearMagnificationSpec(Transaction t) {
2011         if (mLastMagnificationSpec != null) {
2012             t.setMatrix(mSurfaceControl, 1, 0, 0, 1)
2013                 .setPosition(mSurfaceControl, 0, 0);
2014         }
2015         mLastMagnificationSpec = null;
2016         for (int i = 0; i < mChildren.size(); i++) {
2017             mChildren.get(i).clearMagnificationSpec(t);
2018         }
2019     }
2020 
prepareSurfaces()2021     void prepareSurfaces() {
2022         // If a leash has been set when the transaction was committed, then the leash reparent has
2023         // been committed.
2024         mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash();
2025         for (int i = 0; i < mChildren.size(); i++) {
2026             mChildren.get(i).prepareSurfaces();
2027         }
2028     }
2029 
2030     /**
2031      * @return true if the reparent to animation leash transaction has been committed, false
2032      * otherwise.
2033      */
hasCommittedReparentToAnimationLeash()2034     boolean hasCommittedReparentToAnimationLeash() {
2035         return mCommittedReparentToAnimationLeash;
2036     }
2037 
2038     /**
2039      * Trigger a call to prepareSurfaces from the animation thread, such that pending transactions
2040      * will be applied.
2041      */
scheduleAnimation()2042     void scheduleAnimation() {
2043         if (mParent != null) {
2044             mParent.scheduleAnimation();
2045         }
2046     }
2047 
2048     /**
2049      * @return The SurfaceControl for this container.
2050      *         The SurfaceControl must be valid if non-null.
2051      */
2052     @Override
getSurfaceControl()2053     public SurfaceControl getSurfaceControl() {
2054         return mSurfaceControl;
2055     }
2056 
2057     /**
2058      * Use this method instead of {@link #getPendingTransaction()} if the Transaction should be
2059      * synchronized with the client.
2060      *
2061      * @return {@link #mBLASTSyncTransaction} if available. Otherwise, returns
2062      * {@link #getPendingTransaction()}
2063      */
getSyncTransaction()2064     public Transaction getSyncTransaction() {
2065         if (mUsingBLASTSyncTransaction) {
2066             return mBLASTSyncTransaction;
2067         }
2068 
2069         return getPendingTransaction();
2070     }
2071 
2072     @Override
getPendingTransaction()2073     public Transaction getPendingTransaction() {
2074         final DisplayContent displayContent = getDisplayContent();
2075         if (displayContent != null && displayContent != this) {
2076             return displayContent.getPendingTransaction();
2077         }
2078         // This WindowContainer has not attached to a display yet or this is a DisplayContent, so we
2079         // let the caller to save the surface operations within the local mPendingTransaction.
2080         // If this is not a DisplayContent, we will merge it to the pending transaction of its
2081         // display once it attaches to it.
2082         return mPendingTransaction;
2083     }
2084 
2085     /**
2086      * Starts an animation on the container.
2087      *
2088      * @param anim The animation to run.
2089      * @param hidden Whether our container is currently hidden. TODO This should use isVisible at
2090      *               some point but the meaning is too weird to work for all containers.
2091      * @param type The type of animation defined as {@link AnimationType}.
2092      * @param animationFinishedCallback The callback being triggered when the animation finishes.
2093      */
startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, @AnimationType int type, @Nullable OnAnimationFinishedCallback animationFinishedCallback)2094     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
2095             @AnimationType int type,
2096             @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
2097         if (DEBUG_ANIM) {
2098             Slog.v(TAG, "Starting animation on " + this + ": type=" + type + ", anim=" + anim);
2099         }
2100 
2101         // TODO: This should use isVisible() but because isVisible has a really weird meaning at
2102         // the moment this doesn't work for all animatable window containers.
2103         mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
2104                 mSurfaceFreezer);
2105     }
2106 
startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, @AnimationType int type)2107     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
2108             @AnimationType int type) {
2109         startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */);
2110     }
2111 
transferAnimation(WindowContainer from)2112     void transferAnimation(WindowContainer from) {
2113         mSurfaceAnimator.transferAnimation(from.mSurfaceAnimator);
2114     }
2115 
cancelAnimation()2116     void cancelAnimation() {
2117         doAnimationFinished(mSurfaceAnimator.getAnimationType(), mSurfaceAnimator.getAnimation());
2118         mSurfaceAnimator.cancelAnimation();
2119         mSurfaceFreezer.unfreeze(getPendingTransaction());
2120     }
2121 
getAnimationSources()2122     ArraySet<WindowContainer> getAnimationSources() {
2123         return mSurfaceAnimationSources;
2124     }
2125 
2126     @Override
getFreezeSnapshotTarget()2127     public SurfaceControl getFreezeSnapshotTarget() {
2128         return null;
2129     }
2130 
2131     @Override
makeAnimationLeash()2132     public Builder makeAnimationLeash() {
2133         return makeSurface().setContainerLayer();
2134     }
2135 
2136     @Override
getAnimationLeashParent()2137     public SurfaceControl getAnimationLeashParent() {
2138         return getParentSurfaceControl();
2139     }
2140 
2141     /**
2142      * @return The layer on which all app animations are happening.
2143      */
getAppAnimationLayer(@nimationLayer int animationLayer)2144     SurfaceControl getAppAnimationLayer(@AnimationLayer int animationLayer) {
2145         final WindowContainer parent = getParent();
2146         if (parent != null) {
2147             return parent.getAppAnimationLayer(animationLayer);
2148         }
2149         return null;
2150     }
2151 
2152     // TODO: Remove this and use #getBounds() instead once we set an app transition animation
2153     // on TaskStack.
getAnimationBounds(int appStackClipMode)2154     Rect getAnimationBounds(int appStackClipMode) {
2155         return getBounds();
2156     }
2157 
2158     /** Gets the position relative to parent for animation. */
getAnimationPosition(Point outPosition)2159     void getAnimationPosition(Point outPosition) {
2160         getRelativePosition(outPosition);
2161     }
2162 
2163     /**
2164      * Applies the app transition animation according the given the layout properties in the
2165      * window hierarchy.
2166      *
2167      * @param lp The layout parameters of the window.
2168      * @param transit The app transition type indicates what kind of transition to be applied.
2169      * @param enter Whether the app transition is entering transition or not.
2170      * @param isVoiceInteraction Whether the container is participating in voice interaction or not.
2171      * @param sources {@link ActivityRecord}s which causes this app transition animation.
2172      *
2173      * @return {@code true} when the container applied the app transition, {@code false} if the
2174      *         app transition is disabled or skipped.
2175      *
2176      * @see #getAnimationAdapter
2177      */
applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources)2178     boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
2179             boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) {
2180         if (mWmService.mDisableTransitionAnimation) {
2181             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
2182                     "applyAnimation: transition animation is disabled or skipped. "
2183                             + "container=%s", this);
2184             cancelAnimation();
2185             return false;
2186         }
2187 
2188         // Only apply an animation if the display isn't frozen. If it is frozen, there is no reason
2189         // to animate and it can cause strange artifacts when we unfreeze the display if some
2190         // different animation is running.
2191         try {
2192             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation");
2193             if (okToAnimate()) {
2194                 applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
2195             } else {
2196                 cancelAnimation();
2197             }
2198         } finally {
2199             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
2200         }
2201 
2202         return isAnimating();
2203     }
2204 
2205     /**
2206      * Gets the {@link AnimationAdapter} according the given window layout properties in the window
2207      * hierarchy.
2208      *
2209      * @return The return value will always contain two elements, one for normal animations and the
2210      *         other for thumbnail animation, both can be {@code null}.
2211      *
2212      * @See com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord
2213      * @See LocalAnimationAdapter
2214      */
getAnimationAdapter(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction)2215     Pair<AnimationAdapter, AnimationAdapter> getAnimationAdapter(WindowManager.LayoutParams lp,
2216             int transit, boolean enter, boolean isVoiceInteraction) {
2217         final Pair<AnimationAdapter, AnimationAdapter> resultAdapters;
2218         final int appStackClipMode = getDisplayContent().mAppTransition.getAppStackClipMode();
2219 
2220         // Separate position and size for use in animators.
2221         final Rect screenBounds = getAnimationBounds(appStackClipMode);
2222         mTmpRect.set(screenBounds);
2223         getAnimationPosition(mTmpPoint);
2224         if (!sHierarchicalAnimations) {
2225             // Non-hierarchical animation uses position in global coordinates.
2226             mTmpPoint.set(mTmpRect.left, mTmpRect.top);
2227         }
2228         mTmpRect.offsetTo(0, 0);
2229 
2230         final RemoteAnimationController controller =
2231                 getDisplayContent().mAppTransition.getRemoteAnimationController();
2232         final boolean isChanging = AppTransition.isChangeTransit(transit) && enter
2233                 && isChangingAppTransition();
2234 
2235         // Delaying animation start isn't compatible with remote animations at all.
2236         if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) {
2237             final Rect localBounds = new Rect(mTmpRect);
2238             localBounds.offsetTo(mTmpPoint.x, mTmpPoint.y);
2239             final RemoteAnimationController.RemoteAnimationRecord adapters =
2240                     controller.createRemoteAnimationRecord(this, mTmpPoint, localBounds,
2241                             screenBounds, (isChanging ? mSurfaceFreezer.mFreezeBounds : null));
2242             resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
2243         } else if (isChanging) {
2244             final float durationScale = mWmService.getTransitionAnimationScaleLocked();
2245             final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
2246             mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);
2247 
2248             final AnimationAdapter adapter = new LocalAnimationAdapter(
2249                     new WindowChangeAnimationSpec(mSurfaceFreezer.mFreezeBounds, mTmpRect,
2250                             displayInfo, durationScale, true /* isAppAnimation */,
2251                             false /* isThumbnail */),
2252                     getSurfaceAnimationRunner());
2253 
2254             final AnimationAdapter thumbnailAdapter = mSurfaceFreezer.mSnapshot != null
2255                     ? new LocalAnimationAdapter(new WindowChangeAnimationSpec(
2256                     mSurfaceFreezer.mFreezeBounds, mTmpRect, displayInfo, durationScale,
2257                     true /* isAppAnimation */, true /* isThumbnail */), getSurfaceAnimationRunner())
2258                     : null;
2259             resultAdapters = new Pair<>(adapter, thumbnailAdapter);
2260             mTransit = transit;
2261             mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
2262         } else {
2263             mNeedsAnimationBoundsLayer = (appStackClipMode == STACK_CLIP_AFTER_ANIM);
2264             final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
2265 
2266             if (a != null) {
2267                 // Only apply corner radius to animation if we're not in multi window mode.
2268                 // We don't want rounded corners when in pip or split screen.
2269                 final float windowCornerRadius = !inMultiWindowMode()
2270                         ? getDisplayContent().getWindowCornerRadius()
2271                         : 0;
2272                 AnimationAdapter adapter = new LocalAnimationAdapter(
2273                         new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
2274                                 getDisplayContent().mAppTransition.canSkipFirstFrame(),
2275                                 appStackClipMode, true /* isAppAnimation */, windowCornerRadius),
2276                         getSurfaceAnimationRunner());
2277 
2278                 resultAdapters = new Pair<>(adapter, null);
2279                 mNeedsZBoost = a.getZAdjustment() == Animation.ZORDER_TOP
2280                         || AppTransition.isClosingTransit(transit);
2281                 mTransit = transit;
2282                 mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
2283             } else {
2284                 resultAdapters = new Pair<>(null, null);
2285             }
2286         }
2287         return resultAdapters;
2288     }
2289 
applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter, int transit, boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources)2290     protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
2291             int transit, boolean isVoiceInteraction,
2292             @Nullable ArrayList<WindowContainer> sources) {
2293         final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
2294                 transit, enter, isVoiceInteraction);
2295         AnimationAdapter adapter = adapters.first;
2296         AnimationAdapter thumbnailAdapter = adapters.second;
2297         if (adapter != null) {
2298             if (sources != null) {
2299                 mSurfaceAnimationSources.addAll(sources);
2300             }
2301             startAnimation(getPendingTransaction(), adapter, !isVisible(),
2302                     ANIMATION_TYPE_APP_TRANSITION);
2303             if (adapter.getShowWallpaper()) {
2304                 getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
2305             }
2306             if (thumbnailAdapter != null) {
2307                 mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(),
2308                         thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION, (type, anim) -> { });
2309             }
2310         }
2311     }
2312 
getSurfaceAnimationRunner()2313     final SurfaceAnimationRunner getSurfaceAnimationRunner() {
2314         return mWmService.mSurfaceAnimationRunner;
2315     }
2316 
loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction)2317     private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
2318                                     boolean isVoiceInteraction) {
2319         if (isOrganized()) {
2320             // Defer to the task organizer to run animations
2321             return null;
2322         }
2323 
2324         final DisplayContent displayContent = getDisplayContent();
2325         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
2326         final int width = displayInfo.appWidth;
2327         final int height = displayInfo.appHeight;
2328         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: container=%s", this);
2329 
2330         // Determine the visible rect to calculate the thumbnail clip with
2331         // getAnimationFrames.
2332         final Rect frame = new Rect(0, 0, width, height);
2333         final Rect displayFrame = new Rect(0, 0,
2334                 displayInfo.logicalWidth, displayInfo.logicalHeight);
2335         final Rect insets = new Rect();
2336         final Rect stableInsets = new Rect();
2337         final Rect surfaceInsets = new Rect();
2338         getAnimationFrames(frame, insets, stableInsets, surfaceInsets);
2339 
2340         if (mLaunchTaskBehind) {
2341             // Differentiate the two animations. This one which is briefly on the screen
2342             // gets the !enter animation, and the other one which remains on the
2343             // screen gets the enter animation. Both appear in the mOpeningApps set.
2344             enter = false;
2345         }
2346         ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
2347                 "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s "
2348                         + "surfaceInsets=%s",
2349                 AppTransition.appTransitionToString(transit), enter, frame, insets, surfaceInsets);
2350         final Configuration displayConfig = displayContent.getConfiguration();
2351         final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter,
2352                 displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
2353                 surfaceInsets, stableInsets, isVoiceInteraction, inFreeformWindowingMode(), this);
2354         if (a != null) {
2355             if (a != null) {
2356                 // Setup the maximum app transition duration to prevent malicious app may set a long
2357                 // animation duration or infinite repeat counts for the app transition through
2358                 // ActivityOption#makeCustomAnimation or WindowManager#overridePendingTransition.
2359                 a.restrictDuration(MAX_APP_TRANSITION_DURATION);
2360             }
2361             if (DEBUG_ANIM) {
2362                 logWithStack(TAG, "Loaded animation " + a + " for " + this
2363                         + ", duration: " + ((a != null) ? a.getDuration() : 0));
2364             }
2365             final int containingWidth = frame.width();
2366             final int containingHeight = frame.height();
2367             a.initialize(containingWidth, containingHeight, width, height);
2368             a.scaleCurrentDuration(mWmService.getTransitionAnimationScaleLocked());
2369         }
2370         return a;
2371     }
2372 
createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record)2373     RemoteAnimationTarget createRemoteAnimationTarget(
2374             RemoteAnimationController.RemoteAnimationRecord record) {
2375         return null;
2376     }
2377 
canCreateRemoteAnimationTarget()2378     boolean canCreateRemoteAnimationTarget() {
2379         return false;
2380     }
2381 
okToDisplay()2382     boolean okToDisplay() {
2383         final DisplayContent dc = getDisplayContent();
2384         return dc != null && dc.okToDisplay();
2385     }
2386 
okToAnimate()2387     boolean okToAnimate() {
2388         return okToAnimate(false /* ignoreFrozen */);
2389     }
2390 
okToAnimate(boolean ignoreFrozen)2391     boolean okToAnimate(boolean ignoreFrozen) {
2392         final DisplayContent dc = getDisplayContent();
2393         return dc != null && dc.okToAnimate(ignoreFrozen);
2394     }
2395 
2396     @Override
commitPendingTransaction()2397     public void commitPendingTransaction() {
2398         scheduleAnimation();
2399     }
2400 
reassignLayer(Transaction t)2401     void reassignLayer(Transaction t) {
2402         final WindowContainer parent = getParent();
2403         if (parent != null) {
2404             parent.assignChildLayers(t);
2405         }
2406     }
2407 
resetSurfacePositionForAnimationLeash(Transaction t)2408     void resetSurfacePositionForAnimationLeash(Transaction t) {
2409         t.setPosition(mSurfaceControl, 0, 0);
2410         mLastSurfacePosition.set(0, 0);
2411     }
2412 
2413     @Override
onAnimationLeashCreated(Transaction t, SurfaceControl leash)2414     public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
2415         mLastLayer = -1;
2416         reassignLayer(t);
2417 
2418         // Leash is now responsible for position, so set our position to 0.
2419         resetSurfacePositionForAnimationLeash(t);
2420     }
2421 
2422     @Override
onAnimationLeashLost(Transaction t)2423     public void onAnimationLeashLost(Transaction t) {
2424         mLastLayer = -1;
2425         mSurfaceFreezer.unfreeze(t);
2426         reassignLayer(t);
2427         updateSurfacePosition(t);
2428     }
2429 
doAnimationFinished(@nimationType int type, AnimationAdapter anim)2430     private void doAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
2431         for (int i = 0; i < mSurfaceAnimationSources.size(); ++i) {
2432             mSurfaceAnimationSources.valueAt(i).onAnimationFinished(type, anim);
2433         }
2434         mSurfaceAnimationSources.clear();
2435     }
2436 
2437     /**
2438      * Called when an animation has finished running.
2439      */
onAnimationFinished(@nimationType int type, AnimationAdapter anim)2440     protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
2441         doAnimationFinished(type, anim);
2442         mWmService.onAnimationFinished();
2443         mNeedsZBoost = false;
2444     }
2445 
2446     /**
2447      * @return The currently running animation, if any, or {@code null} otherwise.
2448      */
getAnimation()2449     AnimationAdapter getAnimation() {
2450         return mSurfaceAnimator.getAnimation();
2451     }
2452 
2453     /**
2454      * @return The {@link WindowContainer} which is running an animation.
2455      *
2456      * By default this only checks if this container itself is actually running an animation, but
2457      * you can extend the check target over its relatives, or relax the condition so that this can
2458      * return {@code WindowContainer} if an animation starts soon by giving a combination
2459      * of {@link AnimationFlags}.
2460      *
2461      * Note that you can give a combination of bitmask flags to specify targets and condition for
2462      * checking animating status.
2463      * e.g. {@code isAnimating(TRANSITION | PARENT)} returns {@code true} if either this
2464      * container itself or one of its parents is running an animation or waiting for an app
2465      * transition.
2466      *
2467      * Note that TRANSITION propagates to parents and children as well.
2468      *
2469      * @param flags The combination of bitmask flags to specify targets and condition for
2470      *              checking animating status.
2471      * @param typesToCheck The combination of bitmask {@link AnimationType} to compare when
2472      *                     determining if animating.
2473      *
2474      * @see AnimationFlags#TRANSITION
2475      * @see AnimationFlags#PARENTS
2476      * @see AnimationFlags#CHILDREN
2477      */
2478     @Nullable
getAnimatingContainer(int flags, int typesToCheck)2479     WindowContainer getAnimatingContainer(int flags, int typesToCheck) {
2480         if (isSelfAnimating(flags, typesToCheck)) {
2481             return this;
2482         }
2483         if ((flags & PARENTS) != 0) {
2484             WindowContainer parent = getParent();
2485             while (parent != null) {
2486                 if (parent.isSelfAnimating(flags, typesToCheck)) {
2487                     return parent;
2488                 }
2489                 parent = parent.getParent();
2490             }
2491         }
2492         if ((flags & CHILDREN) != 0) {
2493             for (int i = 0; i < mChildren.size(); ++i) {
2494                 final WindowContainer wc = mChildren.get(i).getAnimatingContainer(
2495                         flags & ~PARENTS, typesToCheck);
2496                 if (wc != null) {
2497                     return wc;
2498                 }
2499             }
2500         }
2501         return null;
2502     }
2503 
2504     /**
2505      * Internal method only to be used during {@link #getAnimatingContainer(int, int)}.DO NOT CALL
2506      * FROM OUTSIDE.
2507      */
isSelfAnimating(int flags, int typesToCheck)2508     protected boolean isSelfAnimating(int flags, int typesToCheck) {
2509         if (mSurfaceAnimator.isAnimating()
2510                 && (mSurfaceAnimator.getAnimationType() & typesToCheck) > 0) {
2511             return true;
2512         }
2513         if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) {
2514             return true;
2515         }
2516         return false;
2517     }
2518 
2519     /**
2520      * @deprecated Use {@link #getAnimatingContainer(int, int)} instead.
2521      */
2522     @Nullable
2523     @Deprecated
getAnimatingContainer()2524     final WindowContainer getAnimatingContainer() {
2525         return getAnimatingContainer(PARENTS, ANIMATION_TYPE_ALL);
2526     }
2527 
2528     /**
2529      * @see SurfaceAnimator#startDelayingAnimationStart
2530      */
startDelayingAnimationStart()2531     void startDelayingAnimationStart() {
2532         mSurfaceAnimator.startDelayingAnimationStart();
2533     }
2534 
2535     /**
2536      * @see SurfaceAnimator#endDelayingAnimationStart
2537      */
endDelayingAnimationStart()2538     void endDelayingAnimationStart() {
2539         mSurfaceAnimator.endDelayingAnimationStart();
2540     }
2541 
2542     @Override
getSurfaceWidth()2543     public int getSurfaceWidth() {
2544         return mSurfaceControl.getWidth();
2545     }
2546 
2547     @Override
getSurfaceHeight()2548     public int getSurfaceHeight() {
2549         return mSurfaceControl.getHeight();
2550     }
2551 
2552     @CallSuper
dump(PrintWriter pw, String prefix, boolean dumpAll)2553     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
2554         if (mSurfaceAnimator.isAnimating()) {
2555             pw.print(prefix); pw.println("ContainerAnimator:");
2556             mSurfaceAnimator.dump(pw, prefix + "  ");
2557         }
2558         if (mLastOrientationSource != null) {
2559             pw.println(prefix + "mLastOrientationSource=" + mLastOrientationSource);
2560         }
2561     }
2562 
updateSurfacePosition()2563     final void updateSurfacePosition() {
2564         updateSurfacePosition(getSyncTransaction());
2565     }
2566 
updateSurfacePosition(Transaction t)2567     void updateSurfacePosition(Transaction t) {
2568         // Avoid fighting with the organizer over Surface position.
2569         if (isOrganized()) return;
2570 
2571         if (mSurfaceControl == null || mSurfaceAnimator.hasLeash()) {
2572             return;
2573         }
2574 
2575         getRelativePosition(mTmpPos);
2576         if (mTmpPos.equals(mLastSurfacePosition)) {
2577             return;
2578         }
2579 
2580         t.setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y);
2581         mLastSurfacePosition.set(mTmpPos.x, mTmpPos.y);
2582     }
2583 
2584     @VisibleForTesting
getLastSurfacePosition()2585     Point getLastSurfacePosition() {
2586         return mLastSurfacePosition;
2587     }
2588 
2589     /**
2590      * The {@code outFrame} retrieved by this method specifies where the animation will finish
2591      * the entrance animation, as the next frame will display the window at these coordinates. In
2592      * case of exit animation, this is where the animation will start, as the frame before the
2593      * animation is displaying the window at these bounds.
2594      *
2595      * @param outFrame The bounds where entrance animation finishes or exit animation starts.
2596      * @param outInsets Insets that are covered by system windows.
2597      * @param outStableInsets Insets that determine the area covered by the stable system windows.
2598      * @param outSurfaceInsets Positive insets between the drawing surface and window content.
2599      */
getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, Rect outSurfaceInsets)2600     void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
2601             Rect outSurfaceInsets) {
2602         final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
2603         outFrame.set(0, 0, displayInfo.appWidth, displayInfo.appHeight);
2604         outInsets.setEmpty();
2605         outStableInsets.setEmpty();
2606         outSurfaceInsets.setEmpty();
2607     }
2608 
getRelativePosition(Point outPos)2609     void getRelativePosition(Point outPos) {
2610         // In addition to updateSurfacePosition, we keep other code that sets
2611         // position from fighting with the organizer
2612         if (isOrganized()) {
2613             outPos.set(0, 0);
2614             return;
2615         }
2616 
2617         final Rect dispBounds = getBounds();
2618         outPos.set(dispBounds.left, dispBounds.top);
2619         final WindowContainer parent = getParent();
2620         if (parent != null) {
2621             final Rect parentBounds = parent.getBounds();
2622             outPos.offset(-parentBounds.left, -parentBounds.top);
2623         }
2624     }
2625 
waitForAllWindowsDrawn()2626     void waitForAllWindowsDrawn() {
2627         forAllWindows(w -> {
2628             w.requestDrawIfNeeded(mWaitingForDrawn);
2629         }, true /* traverseTopToBottom */);
2630     }
2631 
getDimmer()2632     Dimmer getDimmer() {
2633         if (mParent == null) {
2634             return null;
2635         }
2636         return mParent.getDimmer();
2637     }
2638 
setSurfaceControl(SurfaceControl sc)2639     void setSurfaceControl(SurfaceControl sc) {
2640         mSurfaceControl = sc;
2641     }
2642 
getRemoteAnimationDefinition()2643     RemoteAnimationDefinition getRemoteAnimationDefinition() {
2644         return null;
2645     }
2646 
2647     /** Cheap way of doing cast and instanceof. */
asTask()2648     Task asTask() {
2649         return null;
2650     }
2651 
2652     /** Cheap way of doing cast and instanceof. */
asActivityRecord()2653     ActivityRecord asActivityRecord() {
2654         return null;
2655     }
2656 
2657     /**
2658      * @return {@code true} if window container is manage by a
2659      *          {@link android.window.WindowOrganizer}
2660      */
isOrganized()2661     boolean isOrganized() {
2662         return false;
2663     }
2664 
fromBinder(IBinder binder)2665     static WindowContainer fromBinder(IBinder binder) {
2666         return RemoteToken.fromBinder(binder).getContainer();
2667     }
2668 
2669     static class RemoteToken extends IWindowContainerToken.Stub {
2670 
2671         final WeakReference<WindowContainer> mWeakRef;
2672         private WindowContainerToken mWindowContainerToken;
2673 
RemoteToken(WindowContainer container)2674         RemoteToken(WindowContainer container) {
2675             mWeakRef = new WeakReference<>(container);
2676         }
2677 
getContainer()2678         WindowContainer getContainer() {
2679             return mWeakRef.get();
2680         }
2681 
fromBinder(IBinder binder)2682         static RemoteToken fromBinder(IBinder binder) {
2683             return (RemoteToken) binder;
2684         }
2685 
toWindowContainerToken()2686         WindowContainerToken toWindowContainerToken() {
2687             if (mWindowContainerToken == null) {
2688                 mWindowContainerToken = new WindowContainerToken(this);
2689             }
2690             return mWindowContainerToken;
2691         }
2692 
2693         @Override
toString()2694         public String toString() {
2695             StringBuilder sb = new StringBuilder(128);
2696             sb.append("RemoteToken{");
2697             sb.append(Integer.toHexString(System.identityHashCode(this)));
2698             sb.append(' ');
2699             sb.append(mWeakRef.get());
2700             sb.append('}');
2701             return sb.toString();
2702         }
2703     }
2704 
2705     @Override
onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady)2706     public void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady) {
2707         if (mWaitingListener == null) {
2708             return;
2709         }
2710 
2711         windowContainersReady.add(this);
2712         mWaitingListener.onTransactionReady(mWaitingSyncId, windowContainersReady);
2713 
2714         mWaitingListener = null;
2715         mWaitingSyncId = -1;
2716     }
2717 
2718     /**
2719      * Returns true if any of the children elected to participate in the Sync
2720      */
addChildrenToSyncSet(int localId)2721     boolean addChildrenToSyncSet(int localId) {
2722         boolean willSync = false;
2723 
2724         for (int i = 0; i < mChildren.size(); i++) {
2725             final WindowContainer child = mChildren.get(i);
2726             willSync |= mBLASTSyncEngine.addToSyncSet(localId, child);
2727         }
2728         return willSync;
2729     }
2730 
setPendingListener(BLASTSyncEngine.TransactionReadyListener waitingListener, int waitingId)2731     boolean setPendingListener(BLASTSyncEngine.TransactionReadyListener waitingListener,
2732         int waitingId) {
2733         // If we are invisible, no need to sync, likewise if we are already engaged in a sync,
2734         // we can't support overlapping syncs on a single container yet.
2735         if (!isVisible() || mWaitingListener != null) {
2736             return false;
2737         }
2738         mUsingBLASTSyncTransaction = true;
2739 
2740         // Make sure to set these before we call setReady in case the sync was a no-op
2741         mWaitingSyncId = waitingId;
2742         mWaitingListener = waitingListener;
2743         return true;
2744     }
2745 
prepareForSync(BLASTSyncEngine.TransactionReadyListener waitingListener, int waitingId)2746     boolean prepareForSync(BLASTSyncEngine.TransactionReadyListener waitingListener,
2747             int waitingId) {
2748         boolean willSync = setPendingListener(waitingListener, waitingId);
2749         if (!willSync) {
2750             return false;
2751         }
2752 
2753         int localId = mBLASTSyncEngine.startSyncSet(this);
2754         willSync |= addChildrenToSyncSet(localId);
2755         mBLASTSyncEngine.setReady(localId);
2756 
2757         return willSync;
2758     }
2759 
useBLASTSync()2760     boolean useBLASTSync() {
2761         return mUsingBLASTSyncTransaction;
2762     }
2763 
mergeBlastSyncTransaction(Transaction t)2764     void mergeBlastSyncTransaction(Transaction t) {
2765         t.merge(mBLASTSyncTransaction);
2766         mUsingBLASTSyncTransaction = false;
2767     }
2768 }
2769