Home | History | Annotate | Download | only in wm
      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 
    130     WindowContainer(WindowManagerService service) {
    131         mService = service;
    132         mPendingTransaction = service.mTransactionFactory.make();
    133         mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
    134     }
    135 
    136     @Override
    137     final protected WindowContainer getParent() {
    138         return mParent;
    139     }
    140 
    141     @Override
    142     protected int getChildCount() {
    143         return mChildren.size();
    144     }
    145 
    146     @Override
    147     protected E getChildAt(int index) {
    148         return mChildren.get(index);
    149     }
    150 
    151     @Override
    152     public void onConfigurationChanged(Configuration newParentConfig) {
    153         super.onConfigurationChanged(newParentConfig);
    154         updateSurfacePosition();
    155         scheduleAnimation();
    156     }
    157 
    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      */
    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
    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
    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 
    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
    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 
    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
    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      */
    335     int getPrefixOrderIndex() {
    336         if (mParent == null) {
    337             return 0;
    338         }
    339         return mParent.getPrefixOrderIndex(this);
    340     }
    341 
    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...
    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. */
    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
    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
    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      */
    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      */
    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 
    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 
    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 
    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 
    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 
    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 
    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      */
    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      */
    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      */
    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      */
    584     boolean isSelfAnimating() {
    585         return mSurfaceAnimator.isAnimating();
    586     }
    587 
    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      */
    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      */
    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      */
    639     boolean isOnTop() {
    640         return getParent().getTopChild() == this && getParent().isOnTop();
    641     }
    642 
    643     /** Returns the top child container. */
    644     E getTopChild() {
    645         return mChildren.peekLast();
    646     }
    647 
    648     /** Returns true if there is still a removal being deferred */
    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. */
    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 
    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 
    675     void setOrientation(int orientation) {
    676         mOrientation = orientation;
    677     }
    678 
    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      */
    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      */
    746     boolean fillsParent() {
    747         return false;
    748     }
    749 
    750     // TODO: Users would have their own window containers under the display container?
    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      */
    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 
    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      */
    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 
    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
    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 
    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 
    878     WindowContainerController getController() {
    879         return mController;
    880     }
    881 
    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 
    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      */
    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
    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      */
    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 
    937     SurfaceSession getSession() {
    938         if (getParent() != null) {
    939             return getParent().getSession();
    940         }
    941         return null;
    942     }
    943 
    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 
    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 
    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 
    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 
    976     protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
    977         mSurfaceAnimator.reparent(t, newParent);
    978     }
    979 
    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 
   1000     void assignChildLayers() {
   1001         assignChildLayers(getPendingTransaction());
   1002         scheduleAnimation();
   1003     }
   1004 
   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
   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 
   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 
   1047         void setConsumer(Consumer<WindowState> consumer) {
   1048             mConsumer = consumer;
   1049         }
   1050 
   1051         @Override
   1052         public boolean apply(WindowState w) {
   1053             mConsumer.accept(w);
   1054             return false;
   1055         }
   1056 
   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).
   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      */
   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      */
   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      */
   1104     void scheduleAnimation() {
   1105         if (mParent != null) {
   1106             mParent.scheduleAnimation();
   1107         }
   1108     }
   1109 
   1110     @Override
   1111     public SurfaceControl getSurfaceControl() {
   1112         return mSurfaceControl;
   1113     }
   1114 
   1115     @Override
   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      */
   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 
   1135     void transferAnimation(WindowContainer from) {
   1136         mSurfaceAnimator.transferAnimation(from.mSurfaceAnimator);
   1137     }
   1138 
   1139     void cancelAnimation() {
   1140         mSurfaceAnimator.cancelAnimation();
   1141     }
   1142 
   1143     @Override
   1144     public Builder makeAnimationLeash() {
   1145         return makeSurface();
   1146     }
   1147 
   1148     @Override
   1149     public SurfaceControl getAnimationLeashParent() {
   1150         return getParentSurfaceControl();
   1151     }
   1152 
   1153     /**
   1154      * @return The layer on which all app animations are happening.
   1155      */
   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
   1165     public void commitPendingTransaction() {
   1166         scheduleAnimation();
   1167     }
   1168 
   1169     void reassignLayer(Transaction t) {
   1170         final WindowContainer parent = getParent();
   1171         if (parent != null) {
   1172             parent.assignChildLayers(t);
   1173         }
   1174     }
   1175 
   1176     @Override
   1177     public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
   1178         mLastLayer = -1;
   1179         reassignLayer(t);
   1180     }
   1181 
   1182     @Override
   1183     public void onAnimationLeashDestroyed(Transaction t) {
   1184         mLastLayer = -1;
   1185         reassignLayer(t);
   1186     }
   1187 
   1188     /**
   1189      * Called when an animation has finished running.
   1190      */
   1191     protected void onAnimationFinished() {
   1192     }
   1193 
   1194     /**
   1195      * @return The currently running animation, if any, or {@code null} otherwise.
   1196      */
   1197     AnimationAdapter getAnimation() {
   1198         return mSurfaceAnimator.getAnimation();
   1199     }
   1200 
   1201     /**
   1202      * @see SurfaceAnimator#startDelayingAnimationStart
   1203      */
   1204     void startDelayingAnimationStart() {
   1205         mSurfaceAnimator.startDelayingAnimationStart();
   1206     }
   1207 
   1208     /**
   1209      * @see SurfaceAnimator#endDelayingAnimationStart
   1210      */
   1211     void endDelayingAnimationStart() {
   1212         mSurfaceAnimator.endDelayingAnimationStart();
   1213     }
   1214 
   1215     @Override
   1216     public int getSurfaceWidth() {
   1217         return mSurfaceControl.getWidth();
   1218     }
   1219 
   1220     @Override
   1221     public int getSurfaceHeight() {
   1222         return mSurfaceControl.getHeight();
   1223     }
   1224 
   1225     @CallSuper
   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 
   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 
   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 
   1257     Dimmer getDimmer() {
   1258         if (mParent == null) {
   1259             return null;
   1260         }
   1261         return mParent.getDimmer();
   1262     }
   1263 }
   1264