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