2 * Copyright (C) 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.wm;
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;
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;
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;
57 import java.io.PrintWriter;
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;
65 /** Dimming amount for non-focused stack when stacks are IME-adjusted. */
66 private static final float IME_ADJUST_DIM_AMOUNT = 0.25f;
68 /** Unique identifier */
72 private final WindowManagerService mService;
74 /** The display this stack sits under. */
75 // TODO: Track parent marks like this in WindowContainer.
76 private DisplayContent mDisplayContent;
78 /** For comparison with DisplayContent bounds. */
79 private Rect mTmpRect = new Rect();
80 private Rect mTmpRect2 = new Rect();
81 private Rect mTmpRect3 = new Rect();
83 /** Content limits relative to the DisplayContent this sits in. */
84 private Rect mBounds = new Rect();
86 /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
87 private final Rect mAdjustedBounds = new Rect();
90 * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they
91 * represent the state when the animation has ended.
93 private final Rect mFullyAdjustedImeBounds = new Rect();
95 /** Whether mBounds is fullscreen */
96 private boolean mFillsParent = true;
98 // Device rotation as of the last time {@link #mBounds} was set.
99 private int mRotation;
101 /** Density as of last time {@link #mBounds} was set. */
102 private int mDensity;
104 /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
105 private DimLayer mAnimationBackgroundSurface;
107 /** The particular window with an Animation with non-zero background color. */
108 private WindowStateAnimator mAnimationBackgroundAnimator;
110 /** Application tokens that are exiting, but still on screen for animations. */
111 final AppTokenList mExitingAppTokens = new AppTokenList();
113 /** Detach this stack from its display when animation completes. */
114 // TODO: maybe tie this to WindowContainer#removeChild some how...
115 boolean mDeferRemoval;
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;
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();
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();
142 TaskStack(WindowManagerService service, int 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);
150 DisplayContent getDisplayContent() {
151 return mDisplayContent;
154 Task findHomeTask() {
155 if (mStackId != HOME_STACK_ID) {
159 for (int i = mChildren.size() - 1; i >= 0; i--) {
160 if (mChildren.get(i).isHomeTask()) {
161 return mChildren.get(i);
167 boolean hasMultipleTaskWithHomeTaskNotTop() {
168 return mChildren.size() > 1 && !mChildren.get(mChildren.size() - 1).isHomeTask();
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.
179 Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
180 SparseArray<Rect> taskTempInsetBounds) {
181 setBounds(stackBounds);
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);
193 Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
199 void prepareFreezingTaskBounds() {
200 for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
201 final Task task = mChildren.get(taskNdx);
202 task.prepareFreezingBounds();
207 * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
208 * the normal task bounds.
210 * @param bounds The adjusted bounds.
212 private void setAdjustedBounds(Rect bounds) {
213 if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) {
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) {
224 insetBounds = mBounds;
226 insetBounds = mFullyAdjustedImeBounds;
229 alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds);
230 mDisplayContent.setLayoutNeeded();
233 private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
238 final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
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);
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;
261 if (bounds == null) {
262 // Can't set to fullscreen if we don't have a display to get bounds from...
265 if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) {
269 if (mDisplayContent != null) {
270 mDisplayContent.mDimLayerController.updateDimLayer(this);
271 mAnimationBackgroundSurface.setBounds(bounds);
275 mRotation = rotation;
278 updateAdjustedBounds();
283 /** Bounds of the stack without adjusting for other factors in the system like visibility
285 * Most callers should be using {@link #getBounds} as it take into consideration other system
287 void getRawBounds(Rect out) {
291 /** Return true if the current bound can get outputted to the rest of the system as-is. */
292 private boolean useCurrentBounds() {
294 || !StackId.isResizeableByDockedStack(mStackId)
295 || mDisplayContent == null
296 || mDisplayContent.getDockedStackLocked() != null) {
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
308 if (!mAdjustedBounds.isEmpty()) {
309 out.set(mAdjustedBounds);
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
319 mDisplayContent.getLogicalDisplayRect(out);
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.
326 void setAnimationFinalBounds(Rect sourceHintBounds, Rect destBounds, boolean toFullscreen) {
327 mBoundsAnimatingRequested = true;
328 mBoundsAnimatingToFullscreen = toFullscreen;
329 if (destBounds != null) {
330 mBoundsAnimationTarget.set(destBounds);
332 mBoundsAnimationTarget.setEmpty();
334 if (sourceHintBounds != null) {
335 mBoundsAnimationSourceHintBounds.set(sourceHintBounds);
337 mBoundsAnimationSourceHintBounds.setEmpty();
342 * @return the final bounds for the bounds animation.
344 void getFinalAnimationBounds(Rect outBounds) {
345 outBounds.set(mBoundsAnimationTarget);
349 * @return the final source bounds for the bounds animation.
351 void getFinalAnimationSourceHintBounds(Rect outBounds) {
352 outBounds.set(mBoundsAnimationSourceHintBounds);
356 * @return the final animation bounds if the task stack is currently being animated, or the
357 * current stack bounds otherwise.
359 void getAnimationOrCurrentBounds(Rect outBounds) {
360 if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) {
361 getFinalAnimationBounds(outBounds);
364 getBounds(outBounds);
367 /** Bounds of the stack with other system factors taken into consideration. */
369 public void getDimBounds(Rect out) {
373 void updateDisplayInfo(Rect bounds) {
374 if (mDisplayContent == null) {
378 for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
379 mChildren.get(taskNdx).updateDisplayInfo(mDisplayContent);
381 if (bounds != null) {
384 } else if (mFillsParent) {
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);
396 // If the rotation or density didn't match, we'll update it in onConfigurationChanged.
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.
407 if (mStackId == PINNED_STACK_ID) {
408 getAnimationOrCurrentBounds(mTmpRect2);
409 boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
410 mTmpRect2, mTmpRect3);
412 mBoundsAfterRotation.set(mTmpRect3);
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;
424 final int newRotation = getDisplayInfo().rotation;
425 final int newDensity = getDisplayInfo().logicalDensityDpi;
427 if (mRotation == newRotation && mDensity == newDensity) {
428 // Nothing to do here as we already update the state in updateDisplayInfo.
433 // Update stack bounds again since rotation changed since updateDisplayInfo().
435 // Return false since we don't need the client to resize.
439 mTmpRect2.set(mBounds);
440 mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
442 case DOCKED_STACK_ID:
443 repositionDockedStackAfterRotation(mTmpRect2);
444 snapDockedStackAfterRotation(mTmpRect2);
445 final int newDockSide = getDockSide(mTmpRect2);
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,
454 mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
458 mBoundsAfterRotation.set(mTmpRect2);
462 void getBoundsForNewConfiguration(Rect outBounds) {
463 outBounds.set(mBoundsAfterRotation);
464 mBoundsAfterRotation.setEmpty();
468 * Some dock sides are not allowed by the policy. This method queries the policy and moves
469 * the docked stack around if needed.
471 * @param inOutBounds the bounds of the docked stack to adjust
473 private void repositionDockedStackAfterRotation(Rect inOutBounds) {
474 int dockSide = getDockSide(inOutBounds);
475 if (mService.mPolicy.isDockSideAllowed(dockSide)) {
478 mDisplayContent.getLogicalDisplayRect(mTmpRect);
479 dockSide = DockedDividerUtils.invertDockSide(dockSide);
482 int movement = inOutBounds.left;
483 inOutBounds.left -= movement;
484 inOutBounds.right -= movement;
487 movement = mTmpRect.right - inOutBounds.right;
488 inOutBounds.left += movement;
489 inOutBounds.right += movement;
492 movement = inOutBounds.top;
493 inOutBounds.top -= movement;
494 inOutBounds.bottom -= movement;
497 movement = mTmpRect.bottom - inOutBounds.bottom;
498 inOutBounds.top += movement;
499 inOutBounds.bottom += movement;
505 * Snaps the bounds after rotation to the closest snap target for the docked stack.
507 private void snapDockedStackAfterRotation(Rect outBounds) {
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;
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);
528 // Recalculate the bounds based on the position of the target.
529 DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
530 outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
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 */);
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.
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);
559 addChild(task, null);
561 // Move child to a proper position, as some restriction for position might apply.
562 positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
566 void positionChildAt(int position, Task child, boolean includingParents) {
567 positionChildAt(position, child, includingParents, child.showForAllUsers());
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()}.
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);
582 if (DEBUG_TASK_MOVEMENT)
583 Slog.d(TAG_WM, "positionTask: task=" + this + " position=" + position);
585 final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0;
586 EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition);
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,
593 final boolean canShowTask =
594 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId);
596 final int stackSize = mChildren.size();
598 int maxPosition = addingNew ? stackSize : stackSize - 1;
601 minPosition = computeMinPosition(minPosition, stackSize);
603 maxPosition = computeMaxPosition(maxPosition);
605 // Reset position based on minimum/maximum possible positions.
606 return Math.min(Math.max(targetPosition, minPosition), maxPosition);
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.
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) {
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.
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) {
649 * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the
651 * @param task The Task to delete.
654 void removeChild(Task task) {
655 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + task);
657 super.removeChild(task);
660 if (mDisplayContent != null) {
661 if (mChildren.isEmpty()) {
662 getParent().positionChildAt(POSITION_BOTTOM, this, false /* includingParents */);
664 mDisplayContent.setLayoutNeeded();
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);
675 void onDisplayChanged(DisplayContent dc) {
676 if (mDisplayContent != null) {
677 throw new IllegalStateException("onDisplayChanged: Already attached");
680 mDisplayContent = dc;
681 mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(),
682 "animation background stackId=" + mStackId);
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.
694 dc.getLogicalDisplayRect(mTmpRect);
695 mTmpRect2.setEmpty();
696 if (dockedStack != null) {
697 dockedStack.getRawBounds(mTmpRect2);
699 final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
700 == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
701 getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2,
702 mDisplayContent.mDividerControllerLocked.getContentWidth(),
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);
710 bounds = new Rect(mTmpRect3);
714 updateDisplayInfo(bounds);
715 super.onDisplayChanged(dc);
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
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
731 void getStackDockedModeBoundsLocked(Rect currentTempTaskBounds, Rect outStackBounds,
732 Rect outTempTaskBounds, boolean ignoreVisibility) {
733 outTempTaskBounds.setEmpty();
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
740 getDisplayContent().mDividerControllerLocked
741 .getHomeStackBoundsInDockedMode(outStackBounds);
743 // Home stack isn't resizeable, so don't specify stack bounds.
744 outStackBounds.setEmpty();
747 outTempTaskBounds.set(outStackBounds);
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);
758 if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
759 || mDisplayContent == null) {
760 outStackBounds.set(mBounds);
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.");
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);
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);
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);
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.
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();
810 outBounds.set(displayRect);
812 if (mService.mDockedStackCreateBounds != null) {
813 outBounds.set(mService.mDockedStackCreateBounds);
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,
823 final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
827 mDisplayContent.getConfiguration().orientation == ORIENTATION_PORTRAIT,
828 mTmpRect2).getMiddleTarget().position;
830 if (dockOnTopOrLeft) {
831 if (splitHorizontally) {
832 outBounds.right = position;
834 outBounds.bottom = position;
837 if (splitHorizontally) {
838 outBounds.left = position + dockDividerWidth;
840 outBounds.top = position + dockDividerWidth;
846 // Other stacks occupy whatever space is left by the docked stack.
847 if (!dockOnTopOrLeft) {
848 if (splitHorizontally) {
849 outBounds.right = dockedBounds.left - dockDividerWidth;
851 outBounds.bottom = dockedBounds.top - dockDividerWidth;
854 if (splitHorizontally) {
855 outBounds.left = dockedBounds.right + dockDividerWidth;
857 outBounds.top = dockedBounds.bottom + dockDividerWidth;
860 DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
863 void resetDockedStackToMiddle() {
864 if (mStackId != DOCKED_STACK_ID) {
865 throw new IllegalStateException("Not a docked stack=" + this);
868 mService.mDockedStackCreateBounds = null;
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);
878 StackWindowController getController() {
879 return (StackWindowController) super.getController();
883 void removeIfPossible() {
885 mDeferRemoval = true;
892 void removeImmediately() {
893 super.removeImmediately();
895 onRemovedFromDisplay();
899 * Removes the stack it from its current parent, so it can be either destroyed completely or
902 void onRemovedFromDisplay() {
903 mDisplayContent.mDimLayerController.removeDimLayerUser(this);
904 EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
906 if (mAnimationBackgroundSurface != null) {
907 mAnimationBackgroundSurface.destroySurface();
908 mAnimationBackgroundSurface = null;
911 if (mStackId == DOCKED_STACK_ID) {
912 mDisplayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(false);
915 mDisplayContent = null;
916 mService.mWindowPlacerLocked.requestTraversal();
919 void resetAnimationBackgroundAnimator() {
920 mAnimationBackgroundAnimator = null;
921 mAnimationBackgroundSurface.hide();
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);
935 // TODO: Should each user have there own stacks?
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);
951 * Adjusts the stack bounds if the IME is visible.
953 * @param imeWin The IME window.
955 void setAdjustedForIme(WindowState imeWin, boolean forceUpdate) {
957 mImeGoingAway = false;
958 if (!mAdjustedForIme || forceUpdate) {
959 mAdjustedForIme = true;
960 mAdjustImeAmount = 0f;
961 mAdjustDividerAmount = 0f;
962 updateAdjustForIme(0f, 0f, true /* force */);
966 boolean isAdjustedForIme() {
967 return mAdjustedForIme;
970 boolean isAnimatingForIme() {
971 return mImeWin != null && mImeWin.isAnimatingLw();
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.
980 * @return true if a traversal should be performed after the adjustment.
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();
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
1000 void resetAdjustedForIme(boolean adjustBoundsNow) {
1001 if (adjustBoundsNow) {
1003 mAdjustedForIme = false;
1004 mImeGoingAway = false;
1005 mAdjustImeAmount = 0f;
1006 mAdjustDividerAmount = 0f;
1007 updateAdjustedBounds();
1008 mService.setResizeDimLayer(false, mStackId, 1.0f);
1010 mImeGoingAway |= mAdjustedForIme;
1015 * Sets the amount how much we currently minimize our stack.
1017 * @param minimizeAmount The amount, between 0 and 1.
1018 * @return Whether the amount has changed and a layout is needed.
1020 boolean setAdjustedForMinimizedDock(float minimizeAmount) {
1021 if (minimizeAmount != mMinimizeAmount) {
1022 mMinimizeAmount = minimizeAmount;
1023 updateAdjustedBounds();
1030 boolean shouldIgnoreInput() {
1031 return isAdjustedForMinimizedDockedStack() || mStackId == DOCKED_STACK_ID &&
1032 isMinimizedDockAndHomeStackResizable();
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.
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();
1050 * Resets the resizing state of all windows.
1052 void endImeAdjustAnimation() {
1053 for (int j = mChildren.size() - 1; j >= 0; j--) {
1054 mChildren.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
1058 int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
1059 return displayContentRect.top + (int)
1060 ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN);
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) {
1070 final Rect displayContentRect = mTmpRect;
1071 final Rect contentBounds = mTmpRect2;
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);
1078 imeTop += imeWin.getGivenContentInsetsLw().top;
1079 if (contentBounds.bottom > imeTop) {
1080 contentBounds.bottom = imeTop;
1083 final int yOffset = displayContentRect.bottom - contentBounds.bottom;
1085 final int dividerWidth =
1086 getDisplayContent().mDividerControllerLocked.getContentWidth();
1087 final int dividerWidthInactive =
1088 getDisplayContent().mDividerControllerLocked.getContentWidthInactive();
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,
1099 mTmpAdjustedBounds.set(mBounds);
1100 mTmpAdjustedBounds.bottom =
1101 (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom);
1102 mFullyAdjustedImeBounds.set(mBounds);
1104 // When the stack is on bottom and has no focus, it's only adjusted for divider width.
1105 final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
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);
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();
1132 private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
1133 final int dockSide = getDockSide();
1134 if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
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);
1160 private boolean isMinimizedDockAndHomeStackResizable() {
1161 return mDisplayContent.mDividerControllerLocked.isMinimizedDock()
1162 && mDisplayContent.mDividerControllerLocked.isHomeStackResizable();
1166 * @return the distance in pixels how much the stack gets minimized from it's original size
1168 int getMinimizeDistance() {
1169 final int dockSide = getDockSide();
1170 if (dockSide == DOCKED_INVALID) {
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;
1186 * Updates the adjustment depending on it's current state.
1188 private void updateAdjustedBounds() {
1189 boolean adjust = false;
1190 if (mMinimizeAmount != 0f) {
1191 adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
1192 } else if (mAdjustedForIme) {
1193 adjust = adjustForIME(mImeWin);
1196 mTmpAdjustedBounds.setEmpty();
1198 setAdjustedBounds(mTmpAdjustedBounds);
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);
1208 void applyAdjustForImeIfNeeded(Task task) {
1209 if (mMinimizeAmount != 0f || !mAdjustedForIme || mAdjustedBounds.isEmpty()) {
1213 final Rect insetBounds = mImeGoingAway ? mBounds : mFullyAdjustedImeBounds;
1214 task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP);
1215 mDisplayContent.setLayoutNeeded();
1218 boolean isAdjustedForMinimizedDockedStack() {
1219 return mMinimizeAmount != 0f;
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);
1230 if (mAdjustedForIme) {
1231 pw.println(prefix + "mAdjustedForIme=true");
1232 pw.println(prefix + "mAdjustImeAmount=" + mAdjustImeAmount);
1233 pw.println(prefix + "mAdjustDividerAmount=" + mAdjustDividerAmount);
1235 if (!mAdjustedBounds.isEmpty()) {
1236 pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString());
1238 for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
1239 mChildren.get(taskNdx).dump(prefix + " ", pw);
1241 if (mAnimationBackgroundSurface.isDimming()) {
1242 pw.println(prefix + "mWindowAnimationBackgroundSurface:");
1243 mAnimationBackgroundSurface.printTo(prefix + " ", pw);
1245 if (!mExitingAppTokens.isEmpty()) {
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);
1253 token.dump(pw, " ");
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;
1267 public boolean dimFullscreen() {
1268 return StackId.isHomeOrRecentsStack(mStackId) || fillsParent();
1272 boolean fillsParent() {
1273 if (useCurrentBounds()) {
1274 return mFillsParent;
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
1283 public DisplayInfo getDisplayInfo() {
1284 return mDisplayContent.getDisplayInfo();
1288 public boolean isAttachedToDisplay() {
1289 return mDisplayContent != null;
1293 public String toString() {
1294 return "{stackId=" + mStackId + " tasks=" + mChildren + "}";
1298 return toShortString();
1302 public String toShortString() {
1303 return "Stack=" + mStackId;
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.
1311 return getDockSide(mBounds);
1314 int getDockSide(Rect bounds) {
1315 if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) {
1316 return DOCKED_INVALID;
1318 if (mDisplayContent == null) {
1319 return DOCKED_INVALID;
1321 mDisplayContent.getLogicalDisplayRect(mTmpRect);
1322 final int orientation = mDisplayContent.getConfiguration().orientation;
1323 return getDockSideUnchecked(bounds, mTmpRect, orientation);
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) {
1332 return DOCKED_BOTTOM;
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) {
1339 return DOCKED_RIGHT;
1342 return DOCKED_INVALID;
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) {
1356 int taskIdFromPoint(int x, int y) {
1357 getBounds(mTmpRect);
1358 if (!mTmpRect.contains(x, y) || isAdjustedForMinimizedDockedStack()) {
1362 for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
1363 final Task task = mChildren.get(taskNdx);
1364 final WindowState win = task.getTopVisibleAppMainWindow();
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;
1381 void findTaskForResizePoint(int x, int y, int delta,
1382 DisplayContent.TaskForResizePointSearchResult results) {
1383 if (!StackId.isTaskResizeAllowed(mStackId)) {
1384 results.searchDone = true;
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;
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);
1405 results.searchDone = true;
1407 if (!mTmpRect.contains(x, y)) {
1408 results.taskForResize = task;
1411 // User touched inside the task. No need to look further,
1412 // focus transfer will be handled in ACTION_UP.
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()) {
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).
1433 * We save the focused task region once we find it, and add it back at the end.
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.
1440 if (task.isHomeTask() && isMinimizedDockAndHomeStackResizable()) {
1441 mDisplayContent.getLogicalDisplayRect(mTmpRect);
1443 task.getDimBounds(mTmpRect);
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);
1452 final boolean isFreeformed = task.inFreeformWorkspace();
1453 if (task != focusedTask || 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);
1465 touchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
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) {
1479 mService.mActivityManager.resizePinnedStack(stackBounds, tempTaskBounds);
1480 } catch (RemoteException e) {
1481 // I don't believe you.
1486 void onAllWindowsDrawn() {
1487 if (!mBoundsAnimating) {
1491 mService.mBoundsAnimationController.onAllWindowsDrawn();
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;
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 */);
1510 if (mStackId == PINNED_STACK_ID) {
1512 mService.mActivityManager.notifyPinnedStackAnimationStarted();
1513 } catch (RemoteException e) {
1514 // I don't believe you...
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
1522 controller.updatePictureInPictureModeForPinnedStackAnimation(null);
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();
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
1542 controller.updatePictureInPictureModeForPinnedStackAnimation(
1543 mBoundsAnimationTarget);
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);
1553 mService.mActivityManager.notifyPinnedStackAnimationEnded();
1554 if (moveToFullscreen) {
1555 mService.mActivityManager.moveTasksToFullscreenStack(mStackId,
1558 } catch (RemoteException e) {
1559 // I don't believe you...
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.
1568 public boolean deferScheduleMultiWindowModeChanged() {
1569 if (mStackId == PINNED_STACK_ID) {
1570 return (mBoundsAnimatingRequested || mBoundsAnimating);
1575 public boolean hasMovementAnimations() {
1576 return StackId.hasMovementAnimations(mStackId);
1579 public boolean isForceScaled() {
1580 return mBoundsAnimating;
1583 public boolean isAnimatingBounds() {
1584 return mBoundsAnimating;
1587 public boolean isAnimatingBoundsToFullscreen() {
1588 return mBoundsAnimating && mBoundsAnimatingToFullscreen;
1591 public boolean pinnedStackResizeDisallowed() {
1592 if (mBoundsAnimating && mCancelCurrentBoundsAnimation) {
1598 /** Returns true if a removal action is still being deferred. */
1599 boolean checkCompleteDeferredRemoval() {
1600 if (isAnimating()) {
1603 if (mDeferRemoval) {
1604 removeImmediately();
1607 return super.checkCompleteDeferredRemoval();
1610 void stepAppWindowsAnimation(long currentTime) {
1611 super.stepAppWindowsAnimation(currentTime);
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);
1633 int getOrientation() {
1634 return (StackId.canSpecifyOrientation(mStackId))
1635 ? super.getOrientation() : SCREEN_ORIENTATION_UNSET;