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