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