Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.wm;
     18 
     19 import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
     20 import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
     21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
     22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
     23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
     24 import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
     25 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
     26 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
     27 import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
     28 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
     29 import static android.view.Display.DEFAULT_DISPLAY;
     30 import static android.view.WindowManager.DOCKED_BOTTOM;
     31 import static android.view.WindowManager.DOCKED_INVALID;
     32 import static android.view.WindowManager.DOCKED_LEFT;
     33 import static android.view.WindowManager.DOCKED_RIGHT;
     34 import static android.view.WindowManager.DOCKED_TOP;
     35 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
     36 import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
     37 import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
     38 import static com.android.server.wm.StackProto.ADJUST_DIVIDER_AMOUNT;
     39 import static com.android.server.wm.StackProto.ADJUST_IME_AMOUNT;
     40 import static com.android.server.wm.StackProto.ANIMATING_BOUNDS;
     41 import static com.android.server.wm.StackProto.ANIMATION_BACKGROUND_SURFACE_IS_DIMMING;
     42 import static com.android.server.wm.StackProto.BOUNDS;
     43 import static com.android.server.wm.StackProto.DEFER_REMOVAL;
     44 import static com.android.server.wm.StackProto.FILLS_PARENT;
     45 import static com.android.server.wm.StackProto.ID;
     46 import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT;
     47 import static com.android.server.wm.StackProto.TASKS;
     48 import static com.android.server.wm.StackProto.WINDOW_CONTAINER;
     49 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
     50 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     51 
     52 import android.annotation.CallSuper;
     53 import android.content.res.Configuration;
     54 import android.graphics.Point;
     55 import android.graphics.Rect;
     56 import android.graphics.Region;
     57 import android.os.RemoteException;
     58 import android.util.DisplayMetrics;
     59 import android.util.EventLog;
     60 import android.util.Slog;
     61 import android.util.SparseArray;
     62 import android.util.proto.ProtoOutputStream;
     63 import android.view.DisplayInfo;
     64 import android.view.Surface;
     65 import android.view.SurfaceControl;
     66 import com.android.internal.policy.DividerSnapAlgorithm;
     67 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
     68 import com.android.internal.policy.DockedDividerUtils;
     69 import com.android.server.EventLogTags;
     70 import java.io.PrintWriter;
     71 
     72 public class TaskStack extends WindowContainer<Task> implements
     73         BoundsAnimationTarget {
     74     /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
     75      * restrict IME adjustment so that a min portion of top stack remains visible.*/
     76     private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
     77 
     78     /** Dimming amount for non-focused stack when stacks are IME-adjusted. */
     79     private static final float IME_ADJUST_DIM_AMOUNT = 0.25f;
     80 
     81     /** Unique identifier */
     82     final int mStackId;
     83 
     84     /** The display this stack sits under. */
     85     // TODO: Track parent marks like this in WindowContainer.
     86     private DisplayContent mDisplayContent;
     87 
     88     /** For comparison with DisplayContent bounds. */
     89     private Rect mTmpRect = new Rect();
     90     private Rect mTmpRect2 = new Rect();
     91     private Rect mTmpRect3 = new Rect();
     92 
     93     /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
     94     private final Rect mAdjustedBounds = new Rect();
     95 
     96     /**
     97      * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they
     98      * represent the state when the animation has ended.
     99      */
    100     private final Rect mFullyAdjustedImeBounds = new Rect();
    101 
    102     // Device rotation as of the last time {@link #mBounds} was set.
    103     private int mRotation;
    104 
    105     /** Density as of last time {@link #mBounds} was set. */
    106     private int mDensity;
    107 
    108     private SurfaceControl mAnimationBackgroundSurface;
    109     private boolean mAnimationBackgroundSurfaceIsShown = false;
    110 
    111     /** The particular window with an Animation with non-zero background color. */
    112     private WindowStateAnimator mAnimationBackgroundAnimator;
    113 
    114     /** Application tokens that are exiting, but still on screen for animations. */
    115     final AppTokenList mExitingAppTokens = new AppTokenList();
    116     final AppTokenList mTmpAppTokens = new AppTokenList();
    117 
    118     /** Detach this stack from its display when animation completes. */
    119     // TODO: maybe tie this to WindowContainer#removeChild some how...
    120     boolean mDeferRemoval;
    121 
    122     private final Rect mTmpAdjustedBounds = new Rect();
    123     private boolean mAdjustedForIme;
    124     private boolean mImeGoingAway;
    125     private WindowState mImeWin;
    126     private float mMinimizeAmount;
    127     private float mAdjustImeAmount;
    128     private float mAdjustDividerAmount;
    129     private final int mDockedStackMinimizeThickness;
    130 
    131     // If this is true, we are in the bounds animating mode. The task will be down or upscaled to
    132     // perfectly fit the region it would have been cropped to. We may also avoid certain logic we
    133     // would otherwise apply while resizing, while resizing in the bounds animating mode.
    134     private boolean mBoundsAnimating = false;
    135     // Set when an animation has been requested but has not yet started from the UI thread. This is
    136     // cleared when the animation actually starts.
    137     private boolean mBoundsAnimatingRequested = false;
    138     private boolean mBoundsAnimatingToFullscreen = false;
    139     private boolean mCancelCurrentBoundsAnimation = false;
    140     private Rect mBoundsAnimationTarget = new Rect();
    141     private Rect mBoundsAnimationSourceHintBounds = new Rect();
    142 
    143     // Temporary storage for the new bounds that should be used after the configuration change.
    144     // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
    145     private final Rect mBoundsAfterRotation = new Rect();
    146 
    147     Rect mPreAnimationBounds = new Rect();
    148 
    149     private Dimmer mDimmer = new Dimmer(this);
    150 
    151     /**
    152      * For {@link #prepareSurfaces}.
    153      */
    154     final Rect mTmpDimBoundsRect = new Rect();
    155     private final Point mLastSurfaceSize = new Point();
    156 
    157     private final AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry =
    158             new AnimatingAppWindowTokenRegistry();
    159 
    160     TaskStack(WindowManagerService service, int stackId, StackWindowController controller) {
    161         super(service);
    162         mStackId = stackId;
    163         setController(controller);
    164         mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
    165                 com.android.internal.R.dimen.docked_stack_minimize_thickness);
    166         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
    167     }
    168 
    169     DisplayContent getDisplayContent() {
    170         return mDisplayContent;
    171     }
    172 
    173     Task findHomeTask() {
    174         if (!isActivityTypeHome() || mChildren.isEmpty()) {
    175             return null;
    176         }
    177         return mChildren.get(mChildren.size() - 1);
    178     }
    179 
    180     /**
    181      * Set the bounds of the stack and its containing tasks.
    182      * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
    183      * @param taskBounds Bounds for individual tasks, keyed by task id.
    184      * @param taskTempInsetBounds Inset bounds for individual tasks, keyed by task id.
    185      * @return True if the stack bounds was changed.
    186      * */
    187     boolean setBounds(
    188             Rect stackBounds, SparseArray<Rect> taskBounds, SparseArray<Rect> taskTempInsetBounds) {
    189         setBounds(stackBounds);
    190 
    191         // Update bounds of containing tasks.
    192         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
    193             final Task task = mChildren.get(taskNdx);
    194             task.setBounds(taskBounds.get(task.mTaskId), false /* forced */);
    195             task.setTempInsetBounds(taskTempInsetBounds != null ?
    196                     taskTempInsetBounds.get(task.mTaskId) : null);
    197         }
    198         return true;
    199     }
    200 
    201     void prepareFreezingTaskBounds() {
    202         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
    203             final Task task = mChildren.get(taskNdx);
    204             task.prepareFreezingBounds();
    205         }
    206     }
    207 
    208     /**
    209      * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
    210      * the normal task bounds.
    211      *
    212      * @param bounds The adjusted bounds.
    213      */
    214     private void setAdjustedBounds(Rect bounds) {
    215         if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) {
    216             return;
    217         }
    218 
    219         mAdjustedBounds.set(bounds);
    220         final boolean adjusted = !mAdjustedBounds.isEmpty();
    221         Rect insetBounds = null;
    222         if (adjusted && isAdjustedForMinimizedDockedStack()) {
    223             insetBounds = getRawBounds();
    224         } else if (adjusted && mAdjustedForIme) {
    225             if (mImeGoingAway) {
    226                 insetBounds = getRawBounds();
    227             } else {
    228                 insetBounds = mFullyAdjustedImeBounds;
    229             }
    230         }
    231         alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : getRawBounds(), insetBounds);
    232         mDisplayContent.setLayoutNeeded();
    233 
    234         updateSurfaceBounds();
    235     }
    236 
    237     private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
    238         if (matchParentBounds()) {
    239             return;
    240         }
    241 
    242         final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
    243 
    244         // Update bounds of containing tasks.
    245         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
    246             final Task task = mChildren.get(taskNdx);
    247             task.alignToAdjustedBounds(adjustedBounds, tempInsetBounds, alignBottom);
    248         }
    249     }
    250 
    251     private void updateAnimationBackgroundBounds() {
    252         if (mAnimationBackgroundSurface == null) {
    253             return;
    254         }
    255         getRawBounds(mTmpRect);
    256         final Rect stackBounds = getBounds();
    257         getPendingTransaction()
    258                 .setSize(mAnimationBackgroundSurface, mTmpRect.width(), mTmpRect.height())
    259                 .setPosition(mAnimationBackgroundSurface, mTmpRect.left - stackBounds.left,
    260                         mTmpRect.top - stackBounds.top);
    261         scheduleAnimation();
    262     }
    263 
    264     private void hideAnimationSurface() {
    265         if (mAnimationBackgroundSurface == null) {
    266             return;
    267         }
    268         getPendingTransaction().hide(mAnimationBackgroundSurface);
    269         mAnimationBackgroundSurfaceIsShown = false;
    270         scheduleAnimation();
    271     }
    272 
    273     private void showAnimationSurface(float alpha) {
    274         if (mAnimationBackgroundSurface == null) {
    275             return;
    276         }
    277         getPendingTransaction().setLayer(mAnimationBackgroundSurface, Integer.MIN_VALUE)
    278                 .setAlpha(mAnimationBackgroundSurface, alpha)
    279                 .show(mAnimationBackgroundSurface);
    280         mAnimationBackgroundSurfaceIsShown = true;
    281         scheduleAnimation();
    282     }
    283 
    284     @Override
    285     public int setBounds(Rect bounds) {
    286         return setBounds(getOverrideBounds(), bounds);
    287     }
    288 
    289     private int setBounds(Rect existing, Rect bounds) {
    290         int rotation = Surface.ROTATION_0;
    291         int density = DENSITY_DPI_UNDEFINED;
    292         if (mDisplayContent != null) {
    293             mDisplayContent.getBounds(mTmpRect);
    294             rotation = mDisplayContent.getDisplayInfo().rotation;
    295             density = mDisplayContent.getDisplayInfo().logicalDensityDpi;
    296         }
    297 
    298         if (equivalentBounds(existing, bounds) && mRotation == rotation) {
    299             return BOUNDS_CHANGE_NONE;
    300         }
    301 
    302         final int result = super.setBounds(bounds);
    303 
    304         if (mDisplayContent != null) {
    305             updateAnimationBackgroundBounds();
    306         }
    307 
    308         mRotation = rotation;
    309         mDensity = density;
    310 
    311         updateAdjustedBounds();
    312 
    313         updateSurfaceBounds();
    314         return result;
    315     }
    316 
    317     /** Bounds of the stack without adjusting for other factors in the system like visibility
    318      * of docked stack.
    319      * Most callers should be using {@link ConfigurationContainer#getOverrideBounds} as it take into
    320      * consideration other system factors. */
    321     void getRawBounds(Rect out) {
    322         out.set(getRawBounds());
    323     }
    324 
    325     Rect getRawBounds() {
    326         return super.getBounds();
    327     }
    328 
    329     /** Return true if the current bound can get outputted to the rest of the system as-is. */
    330     private boolean useCurrentBounds() {
    331         if (matchParentBounds()
    332                 || !inSplitScreenSecondaryWindowingMode()
    333                 || mDisplayContent == null
    334                 || mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null) {
    335             return true;
    336         }
    337         return false;
    338     }
    339 
    340     @Override
    341     public void getBounds(Rect bounds) {
    342         bounds.set(getBounds());
    343     }
    344 
    345     @Override
    346     public Rect getBounds() {
    347         if (useCurrentBounds()) {
    348             // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
    349             // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
    350             // stack is visible since it is already what we want to represent to the rest of the
    351             // system.
    352             if (!mAdjustedBounds.isEmpty()) {
    353                 return mAdjustedBounds;
    354             } else {
    355                 return super.getBounds();
    356             }
    357         }
    358 
    359         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
    360         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
    361         // system.
    362         return mDisplayContent.getBounds();
    363     }
    364 
    365     /**
    366      * Sets the bounds animation target bounds ahead of an animation.  This can't currently be done
    367      * in onAnimationStart() since that is started on the UiThread.
    368      */
    369     void setAnimationFinalBounds(Rect sourceHintBounds, Rect destBounds, boolean toFullscreen) {
    370         mBoundsAnimatingRequested = true;
    371         mBoundsAnimatingToFullscreen = toFullscreen;
    372         if (destBounds != null) {
    373             mBoundsAnimationTarget.set(destBounds);
    374         } else {
    375             mBoundsAnimationTarget.setEmpty();
    376         }
    377         if (sourceHintBounds != null) {
    378             mBoundsAnimationSourceHintBounds.set(sourceHintBounds);
    379         } else {
    380             mBoundsAnimationSourceHintBounds.setEmpty();
    381         }
    382 
    383         mPreAnimationBounds.set(getRawBounds());
    384     }
    385 
    386     /**
    387      * @return the final bounds for the bounds animation.
    388      */
    389     void getFinalAnimationBounds(Rect outBounds) {
    390         outBounds.set(mBoundsAnimationTarget);
    391     }
    392 
    393     /**
    394      * @return the final source bounds for the bounds animation.
    395      */
    396     void getFinalAnimationSourceHintBounds(Rect outBounds) {
    397         outBounds.set(mBoundsAnimationSourceHintBounds);
    398     }
    399 
    400     /**
    401      * @return the final animation bounds if the task stack is currently being animated, or the
    402      *         current stack bounds otherwise.
    403      */
    404     void getAnimationOrCurrentBounds(Rect outBounds) {
    405         if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) {
    406             getFinalAnimationBounds(outBounds);
    407             return;
    408         }
    409         getBounds(outBounds);
    410     }
    411 
    412     /** Bounds of the stack with other system factors taken into consideration. */
    413     public void getDimBounds(Rect out) {
    414         getBounds(out);
    415     }
    416 
    417     void updateDisplayInfo(Rect bounds) {
    418         if (mDisplayContent == null) {
    419             return;
    420         }
    421 
    422         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
    423             mChildren.get(taskNdx).updateDisplayInfo(mDisplayContent);
    424         }
    425         if (bounds != null) {
    426             setBounds(bounds);
    427             return;
    428         } else if (matchParentBounds()) {
    429             setBounds(null);
    430             return;
    431         }
    432 
    433         mTmpRect2.set(getRawBounds());
    434         final int newRotation = mDisplayContent.getDisplayInfo().rotation;
    435         final int newDensity = mDisplayContent.getDisplayInfo().logicalDensityDpi;
    436         if (mRotation == newRotation && mDensity == newDensity) {
    437             setBounds(mTmpRect2);
    438         }
    439 
    440         // If the rotation or density didn't match, we'll update it in onConfigurationChanged.
    441     }
    442 
    443     /** @return true if bounds were updated to some non-empty value. */
    444     boolean updateBoundsAfterConfigChange() {
    445         if (mDisplayContent == null) {
    446             // If the stack is already detached we're not updating anything,
    447             // as it's going away soon anyway.
    448             return false;
    449         }
    450 
    451         if (inPinnedWindowingMode()) {
    452             getAnimationOrCurrentBounds(mTmpRect2);
    453             boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
    454                     mTmpRect2, mTmpRect3);
    455             if (updated) {
    456                 mBoundsAfterRotation.set(mTmpRect3);
    457 
    458                 // Once we've set the bounds based on the rotation of the old bounds in the new
    459                 // orientation, clear the animation target bounds since they are obsolete, and
    460                 // cancel any currently running animations
    461                 mBoundsAnimationTarget.setEmpty();
    462                 mBoundsAnimationSourceHintBounds.setEmpty();
    463                 mCancelCurrentBoundsAnimation = true;
    464                 return true;
    465             }
    466         }
    467 
    468         final int newRotation = getDisplayInfo().rotation;
    469         final int newDensity = getDisplayInfo().logicalDensityDpi;
    470 
    471         if (mRotation == newRotation && mDensity == newDensity) {
    472             // Nothing to do here as we already update the state in updateDisplayInfo.
    473             return false;
    474         }
    475 
    476         if (matchParentBounds()) {
    477             // Update stack bounds again since rotation changed since updateDisplayInfo().
    478             setBounds(null);
    479             // Return false since we don't need the client to resize.
    480             return false;
    481         }
    482 
    483         mTmpRect2.set(getRawBounds());
    484         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
    485         if (inSplitScreenPrimaryWindowingMode()) {
    486             repositionPrimarySplitScreenStackAfterRotation(mTmpRect2);
    487             snapDockedStackAfterRotation(mTmpRect2);
    488             final int newDockSide = getDockSide(mTmpRect2);
    489 
    490             // Update the dock create mode and clear the dock create bounds, these
    491             // might change after a rotation and the original values will be invalid.
    492             mService.setDockedStackCreateStateLocked(
    493                     (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
    494                             ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
    495                             : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
    496                     null);
    497             mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
    498         }
    499 
    500         mBoundsAfterRotation.set(mTmpRect2);
    501         return true;
    502     }
    503 
    504     void getBoundsForNewConfiguration(Rect outBounds) {
    505         outBounds.set(mBoundsAfterRotation);
    506         mBoundsAfterRotation.setEmpty();
    507     }
    508 
    509     /**
    510      * Some primary split screen sides are not allowed by the policy. This method queries the policy
    511      * and moves the primary stack around if needed.
    512      *
    513      * @param inOutBounds the bounds of the primary stack to adjust
    514      */
    515     private void repositionPrimarySplitScreenStackAfterRotation(Rect inOutBounds) {
    516         int dockSide = getDockSide(inOutBounds);
    517         if (mDisplayContent.getDockedDividerController().canPrimaryStackDockTo(dockSide)) {
    518             return;
    519         }
    520         mDisplayContent.getBounds(mTmpRect);
    521         dockSide = DockedDividerUtils.invertDockSide(dockSide);
    522         switch (dockSide) {
    523             case DOCKED_LEFT:
    524                 int movement = inOutBounds.left;
    525                 inOutBounds.left -= movement;
    526                 inOutBounds.right -= movement;
    527                 break;
    528             case DOCKED_RIGHT:
    529                 movement = mTmpRect.right - inOutBounds.right;
    530                 inOutBounds.left += movement;
    531                 inOutBounds.right += movement;
    532                 break;
    533             case DOCKED_TOP:
    534                 movement = inOutBounds.top;
    535                 inOutBounds.top -= movement;
    536                 inOutBounds.bottom -= movement;
    537                 break;
    538             case DOCKED_BOTTOM:
    539                 movement = mTmpRect.bottom - inOutBounds.bottom;
    540                 inOutBounds.top += movement;
    541                 inOutBounds.bottom += movement;
    542                 break;
    543         }
    544     }
    545 
    546     /**
    547      * Snaps the bounds after rotation to the closest snap target for the docked stack.
    548      */
    549     private void snapDockedStackAfterRotation(Rect outBounds) {
    550 
    551         // Calculate the current position.
    552         final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
    553         final int dividerSize = mDisplayContent.getDockedDividerController().getContentWidth();
    554         final int dockSide = getDockSide(outBounds);
    555         final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
    556                 dockSide, dividerSize);
    557         final int displayWidth = displayInfo.logicalWidth;
    558         final int displayHeight = displayInfo.logicalHeight;
    559 
    560         // Snap the position to a target.
    561         final int rotation = displayInfo.rotation;
    562         final int orientation = mDisplayContent.getConfiguration().orientation;
    563         mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight,
    564                 displayInfo.displayCutout, outBounds);
    565         final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
    566                 mService.mContext.getResources(), displayWidth, displayHeight,
    567                 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
    568                 getDockSide(), isMinimizedDockAndHomeStackResizable());
    569         final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
    570 
    571         // Recalculate the bounds based on the position of the target.
    572         DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
    573                 outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
    574                 dividerSize);
    575     }
    576 
    577     // TODO: Checkout the call points of this method and the ones below to see how they can fit in WC.
    578     void addTask(Task task, int position) {
    579         addTask(task, position, task.showForAllUsers(), true /* moveParents */);
    580     }
    581 
    582     /**
    583      * Put a Task in this stack. Used for adding only.
    584      * When task is added to top of the stack, the entire branch of the hierarchy (including stack
    585      * and display) will be brought to top.
    586      * @param task The task to add.
    587      * @param position Target position to add the task to.
    588      * @param showForAllUsers Whether to show the task regardless of the current user.
    589      */
    590     void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) {
    591         final TaskStack currentStack = task.mStack;
    592         // TODO: We pass stack to task's constructor, but we still need to call this method.
    593         // This doesn't make sense, mStack will already be set equal to "this" at this point.
    594         if (currentStack != null && currentStack.mStackId != mStackId) {
    595             throw new IllegalStateException("Trying to add taskId=" + task.mTaskId
    596                     + " to stackId=" + mStackId
    597                     + ", but it is already attached to stackId=" + task.mStack.mStackId);
    598         }
    599 
    600         // Add child task.
    601         task.mStack = this;
    602         addChild(task, null);
    603 
    604         // Move child to a proper position, as some restriction for position might apply.
    605         positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
    606     }
    607 
    608     @Override
    609     void positionChildAt(int position, Task child, boolean includingParents) {
    610         positionChildAt(position, child, includingParents, child.showForAllUsers());
    611     }
    612 
    613     /**
    614      * Overridden version of {@link TaskStack#positionChildAt(int, Task, boolean)}. Used in
    615      * {@link TaskStack#addTask(Task, int, boolean showForAllUsers, boolean)}, as it can receive
    616      * showForAllUsers param from {@link AppWindowToken} instead of {@link Task#showForAllUsers()}.
    617      */
    618     private void positionChildAt(int position, Task child, boolean includingParents,
    619             boolean showForAllUsers) {
    620         final int targetPosition = findPositionForTask(child, position, showForAllUsers,
    621                 false /* addingNew */);
    622         super.positionChildAt(targetPosition, child, includingParents);
    623 
    624         // Log positioning.
    625         if (DEBUG_TASK_MOVEMENT)
    626             Slog.d(TAG_WM, "positionTask: task=" + this + " position=" + position);
    627 
    628         final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0;
    629         EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition);
    630     }
    631 
    632     // TODO: We should really have users as a window container in the hierarchy so that we don't
    633     // have to do complicated things like we are doing in this method.
    634     private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers,
    635             boolean addingNew) {
    636         final boolean canShowTask =
    637                 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId);
    638 
    639         final int stackSize = mChildren.size();
    640         int minPosition = 0;
    641         int maxPosition = addingNew ? stackSize : stackSize - 1;
    642 
    643         if (canShowTask) {
    644             minPosition = computeMinPosition(minPosition, stackSize);
    645         } else {
    646             maxPosition = computeMaxPosition(maxPosition);
    647         }
    648 
    649         // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid.
    650         if (targetPosition == POSITION_BOTTOM && minPosition == 0) {
    651             return POSITION_BOTTOM;
    652         } else if (targetPosition == POSITION_TOP
    653                 && maxPosition == (addingNew ? stackSize : stackSize - 1)) {
    654             return POSITION_TOP;
    655         }
    656         // Reset position based on minimum/maximum possible positions.
    657         return Math.min(Math.max(targetPosition, minPosition), maxPosition);
    658     }
    659 
    660     /** Calculate the minimum possible position for a task that can be shown to the user.
    661      *  The minimum position will be above all other tasks that can't be shown.
    662      *  @param minPosition The minimum position the caller is suggesting.
    663      *                  We will start adjusting up from here.
    664      *  @param size The size of the current task list.
    665      */
    666     private int computeMinPosition(int minPosition, int size) {
    667         while (minPosition < size) {
    668             final Task tmpTask = mChildren.get(minPosition);
    669             final boolean canShowTmpTask =
    670                     tmpTask.showForAllUsers()
    671                             || mService.isCurrentProfileLocked(tmpTask.mUserId);
    672             if (canShowTmpTask) {
    673                 break;
    674             }
    675             minPosition++;
    676         }
    677         return minPosition;
    678     }
    679 
    680     /** Calculate the maximum possible position for a task that can't be shown to the user.
    681      *  The maximum position will be below all other tasks that can be shown.
    682      *  @param maxPosition The maximum position the caller is suggesting.
    683      *                  We will start adjusting down from here.
    684      */
    685     private int computeMaxPosition(int maxPosition) {
    686         while (maxPosition > 0) {
    687             final Task tmpTask = mChildren.get(maxPosition);
    688             final boolean canShowTmpTask =
    689                     tmpTask.showForAllUsers()
    690                             || mService.isCurrentProfileLocked(tmpTask.mUserId);
    691             if (!canShowTmpTask) {
    692                 break;
    693             }
    694             maxPosition--;
    695         }
    696         return maxPosition;
    697     }
    698 
    699     /**
    700      * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the
    701      * back.
    702      * @param task The Task to delete.
    703      */
    704     @Override
    705     void removeChild(Task task) {
    706         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + task);
    707 
    708         super.removeChild(task);
    709         task.mStack = null;
    710 
    711         if (mDisplayContent != null) {
    712             if (mChildren.isEmpty()) {
    713                 getParent().positionChildAt(POSITION_BOTTOM, this, false /* includingParents */);
    714             }
    715             mDisplayContent.setLayoutNeeded();
    716         }
    717         for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
    718             final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
    719             if (wtoken.getTask() == task) {
    720                 wtoken.mIsExiting = false;
    721                 mExitingAppTokens.remove(appNdx);
    722             }
    723         }
    724     }
    725 
    726     @Override
    727     public void onConfigurationChanged(Configuration newParentConfig) {
    728         final int prevWindowingMode = getWindowingMode();
    729         super.onConfigurationChanged(newParentConfig);
    730 
    731         // Only need to update surface size here since the super method will handle updating
    732         // surface position.
    733         updateSurfaceSize(getPendingTransaction());
    734         final int windowingMode = getWindowingMode();
    735 
    736         if (mDisplayContent == null || prevWindowingMode == windowingMode) {
    737             return;
    738         }
    739         mDisplayContent.onStackWindowingModeChanged(this);
    740         updateBoundsForWindowModeChange();
    741     }
    742 
    743     private void updateSurfaceBounds() {
    744         updateSurfaceSize(getPendingTransaction());
    745         updateSurfacePosition();
    746         scheduleAnimation();
    747     }
    748 
    749     /**
    750      * Calculate an amount by which to expand the stack bounds in each direction.
    751      * Used to make room for shadows in the pinned windowing mode.
    752      */
    753     int getStackOutset() {
    754         DisplayContent displayContent = getDisplayContent();
    755         if (inPinnedWindowingMode() && displayContent != null) {
    756             final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
    757 
    758             // We multiply by two to match the client logic for converting view elevation
    759             // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets}
    760             return (int)Math.ceil(mService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP,
    761                     displayMetrics) * 2);
    762         }
    763         return 0;
    764     }
    765 
    766     private void updateSurfaceSize(SurfaceControl.Transaction transaction) {
    767         if (mSurfaceControl == null) {
    768             return;
    769         }
    770 
    771         final Rect stackBounds = getBounds();
    772         int width = stackBounds.width();
    773         int height = stackBounds.height();
    774 
    775         final int outset = getStackOutset();
    776         width += 2*outset;
    777         height += 2*outset;
    778 
    779         if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
    780             return;
    781         }
    782         transaction.setSize(mSurfaceControl, width, height);
    783         mLastSurfaceSize.set(width, height);
    784     }
    785 
    786     @Override
    787     void onDisplayChanged(DisplayContent dc) {
    788         if (mDisplayContent != null) {
    789             throw new IllegalStateException("onDisplayChanged: Already attached");
    790         }
    791 
    792         mDisplayContent = dc;
    793 
    794         updateBoundsForWindowModeChange();
    795         mAnimationBackgroundSurface = makeChildSurface(null).setColorLayer(true)
    796             .setName("animation background stackId=" + mStackId)
    797             .build();
    798 
    799         super.onDisplayChanged(dc);
    800     }
    801 
    802     private void updateBoundsForWindowModeChange() {
    803         final Rect bounds = calculateBoundsForWindowModeChange();
    804 
    805         if (inSplitScreenSecondaryWindowingMode()) {
    806             // When the stack is resized due to entering split screen secondary, offset the
    807             // windows to compensate for the new stack position.
    808             forAllWindows(w -> {
    809                 w.mWinAnimator.setOffsetPositionForStackResize(true);
    810             }, true);
    811         }
    812 
    813         updateDisplayInfo(bounds);
    814         updateSurfaceBounds();
    815     }
    816 
    817     private Rect calculateBoundsForWindowModeChange() {
    818         final boolean inSplitScreenPrimary = inSplitScreenPrimaryWindowingMode();
    819         final TaskStack splitScreenStack =
    820                 mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
    821         if (inSplitScreenPrimary || (splitScreenStack != null
    822                 && inSplitScreenSecondaryWindowingMode() && !splitScreenStack.fillsParent())) {
    823             // The existence of a docked stack affects the size of other static stack created since
    824             // the docked stack occupies a dedicated region on screen, but only if the dock stack is
    825             // not fullscreen. If it's fullscreen, it means that we are in the transition of
    826             // dismissing it, so we must not resize this stack.
    827             final Rect bounds = new Rect();
    828             mDisplayContent.getBounds(mTmpRect);
    829             mTmpRect2.setEmpty();
    830             if (splitScreenStack != null) {
    831                 if (inSplitScreenSecondaryWindowingMode()
    832                         && mDisplayContent.mDividerControllerLocked.isMinimizedDock()
    833                         && splitScreenStack.getTopChild() != null) {
    834                     // If the primary split screen stack is currently minimized, then don't use the
    835                     // stack bounds of the minimized stack, instead, use the temporary task bounds
    836                     // to calculate the appropriate uniminized size of any secondary split stack
    837                     // TODO: Find a cleaner way for computing new stack bounds while minimized that
    838                     //       doesn't assume the primary stack's task bounds as the temp task bounds
    839                     splitScreenStack.getTopChild().getBounds(mTmpRect2);
    840                 } else {
    841                     splitScreenStack.getRawBounds(mTmpRect2);
    842                 }
    843             }
    844             final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
    845                     == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
    846             getStackDockedModeBounds(mTmpRect, bounds, mTmpRect2,
    847                     mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
    848             return bounds;
    849         } else if (inPinnedWindowingMode()) {
    850             // Update the bounds based on any changes to the display info
    851             getAnimationOrCurrentBounds(mTmpRect2);
    852             if (mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
    853                     mTmpRect2, mTmpRect3)) {
    854                 return new Rect(mTmpRect3);
    855             }
    856         }
    857         return null;
    858     }
    859 
    860     /**
    861      * Determines the stack and task bounds of the other stack when in docked mode. The current task
    862      * bounds is passed in but depending on the stack, the task and stack must match. Only in
    863      * minimized mode with resizable launcher, the other stack ignores calculating the stack bounds
    864      * and uses the task bounds passed in as the stack and task bounds, otherwise the stack bounds
    865      * is calculated and is also used for its task bounds.
    866      * If any of the out bounds are empty, it represents default bounds
    867      *
    868      * @param currentTempTaskBounds the current task bounds of the other stack
    869      * @param outStackBounds the calculated stack bounds of the other stack
    870      * @param outTempTaskBounds the calculated task bounds of the other stack
    871      * @param ignoreVisibility ignore visibility in getting the stack bounds
    872      */
    873     void getStackDockedModeBoundsLocked(Rect currentTempTaskBounds, Rect outStackBounds,
    874             Rect outTempTaskBounds, boolean ignoreVisibility) {
    875         outTempTaskBounds.setEmpty();
    876 
    877         // When the home stack is resizable, should always have the same stack and task bounds
    878         if (isActivityTypeHome()) {
    879             final Task homeTask = findHomeTask();
    880             if (homeTask != null && homeTask.isResizeable()) {
    881                 // Calculate the home stack bounds when in docked mode and the home stack is
    882                 // resizeable.
    883                 getDisplayContent().mDividerControllerLocked
    884                         .getHomeStackBoundsInDockedMode(outStackBounds);
    885             } else {
    886                 // Home stack isn't resizeable, so don't specify stack bounds.
    887                 outStackBounds.setEmpty();
    888             }
    889 
    890             outTempTaskBounds.set(outStackBounds);
    891             return;
    892         }
    893 
    894         // When minimized state, the stack bounds for all non-home and docked stack bounds should
    895         // match the passed task bounds
    896         if (isMinimizedDockAndHomeStackResizable() && currentTempTaskBounds != null) {
    897             outStackBounds.set(currentTempTaskBounds);
    898             return;
    899         }
    900 
    901         if (!inSplitScreenWindowingMode() || mDisplayContent == null) {
    902             outStackBounds.set(getRawBounds());
    903             return;
    904         }
    905 
    906         final TaskStack dockedStack =
    907                 mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
    908         if (dockedStack == null) {
    909             // Not sure why you are calling this method when there is no docked stack...
    910             throw new IllegalStateException(
    911                     "Calling getStackDockedModeBoundsLocked() when there is no docked stack.");
    912         }
    913         if (!ignoreVisibility && !dockedStack.isVisible()) {
    914             // The docked stack is being dismissed, but we caught before it finished being
    915             // dismissed. In that case we want to treat it as if it is not occupying any space and
    916             // let others occupy the whole display.
    917             mDisplayContent.getBounds(outStackBounds);
    918             return;
    919         }
    920 
    921         final int dockedSide = dockedStack.getDockSide();
    922         if (dockedSide == DOCKED_INVALID) {
    923             // Not sure how you got here...Only thing we can do is return current bounds.
    924             Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack);
    925             outStackBounds.set(getRawBounds());
    926             return;
    927         }
    928 
    929         mDisplayContent.getBounds(mTmpRect);
    930         dockedStack.getRawBounds(mTmpRect2);
    931         final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
    932         getStackDockedModeBounds(mTmpRect, outStackBounds, mTmpRect2,
    933                 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
    934 
    935     }
    936 
    937     /**
    938      * Outputs the bounds a stack should be given the presence of a docked stack on the display.
    939      * @param displayRect The bounds of the display the docked stack is on.
    940      * @param outBounds Output bounds that should be used for the stack.
    941      * @param dockedBounds Bounds of the docked stack.
    942      * @param dockDividerWidth We need to know the width of the divider make to the output bounds
    943      *                         close to the side of the dock.
    944      * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
    945      */
    946     private void getStackDockedModeBounds(
    947             Rect displayRect, Rect outBounds, Rect dockedBounds, int dockDividerWidth,
    948             boolean dockOnTopOrLeft) {
    949         final boolean dockedStack = inSplitScreenPrimaryWindowingMode();
    950         final boolean splitHorizontally = displayRect.width() > displayRect.height();
    951 
    952         outBounds.set(displayRect);
    953         if (dockedStack) {
    954             if (mService.mDockedStackCreateBounds != null) {
    955                 outBounds.set(mService.mDockedStackCreateBounds);
    956                 return;
    957             }
    958 
    959             // The initial bounds of the docked stack when it is created about half the screen space
    960             // and its bounds can be adjusted after that. The bounds of all other stacks are
    961             // adjusted to occupy whatever screen space the docked stack isn't occupying.
    962             final DisplayInfo di = mDisplayContent.getDisplayInfo();
    963             mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
    964                     di.displayCutout, mTmpRect2);
    965             final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
    966                     di.logicalWidth,
    967                     di.logicalHeight,
    968                     dockDividerWidth,
    969                     mDisplayContent.getConfiguration().orientation == ORIENTATION_PORTRAIT,
    970                     mTmpRect2).getMiddleTarget().position;
    971 
    972             if (dockOnTopOrLeft) {
    973                 if (splitHorizontally) {
    974                     outBounds.right = position;
    975                 } else {
    976                     outBounds.bottom = position;
    977                 }
    978             } else {
    979                 if (splitHorizontally) {
    980                     outBounds.left = position + dockDividerWidth;
    981                 } else {
    982                     outBounds.top = position + dockDividerWidth;
    983                 }
    984             }
    985             return;
    986         }
    987 
    988         // Other stacks occupy whatever space is left by the docked stack.
    989         if (!dockOnTopOrLeft) {
    990             if (splitHorizontally) {
    991                 outBounds.right = dockedBounds.left - dockDividerWidth;
    992             } else {
    993                 outBounds.bottom = dockedBounds.top - dockDividerWidth;
    994             }
    995         } else {
    996             if (splitHorizontally) {
    997                 outBounds.left = dockedBounds.right + dockDividerWidth;
    998             } else {
    999                 outBounds.top = dockedBounds.bottom + dockDividerWidth;
   1000             }
   1001         }
   1002         DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
   1003     }
   1004 
   1005     void resetDockedStackToMiddle() {
   1006         if (inSplitScreenPrimaryWindowingMode()) {
   1007             throw new IllegalStateException("Not a docked stack=" + this);
   1008         }
   1009 
   1010         mService.mDockedStackCreateBounds = null;
   1011 
   1012         final Rect bounds = new Rect();
   1013         final Rect tempBounds = new Rect();
   1014         getStackDockedModeBoundsLocked(null /* currentTempTaskBounds */, bounds, tempBounds,
   1015                 true /*ignoreVisibility*/);
   1016         getController().requestResize(bounds);
   1017     }
   1018 
   1019     @Override
   1020     StackWindowController getController() {
   1021         return (StackWindowController) super.getController();
   1022     }
   1023 
   1024     @Override
   1025     void removeIfPossible() {
   1026         if (isSelfOrChildAnimating()) {
   1027             mDeferRemoval = true;
   1028             return;
   1029         }
   1030         removeImmediately();
   1031     }
   1032 
   1033     @Override
   1034     void onParentSet() {
   1035         super.onParentSet();
   1036 
   1037         if (getParent() != null || mDisplayContent == null) {
   1038             return;
   1039         }
   1040 
   1041         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
   1042 
   1043         if (mAnimationBackgroundSurface != null) {
   1044             mAnimationBackgroundSurface.destroy();
   1045             mAnimationBackgroundSurface = null;
   1046         }
   1047 
   1048         mDisplayContent = null;
   1049         mService.mWindowPlacerLocked.requestTraversal();
   1050     }
   1051 
   1052     void resetAnimationBackgroundAnimator() {
   1053         mAnimationBackgroundAnimator = null;
   1054         hideAnimationSurface();
   1055     }
   1056 
   1057     void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
   1058         int animLayer = winAnimator.mAnimLayer;
   1059         if (mAnimationBackgroundAnimator == null
   1060                 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) {
   1061             mAnimationBackgroundAnimator = winAnimator;
   1062             animLayer = mDisplayContent.getLayerForAnimationBackground(winAnimator);
   1063             showAnimationSurface(((color >> 24) & 0xff) / 255f);
   1064         }
   1065     }
   1066 
   1067     // TODO: Should each user have there own stacks?
   1068     @Override
   1069     void switchUser() {
   1070         super.switchUser();
   1071         int top = mChildren.size();
   1072         for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
   1073             Task task = mChildren.get(taskNdx);
   1074             if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
   1075                 mChildren.remove(taskNdx);
   1076                 mChildren.add(task);
   1077                 --top;
   1078             }
   1079         }
   1080     }
   1081 
   1082     /**
   1083      * Adjusts the stack bounds if the IME is visible.
   1084      *
   1085      * @param imeWin The IME window.
   1086      */
   1087     void setAdjustedForIme(WindowState imeWin, boolean forceUpdate) {
   1088         mImeWin = imeWin;
   1089         mImeGoingAway = false;
   1090         if (!mAdjustedForIme || forceUpdate) {
   1091             mAdjustedForIme = true;
   1092             mAdjustImeAmount = 0f;
   1093             mAdjustDividerAmount = 0f;
   1094             updateAdjustForIme(0f, 0f, true /* force */);
   1095         }
   1096     }
   1097 
   1098     boolean isAdjustedForIme() {
   1099         return mAdjustedForIme;
   1100     }
   1101 
   1102     boolean isAnimatingForIme() {
   1103         return mImeWin != null && mImeWin.isAnimatingLw();
   1104     }
   1105 
   1106     /**
   1107      * Update the stack's bounds (crop or position) according to the IME window's
   1108      * current position. When IME window is animated, the bottom stack is animated
   1109      * together to track the IME window's current position, and the top stack is
   1110      * cropped as necessary.
   1111      *
   1112      * @return true if a traversal should be performed after the adjustment.
   1113      */
   1114     boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
   1115         if (adjustAmount != mAdjustImeAmount
   1116                 || adjustDividerAmount != mAdjustDividerAmount || force) {
   1117             mAdjustImeAmount = adjustAmount;
   1118             mAdjustDividerAmount = adjustDividerAmount;
   1119             updateAdjustedBounds();
   1120             return isVisible();
   1121         } else {
   1122             return false;
   1123         }
   1124     }
   1125 
   1126     /**
   1127      * Resets the adjustment after it got adjusted for the IME.
   1128      * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about
   1129      *                        animations; otherwise, set flag and animates the window away together
   1130      *                        with IME window.
   1131      */
   1132     void resetAdjustedForIme(boolean adjustBoundsNow) {
   1133         if (adjustBoundsNow) {
   1134             mImeWin = null;
   1135             mImeGoingAway = false;
   1136             mAdjustImeAmount = 0f;
   1137             mAdjustDividerAmount = 0f;
   1138             if (!mAdjustedForIme) {
   1139                 return;
   1140             }
   1141             mAdjustedForIme = false;
   1142             updateAdjustedBounds();
   1143             mService.setResizeDimLayer(false, getWindowingMode(), 1.0f);
   1144         } else {
   1145             mImeGoingAway |= mAdjustedForIme;
   1146         }
   1147     }
   1148 
   1149     /**
   1150      * Sets the amount how much we currently minimize our stack.
   1151      *
   1152      * @param minimizeAmount The amount, between 0 and 1.
   1153      * @return Whether the amount has changed and a layout is needed.
   1154      */
   1155     boolean setAdjustedForMinimizedDock(float minimizeAmount) {
   1156         if (minimizeAmount != mMinimizeAmount) {
   1157             mMinimizeAmount = minimizeAmount;
   1158             updateAdjustedBounds();
   1159             return isVisible();
   1160         } else {
   1161             return false;
   1162         }
   1163     }
   1164 
   1165     boolean shouldIgnoreInput() {
   1166         return isAdjustedForMinimizedDockedStack() ||
   1167                 (inSplitScreenPrimaryWindowingMode() && isMinimizedDockAndHomeStackResizable());
   1168     }
   1169 
   1170     /**
   1171      * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows
   1172      * to the list of to be drawn windows the service is waiting for.
   1173      */
   1174     void beginImeAdjustAnimation() {
   1175         for (int j = mChildren.size() - 1; j >= 0; j--) {
   1176             final Task task = mChildren.get(j);
   1177             if (task.hasContentToDisplay()) {
   1178                 task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
   1179                 task.setWaitingForDrawnIfResizingChanged();
   1180             }
   1181         }
   1182     }
   1183 
   1184     /**
   1185      * Resets the resizing state of all windows.
   1186      */
   1187     void endImeAdjustAnimation() {
   1188         for (int j = mChildren.size() - 1; j >= 0; j--) {
   1189             mChildren.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
   1190         }
   1191     }
   1192 
   1193     int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
   1194         return displayContentRect.top + (int)
   1195                 ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN);
   1196     }
   1197 
   1198     private boolean adjustForIME(final WindowState imeWin) {
   1199         final int dockedSide = getDockSide();
   1200         final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
   1201         if (imeWin == null || !dockedTopOrBottom) {
   1202             return false;
   1203         }
   1204 
   1205         final Rect displayStableRect = mTmpRect;
   1206         final Rect contentBounds = mTmpRect2;
   1207 
   1208         // Calculate the content bounds excluding the area occupied by IME
   1209         getDisplayContent().getStableRect(displayStableRect);
   1210         contentBounds.set(displayStableRect);
   1211         int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
   1212 
   1213         imeTop += imeWin.getGivenContentInsetsLw().top;
   1214         if (contentBounds.bottom > imeTop) {
   1215             contentBounds.bottom = imeTop;
   1216         }
   1217 
   1218         final int yOffset = displayStableRect.bottom - contentBounds.bottom;
   1219 
   1220         final int dividerWidth =
   1221                 getDisplayContent().mDividerControllerLocked.getContentWidth();
   1222         final int dividerWidthInactive =
   1223                 getDisplayContent().mDividerControllerLocked.getContentWidthInactive();
   1224 
   1225         if (dockedSide == DOCKED_TOP) {
   1226             // If this stack is docked on top, we make it smaller so the bottom stack is not
   1227             // occluded by IME. We shift its bottom up by the height of the IME, but
   1228             // leaves at least 30% of the top stack visible.
   1229             final int minTopStackBottom =
   1230                     getMinTopStackBottom(displayStableRect, getRawBounds().bottom);
   1231             final int bottom = Math.max(
   1232                     getRawBounds().bottom - yOffset + dividerWidth - dividerWidthInactive,
   1233                     minTopStackBottom);
   1234             mTmpAdjustedBounds.set(getRawBounds());
   1235             mTmpAdjustedBounds.bottom = (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount)
   1236                     * getRawBounds().bottom);
   1237             mFullyAdjustedImeBounds.set(getRawBounds());
   1238         } else {
   1239             // When the stack is on bottom and has no focus, it's only adjusted for divider width.
   1240             final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
   1241 
   1242             // When the stack is on bottom and has focus, it needs to be moved up so as to
   1243             // not occluded by IME, and at the same time adjusted for divider width.
   1244             // We try to move it up by the height of the IME window, but only to the extent
   1245             // that leaves at least 30% of the top stack visible.
   1246             // 'top' is where the top of bottom stack will move to in this case.
   1247             final int topBeforeImeAdjust =
   1248                     getRawBounds().top - dividerWidth + dividerWidthInactive;
   1249             final int minTopStackBottom =
   1250                     getMinTopStackBottom(displayStableRect,
   1251                             getRawBounds().top - dividerWidth);
   1252             final int top = Math.max(
   1253                     getRawBounds().top - yOffset, minTopStackBottom + dividerWidthInactive);
   1254 
   1255             mTmpAdjustedBounds.set(getRawBounds());
   1256             // Account for the adjustment for IME and divider width separately.
   1257             // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
   1258             // and dividerWidthDelta is due to divider width change only.
   1259             mTmpAdjustedBounds.top = getRawBounds().top +
   1260                     (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) +
   1261                             mAdjustDividerAmount * dividerWidthDelta);
   1262             mFullyAdjustedImeBounds.set(getRawBounds());
   1263             mFullyAdjustedImeBounds.top = top;
   1264             mFullyAdjustedImeBounds.bottom = top + getRawBounds().height();
   1265         }
   1266         return true;
   1267     }
   1268 
   1269     private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
   1270         final int dockSide = getDockSide();
   1271         if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
   1272             return false;
   1273         }
   1274 
   1275         if (dockSide == DOCKED_TOP) {
   1276             mService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
   1277             int topInset = mTmpRect.top;
   1278             mTmpAdjustedBounds.set(getRawBounds());
   1279             mTmpAdjustedBounds.bottom = (int) (minimizeAmount * topInset + (1 - minimizeAmount)
   1280                     * getRawBounds().bottom);
   1281         } else if (dockSide == DOCKED_LEFT) {
   1282             mTmpAdjustedBounds.set(getRawBounds());
   1283             final int width = getRawBounds().width();
   1284             mTmpAdjustedBounds.right =
   1285                     (int) (minimizeAmount * mDockedStackMinimizeThickness
   1286                             + (1 - minimizeAmount) * getRawBounds().right);
   1287             mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
   1288         } else if (dockSide == DOCKED_RIGHT) {
   1289             mTmpAdjustedBounds.set(getRawBounds());
   1290             mTmpAdjustedBounds.left = (int) (minimizeAmount *
   1291                     (getRawBounds().right - mDockedStackMinimizeThickness)
   1292                             + (1 - minimizeAmount) * getRawBounds().left);
   1293         }
   1294         return true;
   1295     }
   1296 
   1297     private boolean isMinimizedDockAndHomeStackResizable() {
   1298         return mDisplayContent.mDividerControllerLocked.isMinimizedDock()
   1299                 && mDisplayContent.mDividerControllerLocked.isHomeStackResizable();
   1300     }
   1301 
   1302     /**
   1303      * @return the distance in pixels how much the stack gets minimized from it's original size
   1304      */
   1305     int getMinimizeDistance() {
   1306         final int dockSide = getDockSide();
   1307         if (dockSide == DOCKED_INVALID) {
   1308             return 0;
   1309         }
   1310 
   1311         if (dockSide == DOCKED_TOP) {
   1312             mService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
   1313             int topInset = mTmpRect.top;
   1314             return getRawBounds().bottom - topInset;
   1315         } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
   1316             return getRawBounds().width() - mDockedStackMinimizeThickness;
   1317         } else {
   1318             return 0;
   1319         }
   1320     }
   1321 
   1322     /**
   1323      * Updates the adjustment depending on it's current state.
   1324      */
   1325     private void updateAdjustedBounds() {
   1326         boolean adjust = false;
   1327         if (mMinimizeAmount != 0f) {
   1328             adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
   1329         } else if (mAdjustedForIme) {
   1330             adjust = adjustForIME(mImeWin);
   1331         }
   1332         if (!adjust) {
   1333             mTmpAdjustedBounds.setEmpty();
   1334         }
   1335         setAdjustedBounds(mTmpAdjustedBounds);
   1336 
   1337         final boolean isImeTarget = (mService.getImeFocusStackLocked() == this);
   1338         if (mAdjustedForIme && adjust && !isImeTarget) {
   1339             final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
   1340                     * IME_ADJUST_DIM_AMOUNT;
   1341             mService.setResizeDimLayer(true, getWindowingMode(), alpha);
   1342         }
   1343     }
   1344 
   1345     void applyAdjustForImeIfNeeded(Task task) {
   1346         if (mMinimizeAmount != 0f || !mAdjustedForIme || mAdjustedBounds.isEmpty()) {
   1347             return;
   1348         }
   1349 
   1350         final Rect insetBounds = mImeGoingAway ? getRawBounds() : mFullyAdjustedImeBounds;
   1351         task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP);
   1352         mDisplayContent.setLayoutNeeded();
   1353     }
   1354 
   1355 
   1356     boolean isAdjustedForMinimizedDockedStack() {
   1357         return mMinimizeAmount != 0f;
   1358     }
   1359 
   1360     /**
   1361      * @return {@code true} if we have a {@link Task} that is animating (currently only used for the
   1362      *         recents animation); {@code false} otherwise.
   1363      */
   1364     boolean isTaskAnimating() {
   1365         for (int j = mChildren.size() - 1; j >= 0; j--) {
   1366             final Task task = mChildren.get(j);
   1367             if (task.isTaskAnimating()) {
   1368                 return true;
   1369             }
   1370         }
   1371         return false;
   1372     }
   1373 
   1374     @CallSuper
   1375     @Override
   1376     public void writeToProto(ProtoOutputStream proto, long fieldId, boolean trim) {
   1377         final long token = proto.start(fieldId);
   1378         super.writeToProto(proto, WINDOW_CONTAINER, trim);
   1379         proto.write(ID, mStackId);
   1380         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
   1381             mChildren.get(taskNdx).writeToProto(proto, TASKS, trim);
   1382         }
   1383         proto.write(FILLS_PARENT, matchParentBounds());
   1384         getRawBounds().writeToProto(proto, BOUNDS);
   1385         proto.write(ANIMATION_BACKGROUND_SURFACE_IS_DIMMING, mAnimationBackgroundSurfaceIsShown);
   1386         proto.write(DEFER_REMOVAL, mDeferRemoval);
   1387         proto.write(MINIMIZE_AMOUNT, mMinimizeAmount);
   1388         proto.write(ADJUSTED_FOR_IME, mAdjustedForIme);
   1389         proto.write(ADJUST_IME_AMOUNT, mAdjustImeAmount);
   1390         proto.write(ADJUST_DIVIDER_AMOUNT, mAdjustDividerAmount);
   1391         mAdjustedBounds.writeToProto(proto, ADJUSTED_BOUNDS);
   1392         proto.write(ANIMATING_BOUNDS, mBoundsAnimating);
   1393         proto.end(token);
   1394     }
   1395 
   1396     @Override
   1397      void dump(PrintWriter pw, String prefix, boolean dumpAll) {
   1398         pw.println(prefix + "mStackId=" + mStackId);
   1399         pw.println(prefix + "mDeferRemoval=" + mDeferRemoval);
   1400         pw.println(prefix + "mBounds=" + getRawBounds().toShortString());
   1401         if (mMinimizeAmount != 0f) {
   1402             pw.println(prefix + "mMinimizeAmount=" + mMinimizeAmount);
   1403         }
   1404         if (mAdjustedForIme) {
   1405             pw.println(prefix + "mAdjustedForIme=true");
   1406             pw.println(prefix + "mAdjustImeAmount=" + mAdjustImeAmount);
   1407             pw.println(prefix + "mAdjustDividerAmount=" + mAdjustDividerAmount);
   1408         }
   1409         if (!mAdjustedBounds.isEmpty()) {
   1410             pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString());
   1411         }
   1412         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
   1413             mChildren.get(taskNdx).dump(pw, prefix + "  ", dumpAll);
   1414         }
   1415         if (mAnimationBackgroundSurfaceIsShown) {
   1416             pw.println(prefix + "mWindowAnimationBackgroundSurface is shown");
   1417         }
   1418         if (!mExitingAppTokens.isEmpty()) {
   1419             pw.println();
   1420             pw.println("  Exiting application tokens:");
   1421             for (int i = mExitingAppTokens.size() - 1; i >= 0; i--) {
   1422                 WindowToken token = mExitingAppTokens.get(i);
   1423                 pw.print("  Exiting App #"); pw.print(i);
   1424                 pw.print(' '); pw.print(token);
   1425                 pw.println(':');
   1426                 token.dump(pw, "    ", dumpAll);
   1427             }
   1428         }
   1429         mAnimatingAppWindowTokenRegistry.dump(pw, "AnimatingApps:", prefix);
   1430     }
   1431 
   1432     @Override
   1433     boolean fillsParent() {
   1434         if (useCurrentBounds()) {
   1435             return matchParentBounds();
   1436         }
   1437         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
   1438         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
   1439         // system.
   1440         return true;
   1441     }
   1442 
   1443     @Override
   1444     public String toString() {
   1445         return "{stackId=" + mStackId + " tasks=" + mChildren + "}";
   1446     }
   1447 
   1448     String getName() {
   1449         return toShortString();
   1450     }
   1451 
   1452     public String toShortString() {
   1453         return "Stack=" + mStackId;
   1454     }
   1455 
   1456     /**
   1457      * For docked workspace (or workspace that's side-by-side to the docked), provides
   1458      * information which side of the screen was the dock anchored.
   1459      */
   1460     int getDockSide() {
   1461         return getDockSide(getRawBounds());
   1462     }
   1463 
   1464     int getDockSideForDisplay(DisplayContent dc) {
   1465         return getDockSide(dc, getRawBounds());
   1466     }
   1467 
   1468     private int getDockSide(Rect bounds) {
   1469         if (mDisplayContent == null) {
   1470             return DOCKED_INVALID;
   1471         }
   1472         return getDockSide(mDisplayContent, bounds);
   1473     }
   1474 
   1475     private int getDockSide(DisplayContent dc, Rect bounds) {
   1476         if (!inSplitScreenWindowingMode()) {
   1477             return DOCKED_INVALID;
   1478         }
   1479         dc.getBounds(mTmpRect);
   1480         final int orientation = dc.getConfiguration().orientation;
   1481         return dc.getDockedDividerController().getDockSide(bounds, mTmpRect, orientation);
   1482     }
   1483 
   1484     boolean hasTaskForUser(int userId) {
   1485         for (int i = mChildren.size() - 1; i >= 0; i--) {
   1486             final Task task = mChildren.get(i);
   1487             if (task.mUserId == userId) {
   1488                 return true;
   1489             }
   1490         }
   1491         return false;
   1492     }
   1493 
   1494     int taskIdFromPoint(int x, int y) {
   1495         getBounds(mTmpRect);
   1496         if (!mTmpRect.contains(x, y) || isAdjustedForMinimizedDockedStack()) {
   1497             return -1;
   1498         }
   1499 
   1500         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
   1501             final Task task = mChildren.get(taskNdx);
   1502             final WindowState win = task.getTopVisibleAppMainWindow();
   1503             if (win == null) {
   1504                 continue;
   1505             }
   1506             // We need to use the task's dim bounds (which is derived from the visible bounds of its
   1507             // apps windows) for any touch-related tests. Can't use the task's original bounds
   1508             // because it might be adjusted to fit the content frame. For example, the presence of
   1509             // the IME adjusting the windows frames when the app window is the IME target.
   1510             task.getDimBounds(mTmpRect);
   1511             if (mTmpRect.contains(x, y)) {
   1512                 return task.mTaskId;
   1513             }
   1514         }
   1515 
   1516         return -1;
   1517     }
   1518 
   1519     void findTaskForResizePoint(int x, int y, int delta,
   1520             DisplayContent.TaskForResizePointSearchResult results) {
   1521         if (!getWindowConfiguration().canResizeTask()) {
   1522             results.searchDone = true;
   1523             return;
   1524         }
   1525 
   1526         for (int i = mChildren.size() - 1; i >= 0; --i) {
   1527             final Task task = mChildren.get(i);
   1528             if (task.isFullscreen()) {
   1529                 results.searchDone = true;
   1530                 return;
   1531             }
   1532 
   1533             // We need to use the task's dim bounds (which is derived from the visible bounds of
   1534             // its apps windows) for any touch-related tests. Can't use the task's original
   1535             // bounds because it might be adjusted to fit the content frame. One example is when
   1536             // the task is put to top-left quadrant, the actual visible area would not start at
   1537             // (0,0) after it's adjusted for the status bar.
   1538             task.getDimBounds(mTmpRect);
   1539             mTmpRect.inset(-delta, -delta);
   1540             if (mTmpRect.contains(x, y)) {
   1541                 mTmpRect.inset(delta, delta);
   1542 
   1543                 results.searchDone = true;
   1544 
   1545                 if (!mTmpRect.contains(x, y)) {
   1546                     results.taskForResize = task;
   1547                     return;
   1548                 }
   1549                 // User touched inside the task. No need to look further,
   1550                 // focus transfer will be handled in ACTION_UP.
   1551                 return;
   1552             }
   1553         }
   1554     }
   1555 
   1556     void setTouchExcludeRegion(Task focusedTask, int delta, Region touchExcludeRegion,
   1557             Rect contentRect, Rect postExclude) {
   1558         for (int i = mChildren.size() - 1; i >= 0; --i) {
   1559             final Task task = mChildren.get(i);
   1560             AppWindowToken token = task.getTopVisibleAppToken();
   1561             if (token == null || !token.hasContentToDisplay()) {
   1562                 continue;
   1563             }
   1564 
   1565             /**
   1566              * Exclusion region is the region that TapDetector doesn't care about.
   1567              * Here we want to remove all non-focused tasks from the exclusion region.
   1568              * We also remove the outside touch area for resizing for all freeform
   1569              * tasks (including the focused).
   1570              *
   1571              * We save the focused task region once we find it, and add it back at the end.
   1572              *
   1573              * If the task is home stack and it is resizable in the minimized state, we want to
   1574              * exclude the docked stack from touch so we need the entire screen area and not just a
   1575              * small portion which the home stack currently is resized to.
   1576              */
   1577 
   1578             if (task.isActivityTypeHome() && isMinimizedDockAndHomeStackResizable()) {
   1579                 mDisplayContent.getBounds(mTmpRect);
   1580             } else {
   1581                 task.getDimBounds(mTmpRect);
   1582             }
   1583 
   1584             if (task == focusedTask) {
   1585                 // Add the focused task rect back into the exclude region once we are done
   1586                 // processing stacks.
   1587                 postExclude.set(mTmpRect);
   1588             }
   1589 
   1590             final boolean isFreeformed = task.inFreeformWindowingMode();
   1591             if (task != focusedTask || isFreeformed) {
   1592                 if (isFreeformed) {
   1593                     // If the task is freeformed, enlarge the area to account for outside
   1594                     // touch area for resize.
   1595                     mTmpRect.inset(-delta, -delta);
   1596                     // Intersect with display content rect. If we have system decor (status bar/
   1597                     // navigation bar), we want to exclude that from the tap detection.
   1598                     // Otherwise, if the app is partially placed under some system button (eg.
   1599                     // Recents, Home), pressing that button would cause a full series of
   1600                     // unwanted transfer focus/resume/pause, before we could go home.
   1601                     mTmpRect.intersect(contentRect);
   1602                 }
   1603                 touchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
   1604             }
   1605         }
   1606     }
   1607 
   1608     public boolean setPinnedStackSize(Rect stackBounds, Rect tempTaskBounds) {
   1609         // Hold the lock since this is called from the BoundsAnimator running on the UiThread
   1610         synchronized (mService.mWindowMap) {
   1611             if (mCancelCurrentBoundsAnimation) {
   1612                 return false;
   1613             }
   1614         }
   1615 
   1616         try {
   1617             mService.mActivityManager.resizePinnedStack(stackBounds, tempTaskBounds);
   1618         } catch (RemoteException e) {
   1619             // I don't believe you.
   1620         }
   1621         return true;
   1622     }
   1623 
   1624     void onAllWindowsDrawn() {
   1625         if (!mBoundsAnimating && !mBoundsAnimatingRequested) {
   1626             return;
   1627         }
   1628 
   1629         mService.mBoundsAnimationController.onAllWindowsDrawn();
   1630     }
   1631 
   1632     @Override  // AnimatesBounds
   1633     public void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) {
   1634         // Hold the lock since this is called from the BoundsAnimator running on the UiThread
   1635         synchronized (mService.mWindowMap) {
   1636             mBoundsAnimatingRequested = false;
   1637             mBoundsAnimating = true;
   1638             mCancelCurrentBoundsAnimation = false;
   1639 
   1640             // If we are changing UI mode, as in the PiP to fullscreen
   1641             // transition, then we need to wait for the window to draw.
   1642             if (schedulePipModeChangedCallback) {
   1643                 forAllWindows((w) -> { w.mWinAnimator.resetDrawState(); },
   1644                         false /* traverseTopToBottom */);
   1645             }
   1646         }
   1647 
   1648         if (inPinnedWindowingMode()) {
   1649             try {
   1650                 mService.mActivityManager.notifyPinnedStackAnimationStarted();
   1651             } catch (RemoteException e) {
   1652                 // I don't believe you...
   1653             }
   1654 
   1655             final PinnedStackWindowController controller =
   1656                     (PinnedStackWindowController) getController();
   1657             if (schedulePipModeChangedCallback && controller != null) {
   1658                 // We need to schedule the PiP mode change before the animation up. It is possible
   1659                 // in this case for the animation down to not have been completed, so always
   1660                 // force-schedule and update to the client to ensure that it is notified that it
   1661                 // is no longer in picture-in-picture mode
   1662                 controller.updatePictureInPictureModeForPinnedStackAnimation(null, forceUpdate);
   1663             }
   1664         }
   1665     }
   1666 
   1667     @Override  // AnimatesBounds
   1668     public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize,
   1669             boolean moveToFullscreen) {
   1670         if (inPinnedWindowingMode()) {
   1671             // Update to the final bounds if requested. This is done here instead of in the bounds
   1672             // animator to allow us to coordinate this after we notify the PiP mode changed
   1673 
   1674             final PinnedStackWindowController controller =
   1675                     (PinnedStackWindowController) getController();
   1676             if (schedulePipModeChangedCallback && controller != null) {
   1677                 // We need to schedule the PiP mode change after the animation down, so use the
   1678                 // final bounds
   1679                 controller.updatePictureInPictureModeForPinnedStackAnimation(
   1680                         mBoundsAnimationTarget, false /* forceUpdate */);
   1681             }
   1682 
   1683             if (finalStackSize != null) {
   1684                 setPinnedStackSize(finalStackSize, null);
   1685             } else {
   1686                 // We have been canceled, so the final stack size is null, still run the
   1687                 // animation-end logic
   1688                 onPipAnimationEndResize();
   1689             }
   1690 
   1691             try {
   1692                 mService.mActivityManager.notifyPinnedStackAnimationEnded();
   1693                 if (moveToFullscreen) {
   1694                     mService.mActivityManager.moveTasksToFullscreenStack(mStackId,
   1695                             true /* onTop */);
   1696                 }
   1697             } catch (RemoteException e) {
   1698                 // I don't believe you...
   1699             }
   1700         } else {
   1701             // No PiP animation, just run the normal animation-end logic
   1702             onPipAnimationEndResize();
   1703         }
   1704     }
   1705 
   1706     /**
   1707      * Called immediately prior to resizing the tasks at the end of the pinned stack animation.
   1708      */
   1709     public void onPipAnimationEndResize() {
   1710         mBoundsAnimating = false;
   1711         for (int i = 0; i < mChildren.size(); i++) {
   1712             final Task t = mChildren.get(i);
   1713             t.clearPreserveNonFloatingState();
   1714         }
   1715         mService.requestTraversal();
   1716     }
   1717 
   1718     @Override
   1719     public boolean shouldDeferStartOnMoveToFullscreen() {
   1720         // Workaround for the recents animation -- normally we need to wait for the new activity to
   1721         // show before starting the PiP animation, but because we start and show the home activity
   1722         // early for the recents animation prior to the PiP animation starting, there is no
   1723         // subsequent all-drawn signal. In this case, we can skip the pause when the home stack is
   1724         // already visible and drawn.
   1725         final TaskStack homeStack = mDisplayContent.getHomeStack();
   1726         if (homeStack == null) {
   1727             return true;
   1728         }
   1729         final Task homeTask = homeStack.getTopChild();
   1730         if (homeTask == null) {
   1731             return true;
   1732         }
   1733         final AppWindowToken homeApp = homeTask.getTopVisibleAppToken();
   1734         if (!homeTask.isVisible() || homeApp == null) {
   1735             return true;
   1736         }
   1737         return !homeApp.allDrawn;
   1738     }
   1739 
   1740     /**
   1741      * @return True if we are currently animating the pinned stack from fullscreen to non-fullscreen
   1742      *         bounds and we have a deferred PiP mode changed callback set with the animation.
   1743      */
   1744     public boolean deferScheduleMultiWindowModeChanged() {
   1745         if (inPinnedWindowingMode()) {
   1746             return (mBoundsAnimatingRequested || mBoundsAnimating);
   1747         }
   1748         return false;
   1749     }
   1750 
   1751     public boolean isForceScaled() {
   1752         return mBoundsAnimating;
   1753     }
   1754 
   1755     public boolean isAnimatingBounds() {
   1756         return mBoundsAnimating;
   1757     }
   1758 
   1759     public boolean lastAnimatingBoundsWasToFullscreen() {
   1760         return mBoundsAnimatingToFullscreen;
   1761     }
   1762 
   1763     public boolean isAnimatingBoundsToFullscreen() {
   1764         return isAnimatingBounds() && lastAnimatingBoundsWasToFullscreen();
   1765     }
   1766 
   1767     public boolean pinnedStackResizeDisallowed() {
   1768         if (mBoundsAnimating && mCancelCurrentBoundsAnimation) {
   1769             return true;
   1770         }
   1771         return false;
   1772     }
   1773 
   1774     /** Returns true if a removal action is still being deferred. */
   1775     boolean checkCompleteDeferredRemoval() {
   1776         if (isSelfOrChildAnimating()) {
   1777             return true;
   1778         }
   1779         if (mDeferRemoval) {
   1780             removeImmediately();
   1781         }
   1782 
   1783         return super.checkCompleteDeferredRemoval();
   1784     }
   1785 
   1786     @Override
   1787     int getOrientation() {
   1788         return (canSpecifyOrientation()) ? super.getOrientation() : SCREEN_ORIENTATION_UNSET;
   1789     }
   1790 
   1791     private boolean canSpecifyOrientation() {
   1792         final int windowingMode = getWindowingMode();
   1793         final int activityType = getActivityType();
   1794         return windowingMode == WINDOWING_MODE_FULLSCREEN
   1795                 || activityType == ACTIVITY_TYPE_HOME
   1796                 || activityType == ACTIVITY_TYPE_RECENTS
   1797                 || activityType == ACTIVITY_TYPE_ASSISTANT;
   1798     }
   1799 
   1800     @Override
   1801     Dimmer getDimmer() {
   1802         return mDimmer;
   1803     }
   1804 
   1805     @Override
   1806     void prepareSurfaces() {
   1807         mDimmer.resetDimStates();
   1808         super.prepareSurfaces();
   1809         getDimBounds(mTmpDimBoundsRect);
   1810 
   1811         // Bounds need to be relative, as the dim layer is a child.
   1812         mTmpDimBoundsRect.offsetTo(0, 0);
   1813         if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
   1814             scheduleAnimation();
   1815         }
   1816     }
   1817 
   1818     public DisplayInfo getDisplayInfo() {
   1819         return mDisplayContent.getDisplayInfo();
   1820     }
   1821 
   1822     void dim(float alpha) {
   1823         mDimmer.dimAbove(getPendingTransaction(), alpha);
   1824         scheduleAnimation();
   1825     }
   1826 
   1827     void stopDimming() {
   1828         mDimmer.stopDim(getPendingTransaction());
   1829         scheduleAnimation();
   1830     }
   1831 
   1832     @Override
   1833     void getRelativePosition(Point outPos) {
   1834         super.getRelativePosition(outPos);
   1835         final int outset = getStackOutset();
   1836         outPos.x -= outset;
   1837         outPos.y -= outset;
   1838     }
   1839 
   1840     AnimatingAppWindowTokenRegistry getAnimatingAppWindowTokenRegistry() {
   1841         return mAnimatingAppWindowTokenRegistry;
   1842     }
   1843 }
   1844