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