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