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 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 169 DisplayContent getDisplayContent() { 170 return mDisplayContent; 171 } 172 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 * */ 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 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 */ 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 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 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 264 private void hideAnimationSurface() { 265 if (mAnimationBackgroundSurface == null) { 266 return; 267 } 268 getPendingTransaction().hide(mAnimationBackgroundSurface); 269 mAnimationBackgroundSurfaceIsShown = false; 270 scheduleAnimation(); 271 } 272 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 285 public int setBounds(Rect bounds) { 286 return setBounds(getOverrideBounds(), bounds); 287 } 288 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. */ 321 void getRawBounds(Rect out) { 322 out.set(getRawBounds()); 323 } 324 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. */ 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 341 public void getBounds(Rect bounds) { 342 bounds.set(getBounds()); 343 } 344 345 @Override 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 */ 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 */ 389 void getFinalAnimationBounds(Rect outBounds) { 390 outBounds.set(mBoundsAnimationTarget); 391 } 392 393 /** 394 * @return the final source bounds for the bounds animation. 395 */ 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 */ 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. */ 413 public void getDimBounds(Rect out) { 414 getBounds(out); 415 } 416 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. */ 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 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 */ 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 */ 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. 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 */ 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 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 */ 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. 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 */ 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 */ 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 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 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 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 */ 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 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 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 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 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 */ 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 */ 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 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 1020 StackWindowController getController() { 1021 return (StackWindowController) super.getController(); 1022 } 1023 1024 @Override 1025 void removeIfPossible() { 1026 if (isSelfOrChildAnimating()) { 1027 mDeferRemoval = true; 1028 return; 1029 } 1030 removeImmediately(); 1031 } 1032 1033 @Override 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 1052 void resetAnimationBackgroundAnimator() { 1053 mAnimationBackgroundAnimator = null; 1054 hideAnimationSurface(); 1055 } 1056 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 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 */ 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 1098 boolean isAdjustedForIme() { 1099 return mAdjustedForIme; 1100 } 1101 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 1193 int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) { 1194 return displayContentRect.top + (int) 1195 ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN); 1196 } 1197 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 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 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 */ 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 */ 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 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 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 */ 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 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 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 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 1444 public String toString() { 1445 return "{stackId=" + mStackId + " tasks=" + mChildren + "}"; 1446 } 1447 1448 String getName() { 1449 return toShortString(); 1450 } 1451 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 */ 1460 int getDockSide() { 1461 return getDockSide(getRawBounds()); 1462 } 1463 1464 int getDockSideForDisplay(DisplayContent dc) { 1465 return getDockSide(dc, getRawBounds()); 1466 } 1467 1468 private int getDockSide(Rect bounds) { 1469 if (mDisplayContent == null) { 1470 return DOCKED_INVALID; 1471 } 1472 return getDockSide(mDisplayContent, bounds); 1473 } 1474 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 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 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 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 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 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 1624 void onAllWindowsDrawn() { 1625 if (!mBoundsAnimating && !mBoundsAnimatingRequested) { 1626 return; 1627 } 1628 1629 mService.mBoundsAnimationController.onAllWindowsDrawn(); 1630 } 1631 1632 @Override // AnimatesBounds 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 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 */ 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 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 */ 1744 public boolean deferScheduleMultiWindowModeChanged() { 1745 if (inPinnedWindowingMode()) { 1746 return (mBoundsAnimatingRequested || mBoundsAnimating); 1747 } 1748 return false; 1749 } 1750 1751 public boolean isForceScaled() { 1752 return mBoundsAnimating; 1753 } 1754 1755 public boolean isAnimatingBounds() { 1756 return mBoundsAnimating; 1757 } 1758 1759 public boolean lastAnimatingBoundsWasToFullscreen() { 1760 return mBoundsAnimatingToFullscreen; 1761 } 1762 1763 public boolean isAnimatingBoundsToFullscreen() { 1764 return isAnimatingBounds() && lastAnimatingBoundsWasToFullscreen(); 1765 } 1766 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. */ 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 1787 int getOrientation() { 1788 return (canSpecifyOrientation()) ? super.getOrientation() : SCREEN_ORIENTATION_UNSET; 1789 } 1790 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 1801 Dimmer getDimmer() { 1802 return mDimmer; 1803 } 1804 1805 @Override 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 1818 public DisplayInfo getDisplayInfo() { 1819 return mDisplayContent.getDisplayInfo(); 1820 } 1821 1822 void dim(float alpha) { 1823 mDimmer.dimAbove(getPendingTransaction(), alpha); 1824 scheduleAnimation(); 1825 } 1826 1827 void stopDimming() { 1828 mDimmer.stopDim(getPendingTransaction()); 1829 scheduleAnimation(); 1830 } 1831 1832 @Override 1833 void getRelativePosition(Point outPos) { 1834 super.getRelativePosition(outPos); 1835 final int outset = getStackOutset(); 1836 outPos.x -= outset; 1837 outPos.y -= outset; 1838 } 1839 1840 AnimatingAppWindowTokenRegistry getAnimatingAppWindowTokenRegistry() { 1841 return mAnimatingAppWindowTokenRegistry; 1842 } 1843 } 1844