• 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.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
20 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
21 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
22 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
23 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
24 import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
25 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
26 import static android.view.WindowManager.DOCKED_BOTTOM;
27 import static android.view.WindowManager.DOCKED_INVALID;
28 import static android.view.WindowManager.DOCKED_LEFT;
29 import static android.view.WindowManager.DOCKED_RIGHT;
30 import static android.view.WindowManager.DOCKED_TOP;
31 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
32 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
33 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
34 import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
35 
36 import android.app.ActivityManager.StackId;
37 import android.content.res.Configuration;
38 import android.graphics.Rect;
39 import android.os.Debug;
40 import android.os.RemoteException;
41 import android.util.EventLog;
42 import android.util.Slog;
43 import android.util.SparseArray;
44 import android.view.DisplayInfo;
45 import android.view.Surface;
46 import android.view.SurfaceControl;
47 import android.view.animation.Animation;
48 
49 import com.android.internal.policy.DividerSnapAlgorithm;
50 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
51 import com.android.internal.policy.DockedDividerUtils;
52 import com.android.server.EventLogTags;
53 
54 import java.io.PrintWriter;
55 import java.util.ArrayList;
56 
57 public class TaskStack implements DimLayer.DimLayerUser,
58         BoundsAnimationController.AnimateBoundsUser {
59     /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
60      * restrict IME adjustment so that a min portion of top stack remains visible.*/
61     private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
62 
63     /** Dimming amount for non-focused stack when stacks are IME-adjusted. */
64     private static final float IME_ADJUST_DIM_AMOUNT = 0.25f;
65 
66     /** Unique identifier */
67     final int mStackId;
68 
69     /** The service */
70     private final WindowManagerService mService;
71 
72     /** The display this stack sits under. */
73     private DisplayContent mDisplayContent;
74 
75     /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
76      * mTaskHistory in the ActivityStack with the same mStackId */
77     private final ArrayList<Task> mTasks = new ArrayList<>();
78 
79     /** For comparison with DisplayContent bounds. */
80     private Rect mTmpRect = new Rect();
81     private Rect mTmpRect2 = new Rect();
82 
83     /** Content limits relative to the DisplayContent this sits in. */
84     private Rect mBounds = new Rect();
85 
86     /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
87     private final Rect mAdjustedBounds = new Rect();
88 
89     /**
90      * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they
91      * represent the state when the animation has ended.
92      */
93     private final Rect mFullyAdjustedImeBounds = new Rect();
94 
95     /** Whether mBounds is fullscreen */
96     private boolean mFullscreen = true;
97 
98     // Device rotation as of the last time {@link #mBounds} was set.
99     int mRotation;
100 
101     /** Density as of last time {@link #mBounds} was set. */
102     int mDensity;
103 
104     /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
105     DimLayer mAnimationBackgroundSurface;
106 
107     /** The particular window with an Animation with non-zero background color. */
108     WindowStateAnimator mAnimationBackgroundAnimator;
109 
110     /** Application tokens that are exiting, but still on screen for animations. */
111     final AppTokenList mExitingAppTokens = new AppTokenList();
112 
113     /** Detach this stack from its display when animation completes. */
114     boolean mDeferDetach;
115 
116     // Whether the stack and all its tasks is currently being drag-resized
117     private boolean mDragResizing;
118 
119     private final Rect mTmpAdjustedBounds = new Rect();
120     private boolean mAdjustedForIme;
121     private boolean mImeGoingAway;
122     private WindowState mImeWin;
123     private float mMinimizeAmount;
124     private float mAdjustImeAmount;
125     private float mAdjustDividerAmount;
126     private final int mDockedStackMinimizeThickness;
127 
128     // If this is true, we are in the bounds animating mode.
129     // The task will be down or upscaled to perfectly fit the
130     // region it would have been cropped to. We may also avoid
131     // certain logic we would otherwise apply while resizing,
132     // while resizing in the bounds animating mode.
133     private boolean mBoundsAnimating = false;
134 
135     // Temporary storage for the new bounds that should be used after the configuration change.
136     // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
137     private final Rect mBoundsAfterRotation = new Rect();
138 
TaskStack(WindowManagerService service, int stackId)139     TaskStack(WindowManagerService service, int stackId) {
140         mService = service;
141         mStackId = stackId;
142         mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
143                 com.android.internal.R.dimen.docked_stack_minimize_thickness);
144         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
145     }
146 
getDisplayContent()147     DisplayContent getDisplayContent() {
148         return mDisplayContent;
149     }
150 
getTasks()151     ArrayList<Task> getTasks() {
152         return mTasks;
153     }
154 
findHomeTask()155     Task findHomeTask() {
156         if (mStackId != HOME_STACK_ID) {
157             return null;
158         }
159 
160         for (int i = mTasks.size() - 1; i >= 0; i--) {
161             if (mTasks.get(i).isHomeTask()) {
162                 return mTasks.get(i);
163             }
164         }
165         return null;
166     }
167 
168     /**
169      * Set the bounds of the stack and its containing tasks.
170      * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
171      * @param configs Configuration for individual tasks, keyed by task id.
172      * @param taskBounds Bounds for individual tasks, keyed by task id.
173      * @return True if the stack bounds was changed.
174      * */
setBounds( Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds, SparseArray<Rect> taskTempInsetBounds)175     boolean setBounds(
176             Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
177             SparseArray<Rect> taskTempInsetBounds) {
178         setBounds(stackBounds);
179 
180         // Update bounds of containing tasks.
181         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
182             final Task task = mTasks.get(taskNdx);
183             Configuration config = configs.get(task.mTaskId);
184             if (config != null) {
185                 Rect bounds = taskBounds.get(task.mTaskId);
186                 if (task.isTwoFingerScrollMode()) {
187                     // This is a non-resizeable task that's docked (or side-by-side to the docked
188                     // stack). It might have been scrolled previously, and after the stack resizing,
189                     // it might no longer fully cover the stack area.
190                     // Save the old bounds and re-apply the scroll. This adjusts the bounds to
191                     // fit the new stack bounds.
192                     task.resizeLocked(bounds, config, false /* forced */);
193                     task.getBounds(mTmpRect);
194                     task.scrollLocked(mTmpRect);
195                 } else {
196                     task.resizeLocked(bounds, config, false /* forced */);
197                     task.setTempInsetBounds(
198                             taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId)
199                                     : null);
200                 }
201             } else {
202                 Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
203             }
204         }
205         return true;
206     }
207 
prepareFreezingTaskBounds()208     void prepareFreezingTaskBounds() {
209         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
210             final Task task = mTasks.get(taskNdx);
211             task.prepareFreezingBounds();
212         }
213     }
214 
isFullscreenBounds(Rect bounds)215     boolean isFullscreenBounds(Rect bounds) {
216         if (mDisplayContent == null || bounds == null) {
217             return true;
218         }
219         mDisplayContent.getLogicalDisplayRect(mTmpRect);
220         return mTmpRect.equals(bounds);
221     }
222 
223     /**
224      * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
225      * the normal task bounds.
226      *
227      * @param bounds The adjusted bounds.
228      */
setAdjustedBounds(Rect bounds)229     private void setAdjustedBounds(Rect bounds) {
230         if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) {
231             return;
232         }
233 
234         mAdjustedBounds.set(bounds);
235         final boolean adjusted = !mAdjustedBounds.isEmpty();
236         Rect insetBounds = null;
237         if (adjusted && isAdjustedForMinimizedDock()) {
238             insetBounds = mBounds;
239         } else if (adjusted && mAdjustedForIme) {
240             if (mImeGoingAway) {
241                 insetBounds = mBounds;
242             } else {
243                 insetBounds = mFullyAdjustedImeBounds;
244             }
245         }
246         alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds);
247         mDisplayContent.layoutNeeded = true;
248     }
249 
alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds)250     private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
251         if (mFullscreen) {
252             return;
253         }
254         // Update bounds of containing tasks.
255         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
256             final Task task = mTasks.get(taskNdx);
257             if (task.isTwoFingerScrollMode()) {
258                 // If we're scrolling we don't care about your bounds or configs,
259                 // they should be null as if we were in fullscreen.
260                 task.resizeLocked(null, null, false /* forced */);
261                 task.getBounds(mTmpRect2);
262                 task.scrollLocked(mTmpRect2);
263             } else {
264                 final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
265                 task.alignToAdjustedBounds(adjustedBounds, tempInsetBounds, alignBottom);
266             }
267         }
268     }
269 
setBounds(Rect bounds)270     private boolean setBounds(Rect bounds) {
271         boolean oldFullscreen = mFullscreen;
272         int rotation = Surface.ROTATION_0;
273         int density = DENSITY_DPI_UNDEFINED;
274         if (mDisplayContent != null) {
275             mDisplayContent.getLogicalDisplayRect(mTmpRect);
276             rotation = mDisplayContent.getDisplayInfo().rotation;
277             density = mDisplayContent.getDisplayInfo().logicalDensityDpi;
278             mFullscreen = bounds == null;
279             if (mFullscreen) {
280                 bounds = mTmpRect;
281             }
282         }
283 
284         if (bounds == null) {
285             // Can't set to fullscreen if we don't have a display to get bounds from...
286             return false;
287         }
288         if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
289             return false;
290         }
291 
292         if (mDisplayContent != null) {
293             mDisplayContent.mDimLayerController.updateDimLayer(this);
294             mAnimationBackgroundSurface.setBounds(bounds);
295         }
296 
297         mBounds.set(bounds);
298         mRotation = rotation;
299         mDensity = density;
300 
301         updateAdjustedBounds();
302 
303         return true;
304     }
305 
306     /** Bounds of the stack without adjusting for other factors in the system like visibility
307      * of docked stack.
308      * Most callers should be using {@link #getBounds} as it take into consideration other system
309      * factors. */
getRawBounds(Rect out)310     void getRawBounds(Rect out) {
311         out.set(mBounds);
312     }
313 
314     /** Return true if the current bound can get outputted to the rest of the system as-is. */
useCurrentBounds()315     private boolean useCurrentBounds() {
316         if (mFullscreen
317                 || !StackId.isResizeableByDockedStack(mStackId)
318                 || mDisplayContent == null
319                 || mDisplayContent.getDockedStackLocked() != null) {
320             return true;
321         }
322         return false;
323     }
324 
getBounds(Rect out)325     public void getBounds(Rect out) {
326         if (useCurrentBounds()) {
327             // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
328             // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
329             // stack is visible since it is already what we want to represent to the rest of the
330             // system.
331             if (!mAdjustedBounds.isEmpty()) {
332                 out.set(mAdjustedBounds);
333             } else {
334                 out.set(mBounds);
335             }
336             return;
337         }
338 
339         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
340         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
341         // system.
342         mDisplayContent.getLogicalDisplayRect(out);
343     }
344 
345     /** Bounds of the stack with other system factors taken into consideration. */
346     @Override
getDimBounds(Rect out)347     public void getDimBounds(Rect out) {
348         getBounds(out);
349     }
350 
updateDisplayInfo(Rect bounds)351     void updateDisplayInfo(Rect bounds) {
352         if (mDisplayContent == null) {
353             return;
354         }
355 
356         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
357             mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
358         }
359         if (bounds != null) {
360             setBounds(bounds);
361             return;
362         } else if (mFullscreen) {
363             setBounds(null);
364             return;
365         }
366 
367         mTmpRect2.set(mBounds);
368         final int newRotation = mDisplayContent.getDisplayInfo().rotation;
369         final int newDensity = mDisplayContent.getDisplayInfo().logicalDensityDpi;
370         if (mRotation == newRotation && mDensity == newDensity) {
371             setBounds(mTmpRect2);
372         }
373 
374         // If the rotation or density didn't match, we'll update it in onConfigurationChanged.
375     }
376 
onConfigurationChanged()377     boolean onConfigurationChanged() {
378         return updateBoundsAfterConfigChange();
379     }
380 
updateBoundsAfterConfigChange()381     private boolean updateBoundsAfterConfigChange() {
382         if (mDisplayContent == null) {
383             // If the stack is already detached we're not updating anything,
384             // as it's going away soon anyway.
385             return false;
386         }
387         final int newRotation = getDisplayInfo().rotation;
388         final int newDensity = getDisplayInfo().logicalDensityDpi;
389 
390         if (mRotation == newRotation && mDensity == newDensity) {
391             // Nothing to do here as we already update the state in updateDisplayInfo.
392             return false;
393         }
394 
395         if (mFullscreen) {
396             // Update stack bounds again since rotation changed since updateDisplayInfo().
397             setBounds(null);
398             // Return false since we don't need the client to resize.
399             return false;
400         }
401 
402         mTmpRect2.set(mBounds);
403         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
404         if (mStackId == DOCKED_STACK_ID) {
405             repositionDockedStackAfterRotation(mTmpRect2);
406             snapDockedStackAfterRotation(mTmpRect2);
407             final int newDockSide = getDockSide(mTmpRect2);
408 
409             // Update the dock create mode and clear the dock create bounds, these
410             // might change after a rotation and the original values will be invalid.
411             mService.setDockedStackCreateStateLocked(
412                     (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
413                     ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
414                     : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
415                     null);
416             mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
417         }
418 
419         mBoundsAfterRotation.set(mTmpRect2);
420         return true;
421     }
422 
getBoundsForNewConfiguration(Rect outBounds)423     void getBoundsForNewConfiguration(Rect outBounds) {
424         outBounds.set(mBoundsAfterRotation);
425         mBoundsAfterRotation.setEmpty();
426     }
427 
428     /**
429      * Some dock sides are not allowed by the policy. This method queries the policy and moves
430      * the docked stack around if needed.
431      *
432      * @param inOutBounds the bounds of the docked stack to adjust
433      */
repositionDockedStackAfterRotation(Rect inOutBounds)434     private void repositionDockedStackAfterRotation(Rect inOutBounds) {
435         int dockSide = getDockSide(inOutBounds);
436         if (mService.mPolicy.isDockSideAllowed(dockSide)) {
437             return;
438         }
439         mDisplayContent.getLogicalDisplayRect(mTmpRect);
440         dockSide = DockedDividerUtils.invertDockSide(dockSide);
441         switch (dockSide) {
442             case DOCKED_LEFT:
443                 int movement = inOutBounds.left;
444                 inOutBounds.left -= movement;
445                 inOutBounds.right -= movement;
446                 break;
447             case DOCKED_RIGHT:
448                 movement = mTmpRect.right - inOutBounds.right;
449                 inOutBounds.left += movement;
450                 inOutBounds.right += movement;
451                 break;
452             case DOCKED_TOP:
453                 movement = inOutBounds.top;
454                 inOutBounds.top -= movement;
455                 inOutBounds.bottom -= movement;
456                 break;
457             case DOCKED_BOTTOM:
458                 movement = mTmpRect.bottom - inOutBounds.bottom;
459                 inOutBounds.top += movement;
460                 inOutBounds.bottom += movement;
461                 break;
462         }
463     }
464 
465     /**
466      * Snaps the bounds after rotation to the closest snap target for the docked stack.
467      */
snapDockedStackAfterRotation(Rect outBounds)468     private void snapDockedStackAfterRotation(Rect outBounds) {
469 
470         // Calculate the current position.
471         final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
472         final int dividerSize = mService.getDefaultDisplayContentLocked()
473                 .getDockedDividerController().getContentWidth();
474         final int dockSide = getDockSide(outBounds);
475         final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
476                 dockSide, dividerSize);
477         final int displayWidth = mDisplayContent.getDisplayInfo().logicalWidth;
478         final int displayHeight = mDisplayContent.getDisplayInfo().logicalHeight;
479 
480         // Snap the position to a target.
481         final int rotation = displayInfo.rotation;
482         final int orientation = mService.mCurConfiguration.orientation;
483         mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
484         final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
485                 mService.mContext.getResources(), displayWidth, displayHeight,
486                 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds);
487         final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
488 
489         // Recalculate the bounds based on the position of the target.
490         DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
491                 outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
492                 dividerSize);
493     }
494 
isAnimating()495     boolean isAnimating() {
496         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
497             final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
498             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
499                 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
500                 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
501                     final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
502                     if (winAnimator.isAnimationSet() || winAnimator.mWin.mAnimatingExit) {
503                         return true;
504                     }
505                 }
506             }
507         }
508         return false;
509     }
510 
addTask(Task task, boolean toTop)511     void addTask(Task task, boolean toTop) {
512         addTask(task, toTop, task.showForAllUsers());
513     }
514 
515     /**
516      * Put a Task in this stack. Used for adding and moving.
517      * @param task The task to add.
518      * @param toTop Whether to add it to the top or bottom.
519      * @param showForAllUsers Whether to show the task regardless of the current user.
520      */
addTask(Task task, boolean toTop, boolean showForAllUsers)521     void addTask(Task task, boolean toTop, boolean showForAllUsers) {
522         positionTask(task, toTop ? mTasks.size() : 0, showForAllUsers);
523     }
524 
positionTask(Task task, int position, boolean showForAllUsers)525     void positionTask(Task task, int position, boolean showForAllUsers) {
526         final boolean canShowTask =
527                 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId);
528         mTasks.remove(task);
529         int stackSize = mTasks.size();
530         int minPosition = 0;
531         int maxPosition = stackSize;
532 
533         if (canShowTask) {
534             minPosition = computeMinPosition(minPosition, stackSize);
535         } else {
536             maxPosition = computeMaxPosition(maxPosition);
537         }
538         // Reset position based on minimum/maximum possible positions.
539         position = Math.min(Math.max(position, minPosition), maxPosition);
540 
541         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM,
542                 "positionTask: task=" + task + " position=" + position);
543         mTasks.add(position, task);
544 
545         // If we are moving the task across stacks, the scroll is no longer valid.
546         if (task.mStack != this) {
547             task.resetScrollLocked();
548         }
549         task.mStack = this;
550         task.updateDisplayInfo(mDisplayContent);
551         boolean toTop = position == mTasks.size() - 1;
552         if (toTop) {
553             mDisplayContent.moveStack(this, true);
554         }
555 
556         if (StackId.windowsAreScaleable(mStackId)) {
557             // We force windows out of SCALING_MODE_FREEZE
558             // so that we can continue to animate them
559             // while a resize is pending.
560             forceWindowsScaleable(task, true);
561         } else {
562             forceWindowsScaleable(task, false);
563         }
564         EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, position);
565     }
566 
567     /** Calculate the minimum possible position for a task that can be shown to the user.
568      *  The minimum position will be above all other tasks that can't be shown.
569      *  @param minPosition The minimum position the caller is suggesting.
570      *                  We will start adjusting up from here.
571      *  @param size The size of the current task list.
572      */
computeMinPosition(int minPosition, int size)573     private int computeMinPosition(int minPosition, int size) {
574         while (minPosition < size) {
575             final Task tmpTask = mTasks.get(minPosition);
576             final boolean canShowTmpTask =
577                     tmpTask.showForAllUsers()
578                             || mService.isCurrentProfileLocked(tmpTask.mUserId);
579             if (canShowTmpTask) {
580                 break;
581             }
582             minPosition++;
583         }
584         return minPosition;
585     }
586 
587     /** Calculate the maximum possible position for a task that can't be shown to the user.
588      *  The maximum position will be below all other tasks that can be shown.
589      *  @param maxPosition The maximum position the caller is suggesting.
590      *                  We will start adjusting down from here.
591      */
computeMaxPosition(int maxPosition)592     private int computeMaxPosition(int maxPosition) {
593         while (maxPosition > 0) {
594             final Task tmpTask = mTasks.get(maxPosition - 1);
595             final boolean canShowTmpTask =
596                     tmpTask.showForAllUsers()
597                             || mService.isCurrentProfileLocked(tmpTask.mUserId);
598             if (!canShowTmpTask) {
599                 break;
600             }
601             maxPosition--;
602         }
603         return maxPosition;
604     }
605 
moveTaskToTop(Task task)606     void moveTaskToTop(Task task) {
607         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToTop: task=" + task + " Callers="
608                 + Debug.getCallers(6));
609         mTasks.remove(task);
610         addTask(task, true);
611     }
612 
moveTaskToBottom(Task task)613     void moveTaskToBottom(Task task) {
614         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToBottom: task=" + task);
615         mTasks.remove(task);
616         addTask(task, false);
617     }
618 
619     /**
620      * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the
621      * back.
622      * @param task The Task to delete.
623      */
removeTask(Task task)624     void removeTask(Task task) {
625         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeTask: task=" + task);
626         mTasks.remove(task);
627         if (mDisplayContent != null) {
628             if (mTasks.isEmpty()) {
629                 mDisplayContent.moveStack(this, false);
630             }
631             mDisplayContent.layoutNeeded = true;
632         }
633         for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
634             final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
635             if (wtoken.mTask == task) {
636                 wtoken.mIsExiting = false;
637                 mExitingAppTokens.remove(appNdx);
638             }
639         }
640     }
641 
attachDisplayContent(DisplayContent displayContent)642     void attachDisplayContent(DisplayContent displayContent) {
643         if (mDisplayContent != null) {
644             throw new IllegalStateException("attachDisplayContent: Already attached");
645         }
646 
647         mDisplayContent = displayContent;
648         mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(),
649                 "animation background stackId=" + mStackId);
650 
651         Rect bounds = null;
652         final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
653         if (mStackId == DOCKED_STACK_ID
654                 || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId)
655                         && !dockedStack.isFullscreen())) {
656             // The existence of a docked stack affects the size of other static stack created since
657             // the docked stack occupies a dedicated region on screen, but only if the dock stack is
658             // not fullscreen. If it's fullscreen, it means that we are in the transition of
659             // dismissing it, so we must not resize this stack.
660             bounds = new Rect();
661             displayContent.getLogicalDisplayRect(mTmpRect);
662             mTmpRect2.setEmpty();
663             if (dockedStack != null) {
664                 dockedStack.getRawBounds(mTmpRect2);
665             }
666             final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
667                     == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
668             getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2,
669                     mDisplayContent.mDividerControllerLocked.getContentWidth(),
670                     dockedOnTopOrLeft);
671         }
672 
673         updateDisplayInfo(bounds);
674     }
675 
getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility)676     void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) {
677         if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
678                 || mDisplayContent == null) {
679             outBounds.set(mBounds);
680             return;
681         }
682 
683         final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
684         if (dockedStack == null) {
685             // Not sure why you are calling this method when there is no docked stack...
686             throw new IllegalStateException(
687                     "Calling getStackDockedModeBoundsLocked() when there is no docked stack.");
688         }
689         if (!ignoreVisibility && !dockedStack.isVisibleLocked()) {
690             // The docked stack is being dismissed, but we caught before it finished being
691             // dismissed. In that case we want to treat it as if it is not occupying any space and
692             // let others occupy the whole display.
693             mDisplayContent.getLogicalDisplayRect(outBounds);
694             return;
695         }
696 
697         final int dockedSide = dockedStack.getDockSide();
698         if (dockedSide == DOCKED_INVALID) {
699             // Not sure how you got here...Only thing we can do is return current bounds.
700             Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack);
701             outBounds.set(mBounds);
702             return;
703         }
704 
705         mDisplayContent.getLogicalDisplayRect(mTmpRect);
706         dockedStack.getRawBounds(mTmpRect2);
707         final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
708         getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2,
709                 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
710 
711     }
712 
713     /**
714      * Outputs the bounds a stack should be given the presence of a docked stack on the display.
715      * @param displayRect The bounds of the display the docked stack is on.
716      * @param outBounds Output bounds that should be used for the stack.
717      * @param stackId Id of stack we are calculating the bounds for.
718      * @param dockedBounds Bounds of the docked stack.
719      * @param dockDividerWidth We need to know the width of the divider make to the output bounds
720      *                         close to the side of the dock.
721      * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
722      */
getStackDockedModeBounds( Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth, boolean dockOnTopOrLeft)723     private void getStackDockedModeBounds(
724             Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth,
725             boolean dockOnTopOrLeft) {
726         final boolean dockedStack = stackId == DOCKED_STACK_ID;
727         final boolean splitHorizontally = displayRect.width() > displayRect.height();
728 
729         outBounds.set(displayRect);
730         if (dockedStack) {
731             if (mService.mDockedStackCreateBounds != null) {
732                 outBounds.set(mService.mDockedStackCreateBounds);
733                 return;
734             }
735 
736             // The initial bounds of the docked stack when it is created about half the screen space
737             // and its bounds can be adjusted after that. The bounds of all other stacks are
738             // adjusted to occupy whatever screen space the docked stack isn't occupying.
739             final DisplayInfo di = mDisplayContent.getDisplayInfo();
740             mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
741                     mTmpRect2);
742             final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
743                     di.logicalWidth,
744                     di.logicalHeight,
745                     dockDividerWidth,
746                     mService.mCurConfiguration.orientation == ORIENTATION_PORTRAIT,
747                     mTmpRect2).getMiddleTarget().position;
748 
749             if (dockOnTopOrLeft) {
750                 if (splitHorizontally) {
751                     outBounds.right = position;
752                 } else {
753                     outBounds.bottom = position;
754                 }
755             } else {
756                 if (splitHorizontally) {
757                     outBounds.left = position + dockDividerWidth;
758                 } else {
759                     outBounds.top = position + dockDividerWidth;
760                 }
761             }
762             return;
763         }
764 
765         // Other stacks occupy whatever space is left by the docked stack.
766         if (!dockOnTopOrLeft) {
767             if (splitHorizontally) {
768                 outBounds.right = dockedBounds.left - dockDividerWidth;
769             } else {
770                 outBounds.bottom = dockedBounds.top - dockDividerWidth;
771             }
772         } else {
773             if (splitHorizontally) {
774                 outBounds.left = dockedBounds.right + dockDividerWidth;
775             } else {
776                 outBounds.top = dockedBounds.bottom + dockDividerWidth;
777             }
778         }
779         DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
780     }
781 
resetDockedStackToMiddle()782     void resetDockedStackToMiddle() {
783         if (mStackId != DOCKED_STACK_ID) {
784             throw new IllegalStateException("Not a docked stack=" + this);
785         }
786 
787         mService.mDockedStackCreateBounds = null;
788 
789         final Rect bounds = new Rect();
790         getStackDockedModeBoundsLocked(bounds, true /*ignoreVisibility*/);
791         mService.mH.obtainMessage(RESIZE_STACK, DOCKED_STACK_ID,
792                 1 /*allowResizeInDockedMode*/, bounds).sendToTarget();
793     }
794 
detachDisplay()795     void detachDisplay() {
796         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
797 
798         boolean doAnotherLayoutPass = false;
799         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
800             final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens;
801             for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
802                 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
803                 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
804                     // We are in the middle of changing the state of displays/stacks/tasks. We need
805                     // to finish that, before we let layout interfere with it.
806                     mService.removeWindowLocked(appWindows.get(winNdx));
807                     doAnotherLayoutPass = true;
808                 }
809             }
810         }
811         if (doAnotherLayoutPass) {
812             mService.mWindowPlacerLocked.requestTraversal();
813         }
814 
815         close();
816     }
817 
resetAnimationBackgroundAnimator()818     void resetAnimationBackgroundAnimator() {
819         mAnimationBackgroundAnimator = null;
820         mAnimationBackgroundSurface.hide();
821     }
822 
setAnimationBackground(WindowStateAnimator winAnimator, int color)823     void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
824         int animLayer = winAnimator.mAnimLayer;
825         if (mAnimationBackgroundAnimator == null
826                 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) {
827             mAnimationBackgroundAnimator = winAnimator;
828             animLayer = mService.adjustAnimationBackground(winAnimator);
829             mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM,
830                     ((color >> 24) & 0xff) / 255f, 0);
831         }
832     }
833 
switchUser()834     void switchUser() {
835         int top = mTasks.size();
836         for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
837             Task task = mTasks.get(taskNdx);
838             if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
839                 mTasks.remove(taskNdx);
840                 mTasks.add(task);
841                 --top;
842             }
843         }
844     }
845 
close()846     void close() {
847         if (mAnimationBackgroundSurface != null) {
848             mAnimationBackgroundSurface.destroySurface();
849             mAnimationBackgroundSurface = null;
850         }
851         mDisplayContent = null;
852     }
853 
854     /**
855      * Adjusts the stack bounds if the IME is visible.
856      *
857      * @param imeWin The IME window.
858      */
setAdjustedForIme(WindowState imeWin, boolean forceUpdate)859     void setAdjustedForIme(WindowState imeWin, boolean forceUpdate) {
860         mImeWin = imeWin;
861         mImeGoingAway = false;
862         if (!mAdjustedForIme || forceUpdate) {
863             mAdjustedForIme = true;
864             mAdjustImeAmount = 0f;
865             mAdjustDividerAmount = 0f;
866             updateAdjustForIme(0f, 0f, true /* force */);
867         }
868     }
869 
isAdjustedForIme()870     boolean isAdjustedForIme() {
871         return mAdjustedForIme;
872     }
873 
isAnimatingForIme()874     boolean isAnimatingForIme() {
875         return mImeWin != null && mImeWin.isAnimatingLw();
876     }
877 
878     /**
879      * Update the stack's bounds (crop or position) according to the IME window's
880      * current position. When IME window is animated, the bottom stack is animated
881      * together to track the IME window's current position, and the top stack is
882      * cropped as necessary.
883      *
884      * @return true if a traversal should be performed after the adjustment.
885      */
updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force)886     boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
887         if (adjustAmount != mAdjustImeAmount
888                 || adjustDividerAmount != mAdjustDividerAmount || force) {
889             mAdjustImeAmount = adjustAmount;
890             mAdjustDividerAmount = adjustDividerAmount;
891             updateAdjustedBounds();
892             return isVisibleLocked(true /* ignoreKeyguard */);
893         } else {
894             return false;
895         }
896     }
897 
898     /**
899      * Resets the adjustment after it got adjusted for the IME.
900      * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about
901      *                        animations; otherwise, set flag and animates the window away together
902      *                        with IME window.
903      */
resetAdjustedForIme(boolean adjustBoundsNow)904     void resetAdjustedForIme(boolean adjustBoundsNow) {
905         if (adjustBoundsNow) {
906             mImeWin = null;
907             mAdjustedForIme = false;
908             mImeGoingAway = false;
909             mAdjustImeAmount = 0f;
910             mAdjustDividerAmount = 0f;
911             updateAdjustedBounds();
912             mService.setResizeDimLayer(false, mStackId, 1.0f);
913         } else {
914             mImeGoingAway |= mAdjustedForIme;
915         }
916     }
917 
918     /**
919      * Sets the amount how much we currently minimize our stack.
920      *
921      * @param minimizeAmount The amount, between 0 and 1.
922      * @return Whether the amount has changed and a layout is needed.
923      */
setAdjustedForMinimizedDock(float minimizeAmount)924     boolean setAdjustedForMinimizedDock(float minimizeAmount) {
925         if (minimizeAmount != mMinimizeAmount) {
926             mMinimizeAmount = minimizeAmount;
927             updateAdjustedBounds();
928             return isVisibleLocked(true /* ignoreKeyguard*/);
929         } else {
930             return false;
931         }
932     }
933 
isAdjustedForMinimizedDock()934     boolean isAdjustedForMinimizedDock() {
935         return mMinimizeAmount != 0f;
936     }
937 
938     /**
939      * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows
940      * to the list of to be drawn windows the service is waiting for.
941      */
beginImeAdjustAnimation()942     void beginImeAdjustAnimation() {
943         for (int j = mTasks.size() - 1; j >= 0; j--) {
944             final Task task = mTasks.get(j);
945             if (task.isVisible()) {
946                 task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
947                 task.addWindowsWaitingForDrawnIfResizingChanged();
948             }
949         }
950     }
951 
952     /**
953      * Resets the resizing state of all windows.
954      */
endImeAdjustAnimation()955     void endImeAdjustAnimation() {
956         for (int j = mTasks.size() - 1; j >= 0; j--) {
957             mTasks.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
958         }
959     }
960 
getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom)961     int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
962         return displayContentRect.top + (int)
963                 ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN);
964     }
965 
adjustForIME(final WindowState imeWin)966     private boolean adjustForIME(final WindowState imeWin) {
967         final int dockedSide = getDockSide();
968         final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
969         if (imeWin == null || !dockedTopOrBottom) {
970             return false;
971         }
972 
973         final Rect displayContentRect = mTmpRect;
974         final Rect contentBounds = mTmpRect2;
975 
976         // Calculate the content bounds excluding the area occupied by IME
977         getDisplayContent().getContentRect(displayContentRect);
978         contentBounds.set(displayContentRect);
979         int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
980 
981         imeTop += imeWin.getGivenContentInsetsLw().top;
982         if (contentBounds.bottom > imeTop) {
983             contentBounds.bottom = imeTop;
984         }
985 
986         final int yOffset = displayContentRect.bottom - contentBounds.bottom;
987 
988         final int dividerWidth =
989                 getDisplayContent().mDividerControllerLocked.getContentWidth();
990         final int dividerWidthInactive =
991                 getDisplayContent().mDividerControllerLocked.getContentWidthInactive();
992 
993         if (dockedSide == DOCKED_TOP) {
994             // If this stack is docked on top, we make it smaller so the bottom stack is not
995             // occluded by IME. We shift its bottom up by the height of the IME, but
996             // leaves at least 30% of the top stack visible.
997             final int minTopStackBottom =
998                     getMinTopStackBottom(displayContentRect, mBounds.bottom);
999             final int bottom = Math.max(
1000                     mBounds.bottom - yOffset + dividerWidth - dividerWidthInactive,
1001                     minTopStackBottom);
1002             mTmpAdjustedBounds.set(mBounds);
1003             mTmpAdjustedBounds.bottom =
1004                     (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom);
1005             mFullyAdjustedImeBounds.set(mBounds);
1006         } else {
1007             // When the stack is on bottom and has no focus, it's only adjusted for divider width.
1008             final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
1009 
1010             // When the stack is on bottom and has focus, it needs to be moved up so as to
1011             // not occluded by IME, and at the same time adjusted for divider width.
1012             // We try to move it up by the height of the IME window, but only to the extent
1013             // that leaves at least 30% of the top stack visible.
1014             // 'top' is where the top of bottom stack will move to in this case.
1015             final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive;
1016             final int minTopStackBottom =
1017                     getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
1018             final int top = Math.max(
1019                     mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
1020 
1021             mTmpAdjustedBounds.set(mBounds);
1022             // Account for the adjustment for IME and divider width separately.
1023             // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
1024             // and dividerWidthDelta is due to divider width change only.
1025             mTmpAdjustedBounds.top = mBounds.top +
1026                     (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) +
1027                             mAdjustDividerAmount * dividerWidthDelta);
1028             mFullyAdjustedImeBounds.set(mBounds);
1029             mFullyAdjustedImeBounds.top = top;
1030             mFullyAdjustedImeBounds.bottom = top + mBounds.height();
1031         }
1032         return true;
1033     }
1034 
adjustForMinimizedDockedStack(float minimizeAmount)1035     private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
1036         final int dockSide = getDockSide();
1037         if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
1038             return false;
1039         }
1040 
1041         if (dockSide == DOCKED_TOP) {
1042             mService.getStableInsetsLocked(mTmpRect);
1043             int topInset = mTmpRect.top;
1044             mTmpAdjustedBounds.set(mBounds);
1045             mTmpAdjustedBounds.bottom =
1046                     (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
1047         } else if (dockSide == DOCKED_LEFT) {
1048             mTmpAdjustedBounds.set(mBounds);
1049             final int width = mBounds.width();
1050             mTmpAdjustedBounds.right =
1051                     (int) (minimizeAmount * mDockedStackMinimizeThickness
1052                             + (1 - minimizeAmount) * mBounds.right);
1053             mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
1054         } else if (dockSide == DOCKED_RIGHT) {
1055             mTmpAdjustedBounds.set(mBounds);
1056             mTmpAdjustedBounds.left =
1057                     (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness)
1058                             + (1 - minimizeAmount) * mBounds.left);
1059         }
1060         return true;
1061     }
1062 
1063     /**
1064      * @return the distance in pixels how much the stack gets minimized from it's original size
1065      */
getMinimizeDistance()1066     int getMinimizeDistance() {
1067         final int dockSide = getDockSide();
1068         if (dockSide == DOCKED_INVALID) {
1069             return 0;
1070         }
1071 
1072         if (dockSide == DOCKED_TOP) {
1073             mService.getStableInsetsLocked(mTmpRect);
1074             int topInset = mTmpRect.top;
1075             return mBounds.bottom - topInset;
1076         } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
1077             return mBounds.width() - mDockedStackMinimizeThickness;
1078         } else {
1079             return 0;
1080         }
1081     }
1082 
1083     /**
1084      * Updates the adjustment depending on it's current state.
1085      */
updateAdjustedBounds()1086     private void updateAdjustedBounds() {
1087         boolean adjust = false;
1088         if (mMinimizeAmount != 0f) {
1089             adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
1090         } else if (mAdjustedForIme) {
1091             adjust = adjustForIME(mImeWin);
1092         }
1093         if (!adjust) {
1094             mTmpAdjustedBounds.setEmpty();
1095         }
1096         setAdjustedBounds(mTmpAdjustedBounds);
1097 
1098         final boolean isImeTarget = (mService.getImeFocusStackLocked() == this);
1099         if (mAdjustedForIme && adjust && !isImeTarget) {
1100             final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
1101                     * IME_ADJUST_DIM_AMOUNT;
1102             mService.setResizeDimLayer(true, mStackId, alpha);
1103         }
1104     }
1105 
applyAdjustForImeIfNeeded(Task task)1106     void applyAdjustForImeIfNeeded(Task task) {
1107         if (mMinimizeAmount != 0f || !mAdjustedForIme || mAdjustedBounds.isEmpty()) {
1108             return;
1109         }
1110 
1111         final Rect insetBounds = mImeGoingAway ? mBounds : mFullyAdjustedImeBounds;
1112         task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP);
1113         mDisplayContent.layoutNeeded = true;
1114     }
1115 
isAdjustedForMinimizedDockedStack()1116     boolean isAdjustedForMinimizedDockedStack() {
1117         return mMinimizeAmount != 0f;
1118     }
1119 
dump(String prefix, PrintWriter pw)1120     public void dump(String prefix, PrintWriter pw) {
1121         pw.println(prefix + "mStackId=" + mStackId);
1122         pw.println(prefix + "mDeferDetach=" + mDeferDetach);
1123         pw.println(prefix + "mFullscreen=" + mFullscreen);
1124         pw.println(prefix + "mBounds=" + mBounds.toShortString());
1125         if (mMinimizeAmount != 0f) {
1126             pw.println(prefix + "mMinimizeAmout=" + mMinimizeAmount);
1127         }
1128         if (mAdjustedForIme) {
1129             pw.println(prefix + "mAdjustedForIme=true");
1130             pw.println(prefix + "mAdjustImeAmount=" + mAdjustImeAmount);
1131             pw.println(prefix + "mAdjustDividerAmount=" + mAdjustDividerAmount);
1132         }
1133         if (!mAdjustedBounds.isEmpty()) {
1134             pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString());
1135         }
1136         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) {
1137             mTasks.get(taskNdx).dump(prefix + "  ", pw);
1138         }
1139         if (mAnimationBackgroundSurface.isDimming()) {
1140             pw.println(prefix + "mWindowAnimationBackgroundSurface:");
1141             mAnimationBackgroundSurface.printTo(prefix + "  ", pw);
1142         }
1143         if (!mExitingAppTokens.isEmpty()) {
1144             pw.println();
1145             pw.println("  Exiting application tokens:");
1146             for (int i = mExitingAppTokens.size() - 1; i >= 0; i--) {
1147                 WindowToken token = mExitingAppTokens.get(i);
1148                 pw.print("  Exiting App #"); pw.print(i);
1149                 pw.print(' '); pw.print(token);
1150                 pw.println(':');
1151                 token.dump(pw, "    ");
1152             }
1153         }
1154     }
1155 
1156     /** Fullscreen status of the stack without adjusting for other factors in the system like
1157      * visibility of docked stack.
1158      * Most callers should be using {@link #isFullscreen} as it take into consideration other
1159      * system factors. */
getRawFullscreen()1160     boolean getRawFullscreen() {
1161         return mFullscreen;
1162     }
1163 
1164     @Override
dimFullscreen()1165     public boolean dimFullscreen() {
1166         return mStackId == HOME_STACK_ID || isFullscreen();
1167     }
1168 
isFullscreen()1169     boolean isFullscreen() {
1170         if (useCurrentBounds()) {
1171             return mFullscreen;
1172         }
1173         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
1174         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
1175         // system.
1176         return true;
1177     }
1178 
1179     @Override
getDisplayInfo()1180     public DisplayInfo getDisplayInfo() {
1181         return mDisplayContent.getDisplayInfo();
1182     }
1183 
1184     @Override
toString()1185     public String toString() {
1186         return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
1187     }
1188 
1189     @Override
toShortString()1190     public String toShortString() {
1191         return "Stack=" + mStackId;
1192     }
1193 
1194     /**
1195      * For docked workspace (or workspace that's side-by-side to the docked), provides
1196      * information which side of the screen was the dock anchored.
1197      */
getDockSide()1198     int getDockSide() {
1199         return getDockSide(mBounds);
1200     }
1201 
getDockSide(Rect bounds)1202     int getDockSide(Rect bounds) {
1203         if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) {
1204             return DOCKED_INVALID;
1205         }
1206         if (mDisplayContent == null) {
1207             return DOCKED_INVALID;
1208         }
1209         mDisplayContent.getLogicalDisplayRect(mTmpRect);
1210         final int orientation = mService.mCurConfiguration.orientation;
1211         return getDockSideUnchecked(bounds, mTmpRect, orientation);
1212     }
1213 
getDockSideUnchecked(Rect bounds, Rect displayRect, int orientation)1214     static int getDockSideUnchecked(Rect bounds, Rect displayRect, int orientation) {
1215         if (orientation == Configuration.ORIENTATION_PORTRAIT) {
1216             // Portrait mode, docked either at the top or the bottom.
1217             if (bounds.top - displayRect.top <= displayRect.bottom - bounds.bottom) {
1218                 return DOCKED_TOP;
1219             } else {
1220                 return DOCKED_BOTTOM;
1221             }
1222         } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
1223             // Landscape mode, docked either on the left or on the right.
1224             if (bounds.left - displayRect.left <= displayRect.right - bounds.right) {
1225                 return DOCKED_LEFT;
1226             } else {
1227                 return DOCKED_RIGHT;
1228             }
1229         } else {
1230             return DOCKED_INVALID;
1231         }
1232     }
1233 
isVisibleLocked()1234     boolean isVisibleLocked() {
1235         return isVisibleLocked(false /* ignoreKeyguard */);
1236     }
1237 
isVisibleLocked(boolean ignoreKeyguard)1238     boolean isVisibleLocked(boolean ignoreKeyguard) {
1239         final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded()
1240                 && !mService.mAnimator.mKeyguardGoingAway;
1241         if (!ignoreKeyguard && keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
1242             // The keyguard is showing and the stack shouldn't show on top of the keyguard.
1243             return false;
1244         }
1245 
1246         for (int i = mTasks.size() - 1; i >= 0; i--) {
1247             final Task task = mTasks.get(i);
1248             for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
1249                 if (!task.mAppTokens.get(j).hidden) {
1250                     return true;
1251                 }
1252             }
1253         }
1254 
1255         return false;
1256     }
1257 
isDragResizing()1258     boolean isDragResizing() {
1259         return mDragResizing;
1260     }
1261 
setDragResizingLocked(boolean resizing)1262     void setDragResizingLocked(boolean resizing) {
1263         if (mDragResizing == resizing) {
1264             return;
1265         }
1266         mDragResizing = resizing;
1267         for (int i = mTasks.size() - 1; i >= 0 ; i--) {
1268             mTasks.get(i).resetDragResizingChangeReported();
1269         }
1270     }
1271 
1272     @Override  // AnimatesBounds
setSize(Rect bounds)1273     public boolean setSize(Rect bounds) {
1274         synchronized (mService.mWindowMap) {
1275             if (mDisplayContent == null) {
1276                 return false;
1277             }
1278         }
1279         try {
1280             mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false, -1);
1281         } catch (RemoteException e) {
1282         }
1283         return true;
1284     }
1285 
setPinnedStackSize(Rect bounds, Rect tempTaskBounds)1286     public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) {
1287         synchronized (mService.mWindowMap) {
1288             if (mDisplayContent == null) {
1289                 return false;
1290             }
1291             if (mStackId != PINNED_STACK_ID) {
1292                 Slog.w(TAG_WM, "Attempt to use pinned stack resize animation helper on"
1293                         + "non pinned stack");
1294                 return false;
1295             }
1296         }
1297         try {
1298             mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds);
1299         } catch (RemoteException e) {
1300             // I don't believe you.
1301         }
1302         return true;
1303     }
1304 
forceWindowsScaleable(Task task, boolean force)1305     void forceWindowsScaleable(Task task, boolean force) {
1306         SurfaceControl.openTransaction();
1307         try {
1308             final ArrayList<AppWindowToken> activities = task.mAppTokens;
1309             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
1310                 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
1311                 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
1312                     final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
1313                     if (winAnimator == null || !winAnimator.hasSurface()) {
1314                         continue;
1315                     }
1316                     winAnimator.mSurfaceController.forceScaleableInTransaction(force);
1317                 }
1318             }
1319         } finally {
1320             SurfaceControl.closeTransaction();
1321         }
1322     }
1323 
1324     @Override  // AnimatesBounds
onAnimationStart()1325     public void onAnimationStart() {
1326         synchronized (mService.mWindowMap) {
1327             mBoundsAnimating = true;
1328         }
1329     }
1330 
1331     @Override  // AnimatesBounds
onAnimationEnd()1332     public void onAnimationEnd() {
1333         synchronized (mService.mWindowMap) {
1334             mBoundsAnimating = false;
1335             mService.requestTraversal();
1336         }
1337         if (mStackId == PINNED_STACK_ID) {
1338             try {
1339                 mService.mActivityManager.notifyPinnedStackAnimationEnded();
1340             } catch (RemoteException e) {
1341                 // I don't believe you...
1342             }
1343         }
1344     }
1345 
1346     @Override
moveToFullscreen()1347     public void moveToFullscreen() {
1348         try {
1349             mService.mActivityManager.moveTasksToFullscreenStack(mStackId, true);
1350         } catch (RemoteException e) {
1351             e.printStackTrace();
1352         }
1353     }
1354 
1355     @Override
getFullScreenBounds(Rect bounds)1356     public void getFullScreenBounds(Rect bounds) {
1357         getDisplayContent().getContentRect(bounds);
1358     }
1359 
hasMovementAnimations()1360     public boolean hasMovementAnimations() {
1361         return StackId.hasMovementAnimations(mStackId);
1362     }
1363 
getForceScaleToCrop()1364     public boolean getForceScaleToCrop() {
1365         return mBoundsAnimating;
1366     }
1367 
getBoundsAnimating()1368     public boolean getBoundsAnimating() {
1369         return mBoundsAnimating;
1370     }
1371 
1372     /**
1373      * See {@link WindowManagerService#overridePlayingAppAnimationsLw}
1374      */
overridePlayingAppAnimations(Animation a)1375     void overridePlayingAppAnimations(Animation a) {
1376         for (int i = mTasks.size() - 1; i >= 0; --i) {
1377             mTasks.get(i).overridePlayingAppAnimations(a);
1378         }
1379     }
1380 }
1381