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