OSDN Git Service

Don't specify stack bounds for unsizeable home stack in dock mode
[android-x86/frameworks-base.git] / services / core / java / com / android / server / wm / TaskStack.java
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.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
25 import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
26 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
27 import static android.view.Display.DEFAULT_DISPLAY;
28 import static android.view.WindowManager.DOCKED_BOTTOM;
29 import static android.view.WindowManager.DOCKED_INVALID;
30 import static android.view.WindowManager.DOCKED_LEFT;
31 import static android.view.WindowManager.DOCKED_RIGHT;
32 import static android.view.WindowManager.DOCKED_TOP;
33 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
34 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
35 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
36 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
37 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
38 import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
39
40 import android.app.ActivityManager.StackId;
41 import android.content.res.Configuration;
42 import android.graphics.Rect;
43 import android.graphics.Region;
44 import android.os.RemoteException;
45 import android.util.EventLog;
46 import android.util.Slog;
47 import android.util.SparseArray;
48 import android.view.DisplayInfo;
49 import android.view.Surface;
50
51 import com.android.internal.policy.DividerSnapAlgorithm;
52 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
53 import com.android.internal.policy.DockedDividerUtils;
54 import com.android.server.EventLogTags;
55 import com.android.server.UiThread;
56
57 import java.io.PrintWriter;
58
59 public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLayerUser,
60         BoundsAnimationTarget {
61     /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
62      * restrict IME adjustment so that a min portion of top stack remains visible.*/
63     private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
64
65     /** Dimming amount for non-focused stack when stacks are IME-adjusted. */
66     private static final float IME_ADJUST_DIM_AMOUNT = 0.25f;
67
68     /** Unique identifier */
69     final int mStackId;
70
71     /** The service */
72     private final WindowManagerService mService;
73
74     /** The display this stack sits under. */
75     // TODO: Track parent marks like this in WindowContainer.
76     private DisplayContent mDisplayContent;
77
78     /** For comparison with DisplayContent bounds. */
79     private Rect mTmpRect = new Rect();
80     private Rect mTmpRect2 = new Rect();
81     private Rect mTmpRect3 = 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 mFillsParent = true;
97
98     // Device rotation as of the last time {@link #mBounds} was set.
99     private int mRotation;
100
101     /** Density as of last time {@link #mBounds} was set. */
102     private int mDensity;
103
104     /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
105     private DimLayer mAnimationBackgroundSurface;
106
107     /** The particular window with an Animation with non-zero background color. */
108     private 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     // TODO: maybe tie this to WindowContainer#removeChild some how...
115     boolean mDeferRemoval;
116
117     private final Rect mTmpAdjustedBounds = new Rect();
118     private boolean mAdjustedForIme;
119     private boolean mImeGoingAway;
120     private WindowState mImeWin;
121     private float mMinimizeAmount;
122     private float mAdjustImeAmount;
123     private float mAdjustDividerAmount;
124     private final int mDockedStackMinimizeThickness;
125
126     // If this is true, we are in the bounds animating mode. The task will be down or upscaled to
127     // perfectly fit the region it would have been cropped to. We may also avoid certain logic we
128     // would otherwise apply while resizing, while resizing in the bounds animating mode.
129     private boolean mBoundsAnimating = false;
130     // Set when an animation has been requested but has not yet started from the UI thread. This is
131     // cleared when the animation actually starts.
132     private boolean mBoundsAnimatingRequested = false;
133     private boolean mBoundsAnimatingToFullscreen = false;
134     private boolean mCancelCurrentBoundsAnimation = false;
135     private Rect mBoundsAnimationTarget = new Rect();
136     private Rect mBoundsAnimationSourceHintBounds = new Rect();
137
138     // Temporary storage for the new bounds that should be used after the configuration change.
139     // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
140     private final Rect mBoundsAfterRotation = new Rect();
141
142     TaskStack(WindowManagerService service, int stackId) {
143         mService = service;
144         mStackId = stackId;
145         mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
146                 com.android.internal.R.dimen.docked_stack_minimize_thickness);
147         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
148     }
149
150     DisplayContent getDisplayContent() {
151         return mDisplayContent;
152     }
153
154     Task findHomeTask() {
155         if (mStackId != HOME_STACK_ID) {
156             return null;
157         }
158
159         for (int i = mChildren.size() - 1; i >= 0; i--) {
160             if (mChildren.get(i).isHomeTask()) {
161                 return mChildren.get(i);
162             }
163         }
164         return null;
165     }
166
167     boolean hasMultipleTaskWithHomeTaskNotTop() {
168         return mChildren.size() > 1 && !mChildren.get(mChildren.size() - 1).isHomeTask();
169     }
170
171     /**
172      * Set the bounds of the stack and its containing tasks.
173      * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
174      * @param configs Configuration for individual tasks, keyed by task id.
175      * @param taskBounds Bounds for individual tasks, keyed by task id.
176      * @return True if the stack bounds was changed.
177      * */
178     boolean setBounds(
179             Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
180             SparseArray<Rect> taskTempInsetBounds) {
181         setBounds(stackBounds);
182
183         // Update bounds of containing tasks.
184         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
185             final Task task = mChildren.get(taskNdx);
186             Configuration config = configs.get(task.mTaskId);
187             if (config != null) {
188                 Rect bounds = taskBounds.get(task.mTaskId);
189                 task.resizeLocked(bounds, config, false /* forced */);
190                 task.setTempInsetBounds(taskTempInsetBounds != null ?
191                         taskTempInsetBounds.get(task.mTaskId) : null);
192             } else {
193                 Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
194             }
195         }
196         return true;
197     }
198
199     void prepareFreezingTaskBounds() {
200         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
201             final Task task = mChildren.get(taskNdx);
202             task.prepareFreezingBounds();
203         }
204     }
205
206     /**
207      * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
208      * the normal task bounds.
209      *
210      * @param bounds The adjusted bounds.
211      */
212     private void setAdjustedBounds(Rect bounds) {
213         if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) {
214             return;
215         }
216
217         mAdjustedBounds.set(bounds);
218         final boolean adjusted = !mAdjustedBounds.isEmpty();
219         Rect insetBounds = null;
220         if (adjusted && isAdjustedForMinimizedDockedStack()) {
221             insetBounds = mBounds;
222         } else if (adjusted && mAdjustedForIme) {
223             if (mImeGoingAway) {
224                 insetBounds = mBounds;
225             } else {
226                 insetBounds = mFullyAdjustedImeBounds;
227             }
228         }
229         alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds);
230         mDisplayContent.setLayoutNeeded();
231     }
232
233     private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
234         if (mFillsParent) {
235             return;
236         }
237
238         final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
239
240         // Update bounds of containing tasks.
241         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
242             final Task task = mChildren.get(taskNdx);
243             task.alignToAdjustedBounds(adjustedBounds, tempInsetBounds, alignBottom);
244         }
245     }
246
247     private boolean setBounds(Rect bounds) {
248         boolean oldFullscreen = mFillsParent;
249         int rotation = Surface.ROTATION_0;
250         int density = DENSITY_DPI_UNDEFINED;
251         if (mDisplayContent != null) {
252             mDisplayContent.getLogicalDisplayRect(mTmpRect);
253             rotation = mDisplayContent.getDisplayInfo().rotation;
254             density = mDisplayContent.getDisplayInfo().logicalDensityDpi;
255             mFillsParent = bounds == null;
256             if (mFillsParent) {
257                 bounds = mTmpRect;
258             }
259         }
260
261         if (bounds == null) {
262             // Can't set to fullscreen if we don't have a display to get bounds from...
263             return false;
264         }
265         if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) {
266             return false;
267         }
268
269         if (mDisplayContent != null) {
270             mDisplayContent.mDimLayerController.updateDimLayer(this);
271             mAnimationBackgroundSurface.setBounds(bounds);
272         }
273
274         mBounds.set(bounds);
275         mRotation = rotation;
276         mDensity = density;
277
278         updateAdjustedBounds();
279
280         return true;
281     }
282
283     /** Bounds of the stack without adjusting for other factors in the system like visibility
284      * of docked stack.
285      * Most callers should be using {@link #getBounds} as it take into consideration other system
286      * factors. */
287     void getRawBounds(Rect out) {
288         out.set(mBounds);
289     }
290
291     /** Return true if the current bound can get outputted to the rest of the system as-is. */
292     private boolean useCurrentBounds() {
293         if (mFillsParent
294                 || !StackId.isResizeableByDockedStack(mStackId)
295                 || mDisplayContent == null
296                 || mDisplayContent.getDockedStackLocked() != null) {
297             return true;
298         }
299         return false;
300     }
301
302     public void getBounds(Rect out) {
303         if (useCurrentBounds()) {
304             // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
305             // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
306             // stack is visible since it is already what we want to represent to the rest of the
307             // system.
308             if (!mAdjustedBounds.isEmpty()) {
309                 out.set(mAdjustedBounds);
310             } else {
311                 out.set(mBounds);
312             }
313             return;
314         }
315
316         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
317         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
318         // system.
319         mDisplayContent.getLogicalDisplayRect(out);
320     }
321
322     /**
323      * Sets the bounds animation target bounds ahead of an animation.  This can't currently be done
324      * in onAnimationStart() since that is started on the UiThread.
325      */
326     void setAnimationFinalBounds(Rect sourceHintBounds, Rect destBounds, boolean toFullscreen) {
327         mBoundsAnimatingRequested = true;
328         mBoundsAnimatingToFullscreen = toFullscreen;
329         if (destBounds != null) {
330             mBoundsAnimationTarget.set(destBounds);
331         } else {
332             mBoundsAnimationTarget.setEmpty();
333         }
334         if (sourceHintBounds != null) {
335             mBoundsAnimationSourceHintBounds.set(sourceHintBounds);
336         } else {
337             mBoundsAnimationSourceHintBounds.setEmpty();
338         }
339     }
340
341     /**
342      * @return the final bounds for the bounds animation.
343      */
344     void getFinalAnimationBounds(Rect outBounds) {
345         outBounds.set(mBoundsAnimationTarget);
346     }
347
348     /**
349      * @return the final source bounds for the bounds animation.
350      */
351     void getFinalAnimationSourceHintBounds(Rect outBounds) {
352         outBounds.set(mBoundsAnimationSourceHintBounds);
353     }
354
355     /**
356      * @return the final animation bounds if the task stack is currently being animated, or the
357      *         current stack bounds otherwise.
358      */
359     void getAnimationOrCurrentBounds(Rect outBounds) {
360         if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) {
361             getFinalAnimationBounds(outBounds);
362             return;
363         }
364         getBounds(outBounds);
365     }
366
367     /** Bounds of the stack with other system factors taken into consideration. */
368     @Override
369     public void getDimBounds(Rect out) {
370         getBounds(out);
371     }
372
373     void updateDisplayInfo(Rect bounds) {
374         if (mDisplayContent == null) {
375             return;
376         }
377
378         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
379             mChildren.get(taskNdx).updateDisplayInfo(mDisplayContent);
380         }
381         if (bounds != null) {
382             setBounds(bounds);
383             return;
384         } else if (mFillsParent) {
385             setBounds(null);
386             return;
387         }
388
389         mTmpRect2.set(mBounds);
390         final int newRotation = mDisplayContent.getDisplayInfo().rotation;
391         final int newDensity = mDisplayContent.getDisplayInfo().logicalDensityDpi;
392         if (mRotation == newRotation && mDensity == newDensity) {
393             setBounds(mTmpRect2);
394         }
395
396         // If the rotation or density didn't match, we'll update it in onConfigurationChanged.
397     }
398
399     /** @return true if bounds were updated to some non-empty value. */
400     boolean updateBoundsAfterConfigChange() {
401         if (mDisplayContent == null) {
402             // If the stack is already detached we're not updating anything,
403             // as it's going away soon anyway.
404             return false;
405         }
406
407         if (mStackId == PINNED_STACK_ID) {
408             getAnimationOrCurrentBounds(mTmpRect2);
409             boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
410                     mTmpRect2, mTmpRect3);
411             if (updated) {
412                 mBoundsAfterRotation.set(mTmpRect3);
413
414                 // Once we've set the bounds based on the rotation of the old bounds in the new
415                 // orientation, clear the animation target bounds since they are obsolete, and
416                 // cancel any currently running animations
417                 mBoundsAnimationTarget.setEmpty();
418                 mBoundsAnimationSourceHintBounds.setEmpty();
419                 mCancelCurrentBoundsAnimation = true;
420                 return true;
421             }
422         }
423
424         final int newRotation = getDisplayInfo().rotation;
425         final int newDensity = getDisplayInfo().logicalDensityDpi;
426
427         if (mRotation == newRotation && mDensity == newDensity) {
428             // Nothing to do here as we already update the state in updateDisplayInfo.
429             return false;
430         }
431
432         if (mFillsParent) {
433             // Update stack bounds again since rotation changed since updateDisplayInfo().
434             setBounds(null);
435             // Return false since we don't need the client to resize.
436             return false;
437         }
438
439         mTmpRect2.set(mBounds);
440         mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
441         switch (mStackId) {
442             case DOCKED_STACK_ID:
443                 repositionDockedStackAfterRotation(mTmpRect2);
444                 snapDockedStackAfterRotation(mTmpRect2);
445                 final int newDockSide = getDockSide(mTmpRect2);
446
447                 // Update the dock create mode and clear the dock create bounds, these
448                 // might change after a rotation and the original values will be invalid.
449                 mService.setDockedStackCreateStateLocked(
450                         (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
451                                 ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
452                                 : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
453                         null);
454                 mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
455                 break;
456         }
457
458         mBoundsAfterRotation.set(mTmpRect2);
459         return true;
460     }
461
462     void getBoundsForNewConfiguration(Rect outBounds) {
463         outBounds.set(mBoundsAfterRotation);
464         mBoundsAfterRotation.setEmpty();
465     }
466
467     /**
468      * Some dock sides are not allowed by the policy. This method queries the policy and moves
469      * the docked stack around if needed.
470      *
471      * @param inOutBounds the bounds of the docked stack to adjust
472      */
473     private void repositionDockedStackAfterRotation(Rect inOutBounds) {
474         int dockSide = getDockSide(inOutBounds);
475         if (mService.mPolicy.isDockSideAllowed(dockSide)) {
476             return;
477         }
478         mDisplayContent.getLogicalDisplayRect(mTmpRect);
479         dockSide = DockedDividerUtils.invertDockSide(dockSide);
480         switch (dockSide) {
481             case DOCKED_LEFT:
482                 int movement = inOutBounds.left;
483                 inOutBounds.left -= movement;
484                 inOutBounds.right -= movement;
485                 break;
486             case DOCKED_RIGHT:
487                 movement = mTmpRect.right - inOutBounds.right;
488                 inOutBounds.left += movement;
489                 inOutBounds.right += movement;
490                 break;
491             case DOCKED_TOP:
492                 movement = inOutBounds.top;
493                 inOutBounds.top -= movement;
494                 inOutBounds.bottom -= movement;
495                 break;
496             case DOCKED_BOTTOM:
497                 movement = mTmpRect.bottom - inOutBounds.bottom;
498                 inOutBounds.top += movement;
499                 inOutBounds.bottom += movement;
500                 break;
501         }
502     }
503
504     /**
505      * Snaps the bounds after rotation to the closest snap target for the docked stack.
506      */
507     private void snapDockedStackAfterRotation(Rect outBounds) {
508
509         // Calculate the current position.
510         final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
511         final int dividerSize = mDisplayContent.getDockedDividerController().getContentWidth();
512         final int dockSide = getDockSide(outBounds);
513         final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
514                 dockSide, dividerSize);
515         final int displayWidth = mDisplayContent.getDisplayInfo().logicalWidth;
516         final int displayHeight = mDisplayContent.getDisplayInfo().logicalHeight;
517
518         // Snap the position to a target.
519         final int rotation = displayInfo.rotation;
520         final int orientation = mDisplayContent.getConfiguration().orientation;
521         mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
522         final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
523                 mService.mContext.getResources(), displayWidth, displayHeight,
524                 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
525                 isMinimizedDockAndHomeStackResizable());
526         final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
527
528         // Recalculate the bounds based on the position of the target.
529         DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
530                 outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
531                 dividerSize);
532     }
533
534     // TODO: Checkout the call points of this method and the ones below to see how they can fit in WC.
535     void addTask(Task task, int position) {
536         addTask(task, position, task.showForAllUsers(), true /* moveParents */);
537     }
538
539     /**
540      * Put a Task in this stack. Used for adding only.
541      * When task is added to top of the stack, the entire branch of the hierarchy (including stack
542      * and display) will be brought to top.
543      * @param task The task to add.
544      * @param position Target position to add the task to.
545      * @param showForAllUsers Whether to show the task regardless of the current user.
546      */
547     void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) {
548         final TaskStack currentStack = task.mStack;
549         // TODO: We pass stack to task's constructor, but we still need to call this method.
550         // This doesn't make sense, mStack will already be set equal to "this" at this point.
551         if (currentStack != null && currentStack.mStackId != mStackId) {
552             throw new IllegalStateException("Trying to add taskId=" + task.mTaskId
553                     + " to stackId=" + mStackId
554                     + ", but it is already attached to stackId=" + task.mStack.mStackId);
555         }
556
557         // Add child task.
558         task.mStack = this;
559         addChild(task, null);
560
561         // Move child to a proper position, as some restriction for position might apply.
562         positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
563     }
564
565     @Override
566     void positionChildAt(int position, Task child, boolean includingParents) {
567         positionChildAt(position, child, includingParents, child.showForAllUsers());
568     }
569
570     /**
571      * Overridden version of {@link TaskStack#positionChildAt(int, Task, boolean)}. Used in
572      * {@link TaskStack#addTask(Task, int, boolean showForAllUsers, boolean)}, as it can receive
573      * showForAllUsers param from {@link AppWindowToken} instead of {@link Task#showForAllUsers()}.
574      */
575     private void positionChildAt(int position, Task child, boolean includingParents,
576             boolean showForAllUsers) {
577         final int targetPosition = findPositionForTask(child, position, showForAllUsers,
578                 false /* addingNew */);
579         super.positionChildAt(targetPosition, child, includingParents);
580
581         // Log positioning.
582         if (DEBUG_TASK_MOVEMENT)
583             Slog.d(TAG_WM, "positionTask: task=" + this + " position=" + position);
584
585         final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0;
586         EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition);
587     }
588
589     // TODO: We should really have users as a window container in the hierarchy so that we don't
590     // have to do complicated things like we are doing in this method.
591     private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers,
592             boolean addingNew) {
593         final boolean canShowTask =
594                 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId);
595
596         final int stackSize = mChildren.size();
597         int minPosition = 0;
598         int maxPosition = addingNew ? stackSize : stackSize - 1;
599
600         if (canShowTask) {
601             minPosition = computeMinPosition(minPosition, stackSize);
602         } else {
603             maxPosition = computeMaxPosition(maxPosition);
604         }
605         // Reset position based on minimum/maximum possible positions.
606         return Math.min(Math.max(targetPosition, minPosition), maxPosition);
607     }
608
609     /** Calculate the minimum possible position for a task that can be shown to the user.
610      *  The minimum position will be above all other tasks that can't be shown.
611      *  @param minPosition The minimum position the caller is suggesting.
612      *                  We will start adjusting up from here.
613      *  @param size The size of the current task list.
614      */
615     private int computeMinPosition(int minPosition, int size) {
616         while (minPosition < size) {
617             final Task tmpTask = mChildren.get(minPosition);
618             final boolean canShowTmpTask =
619                     tmpTask.showForAllUsers()
620                             || mService.isCurrentProfileLocked(tmpTask.mUserId);
621             if (canShowTmpTask) {
622                 break;
623             }
624             minPosition++;
625         }
626         return minPosition;
627     }
628
629     /** Calculate the maximum possible position for a task that can't be shown to the user.
630      *  The maximum position will be below all other tasks that can be shown.
631      *  @param maxPosition The maximum position the caller is suggesting.
632      *                  We will start adjusting down from here.
633      */
634     private int computeMaxPosition(int maxPosition) {
635         while (maxPosition > 0) {
636             final Task tmpTask = mChildren.get(maxPosition);
637             final boolean canShowTmpTask =
638                     tmpTask.showForAllUsers()
639                             || mService.isCurrentProfileLocked(tmpTask.mUserId);
640             if (!canShowTmpTask) {
641                 break;
642             }
643             maxPosition--;
644         }
645         return maxPosition;
646     }
647
648     /**
649      * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the
650      * back.
651      * @param task The Task to delete.
652      */
653     @Override
654     void removeChild(Task task) {
655         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + task);
656
657         super.removeChild(task);
658         task.mStack = null;
659
660         if (mDisplayContent != null) {
661             if (mChildren.isEmpty()) {
662                 getParent().positionChildAt(POSITION_BOTTOM, this, false /* includingParents */);
663             }
664             mDisplayContent.setLayoutNeeded();
665         }
666         for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
667             final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
668             if (wtoken.getTask() == task) {
669                 wtoken.mIsExiting = false;
670                 mExitingAppTokens.remove(appNdx);
671             }
672         }
673     }
674
675     void onDisplayChanged(DisplayContent dc) {
676         if (mDisplayContent != null) {
677             throw new IllegalStateException("onDisplayChanged: Already attached");
678         }
679
680         mDisplayContent = dc;
681         mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(),
682                 "animation background stackId=" + mStackId);
683
684         Rect bounds = null;
685         final TaskStack dockedStack = dc.getDockedStackIgnoringVisibility();
686         if (mStackId == DOCKED_STACK_ID
687                 || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId)
688                         && !dockedStack.fillsParent())) {
689             // The existence of a docked stack affects the size of other static stack created since
690             // the docked stack occupies a dedicated region on screen, but only if the dock stack is
691             // not fullscreen. If it's fullscreen, it means that we are in the transition of
692             // dismissing it, so we must not resize this stack.
693             bounds = new Rect();
694             dc.getLogicalDisplayRect(mTmpRect);
695             mTmpRect2.setEmpty();
696             if (dockedStack != null) {
697                 dockedStack.getRawBounds(mTmpRect2);
698             }
699             final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
700                     == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
701             getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2,
702                     mDisplayContent.mDividerControllerLocked.getContentWidth(),
703                     dockedOnTopOrLeft);
704         } else if (mStackId == PINNED_STACK_ID) {
705             // Update the bounds based on any changes to the display info
706             getAnimationOrCurrentBounds(mTmpRect2);
707             boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
708                     mTmpRect2, mTmpRect3);
709             if (updated) {
710                 bounds = new Rect(mTmpRect3);
711             }
712         }
713
714         updateDisplayInfo(bounds);
715         super.onDisplayChanged(dc);
716     }
717
718     /**
719      * Determines the stack and task bounds of the other stack when in docked mode. The current task
720      * bounds is passed in but depending on the stack, the task and stack must match. Only in
721      * minimized mode with resizable launcher, the other stack ignores calculating the stack bounds
722      * and uses the task bounds passed in as the stack and task bounds, otherwise the stack bounds
723      * is calculated and is also used for its task bounds.
724      * If any of the out bounds are empty, it represents default bounds
725      *
726      * @param currentTempTaskBounds the current task bounds of the other stack
727      * @param outStackBounds the calculated stack bounds of the other stack
728      * @param outTempTaskBounds the calculated task bounds of the other stack
729      * @param ignoreVisibility ignore visibility in getting the stack bounds
730      */
731     void getStackDockedModeBoundsLocked(Rect currentTempTaskBounds, Rect outStackBounds,
732             Rect outTempTaskBounds, boolean ignoreVisibility) {
733         outTempTaskBounds.setEmpty();
734
735         // When the home stack is resizable, should always have the same stack and task bounds
736         if (mStackId == HOME_STACK_ID) {
737             if (findHomeTask().isResizeable()) {
738                 // Calculate the home stack bounds when in docked mode and the home stack is
739                 // resizeable.
740                 getDisplayContent().mDividerControllerLocked
741                         .getHomeStackBoundsInDockedMode(outStackBounds);
742             } else {
743                 // Home stack isn't resizeable, so don't specify stack bounds.
744                 outStackBounds.setEmpty();
745             }
746
747             outTempTaskBounds.set(outStackBounds);
748             return;
749         }
750
751         // When minimized state, the stack bounds for all non-home and docked stack bounds should
752         // match the passed task bounds
753         if (isMinimizedDockAndHomeStackResizable() && currentTempTaskBounds != null) {
754             outStackBounds.set(currentTempTaskBounds);
755             return;
756         }
757
758         if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
759                 || mDisplayContent == null) {
760             outStackBounds.set(mBounds);
761             return;
762         }
763
764         final TaskStack dockedStack = mDisplayContent.getDockedStackIgnoringVisibility();
765         if (dockedStack == null) {
766             // Not sure why you are calling this method when there is no docked stack...
767             throw new IllegalStateException(
768                     "Calling getStackDockedModeBoundsLocked() when there is no docked stack.");
769         }
770         if (!ignoreVisibility && !dockedStack.isVisible()) {
771             // The docked stack is being dismissed, but we caught before it finished being
772             // dismissed. In that case we want to treat it as if it is not occupying any space and
773             // let others occupy the whole display.
774             mDisplayContent.getLogicalDisplayRect(outStackBounds);
775             return;
776         }
777
778         final int dockedSide = dockedStack.getDockSide();
779         if (dockedSide == DOCKED_INVALID) {
780             // Not sure how you got here...Only thing we can do is return current bounds.
781             Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack);
782             outStackBounds.set(mBounds);
783             return;
784         }
785
786         mDisplayContent.getLogicalDisplayRect(mTmpRect);
787         dockedStack.getRawBounds(mTmpRect2);
788         final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
789         getStackDockedModeBounds(mTmpRect, outStackBounds, mStackId, mTmpRect2,
790                 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
791
792     }
793
794     /**
795      * Outputs the bounds a stack should be given the presence of a docked stack on the display.
796      * @param displayRect The bounds of the display the docked stack is on.
797      * @param outBounds Output bounds that should be used for the stack.
798      * @param stackId Id of stack we are calculating the bounds for.
799      * @param dockedBounds Bounds of the docked stack.
800      * @param dockDividerWidth We need to know the width of the divider make to the output bounds
801      *                         close to the side of the dock.
802      * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
803      */
804     private void getStackDockedModeBounds(
805             Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth,
806             boolean dockOnTopOrLeft) {
807         final boolean dockedStack = stackId == DOCKED_STACK_ID;
808         final boolean splitHorizontally = displayRect.width() > displayRect.height();
809
810         outBounds.set(displayRect);
811         if (dockedStack) {
812             if (mService.mDockedStackCreateBounds != null) {
813                 outBounds.set(mService.mDockedStackCreateBounds);
814                 return;
815             }
816
817             // The initial bounds of the docked stack when it is created about half the screen space
818             // and its bounds can be adjusted after that. The bounds of all other stacks are
819             // adjusted to occupy whatever screen space the docked stack isn't occupying.
820             final DisplayInfo di = mDisplayContent.getDisplayInfo();
821             mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
822                     mTmpRect2);
823             final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
824                     di.logicalWidth,
825                     di.logicalHeight,
826                     dockDividerWidth,
827                     mDisplayContent.getConfiguration().orientation == ORIENTATION_PORTRAIT,
828                     mTmpRect2).getMiddleTarget().position;
829
830             if (dockOnTopOrLeft) {
831                 if (splitHorizontally) {
832                     outBounds.right = position;
833                 } else {
834                     outBounds.bottom = position;
835                 }
836             } else {
837                 if (splitHorizontally) {
838                     outBounds.left = position + dockDividerWidth;
839                 } else {
840                     outBounds.top = position + dockDividerWidth;
841                 }
842             }
843             return;
844         }
845
846         // Other stacks occupy whatever space is left by the docked stack.
847         if (!dockOnTopOrLeft) {
848             if (splitHorizontally) {
849                 outBounds.right = dockedBounds.left - dockDividerWidth;
850             } else {
851                 outBounds.bottom = dockedBounds.top - dockDividerWidth;
852             }
853         } else {
854             if (splitHorizontally) {
855                 outBounds.left = dockedBounds.right + dockDividerWidth;
856             } else {
857                 outBounds.top = dockedBounds.bottom + dockDividerWidth;
858             }
859         }
860         DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
861     }
862
863     void resetDockedStackToMiddle() {
864         if (mStackId != DOCKED_STACK_ID) {
865             throw new IllegalStateException("Not a docked stack=" + this);
866         }
867
868         mService.mDockedStackCreateBounds = null;
869
870         final Rect bounds = new Rect();
871         final Rect tempBounds = new Rect();
872         getStackDockedModeBoundsLocked(null /* currentTempTaskBounds */, bounds, tempBounds,
873                 true /*ignoreVisibility*/);
874         getController().requestResize(bounds);
875     }
876
877     @Override
878     StackWindowController getController() {
879         return (StackWindowController) super.getController();
880     }
881
882     @Override
883     void removeIfPossible() {
884         if (isAnimating()) {
885             mDeferRemoval = true;
886             return;
887         }
888         removeImmediately();
889     }
890
891     @Override
892     void removeImmediately() {
893         super.removeImmediately();
894
895         onRemovedFromDisplay();
896     }
897
898     /**
899      * Removes the stack it from its current parent, so it can be either destroyed completely or
900      * re-parented.
901      */
902     void onRemovedFromDisplay() {
903         mDisplayContent.mDimLayerController.removeDimLayerUser(this);
904         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
905
906         if (mAnimationBackgroundSurface != null) {
907             mAnimationBackgroundSurface.destroySurface();
908             mAnimationBackgroundSurface = null;
909         }
910
911         if (mStackId == DOCKED_STACK_ID) {
912             mDisplayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(false);
913         }
914
915         mDisplayContent = null;
916         mService.mWindowPlacerLocked.requestTraversal();
917     }
918
919     void resetAnimationBackgroundAnimator() {
920         mAnimationBackgroundAnimator = null;
921         mAnimationBackgroundSurface.hide();
922     }
923
924     void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
925         int animLayer = winAnimator.mAnimLayer;
926         if (mAnimationBackgroundAnimator == null
927                 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) {
928             mAnimationBackgroundAnimator = winAnimator;
929             animLayer = mDisplayContent.getLayerForAnimationBackground(winAnimator);
930             mAnimationBackgroundSurface.show(animLayer - LAYER_OFFSET_DIM,
931                     ((color >> 24) & 0xff) / 255f, 0);
932         }
933     }
934
935     // TODO: Should each user have there own stacks?
936     @Override
937     void switchUser() {
938         super.switchUser();
939         int top = mChildren.size();
940         for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
941             Task task = mChildren.get(taskNdx);
942             if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
943                 mChildren.remove(taskNdx);
944                 mChildren.add(task);
945                 --top;
946             }
947         }
948     }
949
950     /**
951      * Adjusts the stack bounds if the IME is visible.
952      *
953      * @param imeWin The IME window.
954      */
955     void setAdjustedForIme(WindowState imeWin, boolean forceUpdate) {
956         mImeWin = imeWin;
957         mImeGoingAway = false;
958         if (!mAdjustedForIme || forceUpdate) {
959             mAdjustedForIme = true;
960             mAdjustImeAmount = 0f;
961             mAdjustDividerAmount = 0f;
962             updateAdjustForIme(0f, 0f, true /* force */);
963         }
964     }
965
966     boolean isAdjustedForIme() {
967         return mAdjustedForIme;
968     }
969
970     boolean isAnimatingForIme() {
971         return mImeWin != null && mImeWin.isAnimatingLw();
972     }
973
974     /**
975      * Update the stack's bounds (crop or position) according to the IME window's
976      * current position. When IME window is animated, the bottom stack is animated
977      * together to track the IME window's current position, and the top stack is
978      * cropped as necessary.
979      *
980      * @return true if a traversal should be performed after the adjustment.
981      */
982     boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
983         if (adjustAmount != mAdjustImeAmount
984                 || adjustDividerAmount != mAdjustDividerAmount || force) {
985             mAdjustImeAmount = adjustAmount;
986             mAdjustDividerAmount = adjustDividerAmount;
987             updateAdjustedBounds();
988             return isVisible();
989         } else {
990             return false;
991         }
992     }
993
994     /**
995      * Resets the adjustment after it got adjusted for the IME.
996      * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about
997      *                        animations; otherwise, set flag and animates the window away together
998      *                        with IME window.
999      */
1000     void resetAdjustedForIme(boolean adjustBoundsNow) {
1001         if (adjustBoundsNow) {
1002             mImeWin = null;
1003             mAdjustedForIme = false;
1004             mImeGoingAway = false;
1005             mAdjustImeAmount = 0f;
1006             mAdjustDividerAmount = 0f;
1007             updateAdjustedBounds();
1008             mService.setResizeDimLayer(false, mStackId, 1.0f);
1009         } else {
1010             mImeGoingAway |= mAdjustedForIme;
1011         }
1012     }
1013
1014     /**
1015      * Sets the amount how much we currently minimize our stack.
1016      *
1017      * @param minimizeAmount The amount, between 0 and 1.
1018      * @return Whether the amount has changed and a layout is needed.
1019      */
1020     boolean setAdjustedForMinimizedDock(float minimizeAmount) {
1021         if (minimizeAmount != mMinimizeAmount) {
1022             mMinimizeAmount = minimizeAmount;
1023             updateAdjustedBounds();
1024             return isVisible();
1025         } else {
1026             return false;
1027         }
1028     }
1029
1030     boolean shouldIgnoreInput() {
1031         return isAdjustedForMinimizedDockedStack() || mStackId == DOCKED_STACK_ID &&
1032                 isMinimizedDockAndHomeStackResizable();
1033     }
1034
1035     /**
1036      * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows
1037      * to the list of to be drawn windows the service is waiting for.
1038      */
1039     void beginImeAdjustAnimation() {
1040         for (int j = mChildren.size() - 1; j >= 0; j--) {
1041             final Task task = mChildren.get(j);
1042             if (task.hasContentToDisplay()) {
1043                 task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
1044                 task.setWaitingForDrawnIfResizingChanged();
1045             }
1046         }
1047     }
1048
1049     /**
1050      * Resets the resizing state of all windows.
1051      */
1052     void endImeAdjustAnimation() {
1053         for (int j = mChildren.size() - 1; j >= 0; j--) {
1054             mChildren.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
1055         }
1056     }
1057
1058     int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
1059         return displayContentRect.top + (int)
1060                 ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN);
1061     }
1062
1063     private boolean adjustForIME(final WindowState imeWin) {
1064         final int dockedSide = getDockSide();
1065         final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
1066         if (imeWin == null || !dockedTopOrBottom) {
1067             return false;
1068         }
1069
1070         final Rect displayContentRect = mTmpRect;
1071         final Rect contentBounds = mTmpRect2;
1072
1073         // Calculate the content bounds excluding the area occupied by IME
1074         getDisplayContent().getContentRect(displayContentRect);
1075         contentBounds.set(displayContentRect);
1076         int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
1077
1078         imeTop += imeWin.getGivenContentInsetsLw().top;
1079         if (contentBounds.bottom > imeTop) {
1080             contentBounds.bottom = imeTop;
1081         }
1082
1083         final int yOffset = displayContentRect.bottom - contentBounds.bottom;
1084
1085         final int dividerWidth =
1086                 getDisplayContent().mDividerControllerLocked.getContentWidth();
1087         final int dividerWidthInactive =
1088                 getDisplayContent().mDividerControllerLocked.getContentWidthInactive();
1089
1090         if (dockedSide == DOCKED_TOP) {
1091             // If this stack is docked on top, we make it smaller so the bottom stack is not
1092             // occluded by IME. We shift its bottom up by the height of the IME, but
1093             // leaves at least 30% of the top stack visible.
1094             final int minTopStackBottom =
1095                     getMinTopStackBottom(displayContentRect, mBounds.bottom);
1096             final int bottom = Math.max(
1097                     mBounds.bottom - yOffset + dividerWidth - dividerWidthInactive,
1098                     minTopStackBottom);
1099             mTmpAdjustedBounds.set(mBounds);
1100             mTmpAdjustedBounds.bottom =
1101                     (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom);
1102             mFullyAdjustedImeBounds.set(mBounds);
1103         } else {
1104             // When the stack is on bottom and has no focus, it's only adjusted for divider width.
1105             final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
1106
1107             // When the stack is on bottom and has focus, it needs to be moved up so as to
1108             // not occluded by IME, and at the same time adjusted for divider width.
1109             // We try to move it up by the height of the IME window, but only to the extent
1110             // that leaves at least 30% of the top stack visible.
1111             // 'top' is where the top of bottom stack will move to in this case.
1112             final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive;
1113             final int minTopStackBottom =
1114                     getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
1115             final int top = Math.max(
1116                     mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
1117
1118             mTmpAdjustedBounds.set(mBounds);
1119             // Account for the adjustment for IME and divider width separately.
1120             // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
1121             // and dividerWidthDelta is due to divider width change only.
1122             mTmpAdjustedBounds.top = mBounds.top +
1123                     (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) +
1124                             mAdjustDividerAmount * dividerWidthDelta);
1125             mFullyAdjustedImeBounds.set(mBounds);
1126             mFullyAdjustedImeBounds.top = top;
1127             mFullyAdjustedImeBounds.bottom = top + mBounds.height();
1128         }
1129         return true;
1130     }
1131
1132     private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
1133         final int dockSide = getDockSide();
1134         if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
1135             return false;
1136         }
1137
1138         if (dockSide == DOCKED_TOP) {
1139             mService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
1140             int topInset = mTmpRect.top;
1141             mTmpAdjustedBounds.set(mBounds);
1142             mTmpAdjustedBounds.bottom =
1143                     (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
1144         } else if (dockSide == DOCKED_LEFT) {
1145             mTmpAdjustedBounds.set(mBounds);
1146             final int width = mBounds.width();
1147             mTmpAdjustedBounds.right =
1148                     (int) (minimizeAmount * mDockedStackMinimizeThickness
1149                             + (1 - minimizeAmount) * mBounds.right);
1150             mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
1151         } else if (dockSide == DOCKED_RIGHT) {
1152             mTmpAdjustedBounds.set(mBounds);
1153             mTmpAdjustedBounds.left =
1154                     (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness)
1155                             + (1 - minimizeAmount) * mBounds.left);
1156         }
1157         return true;
1158     }
1159
1160     private boolean isMinimizedDockAndHomeStackResizable() {
1161         return mDisplayContent.mDividerControllerLocked.isMinimizedDock()
1162                 && mDisplayContent.mDividerControllerLocked.isHomeStackResizable();
1163     }
1164
1165     /**
1166      * @return the distance in pixels how much the stack gets minimized from it's original size
1167      */
1168     int getMinimizeDistance() {
1169         final int dockSide = getDockSide();
1170         if (dockSide == DOCKED_INVALID) {
1171             return 0;
1172         }
1173
1174         if (dockSide == DOCKED_TOP) {
1175             mService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
1176             int topInset = mTmpRect.top;
1177             return mBounds.bottom - topInset;
1178         } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
1179             return mBounds.width() - mDockedStackMinimizeThickness;
1180         } else {
1181             return 0;
1182         }
1183     }
1184
1185     /**
1186      * Updates the adjustment depending on it's current state.
1187      */
1188     private void updateAdjustedBounds() {
1189         boolean adjust = false;
1190         if (mMinimizeAmount != 0f) {
1191             adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
1192         } else if (mAdjustedForIme) {
1193             adjust = adjustForIME(mImeWin);
1194         }
1195         if (!adjust) {
1196             mTmpAdjustedBounds.setEmpty();
1197         }
1198         setAdjustedBounds(mTmpAdjustedBounds);
1199
1200         final boolean isImeTarget = (mService.getImeFocusStackLocked() == this);
1201         if (mAdjustedForIme && adjust && !isImeTarget) {
1202             final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
1203                     * IME_ADJUST_DIM_AMOUNT;
1204             mService.setResizeDimLayer(true, mStackId, alpha);
1205         }
1206     }
1207
1208     void applyAdjustForImeIfNeeded(Task task) {
1209         if (mMinimizeAmount != 0f || !mAdjustedForIme || mAdjustedBounds.isEmpty()) {
1210             return;
1211         }
1212
1213         final Rect insetBounds = mImeGoingAway ? mBounds : mFullyAdjustedImeBounds;
1214         task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP);
1215         mDisplayContent.setLayoutNeeded();
1216     }
1217
1218     boolean isAdjustedForMinimizedDockedStack() {
1219         return mMinimizeAmount != 0f;
1220     }
1221
1222     public void dump(String prefix, PrintWriter pw) {
1223         pw.println(prefix + "mStackId=" + mStackId);
1224         pw.println(prefix + "mDeferRemoval=" + mDeferRemoval);
1225         pw.println(prefix + "mFillsParent=" + mFillsParent);
1226         pw.println(prefix + "mBounds=" + mBounds.toShortString());
1227         if (mMinimizeAmount != 0f) {
1228             pw.println(prefix + "mMinimizeAmount=" + mMinimizeAmount);
1229         }
1230         if (mAdjustedForIme) {
1231             pw.println(prefix + "mAdjustedForIme=true");
1232             pw.println(prefix + "mAdjustImeAmount=" + mAdjustImeAmount);
1233             pw.println(prefix + "mAdjustDividerAmount=" + mAdjustDividerAmount);
1234         }
1235         if (!mAdjustedBounds.isEmpty()) {
1236             pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString());
1237         }
1238         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
1239             mChildren.get(taskNdx).dump(prefix + "  ", pw);
1240         }
1241         if (mAnimationBackgroundSurface.isDimming()) {
1242             pw.println(prefix + "mWindowAnimationBackgroundSurface:");
1243             mAnimationBackgroundSurface.printTo(prefix + "  ", pw);
1244         }
1245         if (!mExitingAppTokens.isEmpty()) {
1246             pw.println();
1247             pw.println("  Exiting application tokens:");
1248             for (int i = mExitingAppTokens.size() - 1; i >= 0; i--) {
1249                 WindowToken token = mExitingAppTokens.get(i);
1250                 pw.print("  Exiting App #"); pw.print(i);
1251                 pw.print(' '); pw.print(token);
1252                 pw.println(':');
1253                 token.dump(pw, "    ");
1254             }
1255         }
1256     }
1257
1258     /** Fullscreen status of the stack without adjusting for other factors in the system like
1259      * visibility of docked stack.
1260      * Most callers should be using {@link #fillsParent} as it take into consideration other
1261      * system factors. */
1262     boolean getRawFullscreen() {
1263         return mFillsParent;
1264     }
1265
1266     @Override
1267     public boolean dimFullscreen() {
1268         return StackId.isHomeOrRecentsStack(mStackId) || fillsParent();
1269     }
1270
1271     @Override
1272     boolean fillsParent() {
1273         if (useCurrentBounds()) {
1274             return mFillsParent;
1275         }
1276         // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
1277         // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
1278         // system.
1279         return true;
1280     }
1281
1282     @Override
1283     public DisplayInfo getDisplayInfo() {
1284         return mDisplayContent.getDisplayInfo();
1285     }
1286
1287     @Override
1288     public boolean isAttachedToDisplay() {
1289         return mDisplayContent != null;
1290     }
1291
1292     @Override
1293     public String toString() {
1294         return "{stackId=" + mStackId + " tasks=" + mChildren + "}";
1295     }
1296
1297     String getName() {
1298         return toShortString();
1299     }
1300
1301     @Override
1302     public String toShortString() {
1303         return "Stack=" + mStackId;
1304     }
1305
1306     /**
1307      * For docked workspace (or workspace that's side-by-side to the docked), provides
1308      * information which side of the screen was the dock anchored.
1309      */
1310     int getDockSide() {
1311         return getDockSide(mBounds);
1312     }
1313
1314     int getDockSide(Rect bounds) {
1315         if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) {
1316             return DOCKED_INVALID;
1317         }
1318         if (mDisplayContent == null) {
1319             return DOCKED_INVALID;
1320         }
1321         mDisplayContent.getLogicalDisplayRect(mTmpRect);
1322         final int orientation = mDisplayContent.getConfiguration().orientation;
1323         return getDockSideUnchecked(bounds, mTmpRect, orientation);
1324     }
1325
1326     static int getDockSideUnchecked(Rect bounds, Rect displayRect, int orientation) {
1327         if (orientation == Configuration.ORIENTATION_PORTRAIT) {
1328             // Portrait mode, docked either at the top or the bottom.
1329             if (bounds.top - displayRect.top <= displayRect.bottom - bounds.bottom) {
1330                 return DOCKED_TOP;
1331             } else {
1332                 return DOCKED_BOTTOM;
1333             }
1334         } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
1335             // Landscape mode, docked either on the left or on the right.
1336             if (bounds.left - displayRect.left <= displayRect.right - bounds.right) {
1337                 return DOCKED_LEFT;
1338             } else {
1339                 return DOCKED_RIGHT;
1340             }
1341         } else {
1342             return DOCKED_INVALID;
1343         }
1344     }
1345
1346     boolean hasTaskForUser(int userId) {
1347         for (int i = mChildren.size() - 1; i >= 0; i--) {
1348             final Task task = mChildren.get(i);
1349             if (task.mUserId == userId) {
1350                 return true;
1351             }
1352         }
1353         return false;
1354     }
1355
1356     int taskIdFromPoint(int x, int y) {
1357         getBounds(mTmpRect);
1358         if (!mTmpRect.contains(x, y) || isAdjustedForMinimizedDockedStack()) {
1359             return -1;
1360         }
1361
1362         for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
1363             final Task task = mChildren.get(taskNdx);
1364             final WindowState win = task.getTopVisibleAppMainWindow();
1365             if (win == null) {
1366                 continue;
1367             }
1368             // We need to use the task's dim bounds (which is derived from the visible bounds of its
1369             // apps windows) for any touch-related tests. Can't use the task's original bounds
1370             // because it might be adjusted to fit the content frame. For example, the presence of
1371             // the IME adjusting the windows frames when the app window is the IME target.
1372             task.getDimBounds(mTmpRect);
1373             if (mTmpRect.contains(x, y)) {
1374                 return task.mTaskId;
1375             }
1376         }
1377
1378         return -1;
1379     }
1380
1381     void findTaskForResizePoint(int x, int y, int delta,
1382             DisplayContent.TaskForResizePointSearchResult results) {
1383         if (!StackId.isTaskResizeAllowed(mStackId)) {
1384             results.searchDone = true;
1385             return;
1386         }
1387
1388         for (int i = mChildren.size() - 1; i >= 0; --i) {
1389             final Task task = mChildren.get(i);
1390             if (task.isFullscreen()) {
1391                 results.searchDone = true;
1392                 return;
1393             }
1394
1395             // We need to use the task's dim bounds (which is derived from the visible bounds of
1396             // its apps windows) for any touch-related tests. Can't use the task's original
1397             // bounds because it might be adjusted to fit the content frame. One example is when
1398             // the task is put to top-left quadrant, the actual visible area would not start at
1399             // (0,0) after it's adjusted for the status bar.
1400             task.getDimBounds(mTmpRect);
1401             mTmpRect.inset(-delta, -delta);
1402             if (mTmpRect.contains(x, y)) {
1403                 mTmpRect.inset(delta, delta);
1404
1405                 results.searchDone = true;
1406
1407                 if (!mTmpRect.contains(x, y)) {
1408                     results.taskForResize = task;
1409                     return;
1410                 }
1411                 // User touched inside the task. No need to look further,
1412                 // focus transfer will be handled in ACTION_UP.
1413                 return;
1414             }
1415         }
1416     }
1417
1418     void setTouchExcludeRegion(Task focusedTask, int delta, Region touchExcludeRegion,
1419             Rect contentRect, Rect postExclude) {
1420         for (int i = mChildren.size() - 1; i >= 0; --i) {
1421             final Task task = mChildren.get(i);
1422             AppWindowToken token = task.getTopVisibleAppToken();
1423             if (token == null || !token.hasContentToDisplay()) {
1424                 continue;
1425             }
1426
1427             /**
1428              * Exclusion region is the region that TapDetector doesn't care about.
1429              * Here we want to remove all non-focused tasks from the exclusion region.
1430              * We also remove the outside touch area for resizing for all freeform
1431              * tasks (including the focused).
1432              *
1433              * We save the focused task region once we find it, and add it back at the end.
1434              *
1435              * If the task is home stack and it is resizable in the minimized state, we want to
1436              * exclude the docked stack from touch so we need the entire screen area and not just a
1437              * small portion which the home stack currently is resized to.
1438              */
1439
1440             if (task.isHomeTask() && isMinimizedDockAndHomeStackResizable()) {
1441                 mDisplayContent.getLogicalDisplayRect(mTmpRect);
1442             } else {
1443                 task.getDimBounds(mTmpRect);
1444             }
1445
1446             if (task == focusedTask) {
1447                 // Add the focused task rect back into the exclude region once we are done
1448                 // processing stacks.
1449                 postExclude.set(mTmpRect);
1450             }
1451
1452             final boolean isFreeformed = task.inFreeformWorkspace();
1453             if (task != focusedTask || isFreeformed) {
1454                 if (isFreeformed) {
1455                     // If the task is freeformed, enlarge the area to account for outside
1456                     // touch area for resize.
1457                     mTmpRect.inset(-delta, -delta);
1458                     // Intersect with display content rect. If we have system decor (status bar/
1459                     // navigation bar), we want to exclude that from the tap detection.
1460                     // Otherwise, if the app is partially placed under some system button (eg.
1461                     // Recents, Home), pressing that button would cause a full series of
1462                     // unwanted transfer focus/resume/pause, before we could go home.
1463                     mTmpRect.intersect(contentRect);
1464                 }
1465                 touchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
1466             }
1467         }
1468     }
1469
1470     public boolean setPinnedStackSize(Rect stackBounds, Rect tempTaskBounds) {
1471         // Hold the lock since this is called from the BoundsAnimator running on the UiThread
1472         synchronized (mService.mWindowMap) {
1473             if (mCancelCurrentBoundsAnimation) {
1474                 return false;
1475             }
1476         }
1477
1478         try {
1479             mService.mActivityManager.resizePinnedStack(stackBounds, tempTaskBounds);
1480         } catch (RemoteException e) {
1481             // I don't believe you.
1482         }
1483         return true;
1484     }
1485
1486     void onAllWindowsDrawn() {
1487         if (!mBoundsAnimating) {
1488             return;
1489         }
1490
1491         mService.mBoundsAnimationController.onAllWindowsDrawn();
1492     }
1493
1494     @Override  // AnimatesBounds
1495     public void onAnimationStart(boolean schedulePipModeChangedCallback) {
1496         // Hold the lock since this is called from the BoundsAnimator running on the UiThread
1497         synchronized (mService.mWindowMap) {
1498             mBoundsAnimatingRequested = false;
1499             mBoundsAnimating = true;
1500             mCancelCurrentBoundsAnimation = false;
1501
1502             // If we are changing UI mode, as in the PiP to fullscreen
1503             // transition, then we need to wait for the window to draw.
1504             if (schedulePipModeChangedCallback) {
1505                 forAllWindows((w) -> { w.mWinAnimator.resetDrawState(); },
1506                         false /* traverseTopToBottom */);
1507             }
1508         }
1509
1510         if (mStackId == PINNED_STACK_ID) {
1511             try {
1512                 mService.mActivityManager.notifyPinnedStackAnimationStarted();
1513             } catch (RemoteException e) {
1514                 // I don't believe you...
1515             }
1516
1517             final PinnedStackWindowController controller =
1518                     (PinnedStackWindowController) getController();
1519             if (schedulePipModeChangedCallback && controller != null) {
1520                 // We need to schedule the PiP mode change after the animation down, so use the
1521                 // final bounds
1522                 controller.updatePictureInPictureModeForPinnedStackAnimation(null);
1523             }
1524         }
1525     }
1526
1527     @Override  // AnimatesBounds
1528     public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize,
1529             boolean moveToFullscreen) {
1530         // Hold the lock since this is called from the BoundsAnimator running on the UiThread
1531         synchronized (mService.mWindowMap) {
1532             mBoundsAnimating = false;
1533             mService.requestTraversal();
1534         }
1535
1536         if (mStackId == PINNED_STACK_ID) {
1537             final PinnedStackWindowController controller =
1538                     (PinnedStackWindowController) getController();
1539             if (schedulePipModeChangedCallback && controller != null) {
1540                 // We need to schedule the PiP mode change after the animation down, so use the
1541                 // final bounds
1542                 controller.updatePictureInPictureModeForPinnedStackAnimation(
1543                         mBoundsAnimationTarget);
1544             }
1545
1546             // Update to the final bounds if requested. This is done here instead of in the bounds
1547             // animator to allow us to coordinate this after we notify the PiP mode changed
1548             if (finalStackSize != null) {
1549                 setPinnedStackSize(finalStackSize, null);
1550             }
1551
1552             try {
1553                 mService.mActivityManager.notifyPinnedStackAnimationEnded();
1554                 if (moveToFullscreen) {
1555                     mService.mActivityManager.moveTasksToFullscreenStack(mStackId,
1556                             true /* onTop */);
1557                 }
1558             } catch (RemoteException e) {
1559                 // I don't believe you...
1560             }
1561         }
1562     }
1563
1564     /**
1565      * @return True if we are currently animating the pinned stack from fullscreen to non-fullscreen
1566      *         bounds and we have a deferred PiP mode changed callback set with the animation.
1567      */
1568     public boolean deferScheduleMultiWindowModeChanged() {
1569         if (mStackId == PINNED_STACK_ID) {
1570             return (mBoundsAnimatingRequested || mBoundsAnimating);
1571         }
1572         return false;
1573     }
1574
1575     public boolean hasMovementAnimations() {
1576         return StackId.hasMovementAnimations(mStackId);
1577     }
1578
1579     public boolean isForceScaled() {
1580         return mBoundsAnimating;
1581     }
1582
1583     public boolean isAnimatingBounds() {
1584         return mBoundsAnimating;
1585     }
1586
1587     public boolean isAnimatingBoundsToFullscreen() {
1588         return mBoundsAnimating && mBoundsAnimatingToFullscreen;
1589     }
1590
1591     public boolean pinnedStackResizeDisallowed() {
1592         if (mBoundsAnimating && mCancelCurrentBoundsAnimation) {
1593             return true;
1594         }
1595         return false;
1596     }
1597
1598     /** Returns true if a removal action is still being deferred. */
1599     boolean checkCompleteDeferredRemoval() {
1600         if (isAnimating()) {
1601             return true;
1602         }
1603         if (mDeferRemoval) {
1604             removeImmediately();
1605         }
1606
1607         return super.checkCompleteDeferredRemoval();
1608     }
1609
1610     void stepAppWindowsAnimation(long currentTime) {
1611         super.stepAppWindowsAnimation(currentTime);
1612
1613         // TODO: Why aren't we just using the loop above for this? mAppAnimator.animating isn't set
1614         // below but is set in the loop above. See if it really matters...
1615         final int exitingCount = mExitingAppTokens.size();
1616         for (int i = 0; i < exitingCount; i++) {
1617             final AppWindowAnimator appAnimator = mExitingAppTokens.get(i).mAppAnimator;
1618             appAnimator.wasAnimating = appAnimator.animating;
1619             if (appAnimator.stepAnimationLocked(currentTime)) {
1620                 mService.mAnimator.setAnimating(true);
1621                 mService.mAnimator.mAppWindowAnimating = true;
1622             } else if (appAnimator.wasAnimating) {
1623                 // stopped animating, do one more pass through the layout
1624                 appAnimator.mAppToken.setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
1625                         "exiting appToken " + appAnimator.mAppToken + " done");
1626                 if (DEBUG_ANIM) Slog.v(TAG_WM,
1627                         "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
1628             }
1629         }
1630     }
1631
1632     @Override
1633     int getOrientation() {
1634         return (StackId.canSpecifyOrientation(mStackId))
1635                 ? super.getOrientation() : SCREEN_ORIENTATION_UNSET;
1636     }
1637 }