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.FREEFORM_WORKSPACE_STACK_ID;
     21 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
     22 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
     23 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
     24 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
     25 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
     26 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
     27 
     28 import static com.android.server.EventLogTags.WM_TASK_REMOVED;
     29 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
     30 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
     31 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     32 
     33 import android.app.ActivityManager.StackId;
     34 import android.app.ActivityManager.TaskDescription;
     35 import android.content.pm.ActivityInfo;
     36 import android.content.res.Configuration;
     37 import android.graphics.Rect;
     38 import android.util.EventLog;
     39 import android.util.Slog;
     40 import android.view.DisplayInfo;
     41 import android.view.Surface;
     42 
     43 import com.android.internal.annotations.VisibleForTesting;
     44 import com.android.server.wm.DimLayer.DimLayerUser;
     45 
     46 import java.io.PrintWriter;
     47 import java.util.function.Consumer;
     48 
     49 class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerUser {
     50     static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
     51     // Return value from {@link setBounds} indicating no change was made to the Task bounds.
     52     private static final int BOUNDS_CHANGE_NONE = 0;
     53     // Return value from {@link setBounds} indicating the position of the Task bounds changed.
     54     private static final int BOUNDS_CHANGE_POSITION = 1;
     55     // Return value from {@link setBounds} indicating the size of the Task bounds changed.
     56     private static final int BOUNDS_CHANGE_SIZE = 1 << 1;
     57 
     58     // TODO: Track parent marks like this in WindowContainer.
     59     TaskStack mStack;
     60     final int mTaskId;
     61     final int mUserId;
     62     private boolean mDeferRemoval = false;
     63     final WindowManagerService mService;
     64 
     65     // Content limits relative to the DisplayContent this sits in.
     66     private Rect mBounds = new Rect();
     67     final Rect mPreparedFrozenBounds = new Rect();
     68     final Configuration mPreparedFrozenMergedConfig = new Configuration();
     69 
     70     // Bounds used to calculate the insets.
     71     private final Rect mTempInsetBounds = new Rect();
     72 
     73     // Device rotation as of the last time {@link #mBounds} was set.
     74     private int mRotation;
     75 
     76     // Whether mBounds is fullscreen
     77     private boolean mFillsParent = true;
     78 
     79     // For comparison with DisplayContent bounds.
     80     private Rect mTmpRect = new Rect();
     81     // For handling display rotations.
     82     private Rect mTmpRect2 = new Rect();
     83 
     84     // Resize mode of the task. See {@link ActivityInfo#resizeMode}
     85     private int mResizeMode;
     86 
     87     // Whether the task supports picture-in-picture.
     88     // See {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE}
     89     private boolean mSupportsPictureInPicture;
     90 
     91     // Whether the task is currently being drag-resized
     92     private boolean mDragResizing;
     93     private int mDragResizeMode;
     94 
     95     private boolean mHomeTask;
     96 
     97     private TaskDescription mTaskDescription;
     98 
     99     // If set to true, the task will report that it is not in the floating
    100     // state regardless of it's stack affilation. As the floating state drives
    101     // production of content insets this can be used to preserve them across
    102     // stack moves and we in fact do so when moving from full screen to pinned.
    103     private boolean mPreserveNonFloatingState = false;
    104 
    105     Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
    106             Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
    107             boolean homeTask, TaskDescription taskDescription,
    108             TaskWindowContainerController controller) {
    109         mTaskId = taskId;
    110         mStack = stack;
    111         mUserId = userId;
    112         mService = service;
    113         mResizeMode = resizeMode;
    114         mSupportsPictureInPicture = supportsPictureInPicture;
    115         mHomeTask = homeTask;
    116         setController(controller);
    117         setBounds(bounds, overrideConfig);
    118         mTaskDescription = taskDescription;
    119 
    120         // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
    121         setOrientation(SCREEN_ORIENTATION_UNSET);
    122     }
    123 
    124     DisplayContent getDisplayContent() {
    125         return mStack != null ? mStack.getDisplayContent() : null;
    126     }
    127 
    128     private int getAdjustedAddPosition(int suggestedPosition) {
    129         final int size = mChildren.size();
    130         if (suggestedPosition >= size) {
    131             return Math.min(size, suggestedPosition);
    132         }
    133 
    134         for (int pos = 0; pos < size && pos < suggestedPosition; ++pos) {
    135             // TODO: Confirm that this is the behavior we want long term.
    136             if (mChildren.get(pos).removed) {
    137                 // suggestedPosition assumes removed tokens are actually gone.
    138                 ++suggestedPosition;
    139             }
    140         }
    141         return Math.min(size, suggestedPosition);
    142     }
    143 
    144     @Override
    145     void addChild(AppWindowToken wtoken, int position) {
    146         position = getAdjustedAddPosition(position);
    147         super.addChild(wtoken, position);
    148         mDeferRemoval = false;
    149     }
    150 
    151     @Override
    152     void positionChildAt(int position, AppWindowToken child, boolean includingParents) {
    153         position = getAdjustedAddPosition(position);
    154         super.positionChildAt(position, child, includingParents);
    155         mDeferRemoval = false;
    156     }
    157 
    158     private boolean hasWindowsAlive() {
    159         for (int i = mChildren.size() - 1; i >= 0; i--) {
    160             if (mChildren.get(i).hasWindowsAlive()) {
    161                 return true;
    162             }
    163         }
    164         return false;
    165     }
    166 
    167     @VisibleForTesting
    168     boolean shouldDeferRemoval() {
    169         // TODO: This should probably return false if mChildren.isEmpty() regardless if the stack
    170         // is animating...
    171         return hasWindowsAlive() && mStack.isAnimating();
    172     }
    173 
    174     @Override
    175     void removeIfPossible() {
    176         if (shouldDeferRemoval()) {
    177             if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
    178             mDeferRemoval = true;
    179             return;
    180         }
    181         removeImmediately();
    182     }
    183 
    184     @Override
    185     void removeImmediately() {
    186         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
    187         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
    188         mDeferRemoval = false;
    189 
    190         // Make sure to remove dim layer user first before removing task its from parent.
    191         DisplayContent content = getDisplayContent();
    192         if (content != null) {
    193             content.mDimLayerController.removeDimLayerUser(this);
    194         }
    195 
    196         super.removeImmediately();
    197     }
    198 
    199     void reparent(TaskStack stack, int position, boolean moveParents) {
    200         if (stack == mStack) {
    201             throw new IllegalArgumentException(
    202                     "task=" + this + " already child of stack=" + mStack);
    203         }
    204         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
    205                 + " from stack=" + mStack);
    206         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
    207         final DisplayContent prevDisplayContent = getDisplayContent();
    208 
    209         // If we are moving from the fullscreen stack to the pinned stack
    210         // then we want to preserve our insets so that there will not
    211         // be a jump in the area covered by system decorations. We rely
    212         // on the pinned animation to later unset this value.
    213         if (stack.mStackId == PINNED_STACK_ID) {
    214             mPreserveNonFloatingState = true;
    215         } else {
    216             mPreserveNonFloatingState = false;
    217         }
    218 
    219         getParent().removeChild(this);
    220         stack.addTask(this, position, showForAllUsers(), moveParents);
    221 
    222         // Relayout display(s).
    223         final DisplayContent displayContent = stack.getDisplayContent();
    224         displayContent.setLayoutNeeded();
    225         if (prevDisplayContent != displayContent) {
    226             onDisplayChanged(displayContent);
    227             prevDisplayContent.setLayoutNeeded();
    228         }
    229     }
    230 
    231     /** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */
    232     void positionAt(int position, Rect bounds, Configuration overrideConfig) {
    233         mStack.positionChildAt(position, this, false /* includingParents */);
    234         resizeLocked(bounds, overrideConfig, false /* force */);
    235     }
    236 
    237     @Override
    238     void onParentSet() {
    239         // Update task bounds if needed.
    240         updateDisplayInfo(getDisplayContent());
    241 
    242         if (StackId.windowsAreScaleable(mStack.mStackId)) {
    243             // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
    244             // while a resize is pending.
    245             forceWindowsScaleable(true /* force */);
    246         } else {
    247             forceWindowsScaleable(false /* force */);
    248         }
    249     }
    250 
    251     @Override
    252     void removeChild(AppWindowToken token) {
    253         if (!mChildren.contains(token)) {
    254             Slog.e(TAG, "removeChild: token=" + this + " not found.");
    255             return;
    256         }
    257 
    258         super.removeChild(token);
    259 
    260         if (mChildren.isEmpty()) {
    261             EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
    262             if (mDeferRemoval) {
    263                 removeIfPossible();
    264             }
    265         }
    266     }
    267 
    268     void setSendingToBottom(boolean toBottom) {
    269         for (int appTokenNdx = 0; appTokenNdx < mChildren.size(); appTokenNdx++) {
    270             mChildren.get(appTokenNdx).sendingToBottom = toBottom;
    271         }
    272     }
    273 
    274     /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
    275     private int setBounds(Rect bounds, Configuration overrideConfig) {
    276         if (overrideConfig == null) {
    277             overrideConfig = Configuration.EMPTY;
    278         }
    279         if (bounds == null && !Configuration.EMPTY.equals(overrideConfig)) {
    280             throw new IllegalArgumentException("null bounds but non empty configuration: "
    281                     + overrideConfig);
    282         }
    283         if (bounds != null && Configuration.EMPTY.equals(overrideConfig)) {
    284             throw new IllegalArgumentException("non null bounds, but empty configuration");
    285         }
    286         boolean oldFullscreen = mFillsParent;
    287         int rotation = Surface.ROTATION_0;
    288         final DisplayContent displayContent = mStack.getDisplayContent();
    289         if (displayContent != null) {
    290             displayContent.getLogicalDisplayRect(mTmpRect);
    291             rotation = displayContent.getDisplayInfo().rotation;
    292             mFillsParent = bounds == null;
    293             if (mFillsParent) {
    294                 bounds = mTmpRect;
    295             }
    296         }
    297 
    298         if (bounds == null) {
    299             // Can't set to fullscreen if we don't have a display to get bounds from...
    300             return BOUNDS_CHANGE_NONE;
    301         }
    302         if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) {
    303             return BOUNDS_CHANGE_NONE;
    304         }
    305 
    306         int boundsChange = BOUNDS_CHANGE_NONE;
    307         if (mBounds.left != bounds.left || mBounds.top != bounds.top) {
    308             boundsChange |= BOUNDS_CHANGE_POSITION;
    309         }
    310         if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) {
    311             boundsChange |= BOUNDS_CHANGE_SIZE;
    312         }
    313 
    314         mBounds.set(bounds);
    315 
    316         mRotation = rotation;
    317         if (displayContent != null) {
    318             displayContent.mDimLayerController.updateDimLayer(this);
    319         }
    320         onOverrideConfigurationChanged(mFillsParent ? Configuration.EMPTY : overrideConfig);
    321         return boundsChange;
    322     }
    323 
    324     /**
    325      * Sets the bounds used to calculate the insets. See
    326      * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
    327      */
    328     void setTempInsetBounds(Rect tempInsetBounds) {
    329         if (tempInsetBounds != null) {
    330             mTempInsetBounds.set(tempInsetBounds);
    331         } else {
    332             mTempInsetBounds.setEmpty();
    333         }
    334     }
    335 
    336     /**
    337      * Gets the bounds used to calculate the insets. See
    338      * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
    339      */
    340     void getTempInsetBounds(Rect out) {
    341         out.set(mTempInsetBounds);
    342     }
    343 
    344     void setResizeable(int resizeMode) {
    345         mResizeMode = resizeMode;
    346     }
    347 
    348     boolean isResizeable() {
    349         return ActivityInfo.isResizeableMode(mResizeMode) || mSupportsPictureInPicture
    350                 || mService.mForceResizableTasks;
    351     }
    352 
    353     /**
    354      * Tests if the orientation should be preserved upon user interactive resizig operations.
    355 
    356      * @return true if orientation should not get changed upon resizing operation.
    357      */
    358     boolean preserveOrientationOnResize() {
    359         return mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY
    360                 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY
    361                 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
    362     }
    363 
    364     boolean cropWindowsToStackBounds() {
    365         return isResizeable();
    366     }
    367 
    368     boolean isHomeTask() {
    369         return mHomeTask;
    370     }
    371 
    372     boolean resizeLocked(Rect bounds, Configuration overrideConfig, boolean forced) {
    373         int boundsChanged = setBounds(bounds, overrideConfig);
    374         if (forced) {
    375             boundsChanged |= BOUNDS_CHANGE_SIZE;
    376         }
    377         if (boundsChanged == BOUNDS_CHANGE_NONE) {
    378             return false;
    379         }
    380         if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
    381             onResize();
    382         } else {
    383             onMovedByResize();
    384         }
    385         return true;
    386     }
    387 
    388     /**
    389      * Prepares the task bounds to be frozen with the current size. See
    390      * {@link AppWindowToken#freezeBounds}.
    391      */
    392     void prepareFreezingBounds() {
    393         mPreparedFrozenBounds.set(mBounds);
    394         mPreparedFrozenMergedConfig.setTo(getConfiguration());
    395     }
    396 
    397     /**
    398      * Align the task to the adjusted bounds.
    399      *
    400      * @param adjustedBounds Adjusted bounds to which the task should be aligned.
    401      * @param tempInsetBounds Insets bounds for the task.
    402      * @param alignBottom True if the task's bottom should be aligned to the adjusted
    403      *                    bounds's bottom; false if the task's top should be aligned
    404      *                    the adjusted bounds's top.
    405      */
    406     void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
    407         if (!isResizeable() || Configuration.EMPTY.equals(getOverrideConfiguration())) {
    408             return;
    409         }
    410 
    411         getBounds(mTmpRect2);
    412         if (alignBottom) {
    413             int offsetY = adjustedBounds.bottom - mTmpRect2.bottom;
    414             mTmpRect2.offset(0, offsetY);
    415         } else {
    416             mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
    417         }
    418         setTempInsetBounds(tempInsetBounds);
    419         resizeLocked(mTmpRect2, getOverrideConfiguration(), false /* forced */);
    420     }
    421 
    422     /** Return true if the current bound can get outputted to the rest of the system as-is. */
    423     private boolean useCurrentBounds() {
    424         final DisplayContent displayContent = mStack.getDisplayContent();
    425         return mFillsParent
    426                 || !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
    427                 || displayContent == null
    428                 || displayContent.getDockedStackIgnoringVisibility() != null;
    429     }
    430 
    431     /** Original bounds of the task if applicable, otherwise fullscreen rect. */
    432     void getBounds(Rect out) {
    433         if (useCurrentBounds()) {
    434             // No need to adjust the output bounds if fullscreen or the docked stack is visible
    435             // since it is already what we want to represent to the rest of the system.
    436             out.set(mBounds);
    437             return;
    438         }
    439 
    440         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
    441         // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
    442         mStack.getDisplayContent().getLogicalDisplayRect(out);
    443     }
    444 
    445     /**
    446      * Calculate the maximum visible area of this task. If the task has only one app,
    447      * the result will be visible frame of that app. If the task has more than one apps,
    448      * we search from top down if the next app got different visible area.
    449      *
    450      * This effort is to handle the case where some task (eg. GMail composer) might pop up
    451      * a dialog that's different in size from the activity below, in which case we should
    452      * be dimming the entire task area behind the dialog.
    453      *
    454      * @param out Rect containing the max visible bounds.
    455      * @return true if the task has some visible app windows; false otherwise.
    456      */
    457     boolean getMaxVisibleBounds(Rect out) {
    458         boolean foundTop = false;
    459         for (int i = mChildren.size() - 1; i >= 0; i--) {
    460             final AppWindowToken token = mChildren.get(i);
    461             // skip hidden (or about to hide) apps
    462             if (token.mIsExiting || token.isClientHidden() || token.hiddenRequested) {
    463                 continue;
    464             }
    465             final WindowState win = token.findMainWindow();
    466             if (win == null) {
    467                 continue;
    468             }
    469             if (!foundTop) {
    470                 out.set(win.mVisibleFrame);
    471                 foundTop = true;
    472                 continue;
    473             }
    474             if (win.mVisibleFrame.left < out.left) {
    475                 out.left = win.mVisibleFrame.left;
    476             }
    477             if (win.mVisibleFrame.top < out.top) {
    478                 out.top = win.mVisibleFrame.top;
    479             }
    480             if (win.mVisibleFrame.right > out.right) {
    481                 out.right = win.mVisibleFrame.right;
    482             }
    483             if (win.mVisibleFrame.bottom > out.bottom) {
    484                 out.bottom = win.mVisibleFrame.bottom;
    485             }
    486         }
    487         return foundTop;
    488     }
    489 
    490     /** Bounds of the task to be used for dimming, as well as touch related tests. */
    491     @Override
    492     public void getDimBounds(Rect out) {
    493         final DisplayContent displayContent = mStack.getDisplayContent();
    494         // It doesn't matter if we in particular are part of the resize, since we couldn't have
    495         // a DimLayer anyway if we weren't visible.
    496         final boolean dockedResizing = displayContent != null
    497                 && displayContent.mDividerControllerLocked.isResizing();
    498         if (useCurrentBounds()) {
    499             if (inFreeformWorkspace() && getMaxVisibleBounds(out)) {
    500                 return;
    501             }
    502 
    503             if (!mFillsParent) {
    504                 // When minimizing the docked stack when going home, we don't adjust the task bounds
    505                 // so we need to intersect the task bounds with the stack bounds here.
    506                 //
    507                 // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack
    508                 // bounds and so we don't even want to use them. Even if the app should not be resized the Dim
    509                 // should keep up with the divider.
    510                 if (dockedResizing) {
    511                     mStack.getBounds(out);
    512                 } else {
    513                     mStack.getBounds(mTmpRect);
    514                     mTmpRect.intersect(mBounds);
    515                 }
    516                 out.set(mTmpRect);
    517             } else {
    518                 out.set(mBounds);
    519             }
    520             return;
    521         }
    522 
    523         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
    524         // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
    525         if (displayContent != null) {
    526             displayContent.getLogicalDisplayRect(out);
    527         }
    528     }
    529 
    530     void setDragResizing(boolean dragResizing, int dragResizeMode) {
    531         if (mDragResizing != dragResizing) {
    532             if (!DragResizeMode.isModeAllowedForStack(mStack.mStackId, dragResizeMode)) {
    533                 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
    534                         + mStack.mStackId + " dragResizeMode=" + dragResizeMode);
    535             }
    536             mDragResizing = dragResizing;
    537             mDragResizeMode = dragResizeMode;
    538             resetDragResizingChangeReported();
    539         }
    540     }
    541 
    542     boolean isDragResizing() {
    543         return mDragResizing;
    544     }
    545 
    546     int getDragResizeMode() {
    547         return mDragResizeMode;
    548     }
    549 
    550     void updateDisplayInfo(final DisplayContent displayContent) {
    551         if (displayContent == null) {
    552             return;
    553         }
    554         if (mFillsParent) {
    555             setBounds(null, Configuration.EMPTY);
    556             return;
    557         }
    558         final int newRotation = displayContent.getDisplayInfo().rotation;
    559         if (mRotation == newRotation) {
    560             return;
    561         }
    562 
    563         // Device rotation changed.
    564         // - We don't want the task to move around on the screen when this happens, so update the
    565         //   task bounds so it stays in the same place.
    566         // - Rotate the bounds and notify activity manager if the task can be resized independently
    567         //   from its stack. The stack will take care of task rotation for the other case.
    568         mTmpRect2.set(mBounds);
    569 
    570         if (!StackId.isTaskResizeAllowed(mStack.mStackId)) {
    571             setBounds(mTmpRect2, getOverrideConfiguration());
    572             return;
    573         }
    574 
    575         displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
    576         if (setBounds(mTmpRect2, getOverrideConfiguration()) != BOUNDS_CHANGE_NONE) {
    577             final TaskWindowContainerController controller = getController();
    578             if (controller != null) {
    579                 controller.requestResize(mBounds, RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
    580             }
    581         }
    582     }
    583 
    584     /** Cancels any running app transitions associated with the task. */
    585     void cancelTaskWindowTransition() {
    586         for (int i = mChildren.size() - 1; i >= 0; --i) {
    587             mChildren.get(i).mAppAnimator.clearAnimation();
    588         }
    589     }
    590 
    591     /** Cancels any running thumbnail transitions associated with the task. */
    592     void cancelTaskThumbnailTransition() {
    593         for (int i = mChildren.size() - 1; i >= 0; --i) {
    594             mChildren.get(i).mAppAnimator.clearThumbnail();
    595         }
    596     }
    597 
    598     boolean showForAllUsers() {
    599         final int tokensCount = mChildren.size();
    600         return (tokensCount != 0) && mChildren.get(tokensCount - 1).mShowForAllUsers;
    601     }
    602 
    603     boolean inFreeformWorkspace() {
    604         return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
    605     }
    606 
    607     boolean inPinnedWorkspace() {
    608         return mStack != null && mStack.mStackId == PINNED_STACK_ID;
    609     }
    610 
    611     /**
    612      * When we are in a floating stack (Freeform, Pinned, ...) we calculate
    613      * insets differently. However if we are animating to the fullscreen stack
    614      * we need to begin calculating insets as if we were fullscreen, otherwise
    615      * we will have a jump at the end.
    616      */
    617     boolean isFloating() {
    618         return StackId.tasksAreFloating(mStack.mStackId)
    619                 && !mStack.isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState;
    620     }
    621 
    622     WindowState getTopVisibleAppMainWindow() {
    623         final AppWindowToken token = getTopVisibleAppToken();
    624         return token != null ? token.findMainWindow() : null;
    625     }
    626 
    627     AppWindowToken getTopFullscreenAppToken() {
    628         for (int i = mChildren.size() - 1; i >= 0; i--) {
    629             final AppWindowToken token = mChildren.get(i);
    630             final WindowState win = token.findMainWindow();
    631             if (win != null && win.mAttrs.isFullscreen()) {
    632                 return token;
    633             }
    634         }
    635         return null;
    636     }
    637 
    638     AppWindowToken getTopVisibleAppToken() {
    639         for (int i = mChildren.size() - 1; i >= 0; i--) {
    640             final AppWindowToken token = mChildren.get(i);
    641             // skip hidden (or about to hide) apps
    642             if (!token.mIsExiting && !token.isClientHidden() && !token.hiddenRequested) {
    643                 return token;
    644             }
    645         }
    646         return null;
    647     }
    648 
    649     @Override
    650     public boolean dimFullscreen() {
    651         return isFullscreen();
    652     }
    653 
    654     @Override
    655     public int getLayerForDim(WindowStateAnimator animator, int layerOffset, int defaultLayer) {
    656         // If the dim layer is for a starting window, move the dim layer back in the z-order behind
    657         // the lowest activity window to ensure it does not occlude the main window if it is
    658         // translucent
    659         final AppWindowToken appToken = animator.mWin.mAppToken;
    660         if (animator.mAttrType == TYPE_APPLICATION_STARTING && hasChild(appToken) ) {
    661             return Math.min(defaultLayer, appToken.getLowestAnimLayer() - layerOffset);
    662         }
    663         return defaultLayer;
    664     }
    665 
    666     boolean isFullscreen() {
    667         if (useCurrentBounds()) {
    668             return mFillsParent;
    669         }
    670         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
    671         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
    672         // system.
    673         return true;
    674     }
    675 
    676     @Override
    677     public DisplayInfo getDisplayInfo() {
    678         return getDisplayContent().getDisplayInfo();
    679     }
    680 
    681     @Override
    682     public boolean isAttachedToDisplay() {
    683         return getDisplayContent() != null;
    684     }
    685 
    686     void forceWindowsScaleable(boolean force) {
    687         mService.openSurfaceTransaction();
    688         try {
    689             for (int i = mChildren.size() - 1; i >= 0; i--) {
    690                 mChildren.get(i).forceWindowsScaleableInTransaction(force);
    691             }
    692         } finally {
    693             mService.closeSurfaceTransaction();
    694         }
    695     }
    696 
    697     void setTaskDescription(TaskDescription taskDescription) {
    698         mTaskDescription = taskDescription;
    699     }
    700 
    701     TaskDescription getTaskDescription() {
    702         return mTaskDescription;
    703     }
    704 
    705     @Override
    706     boolean fillsParent() {
    707         return mFillsParent || !StackId.isTaskResizeAllowed(mStack.mStackId);
    708     }
    709 
    710     @Override
    711     TaskWindowContainerController getController() {
    712         return (TaskWindowContainerController) super.getController();
    713     }
    714 
    715     @Override
    716     void forAllTasks(Consumer<Task> callback) {
    717         callback.accept(this);
    718     }
    719 
    720     @Override
    721     public String toString() {
    722         return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}";
    723     }
    724 
    725     String getName() {
    726         return toShortString();
    727     }
    728 
    729     void clearPreserveNonFloatingState() {
    730         mPreserveNonFloatingState = false;
    731     }
    732 
    733     @Override
    734     public String toShortString() {
    735         return "Task=" + mTaskId;
    736     }
    737 
    738     public void dump(String prefix, PrintWriter pw) {
    739         final String doublePrefix = prefix + "  ";
    740 
    741         pw.println(prefix + "taskId=" + mTaskId);
    742         pw.println(doublePrefix + "mFillsParent=" + mFillsParent);
    743         pw.println(doublePrefix + "mBounds=" + mBounds.toShortString());
    744         pw.println(doublePrefix + "mdr=" + mDeferRemoval);
    745         pw.println(doublePrefix + "appTokens=" + mChildren);
    746         pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString());
    747 
    748         final String triplePrefix = doublePrefix + "  ";
    749 
    750         for (int i = mChildren.size() - 1; i >= 0; i--) {
    751             final AppWindowToken wtoken = mChildren.get(i);
    752             pw.println(triplePrefix + "Activity #" + i + " " + wtoken);
    753             wtoken.dump(pw, triplePrefix);
    754         }
    755     }
    756 }
    757