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.res.Configuration.DENSITY_DPI_UNDEFINED;
     25 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
     26 import static android.view.WindowManager.DOCKED_BOTTOM;
     27 import static android.view.WindowManager.DOCKED_INVALID;
     28 import static android.view.WindowManager.DOCKED_LEFT;
     29 import static android.view.WindowManager.DOCKED_RIGHT;
     30 import static android.view.WindowManager.DOCKED_TOP;
     31 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
     32 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
     33 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     34 import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
     35 
     36 import android.app.ActivityManager.StackId;
     37 import android.content.res.Configuration;
     38 import android.graphics.Rect;
     39 import android.os.Debug;
     40 import android.os.RemoteException;
     41 import android.util.EventLog;
     42 import android.util.Slog;
     43 import android.util.SparseArray;
     44 import android.view.DisplayInfo;
     45 import android.view.Surface;
     46 import android.view.SurfaceControl;
     47 import android.view.animation.Animation;
     48 
     49 import com.android.internal.policy.DividerSnapAlgorithm;
     50 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
     51 import com.android.internal.policy.DockedDividerUtils;
     52 import com.android.server.EventLogTags;
     53 
     54 import java.io.PrintWriter;
     55 import java.util.ArrayList;
     56 
     57 public class TaskStack implements DimLayer.DimLayerUser,
     58         BoundsAnimationController.AnimateBoundsUser {
     59     /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
     60      * restrict IME adjustment so that a min portion of top stack remains visible.*/
     61     private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
     62 
     63     /** Dimming amount for non-focused stack when stacks are IME-adjusted. */
     64     private static final float IME_ADJUST_DIM_AMOUNT = 0.25f;
     65 
     66     /** Unique identifier */
     67     final int mStackId;
     68 
     69     /** The service */
     70     private final WindowManagerService mService;
     71 
     72     /** The display this stack sits under. */
     73     private DisplayContent mDisplayContent;
     74 
     75     /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
     76      * mTaskHistory in the ActivityStack with the same mStackId */
     77     private final ArrayList<Task> mTasks = new ArrayList<>();
     78 
     79     /** For comparison with DisplayContent bounds. */
     80     private Rect mTmpRect = new Rect();
     81     private Rect mTmpRect2 = 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 mFullscreen = true;
     97 
     98     // Device rotation as of the last time {@link #mBounds} was set.
     99     int mRotation;
    100 
    101     /** Density as of last time {@link #mBounds} was set. */
    102     int mDensity;
    103 
    104     /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
    105     DimLayer mAnimationBackgroundSurface;
    106 
    107     /** The particular window with an Animation with non-zero background color. */
    108     WindowStateAnimator mAnimationBackgroundAnimator;
    109 
    110     /** Application tokens that are exiting, but still on screen for animations. */
    111     final AppTokenList mExitingAppTokens = new AppTokenList();
    112 
    113     /** Detach this stack from its display when animation completes. */
    114     boolean mDeferDetach;
    115 
    116     // Whether the stack and all its tasks is currently being drag-resized
    117     private boolean mDragResizing;
    118 
    119     private final Rect mTmpAdjustedBounds = new Rect();
    120     private boolean mAdjustedForIme;
    121     private boolean mImeGoingAway;
    122     private WindowState mImeWin;
    123     private float mMinimizeAmount;
    124     private float mAdjustImeAmount;
    125     private float mAdjustDividerAmount;
    126     private final int mDockedStackMinimizeThickness;
    127 
    128     // If this is true, we are in the bounds animating mode.
    129     // The task will be down or upscaled to perfectly fit the
    130     // region it would have been cropped to. We may also avoid
    131     // certain logic we would otherwise apply while resizing,
    132     // while resizing in the bounds animating mode.
    133     private boolean mBoundsAnimating = false;
    134 
    135     // Temporary storage for the new bounds that should be used after the configuration change.
    136     // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
    137     private final Rect mBoundsAfterRotation = new Rect();
    138 
    139     TaskStack(WindowManagerService service, int stackId) {
    140         mService = service;
    141         mStackId = stackId;
    142         mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
    143                 com.android.internal.R.dimen.docked_stack_minimize_thickness);
    144         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
    145     }
    146 
    147     DisplayContent getDisplayContent() {
    148         return mDisplayContent;
    149     }
    150 
    151     ArrayList<Task> getTasks() {
    152         return mTasks;
    153     }
    154 
    155     Task findHomeTask() {
    156         if (mStackId != HOME_STACK_ID) {
    157             return null;
    158         }
    159 
    160         for (int i = mTasks.size() - 1; i >= 0; i--) {
    161             if (mTasks.get(i).isHomeTask()) {
    162                 return mTasks.get(i);
    163             }
    164         }
    165         return null;
    166     }
    167 
    168     /**
    169      * Set the bounds of the stack and its containing tasks.
    170      * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
    171      * @param configs Configuration for individual tasks, keyed by task id.
    172      * @param taskBounds Bounds for individual tasks, keyed by task id.
    173      * @return True if the stack bounds was changed.
    174      * */
    175     boolean setBounds(
    176             Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
    177             SparseArray<Rect> taskTempInsetBounds) {
    178         setBounds(stackBounds);
    179 
    180         // Update bounds of containing tasks.
    181         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
    182             final Task task = mTasks.get(taskNdx);
    183             Configuration config = configs.get(task.mTaskId);
    184             if (config != null) {
    185                 Rect bounds = taskBounds.get(task.mTaskId);
    186                 if (task.isTwoFingerScrollMode()) {
    187                     // This is a non-resizeable task that's docked (or side-by-side to the docked
    188                     // stack). It might have been scrolled previously, and after the stack resizing,
    189                     // it might no longer fully cover the stack area.
    190                     // Save the old bounds and re-apply the scroll. This adjusts the bounds to
    191                     // fit the new stack bounds.
    192                     task.resizeLocked(bounds, config, false /* forced */);
    193                     task.getBounds(mTmpRect);
    194                     task.scrollLocked(mTmpRect);
    195                 } else {
    196                     task.resizeLocked(bounds, config, false /* forced */);
    197                     task.setTempInsetBounds(
    198                             taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId)
    199                                     : null);
    200                 }
    201             } else {
    202                 Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
    203             }
    204         }
    205         return true;
    206     }
    207 
    208     void prepareFreezingTaskBounds() {
    209         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
    210             final Task task = mTasks.get(taskNdx);
    211             task.prepareFreezingBounds();
    212         }
    213     }
    214 
    215     boolean isFullscreenBounds(Rect bounds) {
    216         if (mDisplayContent == null || bounds == null) {
    217             return true;
    218         }
    219         mDisplayContent.getLogicalDisplayRect(mTmpRect);
    220         return mTmpRect.equals(bounds);
    221     }
    222 
    223     /**
    224      * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
    225      * the normal task bounds.
    226      *
    227      * @param bounds The adjusted bounds.
    228      */
    229     private void setAdjustedBounds(Rect bounds) {
    230         if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) {
    231             return;
    232         }
    233 
    234         mAdjustedBounds.set(bounds);
    235         final boolean adjusted = !mAdjustedBounds.isEmpty();
    236         Rect insetBounds = null;
    237         if (adjusted && isAdjustedForMinimizedDock()) {
    238             insetBounds = mBounds;
    239         } else if (adjusted && mAdjustedForIme) {
    240             if (mImeGoingAway) {
    241                 insetBounds = mBounds;
    242             } else {
    243                 insetBounds = mFullyAdjustedImeBounds;
    244             }
    245         }
    246         alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds);
    247         mDisplayContent.layoutNeeded = true;
    248     }
    249 
    250     private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
    251         if (mFullscreen) {
    252             return;
    253         }
    254         // Update bounds of containing tasks.
    255         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
    256             final Task task = mTasks.get(taskNdx);
    257             if (task.isTwoFingerScrollMode()) {
    258                 // If we're scrolling we don't care about your bounds or configs,
    259                 // they should be null as if we were in fullscreen.
    260                 task.resizeLocked(null, null, false /* forced */);
    261                 task.getBounds(mTmpRect2);
    262                 task.scrollLocked(mTmpRect2);
    263             } else {
    264                 final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
    265                 task.alignToAdjustedBounds(adjustedBounds, tempInsetBounds, alignBottom);
    266             }
    267         }
    268     }
    269 
    270     private boolean setBounds(Rect bounds) {
    271         boolean oldFullscreen = mFullscreen;
    272         int rotation = Surface.ROTATION_0;
    273         int density = DENSITY_DPI_UNDEFINED;
    274         if (mDisplayContent != null) {
    275             mDisplayContent.getLogicalDisplayRect(mTmpRect);
    276             rotation = mDisplayContent.getDisplayInfo().rotation;
    277             density = mDisplayContent.getDisplayInfo().logicalDensityDpi;
    278             mFullscreen = bounds == null;
    279             if (mFullscreen) {
    280                 bounds = mTmpRect;
    281             }
    282         }
    283 
    284         if (bounds == null) {
    285             // Can't set to fullscreen if we don't have a display to get bounds from...
    286             return false;
    287         }
    288         if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
    289             return false;
    290         }
    291 
    292         if (mDisplayContent != null) {
    293             mDisplayContent.mDimLayerController.updateDimLayer(this);
    294             mAnimationBackgroundSurface.setBounds(bounds);
    295         }
    296 
    297         mBounds.set(bounds);
    298         mRotation = rotation;
    299         mDensity = density;
    300 
    301         updateAdjustedBounds();
    302 
    303         return true;
    304     }
    305 
    306     /** Bounds of the stack without adjusting for other factors in the system like visibility
    307      * of docked stack.
    308      * Most callers should be using {@link #getBounds} as it take into consideration other system
    309      * factors. */
    310     void getRawBounds(Rect out) {
    311         out.set(mBounds);
    312     }
    313 
    314     /** Return true if the current bound can get outputted to the rest of the system as-is. */
    315     private boolean useCurrentBounds() {
    316         if (mFullscreen
    317                 || !StackId.isResizeableByDockedStack(mStackId)
    318                 || mDisplayContent == null
    319                 || mDisplayContent.getDockedStackLocked() != null) {
    320             return true;
    321         }
    322         return false;
    323     }
    324 
    325     public void getBounds(Rect out) {
    326         if (useCurrentBounds()) {
    327             // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
    328             // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
    329             // stack is visible since it is already what we want to represent to the rest of the
    330             // system.
    331             if (!mAdjustedBounds.isEmpty()) {
    332                 out.set(mAdjustedBounds);
    333             } else {
    334                 out.set(mBounds);
    335             }
    336             return;
    337         }
    338 
    339         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
    340         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
    341         // system.
    342         mDisplayContent.getLogicalDisplayRect(out);
    343     }
    344 
    345     /** Bounds of the stack with other system factors taken into consideration. */
    346     @Override
    347     public void getDimBounds(Rect out) {
    348         getBounds(out);
    349     }
    350 
    351     void updateDisplayInfo(Rect bounds) {
    352         if (mDisplayContent == null) {
    353             return;
    354         }
    355 
    356         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
    357             mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
    358         }
    359         if (bounds != null) {
    360             setBounds(bounds);
    361             return;
    362         } else if (mFullscreen) {
    363             setBounds(null);
    364             return;
    365         }
    366 
    367         mTmpRect2.set(mBounds);
    368         final int newRotation = mDisplayContent.getDisplayInfo().rotation;
    369         final int newDensity = mDisplayContent.getDisplayInfo().logicalDensityDpi;
    370         if (mRotation == newRotation && mDensity == newDensity) {
    371             setBounds(mTmpRect2);
    372         }
    373 
    374         // If the rotation or density didn't match, we'll update it in onConfigurationChanged.
    375     }
    376 
    377     boolean onConfigurationChanged() {
    378         return updateBoundsAfterConfigChange();
    379     }
    380 
    381     private boolean updateBoundsAfterConfigChange() {
    382         if (mDisplayContent == null) {
    383             // If the stack is already detached we're not updating anything,
    384             // as it's going away soon anyway.
    385             return false;
    386         }
    387         final int newRotation = getDisplayInfo().rotation;
    388         final int newDensity = getDisplayInfo().logicalDensityDpi;
    389 
    390         if (mRotation == newRotation && mDensity == newDensity) {
    391             // Nothing to do here as we already update the state in updateDisplayInfo.
    392             return false;
    393         }
    394 
    395         if (mFullscreen) {
    396             // Update stack bounds again since rotation changed since updateDisplayInfo().
    397             setBounds(null);
    398             // Return false since we don't need the client to resize.
    399             return false;
    400         }
    401 
    402         mTmpRect2.set(mBounds);
    403         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
    404         if (mStackId == DOCKED_STACK_ID) {
    405             repositionDockedStackAfterRotation(mTmpRect2);
    406             snapDockedStackAfterRotation(mTmpRect2);
    407             final int newDockSide = getDockSide(mTmpRect2);
    408 
    409             // Update the dock create mode and clear the dock create bounds, these
    410             // might change after a rotation and the original values will be invalid.
    411             mService.setDockedStackCreateStateLocked(
    412                     (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
    413                     ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
    414                     : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
    415                     null);
    416             mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
    417         }
    418 
    419         mBoundsAfterRotation.set(mTmpRect2);
    420         return true;
    421     }
    422 
    423     void getBoundsForNewConfiguration(Rect outBounds) {
    424         outBounds.set(mBoundsAfterRotation);
    425         mBoundsAfterRotation.setEmpty();
    426     }
    427 
    428     /**
    429      * Some dock sides are not allowed by the policy. This method queries the policy and moves
    430      * the docked stack around if needed.
    431      *
    432      * @param inOutBounds the bounds of the docked stack to adjust
    433      */
    434     private void repositionDockedStackAfterRotation(Rect inOutBounds) {
    435         int dockSide = getDockSide(inOutBounds);
    436         if (mService.mPolicy.isDockSideAllowed(dockSide)) {
    437             return;
    438         }
    439         mDisplayContent.getLogicalDisplayRect(mTmpRect);
    440         dockSide = DockedDividerUtils.invertDockSide(dockSide);
    441         switch (dockSide) {
    442             case DOCKED_LEFT:
    443                 int movement = inOutBounds.left;
    444                 inOutBounds.left -= movement;
    445                 inOutBounds.right -= movement;
    446                 break;
    447             case DOCKED_RIGHT:
    448                 movement = mTmpRect.right - inOutBounds.right;
    449                 inOutBounds.left += movement;
    450                 inOutBounds.right += movement;
    451                 break;
    452             case DOCKED_TOP:
    453                 movement = inOutBounds.top;
    454                 inOutBounds.top -= movement;
    455                 inOutBounds.bottom -= movement;
    456                 break;
    457             case DOCKED_BOTTOM:
    458                 movement = mTmpRect.bottom - inOutBounds.bottom;
    459                 inOutBounds.top += movement;
    460                 inOutBounds.bottom += movement;
    461                 break;
    462         }
    463     }
    464 
    465     /**
    466      * Snaps the bounds after rotation to the closest snap target for the docked stack.
    467      */
    468     private void snapDockedStackAfterRotation(Rect outBounds) {
    469 
    470         // Calculate the current position.
    471         final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
    472         final int dividerSize = mService.getDefaultDisplayContentLocked()
    473                 .getDockedDividerController().getContentWidth();
    474         final int dockSide = getDockSide(outBounds);
    475         final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
    476                 dockSide, dividerSize);
    477         final int displayWidth = mDisplayContent.getDisplayInfo().logicalWidth;
    478         final int displayHeight = mDisplayContent.getDisplayInfo().logicalHeight;
    479 
    480         // Snap the position to a target.
    481         final int rotation = displayInfo.rotation;
    482         final int orientation = mService.mCurConfiguration.orientation;
    483         mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
    484         final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
    485                 mService.mContext.getResources(), displayWidth, displayHeight,
    486                 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds);
    487         final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
    488 
    489         // Recalculate the bounds based on the position of the target.
    490         DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
    491                 outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
    492                 dividerSize);
    493     }
    494 
    495     boolean isAnimating() {
    496         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
    497             final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
    498             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
    499                 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
    500                 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
    501                     final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
    502                     if (winAnimator.isAnimationSet() || winAnimator.mWin.mAnimatingExit) {
    503                         return true;
    504                     }
    505                 }
    506             }
    507         }
    508         return false;
    509     }
    510 
    511     void addTask(Task task, boolean toTop) {
    512         addTask(task, toTop, task.showForAllUsers());
    513     }
    514 
    515     /**
    516      * Put a Task in this stack. Used for adding and moving.
    517      * @param task The task to add.
    518      * @param toTop Whether to add it to the top or bottom.
    519      * @param showForAllUsers Whether to show the task regardless of the current user.
    520      */
    521     void addTask(Task task, boolean toTop, boolean showForAllUsers) {
    522         positionTask(task, toTop ? mTasks.size() : 0, showForAllUsers);
    523     }
    524 
    525     void positionTask(Task task, int position, boolean showForAllUsers) {
    526         final boolean canShowTask =
    527                 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId);
    528         mTasks.remove(task);
    529         int stackSize = mTasks.size();
    530         int minPosition = 0;
    531         int maxPosition = stackSize;
    532 
    533         if (canShowTask) {
    534             minPosition = computeMinPosition(minPosition, stackSize);
    535         } else {
    536             maxPosition = computeMaxPosition(maxPosition);
    537         }
    538         // Reset position based on minimum/maximum possible positions.
    539         position = Math.min(Math.max(position, minPosition), maxPosition);
    540 
    541         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM,
    542                 "positionTask: task=" + task + " position=" + position);
    543         mTasks.add(position, task);
    544 
    545         // If we are moving the task across stacks, the scroll is no longer valid.
    546         if (task.mStack != this) {
    547             task.resetScrollLocked();
    548         }
    549         task.mStack = this;
    550         task.updateDisplayInfo(mDisplayContent);
    551         boolean toTop = position == mTasks.size() - 1;
    552         if (toTop) {
    553             mDisplayContent.moveStack(this, true);
    554         }
    555 
    556         if (StackId.windowsAreScaleable(mStackId)) {
    557             // We force windows out of SCALING_MODE_FREEZE
    558             // so that we can continue to animate them
    559             // while a resize is pending.
    560             forceWindowsScaleable(task, true);
    561         } else {
    562             forceWindowsScaleable(task, false);
    563         }
    564         EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, position);
    565     }
    566 
    567     /** Calculate the minimum possible position for a task that can be shown to the user.
    568      *  The minimum position will be above all other tasks that can't be shown.
    569      *  @param minPosition The minimum position the caller is suggesting.
    570      *                  We will start adjusting up from here.
    571      *  @param size The size of the current task list.
    572      */
    573     private int computeMinPosition(int minPosition, int size) {
    574         while (minPosition < size) {
    575             final Task tmpTask = mTasks.get(minPosition);
    576             final boolean canShowTmpTask =
    577                     tmpTask.showForAllUsers()
    578                             || mService.isCurrentProfileLocked(tmpTask.mUserId);
    579             if (canShowTmpTask) {
    580                 break;
    581             }
    582             minPosition++;
    583         }
    584         return minPosition;
    585     }
    586 
    587     /** Calculate the maximum possible position for a task that can't be shown to the user.
    588      *  The maximum position will be below all other tasks that can be shown.
    589      *  @param maxPosition The maximum position the caller is suggesting.
    590      *                  We will start adjusting down from here.
    591      */
    592     private int computeMaxPosition(int maxPosition) {
    593         while (maxPosition > 0) {
    594             final Task tmpTask = mTasks.get(maxPosition - 1);
    595             final boolean canShowTmpTask =
    596                     tmpTask.showForAllUsers()
    597                             || mService.isCurrentProfileLocked(tmpTask.mUserId);
    598             if (!canShowTmpTask) {
    599                 break;
    600             }
    601             maxPosition--;
    602         }
    603         return maxPosition;
    604     }
    605 
    606     void moveTaskToTop(Task task) {
    607         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToTop: task=" + task + " Callers="
    608                 + Debug.getCallers(6));
    609         mTasks.remove(task);
    610         addTask(task, true);
    611     }
    612 
    613     void moveTaskToBottom(Task task) {
    614         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToBottom: task=" + task);
    615         mTasks.remove(task);
    616         addTask(task, false);
    617     }
    618 
    619     /**
    620      * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the
    621      * back.
    622      * @param task The Task to delete.
    623      */
    624     void removeTask(Task task) {
    625         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeTask: task=" + task);
    626         mTasks.remove(task);
    627         if (mDisplayContent != null) {
    628             if (mTasks.isEmpty()) {
    629                 mDisplayContent.moveStack(this, false);
    630             }
    631             mDisplayContent.layoutNeeded = true;
    632         }
    633         for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
    634             final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
    635             if (wtoken.mTask == task) {
    636                 wtoken.mIsExiting = false;
    637                 mExitingAppTokens.remove(appNdx);
    638             }
    639         }
    640     }
    641 
    642     void attachDisplayContent(DisplayContent displayContent) {
    643         if (mDisplayContent != null) {
    644             throw new IllegalStateException("attachDisplayContent: Already attached");
    645         }
    646 
    647         mDisplayContent = displayContent;
    648         mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(),
    649                 "animation background stackId=" + mStackId);
    650 
    651         Rect bounds = null;
    652         final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
    653         if (mStackId == DOCKED_STACK_ID
    654                 || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId)
    655                         && !dockedStack.isFullscreen())) {
    656             // The existence of a docked stack affects the size of other static stack created since
    657             // the docked stack occupies a dedicated region on screen, but only if the dock stack is
    658             // not fullscreen. If it's fullscreen, it means that we are in the transition of
    659             // dismissing it, so we must not resize this stack.
    660             bounds = new Rect();
    661             displayContent.getLogicalDisplayRect(mTmpRect);
    662             mTmpRect2.setEmpty();
    663             if (dockedStack != null) {
    664                 dockedStack.getRawBounds(mTmpRect2);
    665             }
    666             final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
    667                     == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
    668             getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2,
    669                     mDisplayContent.mDividerControllerLocked.getContentWidth(),
    670                     dockedOnTopOrLeft);
    671         }
    672 
    673         updateDisplayInfo(bounds);
    674     }
    675 
    676     void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) {
    677         if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
    678                 || mDisplayContent == null) {
    679             outBounds.set(mBounds);
    680             return;
    681         }
    682 
    683         final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
    684         if (dockedStack == null) {
    685             // Not sure why you are calling this method when there is no docked stack...
    686             throw new IllegalStateException(
    687                     "Calling getStackDockedModeBoundsLocked() when there is no docked stack.");
    688         }
    689         if (!ignoreVisibility && !dockedStack.isVisibleLocked()) {
    690             // The docked stack is being dismissed, but we caught before it finished being
    691             // dismissed. In that case we want to treat it as if it is not occupying any space and
    692             // let others occupy the whole display.
    693             mDisplayContent.getLogicalDisplayRect(outBounds);
    694             return;
    695         }
    696 
    697         final int dockedSide = dockedStack.getDockSide();
    698         if (dockedSide == DOCKED_INVALID) {
    699             // Not sure how you got here...Only thing we can do is return current bounds.
    700             Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack);
    701             outBounds.set(mBounds);
    702             return;
    703         }
    704 
    705         mDisplayContent.getLogicalDisplayRect(mTmpRect);
    706         dockedStack.getRawBounds(mTmpRect2);
    707         final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
    708         getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2,
    709                 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
    710 
    711     }
    712 
    713     /**
    714      * Outputs the bounds a stack should be given the presence of a docked stack on the display.
    715      * @param displayRect The bounds of the display the docked stack is on.
    716      * @param outBounds Output bounds that should be used for the stack.
    717      * @param stackId Id of stack we are calculating the bounds for.
    718      * @param dockedBounds Bounds of the docked stack.
    719      * @param dockDividerWidth We need to know the width of the divider make to the output bounds
    720      *                         close to the side of the dock.
    721      * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
    722      */
    723     private void getStackDockedModeBounds(
    724             Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth,
    725             boolean dockOnTopOrLeft) {
    726         final boolean dockedStack = stackId == DOCKED_STACK_ID;
    727         final boolean splitHorizontally = displayRect.width() > displayRect.height();
    728 
    729         outBounds.set(displayRect);
    730         if (dockedStack) {
    731             if (mService.mDockedStackCreateBounds != null) {
    732                 outBounds.set(mService.mDockedStackCreateBounds);
    733                 return;
    734             }
    735 
    736             // The initial bounds of the docked stack when it is created about half the screen space
    737             // and its bounds can be adjusted after that. The bounds of all other stacks are
    738             // adjusted to occupy whatever screen space the docked stack isn't occupying.
    739             final DisplayInfo di = mDisplayContent.getDisplayInfo();
    740             mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
    741                     mTmpRect2);
    742             final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
    743                     di.logicalWidth,
    744                     di.logicalHeight,
    745                     dockDividerWidth,
    746                     mService.mCurConfiguration.orientation == ORIENTATION_PORTRAIT,
    747                     mTmpRect2).getMiddleTarget().position;
    748 
    749             if (dockOnTopOrLeft) {
    750                 if (splitHorizontally) {
    751                     outBounds.right = position;
    752                 } else {
    753                     outBounds.bottom = position;
    754                 }
    755             } else {
    756                 if (splitHorizontally) {
    757                     outBounds.left = position + dockDividerWidth;
    758                 } else {
    759                     outBounds.top = position + dockDividerWidth;
    760                 }
    761             }
    762             return;
    763         }
    764 
    765         // Other stacks occupy whatever space is left by the docked stack.
    766         if (!dockOnTopOrLeft) {
    767             if (splitHorizontally) {
    768                 outBounds.right = dockedBounds.left - dockDividerWidth;
    769             } else {
    770                 outBounds.bottom = dockedBounds.top - dockDividerWidth;
    771             }
    772         } else {
    773             if (splitHorizontally) {
    774                 outBounds.left = dockedBounds.right + dockDividerWidth;
    775             } else {
    776                 outBounds.top = dockedBounds.bottom + dockDividerWidth;
    777             }
    778         }
    779         DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
    780     }
    781 
    782     void resetDockedStackToMiddle() {
    783         if (mStackId != DOCKED_STACK_ID) {
    784             throw new IllegalStateException("Not a docked stack=" + this);
    785         }
    786 
    787         mService.mDockedStackCreateBounds = null;
    788 
    789         final Rect bounds = new Rect();
    790         getStackDockedModeBoundsLocked(bounds, true /*ignoreVisibility*/);
    791         mService.mH.obtainMessage(RESIZE_STACK, DOCKED_STACK_ID,
    792                 1 /*allowResizeInDockedMode*/, bounds).sendToTarget();
    793     }
    794 
    795     void detachDisplay() {
    796         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
    797 
    798         boolean doAnotherLayoutPass = false;
    799         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
    800             final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens;
    801             for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
    802                 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
    803                 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
    804                     // We are in the middle of changing the state of displays/stacks/tasks. We need
    805                     // to finish that, before we let layout interfere with it.
    806                     mService.removeWindowLocked(appWindows.get(winNdx));
    807                     doAnotherLayoutPass = true;
    808                 }
    809             }
    810         }
    811         if (doAnotherLayoutPass) {
    812             mService.mWindowPlacerLocked.requestTraversal();
    813         }
    814 
    815         close();
    816     }
    817 
    818     void resetAnimationBackgroundAnimator() {
    819         mAnimationBackgroundAnimator = null;
    820         mAnimationBackgroundSurface.hide();
    821     }
    822 
    823     void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
    824         int animLayer = winAnimator.mAnimLayer;
    825         if (mAnimationBackgroundAnimator == null
    826                 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) {
    827             mAnimationBackgroundAnimator = winAnimator;
    828             animLayer = mService.adjustAnimationBackground(winAnimator);
    829             mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM,
    830                     ((color >> 24) & 0xff) / 255f, 0);
    831         }
    832     }
    833 
    834     void switchUser() {
    835         int top = mTasks.size();
    836         for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
    837             Task task = mTasks.get(taskNdx);
    838             if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
    839                 mTasks.remove(taskNdx);
    840                 mTasks.add(task);
    841                 --top;
    842             }
    843         }
    844     }
    845 
    846     void close() {
    847         if (mAnimationBackgroundSurface != null) {
    848             mAnimationBackgroundSurface.destroySurface();
    849             mAnimationBackgroundSurface = null;
    850         }
    851         mDisplayContent = null;
    852     }
    853 
    854     /**
    855      * Adjusts the stack bounds if the IME is visible.
    856      *
    857      * @param imeWin The IME window.
    858      */
    859     void setAdjustedForIme(WindowState imeWin, boolean forceUpdate) {
    860         mImeWin = imeWin;
    861         mImeGoingAway = false;
    862         if (!mAdjustedForIme || forceUpdate) {
    863             mAdjustedForIme = true;
    864             mAdjustImeAmount = 0f;
    865             mAdjustDividerAmount = 0f;
    866             updateAdjustForIme(0f, 0f, true /* force */);
    867         }
    868     }
    869 
    870     boolean isAdjustedForIme() {
    871         return mAdjustedForIme;
    872     }
    873 
    874     boolean isAnimatingForIme() {
    875         return mImeWin != null && mImeWin.isAnimatingLw();
    876     }
    877 
    878     /**
    879      * Update the stack's bounds (crop or position) according to the IME window's
    880      * current position. When IME window is animated, the bottom stack is animated
    881      * together to track the IME window's current position, and the top stack is
    882      * cropped as necessary.
    883      *
    884      * @return true if a traversal should be performed after the adjustment.
    885      */
    886     boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
    887         if (adjustAmount != mAdjustImeAmount
    888                 || adjustDividerAmount != mAdjustDividerAmount || force) {
    889             mAdjustImeAmount = adjustAmount;
    890             mAdjustDividerAmount = adjustDividerAmount;
    891             updateAdjustedBounds();
    892             return isVisibleLocked(true /* ignoreKeyguard */);
    893         } else {
    894             return false;
    895         }
    896     }
    897 
    898     /**
    899      * Resets the adjustment after it got adjusted for the IME.
    900      * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about
    901      *                        animations; otherwise, set flag and animates the window away together
    902      *                        with IME window.
    903      */
    904     void resetAdjustedForIme(boolean adjustBoundsNow) {
    905         if (adjustBoundsNow) {
    906             mImeWin = null;
    907             mAdjustedForIme = false;
    908             mImeGoingAway = false;
    909             mAdjustImeAmount = 0f;
    910             mAdjustDividerAmount = 0f;
    911             updateAdjustedBounds();
    912             mService.setResizeDimLayer(false, mStackId, 1.0f);
    913         } else {
    914             mImeGoingAway |= mAdjustedForIme;
    915         }
    916     }
    917 
    918     /**
    919      * Sets the amount how much we currently minimize our stack.
    920      *
    921      * @param minimizeAmount The amount, between 0 and 1.
    922      * @return Whether the amount has changed and a layout is needed.
    923      */
    924     boolean setAdjustedForMinimizedDock(float minimizeAmount) {
    925         if (minimizeAmount != mMinimizeAmount) {
    926             mMinimizeAmount = minimizeAmount;
    927             updateAdjustedBounds();
    928             return isVisibleLocked(true /* ignoreKeyguard*/);
    929         } else {
    930             return false;
    931         }
    932     }
    933 
    934     boolean isAdjustedForMinimizedDock() {
    935         return mMinimizeAmount != 0f;
    936     }
    937 
    938     /**
    939      * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows
    940      * to the list of to be drawn windows the service is waiting for.
    941      */
    942     void beginImeAdjustAnimation() {
    943         for (int j = mTasks.size() - 1; j >= 0; j--) {
    944             final Task task = mTasks.get(j);
    945             if (task.isVisible()) {
    946                 task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
    947                 task.addWindowsWaitingForDrawnIfResizingChanged();
    948             }
    949         }
    950     }
    951 
    952     /**
    953      * Resets the resizing state of all windows.
    954      */
    955     void endImeAdjustAnimation() {
    956         for (int j = mTasks.size() - 1; j >= 0; j--) {
    957             mTasks.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
    958         }
    959     }
    960 
    961     int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
    962         return displayContentRect.top + (int)
    963                 ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN);
    964     }
    965 
    966     private boolean adjustForIME(final WindowState imeWin) {
    967         final int dockedSide = getDockSide();
    968         final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
    969         if (imeWin == null || !dockedTopOrBottom) {
    970             return false;
    971         }
    972 
    973         final Rect displayContentRect = mTmpRect;
    974         final Rect contentBounds = mTmpRect2;
    975 
    976         // Calculate the content bounds excluding the area occupied by IME
    977         getDisplayContent().getContentRect(displayContentRect);
    978         contentBounds.set(displayContentRect);
    979         int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
    980 
    981         imeTop += imeWin.getGivenContentInsetsLw().top;
    982         if (contentBounds.bottom > imeTop) {
    983             contentBounds.bottom = imeTop;
    984         }
    985 
    986         final int yOffset = displayContentRect.bottom - contentBounds.bottom;
    987 
    988         final int dividerWidth =
    989                 getDisplayContent().mDividerControllerLocked.getContentWidth();
    990         final int dividerWidthInactive =
    991                 getDisplayContent().mDividerControllerLocked.getContentWidthInactive();
    992 
    993         if (dockedSide == DOCKED_TOP) {
    994             // If this stack is docked on top, we make it smaller so the bottom stack is not
    995             // occluded by IME. We shift its bottom up by the height of the IME, but
    996             // leaves at least 30% of the top stack visible.
    997             final int minTopStackBottom =
    998                     getMinTopStackBottom(displayContentRect, mBounds.bottom);
    999             final int bottom = Math.max(
   1000                     mBounds.bottom - yOffset + dividerWidth - dividerWidthInactive,
   1001                     minTopStackBottom);
   1002             mTmpAdjustedBounds.set(mBounds);
   1003             mTmpAdjustedBounds.bottom =
   1004                     (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom);
   1005             mFullyAdjustedImeBounds.set(mBounds);
   1006         } else {
   1007             // When the stack is on bottom and has no focus, it's only adjusted for divider width.
   1008             final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
   1009 
   1010             // When the stack is on bottom and has focus, it needs to be moved up so as to
   1011             // not occluded by IME, and at the same time adjusted for divider width.
   1012             // We try to move it up by the height of the IME window, but only to the extent
   1013             // that leaves at least 30% of the top stack visible.
   1014             // 'top' is where the top of bottom stack will move to in this case.
   1015             final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive;
   1016             final int minTopStackBottom =
   1017                     getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
   1018             final int top = Math.max(
   1019                     mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
   1020 
   1021             mTmpAdjustedBounds.set(mBounds);
   1022             // Account for the adjustment for IME and divider width separately.
   1023             // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
   1024             // and dividerWidthDelta is due to divider width change only.
   1025             mTmpAdjustedBounds.top = mBounds.top +
   1026                     (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) +
   1027                             mAdjustDividerAmount * dividerWidthDelta);
   1028             mFullyAdjustedImeBounds.set(mBounds);
   1029             mFullyAdjustedImeBounds.top = top;
   1030             mFullyAdjustedImeBounds.bottom = top + mBounds.height();
   1031         }
   1032         return true;
   1033     }
   1034 
   1035     private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
   1036         final int dockSide = getDockSide();
   1037         if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
   1038             return false;
   1039         }
   1040 
   1041         if (dockSide == DOCKED_TOP) {
   1042             mService.getStableInsetsLocked(mTmpRect);
   1043             int topInset = mTmpRect.top;
   1044             mTmpAdjustedBounds.set(mBounds);
   1045             mTmpAdjustedBounds.bottom =
   1046                     (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
   1047         } else if (dockSide == DOCKED_LEFT) {
   1048             mTmpAdjustedBounds.set(mBounds);
   1049             final int width = mBounds.width();
   1050             mTmpAdjustedBounds.right =
   1051                     (int) (minimizeAmount * mDockedStackMinimizeThickness
   1052                             + (1 - minimizeAmount) * mBounds.right);
   1053             mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
   1054         } else if (dockSide == DOCKED_RIGHT) {
   1055             mTmpAdjustedBounds.set(mBounds);
   1056             mTmpAdjustedBounds.left =
   1057                     (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness)
   1058                             + (1 - minimizeAmount) * mBounds.left);
   1059         }
   1060         return true;
   1061     }
   1062 
   1063     /**
   1064      * @return the distance in pixels how much the stack gets minimized from it's original size
   1065      */
   1066     int getMinimizeDistance() {
   1067         final int dockSide = getDockSide();
   1068         if (dockSide == DOCKED_INVALID) {
   1069             return 0;
   1070         }
   1071 
   1072         if (dockSide == DOCKED_TOP) {
   1073             mService.getStableInsetsLocked(mTmpRect);
   1074             int topInset = mTmpRect.top;
   1075             return mBounds.bottom - topInset;
   1076         } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
   1077             return mBounds.width() - mDockedStackMinimizeThickness;
   1078         } else {
   1079             return 0;
   1080         }
   1081     }
   1082 
   1083     /**
   1084      * Updates the adjustment depending on it's current state.
   1085      */
   1086     private void updateAdjustedBounds() {
   1087         boolean adjust = false;
   1088         if (mMinimizeAmount != 0f) {
   1089             adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
   1090         } else if (mAdjustedForIme) {
   1091             adjust = adjustForIME(mImeWin);
   1092         }
   1093         if (!adjust) {
   1094             mTmpAdjustedBounds.setEmpty();
   1095         }
   1096         setAdjustedBounds(mTmpAdjustedBounds);
   1097 
   1098         final boolean isImeTarget = (mService.getImeFocusStackLocked() == this);
   1099         if (mAdjustedForIme && adjust && !isImeTarget) {
   1100             final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
   1101                     * IME_ADJUST_DIM_AMOUNT;
   1102             mService.setResizeDimLayer(true, mStackId, alpha);
   1103         }
   1104     }
   1105 
   1106     void applyAdjustForImeIfNeeded(Task task) {
   1107         if (mMinimizeAmount != 0f || !mAdjustedForIme || mAdjustedBounds.isEmpty()) {
   1108             return;
   1109         }
   1110 
   1111         final Rect insetBounds = mImeGoingAway ? mBounds : mFullyAdjustedImeBounds;
   1112         task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP);
   1113         mDisplayContent.layoutNeeded = true;
   1114     }
   1115 
   1116     boolean isAdjustedForMinimizedDockedStack() {
   1117         return mMinimizeAmount != 0f;
   1118     }
   1119 
   1120     public void dump(String prefix, PrintWriter pw) {
   1121         pw.println(prefix + "mStackId=" + mStackId);
   1122         pw.println(prefix + "mDeferDetach=" + mDeferDetach);
   1123         pw.println(prefix + "mFullscreen=" + mFullscreen);
   1124         pw.println(prefix + "mBounds=" + mBounds.toShortString());
   1125         if (mMinimizeAmount != 0f) {
   1126             pw.println(prefix + "mMinimizeAmout=" + mMinimizeAmount);
   1127         }
   1128         if (mAdjustedForIme) {
   1129             pw.println(prefix + "mAdjustedForIme=true");
   1130             pw.println(prefix + "mAdjustImeAmount=" + mAdjustImeAmount);
   1131             pw.println(prefix + "mAdjustDividerAmount=" + mAdjustDividerAmount);
   1132         }
   1133         if (!mAdjustedBounds.isEmpty()) {
   1134             pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString());
   1135         }
   1136         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) {
   1137             mTasks.get(taskNdx).dump(prefix + "  ", pw);
   1138         }
   1139         if (mAnimationBackgroundSurface.isDimming()) {
   1140             pw.println(prefix + "mWindowAnimationBackgroundSurface:");
   1141             mAnimationBackgroundSurface.printTo(prefix + "  ", pw);
   1142         }
   1143         if (!mExitingAppTokens.isEmpty()) {
   1144             pw.println();
   1145             pw.println("  Exiting application tokens:");
   1146             for (int i = mExitingAppTokens.size() - 1; i >= 0; i--) {
   1147                 WindowToken token = mExitingAppTokens.get(i);
   1148                 pw.print("  Exiting App #"); pw.print(i);
   1149                 pw.print(' '); pw.print(token);
   1150                 pw.println(':');
   1151                 token.dump(pw, "    ");
   1152             }
   1153         }
   1154     }
   1155 
   1156     /** Fullscreen status of the stack without adjusting for other factors in the system like
   1157      * visibility of docked stack.
   1158      * Most callers should be using {@link #isFullscreen} as it take into consideration other
   1159      * system factors. */
   1160     boolean getRawFullscreen() {
   1161         return mFullscreen;
   1162     }
   1163 
   1164     @Override
   1165     public boolean dimFullscreen() {
   1166         return mStackId == HOME_STACK_ID || isFullscreen();
   1167     }
   1168 
   1169     boolean isFullscreen() {
   1170         if (useCurrentBounds()) {
   1171             return mFullscreen;
   1172         }
   1173         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
   1174         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
   1175         // system.
   1176         return true;
   1177     }
   1178 
   1179     @Override
   1180     public DisplayInfo getDisplayInfo() {
   1181         return mDisplayContent.getDisplayInfo();
   1182     }
   1183 
   1184     @Override
   1185     public String toString() {
   1186         return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
   1187     }
   1188 
   1189     @Override
   1190     public String toShortString() {
   1191         return "Stack=" + mStackId;
   1192     }
   1193 
   1194     /**
   1195      * For docked workspace (or workspace that's side-by-side to the docked), provides
   1196      * information which side of the screen was the dock anchored.
   1197      */
   1198     int getDockSide() {
   1199         return getDockSide(mBounds);
   1200     }
   1201 
   1202     int getDockSide(Rect bounds) {
   1203         if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) {
   1204             return DOCKED_INVALID;
   1205         }
   1206         if (mDisplayContent == null) {
   1207             return DOCKED_INVALID;
   1208         }
   1209         mDisplayContent.getLogicalDisplayRect(mTmpRect);
   1210         final int orientation = mService.mCurConfiguration.orientation;
   1211         return getDockSideUnchecked(bounds, mTmpRect, orientation);
   1212     }
   1213 
   1214     static int getDockSideUnchecked(Rect bounds, Rect displayRect, int orientation) {
   1215         if (orientation == Configuration.ORIENTATION_PORTRAIT) {
   1216             // Portrait mode, docked either at the top or the bottom.
   1217             if (bounds.top - displayRect.top <= displayRect.bottom - bounds.bottom) {
   1218                 return DOCKED_TOP;
   1219             } else {
   1220                 return DOCKED_BOTTOM;
   1221             }
   1222         } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
   1223             // Landscape mode, docked either on the left or on the right.
   1224             if (bounds.left - displayRect.left <= displayRect.right - bounds.right) {
   1225                 return DOCKED_LEFT;
   1226             } else {
   1227                 return DOCKED_RIGHT;
   1228             }
   1229         } else {
   1230             return DOCKED_INVALID;
   1231         }
   1232     }
   1233 
   1234     boolean isVisibleLocked() {
   1235         return isVisibleLocked(false /* ignoreKeyguard */);
   1236     }
   1237 
   1238     boolean isVisibleLocked(boolean ignoreKeyguard) {
   1239         final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded()
   1240                 && !mService.mAnimator.mKeyguardGoingAway;
   1241         if (!ignoreKeyguard && keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
   1242             // The keyguard is showing and the stack shouldn't show on top of the keyguard.
   1243             return false;
   1244         }
   1245 
   1246         for (int i = mTasks.size() - 1; i >= 0; i--) {
   1247             final Task task = mTasks.get(i);
   1248             for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
   1249                 if (!task.mAppTokens.get(j).hidden) {
   1250                     return true;
   1251                 }
   1252             }
   1253         }
   1254 
   1255         return false;
   1256     }
   1257 
   1258     boolean isDragResizing() {
   1259         return mDragResizing;
   1260     }
   1261 
   1262     void setDragResizingLocked(boolean resizing) {
   1263         if (mDragResizing == resizing) {
   1264             return;
   1265         }
   1266         mDragResizing = resizing;
   1267         for (int i = mTasks.size() - 1; i >= 0 ; i--) {
   1268             mTasks.get(i).resetDragResizingChangeReported();
   1269         }
   1270     }
   1271 
   1272     @Override  // AnimatesBounds
   1273     public boolean setSize(Rect bounds) {
   1274         synchronized (mService.mWindowMap) {
   1275             if (mDisplayContent == null) {
   1276                 return false;
   1277             }
   1278         }
   1279         try {
   1280             mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false, -1);
   1281         } catch (RemoteException e) {
   1282         }
   1283         return true;
   1284     }
   1285 
   1286     public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) {
   1287         synchronized (mService.mWindowMap) {
   1288             if (mDisplayContent == null) {
   1289                 return false;
   1290             }
   1291             if (mStackId != PINNED_STACK_ID) {
   1292                 Slog.w(TAG_WM, "Attempt to use pinned stack resize animation helper on"
   1293                         + "non pinned stack");
   1294                 return false;
   1295             }
   1296         }
   1297         try {
   1298             mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds);
   1299         } catch (RemoteException e) {
   1300             // I don't believe you.
   1301         }
   1302         return true;
   1303     }
   1304 
   1305     void forceWindowsScaleable(Task task, boolean force) {
   1306         SurfaceControl.openTransaction();
   1307         try {
   1308             final ArrayList<AppWindowToken> activities = task.mAppTokens;
   1309             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
   1310                 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
   1311                 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
   1312                     final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
   1313                     if (winAnimator == null || !winAnimator.hasSurface()) {
   1314                         continue;
   1315                     }
   1316                     winAnimator.mSurfaceController.forceScaleableInTransaction(force);
   1317                 }
   1318             }
   1319         } finally {
   1320             SurfaceControl.closeTransaction();
   1321         }
   1322     }
   1323 
   1324     @Override  // AnimatesBounds
   1325     public void onAnimationStart() {
   1326         synchronized (mService.mWindowMap) {
   1327             mBoundsAnimating = true;
   1328         }
   1329     }
   1330 
   1331     @Override  // AnimatesBounds
   1332     public void onAnimationEnd() {
   1333         synchronized (mService.mWindowMap) {
   1334             mBoundsAnimating = false;
   1335             mService.requestTraversal();
   1336         }
   1337         if (mStackId == PINNED_STACK_ID) {
   1338             try {
   1339                 mService.mActivityManager.notifyPinnedStackAnimationEnded();
   1340             } catch (RemoteException e) {
   1341                 // I don't believe you...
   1342             }
   1343         }
   1344     }
   1345 
   1346     @Override
   1347     public void moveToFullscreen() {
   1348         try {
   1349             mService.mActivityManager.moveTasksToFullscreenStack(mStackId, true);
   1350         } catch (RemoteException e) {
   1351             e.printStackTrace();
   1352         }
   1353     }
   1354 
   1355     @Override
   1356     public void getFullScreenBounds(Rect bounds) {
   1357         getDisplayContent().getContentRect(bounds);
   1358     }
   1359 
   1360     public boolean hasMovementAnimations() {
   1361         return StackId.hasMovementAnimations(mStackId);
   1362     }
   1363 
   1364     public boolean getForceScaleToCrop() {
   1365         return mBoundsAnimating;
   1366     }
   1367 
   1368     public boolean getBoundsAnimating() {
   1369         return mBoundsAnimating;
   1370     }
   1371 
   1372     /**
   1373      * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
   1374      */
   1375     void overridePlayingAppAnimations(Animation a) {
   1376         for (int i = mTasks.size() - 1; i >= 0; --i) {
   1377             mTasks.get(i).overridePlayingAppAnimations(a);
   1378         }
   1379     }
   1380 }
   1381