• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, boolean homeTask, TaskDescription taskDescription, TaskWindowContainerController controller)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 
getDisplayContent()124     DisplayContent getDisplayContent() {
125         return mStack != null ? mStack.getDisplayContent() : null;
126     }
127 
getAdjustedAddPosition(int suggestedPosition)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
addChild(AppWindowToken wtoken, int position)145     void addChild(AppWindowToken wtoken, int position) {
146         position = getAdjustedAddPosition(position);
147         super.addChild(wtoken, position);
148         mDeferRemoval = false;
149     }
150 
151     @Override
positionChildAt(int position, AppWindowToken child, boolean includingParents)152     void positionChildAt(int position, AppWindowToken child, boolean includingParents) {
153         position = getAdjustedAddPosition(position);
154         super.positionChildAt(position, child, includingParents);
155         mDeferRemoval = false;
156     }
157 
hasWindowsAlive()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
shouldDeferRemoval()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
removeIfPossible()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
removeImmediately()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 
reparent(TaskStack stack, int position, boolean moveParents)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). */
positionAt(int position, Rect bounds, Configuration overrideConfig)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
onParentSet()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
removeChild(AppWindowToken token)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 
setSendingToBottom(boolean toBottom)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. */
setBounds(Rect bounds, Configuration overrideConfig)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      */
setTempInsetBounds(Rect tempInsetBounds)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      */
getTempInsetBounds(Rect out)340     void getTempInsetBounds(Rect out) {
341         out.set(mTempInsetBounds);
342     }
343 
setResizeable(int resizeMode)344     void setResizeable(int resizeMode) {
345         mResizeMode = resizeMode;
346     }
347 
isResizeable()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      */
preserveOrientationOnResize()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 
cropWindowsToStackBounds()364     boolean cropWindowsToStackBounds() {
365         return isResizeable();
366     }
367 
isHomeTask()368     boolean isHomeTask() {
369         return mHomeTask;
370     }
371 
resizeLocked(Rect bounds, Configuration overrideConfig, boolean forced)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      */
prepareFreezingBounds()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      */
alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom)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. */
useCurrentBounds()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. */
getBounds(Rect out)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      */
getMaxVisibleBounds(Rect out)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
getDimBounds(Rect out)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 
setDragResizing(boolean dragResizing, int dragResizeMode)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 
isDragResizing()542     boolean isDragResizing() {
543         return mDragResizing;
544     }
545 
getDragResizeMode()546     int getDragResizeMode() {
547         return mDragResizeMode;
548     }
549 
updateDisplayInfo(final DisplayContent displayContent)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. */
cancelTaskWindowTransition()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. */
cancelTaskThumbnailTransition()592     void cancelTaskThumbnailTransition() {
593         for (int i = mChildren.size() - 1; i >= 0; --i) {
594             mChildren.get(i).mAppAnimator.clearThumbnail();
595         }
596     }
597 
showForAllUsers()598     boolean showForAllUsers() {
599         final int tokensCount = mChildren.size();
600         return (tokensCount != 0) && mChildren.get(tokensCount - 1).mShowForAllUsers;
601     }
602 
inFreeformWorkspace()603     boolean inFreeformWorkspace() {
604         return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
605     }
606 
inPinnedWorkspace()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      */
isFloating()617     boolean isFloating() {
618         return StackId.tasksAreFloating(mStack.mStackId)
619                 && !mStack.isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState;
620     }
621 
getTopVisibleAppMainWindow()622     WindowState getTopVisibleAppMainWindow() {
623         final AppWindowToken token = getTopVisibleAppToken();
624         return token != null ? token.findMainWindow() : null;
625     }
626 
getTopFullscreenAppToken()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 
getTopVisibleAppToken()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
dimFullscreen()650     public boolean dimFullscreen() {
651         return isFullscreen();
652     }
653 
654     @Override
getLayerForDim(WindowStateAnimator animator, int layerOffset, int defaultLayer)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 
isFullscreen()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
getDisplayInfo()677     public DisplayInfo getDisplayInfo() {
678         return getDisplayContent().getDisplayInfo();
679     }
680 
681     @Override
isAttachedToDisplay()682     public boolean isAttachedToDisplay() {
683         return getDisplayContent() != null;
684     }
685 
forceWindowsScaleable(boolean force)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 
setTaskDescription(TaskDescription taskDescription)697     void setTaskDescription(TaskDescription taskDescription) {
698         mTaskDescription = taskDescription;
699     }
700 
getTaskDescription()701     TaskDescription getTaskDescription() {
702         return mTaskDescription;
703     }
704 
705     @Override
fillsParent()706     boolean fillsParent() {
707         return mFillsParent || !StackId.isTaskResizeAllowed(mStack.mStackId);
708     }
709 
710     @Override
getController()711     TaskWindowContainerController getController() {
712         return (TaskWindowContainerController) super.getController();
713     }
714 
715     @Override
forAllTasks(Consumer<Task> callback)716     void forAllTasks(Consumer<Task> callback) {
717         callback.accept(this);
718     }
719 
720     @Override
toString()721     public String toString() {
722         return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}";
723     }
724 
getName()725     String getName() {
726         return toShortString();
727     }
728 
clearPreserveNonFloatingState()729     void clearPreserveNonFloatingState() {
730         mPreserveNonFloatingState = false;
731     }
732 
733     @Override
toShortString()734     public String toShortString() {
735         return "Task=" + mTaskId;
736     }
737 
dump(String prefix, PrintWriter pw)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