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