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.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
     20 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
     21 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
     22 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
     23 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
     24 import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
     25 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
     26 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
     27 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
     28 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
     29 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     30 import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK;
     31 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
     32 
     33 import android.app.ActivityManager.StackId;
     34 import android.content.pm.ActivityInfo;
     35 import android.content.res.Configuration;
     36 import android.graphics.Rect;
     37 import android.util.EventLog;
     38 import android.util.Slog;
     39 import android.view.DisplayInfo;
     40 import android.view.Surface;
     41 import android.view.animation.Animation;
     42 
     43 import com.android.server.EventLogTags;
     44 
     45 import java.io.PrintWriter;
     46 import java.util.ArrayList;
     47 
     48 class Task implements DimLayer.DimLayerUser {
     49     static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
     50     // Return value from {@link setBounds} indicating no change was made to the Task bounds.
     51     static final int BOUNDS_CHANGE_NONE = 0;
     52     // Return value from {@link setBounds} indicating the position of the Task bounds changed.
     53     static final int BOUNDS_CHANGE_POSITION = 1;
     54     // Return value from {@link setBounds} indicating the size of the Task bounds changed.
     55     static final int BOUNDS_CHANGE_SIZE = 1 << 1;
     56 
     57     TaskStack mStack;
     58     final AppTokenList mAppTokens = new AppTokenList();
     59     final int mTaskId;
     60     final int mUserId;
     61     boolean mDeferRemoval = false;
     62     final WindowManagerService mService;
     63 
     64     // Content limits relative to the DisplayContent this sits in.
     65     private Rect mBounds = new Rect();
     66     final Rect mPreparedFrozenBounds = new Rect();
     67     final Configuration mPreparedFrozenMergedConfig = new Configuration();
     68 
     69     private Rect mPreScrollBounds = new Rect();
     70     private boolean mScrollValid;
     71 
     72     // Bounds used to calculate the insets.
     73     private final Rect mTempInsetBounds = new Rect();
     74 
     75     // Device rotation as of the last time {@link #mBounds} was set.
     76     int mRotation;
     77 
     78     // Whether mBounds is fullscreen
     79     private boolean mFullscreen = true;
     80 
     81     // Contains configurations settings that are different from the global configuration due to
     82     // stack specific operations. E.g. {@link #setBounds}.
     83     Configuration mOverrideConfig = Configuration.EMPTY;
     84 
     85     // For comparison with DisplayContent bounds.
     86     private Rect mTmpRect = new Rect();
     87     // For handling display rotations.
     88     private Rect mTmpRect2 = new Rect();
     89 
     90     // Resize mode of the task. See {@link ActivityInfo#resizeMode}
     91     private int mResizeMode;
     92 
     93     // Whether the task is currently being drag-resized
     94     private boolean mDragResizing;
     95     private int mDragResizeMode;
     96 
     97     private boolean mHomeTask;
     98 
     99     Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
    100             Configuration config) {
    101         mTaskId = taskId;
    102         mStack = stack;
    103         mUserId = userId;
    104         mService = service;
    105         setBounds(bounds, config);
    106     }
    107 
    108     DisplayContent getDisplayContent() {
    109         return mStack.getDisplayContent();
    110     }
    111 
    112     void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) {
    113         final int lastPos = mAppTokens.size();
    114         if (addPos >= lastPos) {
    115             addPos = lastPos;
    116         } else {
    117             for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
    118                 if (mAppTokens.get(pos).removed) {
    119                     // addPos assumes removed tokens are actually gone.
    120                     ++addPos;
    121                 }
    122             }
    123         }
    124         mAppTokens.add(addPos, wtoken);
    125         wtoken.mTask = this;
    126         mDeferRemoval = false;
    127         mResizeMode = resizeMode;
    128         mHomeTask = homeTask;
    129     }
    130 
    131     private boolean hasWindowsAlive() {
    132         for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    133             if (mAppTokens.get(i).hasWindowsAlive()) {
    134                 return true;
    135             }
    136         }
    137         return false;
    138     }
    139 
    140     void removeLocked() {
    141         if (hasWindowsAlive() && mStack.isAnimating()) {
    142             if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
    143             mDeferRemoval = true;
    144             return;
    145         }
    146         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
    147         EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
    148         mDeferRemoval = false;
    149         DisplayContent content = getDisplayContent();
    150         if (content != null) {
    151             content.mDimLayerController.removeDimLayerUser(this);
    152         }
    153         mStack.removeTask(this);
    154         mService.mTaskIdToTask.delete(mTaskId);
    155     }
    156 
    157     void moveTaskToStack(TaskStack stack, boolean toTop) {
    158         if (stack == mStack) {
    159             return;
    160         }
    161         if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
    162                 + " from stack=" + mStack);
    163         EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
    164         if (mStack != null) {
    165             mStack.removeTask(this);
    166         }
    167         stack.addTask(this, toTop);
    168     }
    169 
    170     void positionTaskInStack(TaskStack stack, int position, Rect bounds, Configuration config) {
    171         if (mStack != null && stack != mStack) {
    172             if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
    173                     + " from stack=" + mStack);
    174             EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
    175             mStack.removeTask(this);
    176         }
    177         stack.positionTask(this, position, showForAllUsers());
    178         resizeLocked(bounds, config, false /* force */);
    179 
    180         for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
    181             final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
    182             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
    183                 final WindowState win = windows.get(winNdx);
    184                 win.notifyMovedInStack();
    185             }
    186         }
    187     }
    188 
    189     boolean removeAppToken(AppWindowToken wtoken) {
    190         boolean removed = mAppTokens.remove(wtoken);
    191         if (mAppTokens.size() == 0) {
    192             EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
    193             if (mDeferRemoval) {
    194                 removeLocked();
    195             }
    196         }
    197         wtoken.mTask = null;
    198         /* Leave mTaskId for now, it might be useful for debug
    199         wtoken.mTaskId = -1;
    200          */
    201         return removed;
    202     }
    203 
    204     void setSendingToBottom(boolean toBottom) {
    205         for (int appTokenNdx = 0; appTokenNdx < mAppTokens.size(); appTokenNdx++) {
    206             mAppTokens.get(appTokenNdx).sendingToBottom = toBottom;
    207         }
    208     }
    209 
    210     /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
    211     private int setBounds(Rect bounds, Configuration config) {
    212         if (config == null) {
    213             config = Configuration.EMPTY;
    214         }
    215         if (bounds == null && !Configuration.EMPTY.equals(config)) {
    216             throw new IllegalArgumentException("null bounds but non empty configuration: "
    217                     + config);
    218         }
    219         if (bounds != null && Configuration.EMPTY.equals(config)) {
    220             throw new IllegalArgumentException("non null bounds, but empty configuration");
    221         }
    222         boolean oldFullscreen = mFullscreen;
    223         int rotation = Surface.ROTATION_0;
    224         final DisplayContent displayContent = mStack.getDisplayContent();
    225         if (displayContent != null) {
    226             displayContent.getLogicalDisplayRect(mTmpRect);
    227             rotation = displayContent.getDisplayInfo().rotation;
    228             mFullscreen = bounds == null;
    229             if (mFullscreen) {
    230                 bounds = mTmpRect;
    231             }
    232         }
    233 
    234         if (bounds == null) {
    235             // Can't set to fullscreen if we don't have a display to get bounds from...
    236             return BOUNDS_CHANGE_NONE;
    237         }
    238         if (mPreScrollBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
    239             return BOUNDS_CHANGE_NONE;
    240         }
    241 
    242         int boundsChange = BOUNDS_CHANGE_NONE;
    243         if (mPreScrollBounds.left != bounds.left || mPreScrollBounds.top != bounds.top) {
    244             boundsChange |= BOUNDS_CHANGE_POSITION;
    245         }
    246         if (mPreScrollBounds.width() != bounds.width() || mPreScrollBounds.height() != bounds.height()) {
    247             boundsChange |= BOUNDS_CHANGE_SIZE;
    248         }
    249 
    250 
    251         mPreScrollBounds.set(bounds);
    252 
    253         resetScrollLocked();
    254 
    255         mRotation = rotation;
    256         if (displayContent != null) {
    257             displayContent.mDimLayerController.updateDimLayer(this);
    258         }
    259         mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
    260         return boundsChange;
    261     }
    262 
    263     /**
    264      * Sets the bounds used to calculate the insets. See
    265      * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
    266      */
    267     void setTempInsetBounds(Rect tempInsetBounds) {
    268         if (tempInsetBounds != null) {
    269             mTempInsetBounds.set(tempInsetBounds);
    270         } else {
    271             mTempInsetBounds.setEmpty();
    272         }
    273     }
    274 
    275     /**
    276      * Gets the bounds used to calculate the insets. See
    277      * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
    278      */
    279     void getTempInsetBounds(Rect out) {
    280         out.set(mTempInsetBounds);
    281     }
    282 
    283     void setResizeable(int resizeMode) {
    284         mResizeMode = resizeMode;
    285     }
    286 
    287     boolean isResizeable() {
    288         return !mHomeTask
    289                 && (ActivityInfo.isResizeableMode(mResizeMode) || mService.mForceResizableTasks);
    290     }
    291 
    292     boolean cropWindowsToStackBounds() {
    293         return !mHomeTask && (isResizeable() || mResizeMode == RESIZE_MODE_CROP_WINDOWS);
    294     }
    295 
    296     boolean isHomeTask() {
    297         return mHomeTask;
    298     }
    299 
    300     private boolean inCropWindowsResizeMode() {
    301         return !mHomeTask && !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
    302     }
    303 
    304     boolean resizeLocked(Rect bounds, Configuration configuration, boolean forced) {
    305         int boundsChanged = setBounds(bounds, configuration);
    306         if (forced) {
    307             boundsChanged |= BOUNDS_CHANGE_SIZE;
    308         }
    309         if (boundsChanged == BOUNDS_CHANGE_NONE) {
    310             return false;
    311         }
    312         if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
    313             resizeWindows();
    314         } else {
    315             moveWindows();
    316         }
    317         return true;
    318     }
    319 
    320     /**
    321      * Prepares the task bounds to be frozen with the current size. See
    322      * {@link AppWindowToken#freezeBounds}.
    323      */
    324     void prepareFreezingBounds() {
    325         mPreparedFrozenBounds.set(mBounds);
    326         mPreparedFrozenMergedConfig.setTo(mService.mCurConfiguration);
    327         mPreparedFrozenMergedConfig.updateFrom(mOverrideConfig);
    328     }
    329 
    330     /**
    331      * Align the task to the adjusted bounds.
    332      *
    333      * @param adjustedBounds Adjusted bounds to which the task should be aligned.
    334      * @param tempInsetBounds Insets bounds for the task.
    335      * @param alignBottom True if the task's bottom should be aligned to the adjusted
    336      *                    bounds's bottom; false if the task's top should be aligned
    337      *                    the adjusted bounds's top.
    338      */
    339     void alignToAdjustedBounds(
    340             Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
    341         if (!isResizeable() || mOverrideConfig == Configuration.EMPTY) {
    342             return;
    343         }
    344 
    345         getBounds(mTmpRect2);
    346         if (alignBottom) {
    347             int offsetY = adjustedBounds.bottom - mTmpRect2.bottom;
    348             mTmpRect2.offset(0, offsetY);
    349         } else {
    350             mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
    351         }
    352         setTempInsetBounds(tempInsetBounds);
    353         resizeLocked(mTmpRect2, mOverrideConfig, false /* forced */);
    354     }
    355 
    356     void resetScrollLocked() {
    357         if (mScrollValid) {
    358             mScrollValid = false;
    359             applyScrollToAllWindows(0, 0);
    360         }
    361         mBounds.set(mPreScrollBounds);
    362     }
    363 
    364     void applyScrollToAllWindows(final int xOffset, final int yOffset) {
    365         for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
    366             final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
    367             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
    368                 final WindowState win = windows.get(winNdx);
    369                 win.mXOffset = xOffset;
    370                 win.mYOffset = yOffset;
    371             }
    372         }
    373     }
    374 
    375     void applyScrollToWindowIfNeeded(final WindowState win) {
    376         if (mScrollValid) {
    377             win.mXOffset = mBounds.left;
    378             win.mYOffset = mBounds.top;
    379         }
    380     }
    381 
    382     boolean scrollLocked(Rect bounds) {
    383         // shift the task bound if it doesn't fully cover the stack area
    384         mStack.getDimBounds(mTmpRect);
    385         if (mService.mCurConfiguration.orientation == ORIENTATION_LANDSCAPE) {
    386             if (bounds.left > mTmpRect.left) {
    387                 bounds.left = mTmpRect.left;
    388                 bounds.right = mTmpRect.left + mBounds.width();
    389             } else if (bounds.right < mTmpRect.right) {
    390                 bounds.left = mTmpRect.right - mBounds.width();
    391                 bounds.right = mTmpRect.right;
    392             }
    393         } else {
    394             if (bounds.top > mTmpRect.top) {
    395                 bounds.top = mTmpRect.top;
    396                 bounds.bottom = mTmpRect.top + mBounds.height();
    397             } else if (bounds.bottom < mTmpRect.bottom) {
    398                 bounds.top = mTmpRect.bottom - mBounds.height();
    399                 bounds.bottom = mTmpRect.bottom;
    400             }
    401         }
    402 
    403         // We can stop here if we're already scrolling and the scrolled bounds not changed.
    404         if (mScrollValid && bounds.equals(mBounds)) {
    405             return false;
    406         }
    407 
    408         // Normal setBounds() does not allow non-null bounds for fullscreen apps.
    409         // We only change bounds for the scrolling case without change it size,
    410         // on resizing path we should still want the validation.
    411         mBounds.set(bounds);
    412         mScrollValid = true;
    413         applyScrollToAllWindows(bounds.left, bounds.top);
    414         return true;
    415     }
    416 
    417     /** Return true if the current bound can get outputted to the rest of the system as-is. */
    418     private boolean useCurrentBounds() {
    419         final DisplayContent displayContent = mStack.getDisplayContent();
    420         if (mFullscreen
    421                 || !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
    422                 || displayContent == null
    423                 || displayContent.getDockedStackVisibleForUserLocked() != null) {
    424             return true;
    425         }
    426         return false;
    427     }
    428 
    429     /** Original bounds of the task if applicable, otherwise fullscreen rect. */
    430     void getBounds(Rect out) {
    431         if (useCurrentBounds()) {
    432             // No need to adjust the output bounds if fullscreen or the docked stack is visible
    433             // since it is already what we want to represent to the rest of the system.
    434             out.set(mBounds);
    435             return;
    436         }
    437 
    438         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
    439         // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
    440         mStack.getDisplayContent().getLogicalDisplayRect(out);
    441     }
    442 
    443     /**
    444      * Calculate the maximum visible area of this task. If the task has only one app,
    445      * the result will be visible frame of that app. If the task has more than one apps,
    446      * we search from top down if the next app got different visible area.
    447      *
    448      * This effort is to handle the case where some task (eg. GMail composer) might pop up
    449      * a dialog that's different in size from the activity below, in which case we should
    450      * be dimming the entire task area behind the dialog.
    451      *
    452      * @param out Rect containing the max visible bounds.
    453      * @return true if the task has some visible app windows; false otherwise.
    454      */
    455     boolean getMaxVisibleBounds(Rect out) {
    456         boolean foundTop = false;
    457         for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    458             final AppWindowToken token = mAppTokens.get(i);
    459             // skip hidden (or about to hide) apps
    460             if (token.mIsExiting || token.clientHidden || token.hiddenRequested) {
    461                 continue;
    462             }
    463             final WindowState win = token.findMainWindow();
    464             if (win == null) {
    465                 continue;
    466             }
    467             if (!foundTop) {
    468                 out.set(win.mVisibleFrame);
    469                 foundTop = true;
    470                 continue;
    471             }
    472             if (win.mVisibleFrame.left < out.left) {
    473                 out.left = win.mVisibleFrame.left;
    474             }
    475             if (win.mVisibleFrame.top < out.top) {
    476                 out.top = win.mVisibleFrame.top;
    477             }
    478             if (win.mVisibleFrame.right > out.right) {
    479                 out.right = win.mVisibleFrame.right;
    480             }
    481             if (win.mVisibleFrame.bottom > out.bottom) {
    482                 out.bottom = win.mVisibleFrame.bottom;
    483             }
    484         }
    485         return foundTop;
    486     }
    487 
    488     /** Bounds of the task to be used for dimming, as well as touch related tests. */
    489     @Override
    490     public void getDimBounds(Rect out) {
    491         final DisplayContent displayContent = mStack.getDisplayContent();
    492         // It doesn't matter if we in particular are part of the resize, since we couldn't have
    493         // a DimLayer anyway if we weren't visible.
    494         final boolean dockedResizing = displayContent != null ?
    495                 displayContent.mDividerControllerLocked.isResizing() : false;
    496         if (useCurrentBounds()) {
    497             if (inFreeformWorkspace() && getMaxVisibleBounds(out)) {
    498                 return;
    499             }
    500 
    501             if (!mFullscreen) {
    502                 // When minimizing the docked stack when going home, we don't adjust the task bounds
    503                 // so we need to intersect the task bounds with the stack bounds here.
    504                 //
    505                 // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack
    506                 // bounds and so we don't even want to use them. Even if the app should not be resized the Dim
    507                 // should keep up with the divider.
    508                 if (dockedResizing) {
    509                     mStack.getBounds(out);
    510                 } else {
    511                     mStack.getBounds(mTmpRect);
    512                     mTmpRect.intersect(mBounds);
    513                 }
    514                 out.set(mTmpRect);
    515             } else {
    516                 out.set(mBounds);
    517             }
    518             return;
    519         }
    520 
    521         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
    522         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
    523         // system.
    524         displayContent.getLogicalDisplayRect(out);
    525     }
    526 
    527     void setDragResizing(boolean dragResizing, int dragResizeMode) {
    528         if (mDragResizing != dragResizing) {
    529             if (!DragResizeMode.isModeAllowedForStack(mStack.mStackId, dragResizeMode)) {
    530                 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
    531                         + mStack.mStackId + " dragResizeMode=" + dragResizeMode);
    532             }
    533             mDragResizing = dragResizing;
    534             mDragResizeMode = dragResizeMode;
    535             resetDragResizingChangeReported();
    536         }
    537     }
    538 
    539     void resetDragResizingChangeReported() {
    540         for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
    541             final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
    542             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
    543                 final WindowState win = windows.get(winNdx);
    544                 win.resetDragResizingChangeReported();
    545             }
    546         }
    547     }
    548 
    549     boolean isDragResizing() {
    550         return mDragResizing || (mStack != null && mStack.isDragResizing());
    551     }
    552 
    553     int getDragResizeMode() {
    554         return mDragResizeMode;
    555     }
    556 
    557     /**
    558      * Adds all of the tasks windows to {@link WindowManagerService#mWaitingForDrawn} if drag
    559      * resizing state of the window has been changed.
    560      */
    561     void addWindowsWaitingForDrawnIfResizingChanged() {
    562         for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
    563             final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
    564             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
    565                 final WindowState win = windows.get(winNdx);
    566                 if (win.isDragResizeChanged()) {
    567                     mService.mWaitingForDrawn.add(win);
    568                 }
    569             }
    570         }
    571     }
    572 
    573     void updateDisplayInfo(final DisplayContent displayContent) {
    574         if (displayContent == null) {
    575             return;
    576         }
    577         if (mFullscreen) {
    578             setBounds(null, Configuration.EMPTY);
    579             return;
    580         }
    581         final int newRotation = displayContent.getDisplayInfo().rotation;
    582         if (mRotation == newRotation) {
    583             return;
    584         }
    585 
    586         // Device rotation changed.
    587         // - Reset the bounds to the pre-scroll bounds as whatever scrolling was done is no longer
    588         // valid.
    589         // - Rotate the bounds and notify activity manager if the task can be resized independently
    590         // from its stack. The stack will take care of task rotation for the other case.
    591         mTmpRect2.set(mPreScrollBounds);
    592 
    593         if (!StackId.isTaskResizeAllowed(mStack.mStackId)) {
    594             setBounds(mTmpRect2, mOverrideConfig);
    595             return;
    596         }
    597 
    598         displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
    599         if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) {
    600             // Post message to inform activity manager of the bounds change simulating a one-way
    601             // call. We do this to prevent a deadlock between window manager lock and activity
    602             // manager lock been held.
    603             mService.mH.obtainMessage(RESIZE_TASK, mTaskId,
    604                     RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mPreScrollBounds).sendToTarget();
    605         }
    606     }
    607 
    608     void resizeWindows() {
    609         final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
    610         for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
    611             final AppWindowToken atoken = mAppTokens.get(activityNdx);
    612 
    613             // Some windows won't go through the resizing process, if they don't have a surface, so
    614             // destroy all saved surfaces here.
    615             atoken.destroySavedSurfaces();
    616             final ArrayList<WindowState> windows = atoken.allAppWindows;
    617             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
    618                 final WindowState win = windows.get(winNdx);
    619                 if (win.mHasSurface && !resizingWindows.contains(win)) {
    620                     if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win);
    621                     resizingWindows.add(win);
    622 
    623                     // If we are not drag resizing, force recreating of a new surface so updating
    624                     // the content and positioning that surface will be in sync.
    625                     //
    626                     // As we use this flag as a hint to freeze surface boundary updates,
    627                     // we'd like to only apply this to TYPE_BASE_APPLICATION,
    628                     // windows of TYPE_APPLICATION (or TYPE_DRAWN_APPLICATION) like dialogs,
    629                     // could appear to not be drag resizing while they resize, but we'd
    630                     // still like to manipulate their frame to update crop, etc...
    631                     //
    632                     // Anyway we don't need to synchronize position and content updates for these
    633                     // windows since they aren't at the base layer and could be moved around anyway.
    634                     if (!win.computeDragResizing() && win.mAttrs.type == TYPE_BASE_APPLICATION &&
    635                             !mStack.getBoundsAnimating() && !win.isGoneForLayoutLw() &&
    636                             !inPinnedWorkspace()) {
    637                         win.setResizedWhileNotDragResizing(true);
    638                     }
    639                 }
    640                 if (win.isGoneForLayoutLw()) {
    641                     win.mResizedWhileGone = true;
    642                 }
    643             }
    644         }
    645     }
    646 
    647     void moveWindows() {
    648         for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
    649             final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
    650             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
    651                 final WindowState win = windows.get(winNdx);
    652                 if (DEBUG_RESIZE) Slog.d(TAG, "moveWindows: Moving " + win);
    653                 win.mMovedByResize = true;
    654             }
    655         }
    656     }
    657 
    658     /**
    659      * Cancels any running app transitions associated with the task.
    660      */
    661     void cancelTaskWindowTransition() {
    662         for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
    663             mAppTokens.get(activityNdx).mAppAnimator.clearAnimation();
    664         }
    665     }
    666 
    667     /**
    668      * Cancels any running thumbnail transitions associated with the task.
    669      */
    670     void cancelTaskThumbnailTransition() {
    671         for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
    672             mAppTokens.get(activityNdx).mAppAnimator.clearThumbnail();
    673         }
    674     }
    675 
    676     boolean showForAllUsers() {
    677         final int tokensCount = mAppTokens.size();
    678         return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
    679     }
    680 
    681     boolean isVisible() {
    682         for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    683             final AppWindowToken appToken = mAppTokens.get(i);
    684             if (appToken.isVisible()) {
    685                 return true;
    686             }
    687         }
    688         return false;
    689     }
    690 
    691     boolean inHomeStack() {
    692         return mStack != null && mStack.mStackId == HOME_STACK_ID;
    693     }
    694 
    695     boolean inFreeformWorkspace() {
    696         return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
    697     }
    698 
    699     boolean inDockedWorkspace() {
    700         return mStack != null && mStack.mStackId == DOCKED_STACK_ID;
    701     }
    702 
    703     boolean inPinnedWorkspace() {
    704         return mStack != null && mStack.mStackId == PINNED_STACK_ID;
    705     }
    706 
    707     boolean isResizeableByDockedStack() {
    708         final DisplayContent displayContent = getDisplayContent();
    709         return displayContent != null && displayContent.getDockedStackLocked() != null
    710                 && mStack != null && StackId.isTaskResizeableByDockedStack(mStack.mStackId);
    711     }
    712 
    713     boolean isFloating() {
    714         return StackId.tasksAreFloating(mStack.mStackId);
    715     }
    716 
    717     /**
    718      * Whether the task should be treated as if it's docked. Returns true if the task
    719      * is currently in docked workspace, or it's side-by-side to a docked task.
    720      */
    721     boolean isDockedInEffect() {
    722         return inDockedWorkspace() || isResizeableByDockedStack();
    723     }
    724 
    725     boolean isTwoFingerScrollMode() {
    726         return inCropWindowsResizeMode() && isDockedInEffect();
    727     }
    728 
    729     WindowState getTopVisibleAppMainWindow() {
    730         final AppWindowToken token = getTopVisibleAppToken();
    731         return token != null ? token.findMainWindow() : null;
    732     }
    733 
    734     AppWindowToken getTopVisibleAppToken() {
    735         for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    736             final AppWindowToken token = mAppTokens.get(i);
    737             // skip hidden (or about to hide) apps
    738             if (!token.mIsExiting && !token.clientHidden && !token.hiddenRequested) {
    739                 return token;
    740             }
    741         }
    742         return null;
    743     }
    744 
    745     AppWindowToken getTopAppToken() {
    746         return mAppTokens.size() > 0 ? mAppTokens.get(mAppTokens.size() - 1) : null;
    747     }
    748 
    749     @Override
    750     public boolean dimFullscreen() {
    751         return isHomeTask() || isFullscreen();
    752     }
    753 
    754     boolean isFullscreen() {
    755         if (useCurrentBounds()) {
    756             return mFullscreen;
    757         }
    758         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
    759         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
    760         // system.
    761         return true;
    762     }
    763 
    764     @Override
    765     public DisplayInfo getDisplayInfo() {
    766         return mStack.getDisplayContent().getDisplayInfo();
    767     }
    768 
    769     /**
    770      * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
    771      */
    772     void overridePlayingAppAnimations(Animation a) {
    773         for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    774             mAppTokens.get(i).overridePlayingAppAnimations(a);
    775         }
    776     }
    777 
    778     @Override
    779     public String toString() {
    780         return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
    781     }
    782 
    783     @Override
    784     public String toShortString() {
    785         return "Task=" + mTaskId;
    786     }
    787 
    788     public void dump(String prefix, PrintWriter pw) {
    789         final String doublePrefix = prefix + "  ";
    790 
    791         pw.println(prefix + "taskId=" + mTaskId);
    792         pw.println(doublePrefix + "mFullscreen=" + mFullscreen);
    793         pw.println(doublePrefix + "mBounds=" + mBounds.toShortString());
    794         pw.println(doublePrefix + "mdr=" + mDeferRemoval);
    795         pw.println(doublePrefix + "appTokens=" + mAppTokens);
    796         pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString());
    797 
    798         final String triplePrefix = doublePrefix + "  ";
    799 
    800         for (int i = mAppTokens.size() - 1; i >= 0; i--) {
    801             final AppWindowToken wtoken = mAppTokens.get(i);
    802             pw.println(triplePrefix + "Activity #" + i + " " + wtoken);
    803             wtoken.dump(pw, triplePrefix);
    804         }
    805 
    806     }
    807 }
    808