1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.server.wm;
18 
19 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
22 import static android.view.SurfaceControl.Transaction;
23 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
24 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
25 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
26 import static com.android.server.wm.WindowContainerProto.CONFIGURATION_CONTAINER;
27 import static com.android.server.wm.WindowContainerProto.ORIENTATION;
28 import static com.android.server.wm.WindowContainerProto.SURFACE_ANIMATOR;
29 import static com.android.server.wm.WindowContainerProto.VISIBLE;
30 
31 import android.annotation.CallSuper;
32 import android.annotation.IntDef;
33 import android.app.WindowConfiguration;
34 import android.content.res.Configuration;
35 import android.graphics.Point;
36 import android.graphics.Rect;
37 import android.util.Pools;
38 import android.util.Slog;
39 import android.util.proto.ProtoOutputStream;
40 import android.view.MagnificationSpec;
41 import android.view.SurfaceControl;
42 import android.view.SurfaceControl.Builder;
43 import android.view.SurfaceSession;
44 
45 import com.android.internal.util.ToBooleanFunction;
46 import com.android.server.wm.SurfaceAnimator.Animatable;
47 
48 import java.io.PrintWriter;
49 import java.util.Comparator;
50 import java.util.LinkedList;
51 import java.util.function.Consumer;
52 import java.util.function.Predicate;
53 
54 /**
55  * Defines common functionality for classes that can hold windows directly or through their
56  * children in a hierarchy form.
57  * The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
58  * changes are made to this class.
59  */
60 class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
61         implements Comparable<WindowContainer>, Animatable {
62 
63     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM;
64 
65     /** Animation layer that happens above all animating {@link TaskStack}s. */
66     static final int ANIMATION_LAYER_STANDARD = 0;
67 
68     /** Animation layer that happens above all {@link TaskStack}s. */
69     static final int ANIMATION_LAYER_BOOSTED = 1;
70 
71     /**
72      * Animation layer that is reserved for {@link WindowConfiguration#ACTIVITY_TYPE_HOME}
73      * activities that happens below all {@link TaskStack}s.
74      */
75     static final int ANIMATION_LAYER_HOME = 2;
76 
77     @IntDef(prefix = { "ANIMATION_LAYER_" }, value = {
78             ANIMATION_LAYER_STANDARD,
79             ANIMATION_LAYER_BOOSTED,
80             ANIMATION_LAYER_HOME,
81     })
82     @interface AnimationLayer {}
83 
84     static final int POSITION_TOP = Integer.MAX_VALUE;
85     static final int POSITION_BOTTOM = Integer.MIN_VALUE;
86 
87     /**
88      * The parent of this window container.
89      * For removing or setting new parent {@link #setParent} should be used, because it also
90      * performs configuration updates based on new parent's settings.
91      */
92     private WindowContainer<WindowContainer> mParent = null;
93 
94     // List of children for this window container. List is in z-order as the children appear on
95     // screen with the top-most window container at the tail of the list.
96     protected final WindowList<E> mChildren = new WindowList<E>();
97 
98     // The specified orientation for this window container.
99     protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
100 
101     private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool =
102             new Pools.SynchronizedPool<>(3);
103 
104     // The owner/creator for this container. No controller if null.
105     WindowContainerController mController;
106 
107     protected SurfaceControl mSurfaceControl;
108     private int mLastLayer = 0;
109     private SurfaceControl mLastRelativeToLayer = null;
110 
111     /**
112      * Applied as part of the animation pass in "prepareSurfaces".
113      */
114     protected final Transaction mPendingTransaction;
115     protected final SurfaceAnimator mSurfaceAnimator;
116     protected final WindowManagerService mService;
117 
118     private final Point mTmpPos = new Point();
119     protected final Point mLastSurfacePosition = new Point();
120 
121     /** Total number of elements in this subtree, including our own hierarchy element. */
122     private int mTreeWeight = 1;
123 
124     /**
125      * Indicates whether we are animating and have committed the transaction to reparent our
126      * surface to the animation leash
127      */
128     private boolean mCommittedReparentToAnimationLeash;
129 
WindowContainer(WindowManagerService service)130     WindowContainer(WindowManagerService service) {
131         mService = service;
132         mPendingTransaction = service.mTransactionFactory.make();
133         mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
134     }
135 
136     @Override
getParent()137     final protected WindowContainer getParent() {
138         return mParent;
139     }
140 
141     @Override
getChildCount()142     protected int getChildCount() {
143         return mChildren.size();
144     }
145 
146     @Override
getChildAt(int index)147     protected E getChildAt(int index) {
148         return mChildren.get(index);
149     }
150 
151     @Override
onConfigurationChanged(Configuration newParentConfig)152     public void onConfigurationChanged(Configuration newParentConfig) {
153         super.onConfigurationChanged(newParentConfig);
154         updateSurfacePosition();
155         scheduleAnimation();
156     }
157 
setParent(WindowContainer<WindowContainer> parent)158     final protected void setParent(WindowContainer<WindowContainer> parent) {
159         mParent = parent;
160         // Removing parent usually means that we've detached this entity to destroy it or to attach
161         // to another parent. In both cases we don't need to update the configuration now.
162         if (mParent != null) {
163             // Update full configuration of this container and all its children.
164             onConfigurationChanged(mParent.getConfiguration());
165             // Update merged override configuration of this container and all its children.
166             onMergedOverrideConfigurationChanged();
167         }
168 
169         onParentSet();
170     }
171 
172     /**
173      * Callback that is triggered when @link WindowContainer#setParent(WindowContainer)} was called.
174      * Supposed to be overridden and contain actions that should be executed after parent was set.
175      */
onParentSet()176     void onParentSet() {
177         if (mParent == null) {
178             return;
179         }
180 
181         if (mSurfaceControl == null) {
182             // If we don't yet have a surface, but we now have a parent, we should
183             // build a surface.
184             mSurfaceControl = makeSurface().build();
185             getPendingTransaction().show(mSurfaceControl);
186             updateSurfacePosition();
187         } else {
188             // If we have a surface but a new parent, we just need to perform a reparent. Go through
189             // surface animator such that hierarchy is preserved when animating, i.e.
190             // mSurfaceControl stays attached to the leash and we just reparent the leash to the
191             // new parent.
192             reparentSurfaceControl(getPendingTransaction(), mParent.mSurfaceControl);
193         }
194 
195         // Either way we need to ask the parent to assign us a Z-order.
196         mParent.assignChildLayers();
197         scheduleAnimation();
198     }
199 
200     // Temp. holders for a chain of containers we are currently processing.
201     private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList<>();
202     private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList<>();
203 
204     /**
205      * Adds the input window container has a child of this container in order based on the input
206      * comparator.
207      * @param child The window container to add as a child of this window container.
208      * @param comparator Comparator to use in determining the position the child should be added to.
209      *                   If null, the child will be added to the top.
210      */
211     @CallSuper
addChild(E child, Comparator<E> comparator)212     protected void addChild(E child, Comparator<E> comparator) {
213         if (child.getParent() != null) {
214             throw new IllegalArgumentException("addChild: container=" + child.getName()
215                     + " is already a child of container=" + child.getParent().getName()
216                     + " can't add to container=" + getName());
217         }
218 
219         int positionToAdd = -1;
220         if (comparator != null) {
221             final int count = mChildren.size();
222             for (int i = 0; i < count; i++) {
223                 if (comparator.compare(child, mChildren.get(i)) < 0) {
224                     positionToAdd = i;
225                     break;
226                 }
227             }
228         }
229 
230         if (positionToAdd == -1) {
231             mChildren.add(child);
232         } else {
233             mChildren.add(positionToAdd, child);
234         }
235         onChildAdded(child);
236 
237         // Set the parent after we've actually added a child in case a subclass depends on this.
238         child.setParent(this);
239     }
240 
241     /** Adds the input window container has a child of this container at the input index. */
242     @CallSuper
addChild(E child, int index)243     void addChild(E child, int index) {
244         if (child.getParent() != null) {
245             throw new IllegalArgumentException("addChild: container=" + child.getName()
246                     + " is already a child of container=" + child.getParent().getName()
247                     + " can't add to container=" + getName());
248         }
249         mChildren.add(index, child);
250         onChildAdded(child);
251 
252         // Set the parent after we've actually added a child in case a subclass depends on this.
253         child.setParent(this);
254     }
255 
onChildAdded(WindowContainer child)256     private void onChildAdded(WindowContainer child) {
257         mTreeWeight += child.mTreeWeight;
258         WindowContainer parent = getParent();
259         while (parent != null) {
260             parent.mTreeWeight += child.mTreeWeight;
261             parent = parent.getParent();
262         }
263     }
264 
265     /**
266      * Removes the input child container from this container which is its parent.
267      *
268      * @return True if the container did contain the input child and it was detached.
269      */
270     @CallSuper
removeChild(E child)271     void removeChild(E child) {
272         if (mChildren.remove(child)) {
273             onChildRemoved(child);
274             child.setParent(null);
275         } else {
276             throw new IllegalArgumentException("removeChild: container=" + child.getName()
277                     + " is not a child of container=" + getName());
278         }
279     }
280 
onChildRemoved(WindowContainer child)281     private void onChildRemoved(WindowContainer child) {
282         mTreeWeight -= child.mTreeWeight;
283         WindowContainer parent = getParent();
284         while (parent != null) {
285             parent.mTreeWeight -= child.mTreeWeight;
286             parent = parent.getParent();
287         }
288     }
289 
290     /**
291      * Removes this window container and its children with no regard for what else might be going on
292      * in the system. For example, the container will be removed during animation if this method is
293      * called which isn't desirable. For most cases you want to call {@link #removeIfPossible()}
294      * which allows the system to defer removal until a suitable time.
295      */
296     @CallSuper
removeImmediately()297     void removeImmediately() {
298         while (!mChildren.isEmpty()) {
299             final E child = mChildren.peekLast();
300             child.removeImmediately();
301             // Need to do this after calling remove on the child because the child might try to
302             // remove/detach itself from its parent which will cause an exception if we remove
303             // it before calling remove on the child.
304             if (mChildren.remove(child)) {
305                 onChildRemoved(child);
306             }
307         }
308 
309         if (mSurfaceControl != null) {
310             mPendingTransaction.destroy(mSurfaceControl);
311 
312             // Merge to parent transaction to ensure the transactions on this WindowContainer are
313             // applied in native even if WindowContainer is removed.
314             if (mParent != null) {
315                 mParent.getPendingTransaction().merge(mPendingTransaction);
316             }
317 
318             mSurfaceControl = null;
319             scheduleAnimation();
320         }
321 
322         if (mParent != null) {
323             mParent.removeChild(this);
324         }
325 
326         if (mController != null) {
327             setController(null);
328         }
329 
330     }
331 
332     /**
333      * @return The index of this element in the hierarchy tree in prefix order.
334      */
getPrefixOrderIndex()335     int getPrefixOrderIndex() {
336         if (mParent == null) {
337             return 0;
338         }
339         return mParent.getPrefixOrderIndex(this);
340     }
341 
getPrefixOrderIndex(WindowContainer child)342     private int getPrefixOrderIndex(WindowContainer child) {
343         int order = 0;
344         for (int i = 0; i < mChildren.size(); i++) {
345             final WindowContainer childI = mChildren.get(i);
346             if (child == childI) {
347                 break;
348             }
349             order += childI.mTreeWeight;
350         }
351         if (mParent != null) {
352             order += mParent.getPrefixOrderIndex(this);
353         }
354 
355         // We also need to count ourselves.
356         order++;
357         return order;
358     }
359 
360     /**
361      * Removes this window container and its children taking care not to remove them during a
362      * critical stage in the system. For example, some containers will not be removed during
363      * animation if this method is called.
364      */
365     // TODO: figure-out implementation that works best for this.
366     // E.g. when do we remove from parent list? maybe not...
removeIfPossible()367     void removeIfPossible() {
368         for (int i = mChildren.size() - 1; i >= 0; --i) {
369             final WindowContainer wc = mChildren.get(i);
370             wc.removeIfPossible();
371         }
372     }
373 
374     /** Returns true if this window container has the input child. */
hasChild(E child)375     boolean hasChild(E child) {
376         for (int i = mChildren.size() - 1; i >= 0; --i) {
377             final E current = mChildren.get(i);
378             if (current == child || current.hasChild(child)) {
379                 return true;
380             }
381         }
382         return false;
383     }
384 
385     /**
386      * Move a child from it's current place in siblings list to the specified position,
387      * with an option to move all its parents to top.
388      * @param position Target position to move the child to.
389      * @param child Child to move to selected position.
390      * @param includingParents Flag indicating whether we need to move the entire branch of the
391      *                         hierarchy when we're moving a child to {@link #POSITION_TOP} or
392      *                         {@link #POSITION_BOTTOM}. When moving to other intermediate positions
393      *                         this flag will do nothing.
394      */
395     @CallSuper
positionChildAt(int position, E child, boolean includingParents)396     void positionChildAt(int position, E child, boolean includingParents) {
397 
398         if (child.getParent() != this) {
399             throw new IllegalArgumentException("removeChild: container=" + child.getName()
400                     + " is not a child of container=" + getName()
401                     + " current parent=" + child.getParent());
402         }
403 
404         if ((position < 0 && position != POSITION_BOTTOM)
405                 || (position > mChildren.size() && position != POSITION_TOP)) {
406             throw new IllegalArgumentException("positionAt: invalid position=" + position
407                     + ", children number=" + mChildren.size());
408         }
409 
410         if (position >= mChildren.size() - 1) {
411             position = POSITION_TOP;
412         } else if (position == 0) {
413             position = POSITION_BOTTOM;
414         }
415 
416         switch (position) {
417             case POSITION_TOP:
418                 if (mChildren.peekLast() != child) {
419                     mChildren.remove(child);
420                     mChildren.add(child);
421                 }
422                 if (includingParents && getParent() != null) {
423                     getParent().positionChildAt(POSITION_TOP, this /* child */,
424                             true /* includingParents */);
425                 }
426                 break;
427             case POSITION_BOTTOM:
428                 if (mChildren.peekFirst() != child) {
429                     mChildren.remove(child);
430                     mChildren.addFirst(child);
431                 }
432                 if (includingParents && getParent() != null) {
433                     getParent().positionChildAt(POSITION_BOTTOM, this /* child */,
434                             true /* includingParents */);
435                 }
436                 break;
437             default:
438                 // TODO: Removing the child before reinserting requires the caller to provide a
439                 //       position that takes into account the removed child (if the index of the
440                 //       child < position, then the position should be adjusted). We should consider
441                 //       doing this adjustment here and remove any adjustments in the callers.
442                 mChildren.remove(child);
443                 mChildren.add(position, child);
444         }
445     }
446 
447     /**
448      * Update override configuration and recalculate full config.
449      * @see #mOverrideConfiguration
450      * @see #mFullConfiguration
451      */
452     @Override
onOverrideConfigurationChanged(Configuration overrideConfiguration)453     public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
454         // We must diff before the configuration is applied so that we can capture the change
455         // against the existing bounds.
456         final int diff = diffOverrideBounds(overrideConfiguration.windowConfiguration.getBounds());
457         super.onOverrideConfigurationChanged(overrideConfiguration);
458         if (mParent != null) {
459             mParent.onDescendantOverrideConfigurationChanged();
460         }
461 
462         if (diff == BOUNDS_CHANGE_NONE) {
463             return;
464         }
465 
466         if ((diff & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
467             onResize();
468         } else {
469             onMovedByResize();
470         }
471     }
472 
473     /**
474      * Notify that a descendant's overrideConfiguration has changed.
475      */
onDescendantOverrideConfigurationChanged()476     void onDescendantOverrideConfigurationChanged() {
477         if (mParent != null) {
478             mParent.onDescendantOverrideConfigurationChanged();
479         }
480     }
481 
482     /**
483      * Notify that the display this container is on has changed.
484      * @param dc The new display this container is on.
485      */
onDisplayChanged(DisplayContent dc)486     void onDisplayChanged(DisplayContent dc) {
487         for (int i = mChildren.size() - 1; i >= 0; --i) {
488             final WindowContainer child = mChildren.get(i);
489             child.onDisplayChanged(dc);
490         }
491     }
492 
setWaitingForDrawnIfResizingChanged()493     void setWaitingForDrawnIfResizingChanged() {
494         for (int i = mChildren.size() - 1; i >= 0; --i) {
495             final WindowContainer wc = mChildren.get(i);
496             wc.setWaitingForDrawnIfResizingChanged();
497         }
498     }
499 
onResize()500     void onResize() {
501         for (int i = mChildren.size() - 1; i >= 0; --i) {
502             final WindowContainer wc = mChildren.get(i);
503             wc.onParentResize();
504         }
505     }
506 
onParentResize()507     void onParentResize() {
508         // In the case this container has specified its own bounds, a parent resize will not
509         // affect its bounds. Any relevant changes will be propagated through changes to the
510         // Configuration override.
511         if (hasOverrideBounds()) {
512             return;
513         }
514 
515         // Default implementation is to treat as resize on self.
516         onResize();
517     }
518 
onMovedByResize()519     void onMovedByResize() {
520         for (int i = mChildren.size() - 1; i >= 0; --i) {
521             final WindowContainer wc = mChildren.get(i);
522             wc.onMovedByResize();
523         }
524     }
525 
resetDragResizingChangeReported()526     void resetDragResizingChangeReported() {
527         for (int i = mChildren.size() - 1; i >= 0; --i) {
528             final WindowContainer wc = mChildren.get(i);
529             wc.resetDragResizingChangeReported();
530         }
531     }
532 
forceWindowsScaleableInTransaction(boolean force)533     void forceWindowsScaleableInTransaction(boolean force) {
534         for (int i = mChildren.size() - 1; i >= 0; --i) {
535             final WindowContainer wc = mChildren.get(i);
536             wc.forceWindowsScaleableInTransaction(force);
537         }
538     }
539 
540     /**
541      * @return Whether our own container is running an animation or any child, no matter how deep in
542      *         the hierarchy, is animating.
543      */
isSelfOrChildAnimating()544     boolean isSelfOrChildAnimating() {
545         if (isSelfAnimating()) {
546             return true;
547         }
548         for (int j = mChildren.size() - 1; j >= 0; j--) {
549             final WindowContainer wc = mChildren.get(j);
550             if (wc.isSelfOrChildAnimating()) {
551                 return true;
552             }
553         }
554         return false;
555     }
556 
557     /**
558      * @return Whether our own container is running an animation or our parent is animating. This
559      *         doesn't consider whether children are animating.
560      */
isAnimating()561     boolean isAnimating() {
562 
563         // We are animating if we ourselves are animating or if our parent is animating.
564         return isSelfAnimating() || mParent != null && mParent.isAnimating();
565     }
566 
567     /**
568      * @return {@code true} if in this subtree of the hierarchy we have an {@link AppWindowToken}
569      *         that is {@link #isSelfAnimating}; {@code false} otherwise.
570      */
isAppAnimating()571     boolean isAppAnimating() {
572         for (int j = mChildren.size() - 1; j >= 0; j--) {
573             final WindowContainer wc = mChildren.get(j);
574             if (wc.isAppAnimating()) {
575                 return true;
576             }
577         }
578         return false;
579     }
580 
581     /**
582      * @return Whether our own container running an animation at the moment.
583      */
isSelfAnimating()584     boolean isSelfAnimating() {
585         return mSurfaceAnimator.isAnimating();
586     }
587 
sendAppVisibilityToClients()588     void sendAppVisibilityToClients() {
589         for (int i = mChildren.size() - 1; i >= 0; --i) {
590             final WindowContainer wc = mChildren.get(i);
591             wc.sendAppVisibilityToClients();
592         }
593     }
594 
595     /**
596      * Returns true if the container or one of its children as some content it can display or wants
597      * to display (e.g. app views or saved surface).
598      *
599      * NOTE: While this method will return true if the there is some content to display, it doesn't
600      * mean the container is visible. Use {@link #isVisible()} to determine if the container is
601      * visible.
602      */
hasContentToDisplay()603     boolean hasContentToDisplay() {
604         for (int i = mChildren.size() - 1; i >= 0; --i) {
605             final WindowContainer wc = mChildren.get(i);
606             if (wc.hasContentToDisplay()) {
607                 return true;
608             }
609         }
610         return false;
611     }
612 
613     /**
614      * Returns true if the container or one of its children is considered visible from the
615      * WindowManager perspective which usually means valid surface and some other internal state
616      * are true.
617      *
618      * NOTE: While this method will return true if the surface is visible, it doesn't mean the
619      * client has actually displayed any content. Use {@link #hasContentToDisplay()} to determine if
620      * the container has any content to display.
621      */
isVisible()622     boolean isVisible() {
623         // TODO: Will this be more correct if it checks the visibility of its parents?
624         // It depends...For example, Tasks and Stacks are only visible if there children are visible
625         // but, WindowState are not visible if there parent are not visible. Maybe have the
626         // container specify which direction to traverse for visibility?
627         for (int i = mChildren.size() - 1; i >= 0; --i) {
628             final WindowContainer wc = mChildren.get(i);
629             if (wc.isVisible()) {
630                 return true;
631             }
632         }
633         return false;
634     }
635 
636     /**
637      * @return Whether this child is on top of the window hierarchy.
638      */
isOnTop()639     boolean isOnTop() {
640         return getParent().getTopChild() == this && getParent().isOnTop();
641     }
642 
643     /** Returns the top child container. */
getTopChild()644     E getTopChild() {
645         return mChildren.peekLast();
646     }
647 
648     /** Returns true if there is still a removal being deferred */
checkCompleteDeferredRemoval()649     boolean checkCompleteDeferredRemoval() {
650         boolean stillDeferringRemoval = false;
651 
652         for (int i = mChildren.size() - 1; i >= 0; --i) {
653             final WindowContainer wc = mChildren.get(i);
654             stillDeferringRemoval |= wc.checkCompleteDeferredRemoval();
655         }
656 
657         return stillDeferringRemoval;
658     }
659 
660     /** Checks if all windows in an app are all drawn and shows them if needed. */
checkAppWindowsReadyToShow()661     void checkAppWindowsReadyToShow() {
662         for (int i = mChildren.size() - 1; i >= 0; --i) {
663             final WindowContainer wc = mChildren.get(i);
664             wc.checkAppWindowsReadyToShow();
665         }
666     }
667 
onAppTransitionDone()668     void onAppTransitionDone() {
669         for (int i = mChildren.size() - 1; i >= 0; --i) {
670             final WindowContainer wc = mChildren.get(i);
671             wc.onAppTransitionDone();
672         }
673     }
674 
setOrientation(int orientation)675     void setOrientation(int orientation) {
676         mOrientation = orientation;
677     }
678 
getOrientation()679     int getOrientation() {
680         return getOrientation(mOrientation);
681     }
682 
683     /**
684      * Returns the specified orientation for this window container or one of its children is there
685      * is one set, or {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSET} if no
686      * specification is set.
687      * NOTE: {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} is a
688      * specification...
689      *
690      * @param candidate The current orientation candidate that will be returned if we don't find a
691      *                  better match.
692      * @return The orientation as specified by this branch or the window hierarchy.
693      */
getOrientation(int candidate)694     int getOrientation(int candidate) {
695         if (!fillsParent()) {
696             // Ignore containers that don't completely fill their parents.
697             return SCREEN_ORIENTATION_UNSET;
698         }
699 
700         // The container fills its parent so we can use it orientation if it has one
701         // specified; otherwise we prefer to use the orientation of its topmost child that has one
702         // specified and fall back on this container's unset or unspecified value as a candidate
703         // if none of the children have a better candidate for the orientation.
704         if (mOrientation != SCREEN_ORIENTATION_UNSET
705                 && mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
706             return mOrientation;
707         }
708 
709         for (int i = mChildren.size() - 1; i >= 0; --i) {
710             final WindowContainer wc = mChildren.get(i);
711 
712             // TODO: Maybe mOrientation should default to SCREEN_ORIENTATION_UNSET vs.
713             // SCREEN_ORIENTATION_UNSPECIFIED?
714             final int orientation = wc.getOrientation(candidate == SCREEN_ORIENTATION_BEHIND
715                     ? SCREEN_ORIENTATION_BEHIND : SCREEN_ORIENTATION_UNSET);
716             if (orientation == SCREEN_ORIENTATION_BEHIND) {
717                 // container wants us to use the orientation of the container behind it. See if we
718                 // can find one. Else return SCREEN_ORIENTATION_BEHIND so the caller can choose to
719                 // look behind this container.
720                 candidate = orientation;
721                 continue;
722             }
723 
724             if (orientation == SCREEN_ORIENTATION_UNSET) {
725                 continue;
726             }
727 
728             if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
729                 // Use the orientation if the container fills its parent or requested an explicit
730                 // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED.
731                 return orientation;
732             }
733         }
734 
735         return candidate;
736     }
737 
738     /**
739      * Returns true if this container is opaque and fills all the space made available by its parent
740      * container.
741      *
742      * NOTE: It is possible for this container to occupy more space than the parent has (or less),
743      * this is just a signal from the client to window manager stating its intent, but not what it
744      * actually does.
745      */
fillsParent()746     boolean fillsParent() {
747         return false;
748     }
749 
750     // TODO: Users would have their own window containers under the display container?
switchUser()751     void switchUser() {
752         for (int i = mChildren.size() - 1; i >= 0; --i) {
753             mChildren.get(i).switchUser();
754         }
755     }
756 
757     /**
758      * For all windows at or below this container call the callback.
759      * @param   callback Calls the {@link ToBooleanFunction#apply} method for each window found and
760      *                   stops the search if {@link ToBooleanFunction#apply} returns true.
761      * @param   traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of
762      *                              z-order, else from bottom-to-top.
763      * @return  True if the search ended before we reached the end of the hierarchy due to
764      *          {@link ToBooleanFunction#apply} returning true.
765      */
forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)766     boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
767         if (traverseTopToBottom) {
768             for (int i = mChildren.size() - 1; i >= 0; --i) {
769                 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
770                     return true;
771                 }
772             }
773         } else {
774             final int count = mChildren.size();
775             for (int i = 0; i < count; i++) {
776                 if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
777                     return true;
778                 }
779             }
780         }
781         return false;
782     }
783 
forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom)784     void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) {
785         ForAllWindowsConsumerWrapper wrapper = obtainConsumerWrapper(callback);
786         forAllWindows(wrapper, traverseTopToBottom);
787         wrapper.release();
788     }
789 
790     /**
791      * For all tasks at or below this container call the callback.
792      *
793      * @param callback Callback to be called for every task.
794      */
forAllTasks(Consumer<Task> callback)795     void forAllTasks(Consumer<Task> callback) {
796         for (int i = mChildren.size() - 1; i >= 0; --i) {
797             mChildren.get(i).forAllTasks(callback);
798         }
799     }
800 
getWindow(Predicate<WindowState> callback)801     WindowState getWindow(Predicate<WindowState> callback) {
802         for (int i = mChildren.size() - 1; i >= 0; --i) {
803             final WindowState w = mChildren.get(i).getWindow(callback);
804             if (w != null) {
805                 return w;
806             }
807         }
808 
809         return null;
810     }
811 
812     /**
813      * Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than
814      * the input container in terms of z-order.
815      */
816     @Override
compareTo(WindowContainer other)817     public int compareTo(WindowContainer other) {
818         if (this == other) {
819             return 0;
820         }
821 
822         if (mParent != null && mParent == other.mParent) {
823             final WindowList<WindowContainer> list = mParent.mChildren;
824             return list.indexOf(this) > list.indexOf(other) ? 1 : -1;
825         }
826 
827         final LinkedList<WindowContainer> thisParentChain = mTmpChain1;
828         final LinkedList<WindowContainer> otherParentChain = mTmpChain2;
829         try {
830             getParents(thisParentChain);
831             other.getParents(otherParentChain);
832 
833             // Find the common ancestor of both containers.
834             WindowContainer commonAncestor = null;
835             WindowContainer thisTop = thisParentChain.peekLast();
836             WindowContainer otherTop = otherParentChain.peekLast();
837             while (thisTop != null && otherTop != null && thisTop == otherTop) {
838                 commonAncestor = thisParentChain.removeLast();
839                 otherParentChain.removeLast();
840                 thisTop = thisParentChain.peekLast();
841                 otherTop = otherParentChain.peekLast();
842             }
843 
844             // Containers don't belong to the same hierarchy???
845             if (commonAncestor == null) {
846                 throw new IllegalArgumentException("No in the same hierarchy this="
847                         + thisParentChain + " other=" + otherParentChain);
848             }
849 
850             // Children are always considered greater than their parents, so if one of the containers
851             // we are comparing it the parent of the other then whichever is the child is greater.
852             if (commonAncestor == this) {
853                 return -1;
854             } else if (commonAncestor == other) {
855                 return 1;
856             }
857 
858             // The position of the first non-common ancestor in the common ancestor list determines
859             // which is greater the which.
860             final WindowList<WindowContainer> list = commonAncestor.mChildren;
861             return list.indexOf(thisParentChain.peekLast()) > list.indexOf(otherParentChain.peekLast())
862                     ? 1 : -1;
863         } finally {
864             mTmpChain1.clear();
865             mTmpChain2.clear();
866         }
867     }
868 
getParents(LinkedList<WindowContainer> parents)869     private void getParents(LinkedList<WindowContainer> parents) {
870         parents.clear();
871         WindowContainer current = this;
872         do {
873             parents.addLast(current);
874             current = current.mParent;
875         } while (current != null);
876     }
877 
getController()878     WindowContainerController getController() {
879         return mController;
880     }
881 
setController(WindowContainerController controller)882     void setController(WindowContainerController controller) {
883         if (mController != null && controller != null) {
884             throw new IllegalArgumentException("Can't set controller=" + mController
885                     + " for container=" + this + " Already set to=" + mController);
886         }
887         if (controller != null) {
888             controller.setContainer(this);
889         } else if (mController != null) {
890             mController.setContainer(null);
891         }
892         mController = controller;
893     }
894 
makeSurface()895     SurfaceControl.Builder makeSurface() {
896         final WindowContainer p = getParent();
897         return p.makeChildSurface(this);
898     }
899 
900     /**
901      * @param child The WindowContainer this child surface is for, or null if the Surface
902      *              is not assosciated with a WindowContainer (e.g. a surface used for Dimming).
903      */
makeChildSurface(WindowContainer child)904     SurfaceControl.Builder makeChildSurface(WindowContainer child) {
905         final WindowContainer p = getParent();
906         // Give the parent a chance to set properties. In hierarchy v1 we rely
907         // on this to set full-screen dimensions on all our Surface-less Layers.
908         return p.makeChildSurface(child)
909                 .setParent(mSurfaceControl);
910     }
911 
912     @Override
getParentSurfaceControl()913     public SurfaceControl getParentSurfaceControl() {
914         final WindowContainer parent = getParent();
915         if (parent == null) {
916             return null;
917         }
918         return parent.getSurfaceControl();
919     }
920 
921     /**
922      * @return Whether this WindowContainer should be magnified by the accessibility magnifier.
923      */
shouldMagnify()924     boolean shouldMagnify() {
925         if (mSurfaceControl == null) {
926             return false;
927         }
928 
929         for (int i = 0; i < mChildren.size(); i++) {
930             if (!mChildren.get(i).shouldMagnify()) {
931                 return false;
932             }
933         }
934         return true;
935     }
936 
getSession()937     SurfaceSession getSession() {
938         if (getParent() != null) {
939             return getParent().getSession();
940         }
941         return null;
942     }
943 
assignLayer(Transaction t, int layer)944     void assignLayer(Transaction t, int layer) {
945         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
946         if (mSurfaceControl != null && changed) {
947             setLayer(t, layer);
948             mLastLayer = layer;
949             mLastRelativeToLayer = null;
950         }
951     }
952 
assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer)953     void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
954         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
955         if (mSurfaceControl != null && changed) {
956             setRelativeLayer(t, relativeTo, layer);
957             mLastLayer = layer;
958             mLastRelativeToLayer = relativeTo;
959         }
960     }
961 
setLayer(Transaction t, int layer)962     protected void setLayer(Transaction t, int layer) {
963 
964         // Route through surface animator to accommodate that our surface control might be
965         // attached to the leash, and leash is attached to parent container.
966         mSurfaceAnimator.setLayer(t, layer);
967     }
968 
setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer)969     protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
970 
971         // Route through surface animator to accommodate that our surface control might be
972         // attached to the leash, and leash is attached to parent container.
973         mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer);
974     }
975 
reparentSurfaceControl(Transaction t, SurfaceControl newParent)976     protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
977         mSurfaceAnimator.reparent(t, newParent);
978     }
979 
assignChildLayers(Transaction t)980     void assignChildLayers(Transaction t) {
981         int layer = 0;
982 
983         // We use two passes as a way to promote children which
984         // need Z-boosting to the end of the list.
985         for (int j = 0; j < mChildren.size(); ++j) {
986             final WindowContainer wc = mChildren.get(j);
987             wc.assignChildLayers(t);
988             if (!wc.needsZBoost()) {
989                 wc.assignLayer(t, layer++);
990             }
991         }
992         for (int j = 0; j < mChildren.size(); ++j) {
993             final WindowContainer wc = mChildren.get(j);
994             if (wc.needsZBoost()) {
995                 wc.assignLayer(t, layer++);
996             }
997         }
998     }
999 
assignChildLayers()1000     void assignChildLayers() {
1001         assignChildLayers(getPendingTransaction());
1002         scheduleAnimation();
1003     }
1004 
needsZBoost()1005     boolean needsZBoost() {
1006         for (int i = 0; i < mChildren.size(); i++) {
1007             if (mChildren.get(i).needsZBoost()) {
1008                 return true;
1009             }
1010         }
1011         return false;
1012     }
1013 
1014     /**
1015      * Write to a protocol buffer output stream. Protocol buffer message definition is at
1016      * {@link com.android.server.wm.WindowContainerProto}.
1017      *
1018      * @param proto     Stream to write the WindowContainer object to.
1019      * @param fieldId   Field Id of the WindowContainer as defined in the parent message.
1020      * @param trim      If true, reduce the amount of data written.
1021      * @hide
1022      */
1023     @CallSuper
1024     @Override
writeToProto(ProtoOutputStream proto, long fieldId, boolean trim)1025     public void writeToProto(ProtoOutputStream proto, long fieldId, boolean trim) {
1026         final long token = proto.start(fieldId);
1027         super.writeToProto(proto, CONFIGURATION_CONTAINER, trim);
1028         proto.write(ORIENTATION, mOrientation);
1029         proto.write(VISIBLE, isVisible());
1030         mSurfaceAnimator.writeToProto(proto, SURFACE_ANIMATOR);
1031         proto.end(token);
1032     }
1033 
obtainConsumerWrapper(Consumer<WindowState> consumer)1034     private ForAllWindowsConsumerWrapper obtainConsumerWrapper(Consumer<WindowState> consumer) {
1035         ForAllWindowsConsumerWrapper wrapper = mConsumerWrapperPool.acquire();
1036         if (wrapper == null) {
1037             wrapper = new ForAllWindowsConsumerWrapper();
1038         }
1039         wrapper.setConsumer(consumer);
1040         return wrapper;
1041     }
1042 
1043     private final class ForAllWindowsConsumerWrapper implements ToBooleanFunction<WindowState> {
1044 
1045         private Consumer<WindowState> mConsumer;
1046 
setConsumer(Consumer<WindowState> consumer)1047         void setConsumer(Consumer<WindowState> consumer) {
1048             mConsumer = consumer;
1049         }
1050 
1051         @Override
apply(WindowState w)1052         public boolean apply(WindowState w) {
1053             mConsumer.accept(w);
1054             return false;
1055         }
1056 
release()1057         void release() {
1058             mConsumer = null;
1059             mConsumerWrapperPool.release(this);
1060         }
1061     }
1062 
1063     // TODO(b/68336570): Should this really be on WindowContainer since it
1064     // can only be used on the top-level nodes that aren't animated?
1065     // (otherwise we would be fighting other callers of setMatrix).
applyMagnificationSpec(Transaction t, MagnificationSpec spec)1066     void applyMagnificationSpec(Transaction t, MagnificationSpec spec) {
1067         if (shouldMagnify()) {
1068             t.setMatrix(mSurfaceControl, spec.scale, 0, 0, spec.scale)
1069                     .setPosition(mSurfaceControl, spec.offsetX, spec.offsetY);
1070         } else {
1071             for (int i = 0; i < mChildren.size(); i++) {
1072                 mChildren.get(i).applyMagnificationSpec(t, spec);
1073             }
1074         }
1075     }
1076 
1077     /**
1078      * TODO: Once we totally eliminate global transaction we will pass transaction in here
1079      * rather than merging to global.
1080      */
prepareSurfaces()1081     void prepareSurfaces() {
1082         SurfaceControl.mergeToGlobalTransaction(getPendingTransaction());
1083 
1084         // If a leash has been set when the transaction was committed, then the leash reparent has
1085         // been committed.
1086         mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash();
1087         for (int i = 0; i < mChildren.size(); i++) {
1088             mChildren.get(i).prepareSurfaces();
1089         }
1090     }
1091 
1092     /**
1093      * @return true if the reparent to animation leash transaction has been committed, false
1094      * otherwise.
1095      */
hasCommittedReparentToAnimationLeash()1096     boolean hasCommittedReparentToAnimationLeash() {
1097         return mCommittedReparentToAnimationLeash;
1098     }
1099 
1100     /**
1101      * Trigger a call to prepareSurfaces from the animation thread, such that
1102      * mPendingTransaction will be applied.
1103      */
scheduleAnimation()1104     void scheduleAnimation() {
1105         if (mParent != null) {
1106             mParent.scheduleAnimation();
1107         }
1108     }
1109 
1110     @Override
getSurfaceControl()1111     public SurfaceControl getSurfaceControl() {
1112         return mSurfaceControl;
1113     }
1114 
1115     @Override
getPendingTransaction()1116     public Transaction getPendingTransaction() {
1117         return mPendingTransaction;
1118     }
1119 
1120     /**
1121      * Starts an animation on the container.
1122      *
1123      * @param anim The animation to run.
1124      * @param hidden Whether our container is currently hidden. TODO This should use isVisible at
1125      *               some point but the meaning is too weird to work for all containers.
1126      */
startAnimation(Transaction t, AnimationAdapter anim, boolean hidden)1127     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
1128         if (DEBUG_ANIM) Slog.v(TAG, "Starting animation on " + this + ": " + anim);
1129 
1130         // TODO: This should use isVisible() but because isVisible has a really weird meaning at
1131         // the moment this doesn't work for all animatable window containers.
1132         mSurfaceAnimator.startAnimation(t, anim, hidden);
1133     }
1134 
transferAnimation(WindowContainer from)1135     void transferAnimation(WindowContainer from) {
1136         mSurfaceAnimator.transferAnimation(from.mSurfaceAnimator);
1137     }
1138 
cancelAnimation()1139     void cancelAnimation() {
1140         mSurfaceAnimator.cancelAnimation();
1141     }
1142 
1143     @Override
makeAnimationLeash()1144     public Builder makeAnimationLeash() {
1145         return makeSurface();
1146     }
1147 
1148     @Override
getAnimationLeashParent()1149     public SurfaceControl getAnimationLeashParent() {
1150         return getParentSurfaceControl();
1151     }
1152 
1153     /**
1154      * @return The layer on which all app animations are happening.
1155      */
getAppAnimationLayer(@nimationLayer int animationLayer)1156     SurfaceControl getAppAnimationLayer(@AnimationLayer int animationLayer) {
1157         final WindowContainer parent = getParent();
1158         if (parent != null) {
1159             return parent.getAppAnimationLayer(animationLayer);
1160         }
1161         return null;
1162     }
1163 
1164     @Override
commitPendingTransaction()1165     public void commitPendingTransaction() {
1166         scheduleAnimation();
1167     }
1168 
reassignLayer(Transaction t)1169     void reassignLayer(Transaction t) {
1170         final WindowContainer parent = getParent();
1171         if (parent != null) {
1172             parent.assignChildLayers(t);
1173         }
1174     }
1175 
1176     @Override
onAnimationLeashCreated(Transaction t, SurfaceControl leash)1177     public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
1178         mLastLayer = -1;
1179         reassignLayer(t);
1180     }
1181 
1182     @Override
onAnimationLeashDestroyed(Transaction t)1183     public void onAnimationLeashDestroyed(Transaction t) {
1184         mLastLayer = -1;
1185         reassignLayer(t);
1186     }
1187 
1188     /**
1189      * Called when an animation has finished running.
1190      */
onAnimationFinished()1191     protected void onAnimationFinished() {
1192     }
1193 
1194     /**
1195      * @return The currently running animation, if any, or {@code null} otherwise.
1196      */
getAnimation()1197     AnimationAdapter getAnimation() {
1198         return mSurfaceAnimator.getAnimation();
1199     }
1200 
1201     /**
1202      * @see SurfaceAnimator#startDelayingAnimationStart
1203      */
startDelayingAnimationStart()1204     void startDelayingAnimationStart() {
1205         mSurfaceAnimator.startDelayingAnimationStart();
1206     }
1207 
1208     /**
1209      * @see SurfaceAnimator#endDelayingAnimationStart
1210      */
endDelayingAnimationStart()1211     void endDelayingAnimationStart() {
1212         mSurfaceAnimator.endDelayingAnimationStart();
1213     }
1214 
1215     @Override
getSurfaceWidth()1216     public int getSurfaceWidth() {
1217         return mSurfaceControl.getWidth();
1218     }
1219 
1220     @Override
getSurfaceHeight()1221     public int getSurfaceHeight() {
1222         return mSurfaceControl.getHeight();
1223     }
1224 
1225     @CallSuper
dump(PrintWriter pw, String prefix, boolean dumpAll)1226     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
1227         if (mSurfaceAnimator.isAnimating()) {
1228             pw.print(prefix); pw.println("ContainerAnimator:");
1229             mSurfaceAnimator.dump(pw, prefix + "  ");
1230         }
1231     }
1232 
updateSurfacePosition()1233     void updateSurfacePosition() {
1234         if (mSurfaceControl == null) {
1235             return;
1236         }
1237 
1238         getRelativePosition(mTmpPos);
1239         if (mTmpPos.equals(mLastSurfacePosition)) {
1240             return;
1241         }
1242 
1243         getPendingTransaction().setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y);
1244         mLastSurfacePosition.set(mTmpPos.x, mTmpPos.y);
1245     }
1246 
getRelativePosition(Point outPos)1247     void getRelativePosition(Point outPos) {
1248         final Rect bounds = getBounds();
1249         outPos.set(bounds.left, bounds.top);
1250         final WindowContainer parent = getParent();
1251         if (parent != null) {
1252             final Rect parentBounds = parent.getBounds();
1253             outPos.offset(-parentBounds.left, -parentBounds.top);
1254         }
1255     }
1256 
getDimmer()1257     Dimmer getDimmer() {
1258         if (mParent == null) {
1259             return null;
1260         }
1261         return mParent.getDimmer();
1262     }
1263 }
1264