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