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