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