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