1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; 20 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; 21 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; 22 import static android.app.ActivityManager.StackId.HOME_STACK_ID; 23 import static android.app.ActivityManager.StackId.PINNED_STACK_ID; 24 import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED; 25 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 26 import static android.view.WindowManager.DOCKED_BOTTOM; 27 import static android.view.WindowManager.DOCKED_INVALID; 28 import static android.view.WindowManager.DOCKED_LEFT; 29 import static android.view.WindowManager.DOCKED_RIGHT; 30 import static android.view.WindowManager.DOCKED_TOP; 31 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; 32 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; 33 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 34 import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK; 35 36 import android.app.ActivityManager.StackId; 37 import android.content.res.Configuration; 38 import android.graphics.Rect; 39 import android.os.Debug; 40 import android.os.RemoteException; 41 import android.util.EventLog; 42 import android.util.Slog; 43 import android.util.SparseArray; 44 import android.view.DisplayInfo; 45 import android.view.Surface; 46 import android.view.SurfaceControl; 47 import android.view.animation.Animation; 48 49 import com.android.internal.policy.DividerSnapAlgorithm; 50 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; 51 import com.android.internal.policy.DockedDividerUtils; 52 import com.android.server.EventLogTags; 53 54 import java.io.PrintWriter; 55 import java.util.ArrayList; 56 57 public class TaskStack implements DimLayer.DimLayerUser, 58 BoundsAnimationController.AnimateBoundsUser { 59 /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to 60 * restrict IME adjustment so that a min portion of top stack remains visible.*/ 61 private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f; 62 63 /** Dimming amount for non-focused stack when stacks are IME-adjusted. */ 64 private static final float IME_ADJUST_DIM_AMOUNT = 0.25f; 65 66 /** Unique identifier */ 67 final int mStackId; 68 69 /** The service */ 70 private final WindowManagerService mService; 71 72 /** The display this stack sits under. */ 73 private DisplayContent mDisplayContent; 74 75 /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match 76 * mTaskHistory in the ActivityStack with the same mStackId */ 77 private final ArrayList<Task> mTasks = new ArrayList<>(); 78 79 /** For comparison with DisplayContent bounds. */ 80 private Rect mTmpRect = new Rect(); 81 private Rect mTmpRect2 = new Rect(); 82 83 /** Content limits relative to the DisplayContent this sits in. */ 84 private Rect mBounds = new Rect(); 85 86 /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */ 87 private final Rect mAdjustedBounds = new Rect(); 88 89 /** 90 * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they 91 * represent the state when the animation has ended. 92 */ 93 private final Rect mFullyAdjustedImeBounds = new Rect(); 94 95 /** Whether mBounds is fullscreen */ 96 private boolean mFullscreen = true; 97 98 // Device rotation as of the last time {@link #mBounds} was set. 99 int mRotation; 100 101 /** Density as of last time {@link #mBounds} was set. */ 102 int mDensity; 103 104 /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */ 105 DimLayer mAnimationBackgroundSurface; 106 107 /** The particular window with an Animation with non-zero background color. */ 108 WindowStateAnimator mAnimationBackgroundAnimator; 109 110 /** Application tokens that are exiting, but still on screen for animations. */ 111 final AppTokenList mExitingAppTokens = new AppTokenList(); 112 113 /** Detach this stack from its display when animation completes. */ 114 boolean mDeferDetach; 115 116 // Whether the stack and all its tasks is currently being drag-resized 117 private boolean mDragResizing; 118 119 private final Rect mTmpAdjustedBounds = new Rect(); 120 private boolean mAdjustedForIme; 121 private boolean mImeGoingAway; 122 private WindowState mImeWin; 123 private float mMinimizeAmount; 124 private float mAdjustImeAmount; 125 private float mAdjustDividerAmount; 126 private final int mDockedStackMinimizeThickness; 127 128 // If this is true, we are in the bounds animating mode. 129 // The task will be down or upscaled to perfectly fit the 130 // region it would have been cropped to. We may also avoid 131 // certain logic we would otherwise apply while resizing, 132 // while resizing in the bounds animating mode. 133 private boolean mBoundsAnimating = false; 134 135 // Temporary storage for the new bounds that should be used after the configuration change. 136 // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration(). 137 private final Rect mBoundsAfterRotation = new Rect(); 138 TaskStack(WindowManagerService service, int stackId)139 TaskStack(WindowManagerService service, int stackId) { 140 mService = service; 141 mStackId = stackId; 142 mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize( 143 com.android.internal.R.dimen.docked_stack_minimize_thickness); 144 EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId); 145 } 146 getDisplayContent()147 DisplayContent getDisplayContent() { 148 return mDisplayContent; 149 } 150 getTasks()151 ArrayList<Task> getTasks() { 152 return mTasks; 153 } 154 findHomeTask()155 Task findHomeTask() { 156 if (mStackId != HOME_STACK_ID) { 157 return null; 158 } 159 160 for (int i = mTasks.size() - 1; i >= 0; i--) { 161 if (mTasks.get(i).isHomeTask()) { 162 return mTasks.get(i); 163 } 164 } 165 return null; 166 } 167 168 /** 169 * Set the bounds of the stack and its containing tasks. 170 * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen. 171 * @param configs Configuration for individual tasks, keyed by task id. 172 * @param taskBounds Bounds for individual tasks, keyed by task id. 173 * @return True if the stack bounds was changed. 174 * */ setBounds( Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds, SparseArray<Rect> taskTempInsetBounds)175 boolean setBounds( 176 Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds, 177 SparseArray<Rect> taskTempInsetBounds) { 178 setBounds(stackBounds); 179 180 // Update bounds of containing tasks. 181 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 182 final Task task = mTasks.get(taskNdx); 183 Configuration config = configs.get(task.mTaskId); 184 if (config != null) { 185 Rect bounds = taskBounds.get(task.mTaskId); 186 if (task.isTwoFingerScrollMode()) { 187 // This is a non-resizeable task that's docked (or side-by-side to the docked 188 // stack). It might have been scrolled previously, and after the stack resizing, 189 // it might no longer fully cover the stack area. 190 // Save the old bounds and re-apply the scroll. This adjusts the bounds to 191 // fit the new stack bounds. 192 task.resizeLocked(bounds, config, false /* forced */); 193 task.getBounds(mTmpRect); 194 task.scrollLocked(mTmpRect); 195 } else { 196 task.resizeLocked(bounds, config, false /* forced */); 197 task.setTempInsetBounds( 198 taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId) 199 : null); 200 } 201 } else { 202 Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?"); 203 } 204 } 205 return true; 206 } 207 prepareFreezingTaskBounds()208 void prepareFreezingTaskBounds() { 209 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 210 final Task task = mTasks.get(taskNdx); 211 task.prepareFreezingBounds(); 212 } 213 } 214 isFullscreenBounds(Rect bounds)215 boolean isFullscreenBounds(Rect bounds) { 216 if (mDisplayContent == null || bounds == null) { 217 return true; 218 } 219 mDisplayContent.getLogicalDisplayRect(mTmpRect); 220 return mTmpRect.equals(bounds); 221 } 222 223 /** 224 * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from 225 * the normal task bounds. 226 * 227 * @param bounds The adjusted bounds. 228 */ setAdjustedBounds(Rect bounds)229 private void setAdjustedBounds(Rect bounds) { 230 if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) { 231 return; 232 } 233 234 mAdjustedBounds.set(bounds); 235 final boolean adjusted = !mAdjustedBounds.isEmpty(); 236 Rect insetBounds = null; 237 if (adjusted && isAdjustedForMinimizedDock()) { 238 insetBounds = mBounds; 239 } else if (adjusted && mAdjustedForIme) { 240 if (mImeGoingAway) { 241 insetBounds = mBounds; 242 } else { 243 insetBounds = mFullyAdjustedImeBounds; 244 } 245 } 246 alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds); 247 mDisplayContent.layoutNeeded = true; 248 } 249 alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds)250 private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) { 251 if (mFullscreen) { 252 return; 253 } 254 // Update bounds of containing tasks. 255 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 256 final Task task = mTasks.get(taskNdx); 257 if (task.isTwoFingerScrollMode()) { 258 // If we're scrolling we don't care about your bounds or configs, 259 // they should be null as if we were in fullscreen. 260 task.resizeLocked(null, null, false /* forced */); 261 task.getBounds(mTmpRect2); 262 task.scrollLocked(mTmpRect2); 263 } else { 264 final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP; 265 task.alignToAdjustedBounds(adjustedBounds, tempInsetBounds, alignBottom); 266 } 267 } 268 } 269 setBounds(Rect bounds)270 private boolean setBounds(Rect bounds) { 271 boolean oldFullscreen = mFullscreen; 272 int rotation = Surface.ROTATION_0; 273 int density = DENSITY_DPI_UNDEFINED; 274 if (mDisplayContent != null) { 275 mDisplayContent.getLogicalDisplayRect(mTmpRect); 276 rotation = mDisplayContent.getDisplayInfo().rotation; 277 density = mDisplayContent.getDisplayInfo().logicalDensityDpi; 278 mFullscreen = bounds == null; 279 if (mFullscreen) { 280 bounds = mTmpRect; 281 } 282 } 283 284 if (bounds == null) { 285 // Can't set to fullscreen if we don't have a display to get bounds from... 286 return false; 287 } 288 if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) { 289 return false; 290 } 291 292 if (mDisplayContent != null) { 293 mDisplayContent.mDimLayerController.updateDimLayer(this); 294 mAnimationBackgroundSurface.setBounds(bounds); 295 } 296 297 mBounds.set(bounds); 298 mRotation = rotation; 299 mDensity = density; 300 301 updateAdjustedBounds(); 302 303 return true; 304 } 305 306 /** Bounds of the stack without adjusting for other factors in the system like visibility 307 * of docked stack. 308 * Most callers should be using {@link #getBounds} as it take into consideration other system 309 * factors. */ getRawBounds(Rect out)310 void getRawBounds(Rect out) { 311 out.set(mBounds); 312 } 313 314 /** Return true if the current bound can get outputted to the rest of the system as-is. */ useCurrentBounds()315 private boolean useCurrentBounds() { 316 if (mFullscreen 317 || !StackId.isResizeableByDockedStack(mStackId) 318 || mDisplayContent == null 319 || mDisplayContent.getDockedStackLocked() != null) { 320 return true; 321 } 322 return false; 323 } 324 getBounds(Rect out)325 public void getBounds(Rect out) { 326 if (useCurrentBounds()) { 327 // If we're currently adjusting for IME or minimized docked stack, we use the adjusted 328 // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked 329 // stack is visible since it is already what we want to represent to the rest of the 330 // system. 331 if (!mAdjustedBounds.isEmpty()) { 332 out.set(mAdjustedBounds); 333 } else { 334 out.set(mBounds); 335 } 336 return; 337 } 338 339 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack 340 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the 341 // system. 342 mDisplayContent.getLogicalDisplayRect(out); 343 } 344 345 /** Bounds of the stack with other system factors taken into consideration. */ 346 @Override getDimBounds(Rect out)347 public void getDimBounds(Rect out) { 348 getBounds(out); 349 } 350 updateDisplayInfo(Rect bounds)351 void updateDisplayInfo(Rect bounds) { 352 if (mDisplayContent == null) { 353 return; 354 } 355 356 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 357 mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent); 358 } 359 if (bounds != null) { 360 setBounds(bounds); 361 return; 362 } else if (mFullscreen) { 363 setBounds(null); 364 return; 365 } 366 367 mTmpRect2.set(mBounds); 368 final int newRotation = mDisplayContent.getDisplayInfo().rotation; 369 final int newDensity = mDisplayContent.getDisplayInfo().logicalDensityDpi; 370 if (mRotation == newRotation && mDensity == newDensity) { 371 setBounds(mTmpRect2); 372 } 373 374 // If the rotation or density didn't match, we'll update it in onConfigurationChanged. 375 } 376 onConfigurationChanged()377 boolean onConfigurationChanged() { 378 return updateBoundsAfterConfigChange(); 379 } 380 updateBoundsAfterConfigChange()381 private boolean updateBoundsAfterConfigChange() { 382 if (mDisplayContent == null) { 383 // If the stack is already detached we're not updating anything, 384 // as it's going away soon anyway. 385 return false; 386 } 387 final int newRotation = getDisplayInfo().rotation; 388 final int newDensity = getDisplayInfo().logicalDensityDpi; 389 390 if (mRotation == newRotation && mDensity == newDensity) { 391 // Nothing to do here as we already update the state in updateDisplayInfo. 392 return false; 393 } 394 395 if (mFullscreen) { 396 // Update stack bounds again since rotation changed since updateDisplayInfo(). 397 setBounds(null); 398 // Return false since we don't need the client to resize. 399 return false; 400 } 401 402 mTmpRect2.set(mBounds); 403 mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2); 404 if (mStackId == DOCKED_STACK_ID) { 405 repositionDockedStackAfterRotation(mTmpRect2); 406 snapDockedStackAfterRotation(mTmpRect2); 407 final int newDockSide = getDockSide(mTmpRect2); 408 409 // Update the dock create mode and clear the dock create bounds, these 410 // might change after a rotation and the original values will be invalid. 411 mService.setDockedStackCreateStateLocked( 412 (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP) 413 ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT 414 : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, 415 null); 416 mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide); 417 } 418 419 mBoundsAfterRotation.set(mTmpRect2); 420 return true; 421 } 422 getBoundsForNewConfiguration(Rect outBounds)423 void getBoundsForNewConfiguration(Rect outBounds) { 424 outBounds.set(mBoundsAfterRotation); 425 mBoundsAfterRotation.setEmpty(); 426 } 427 428 /** 429 * Some dock sides are not allowed by the policy. This method queries the policy and moves 430 * the docked stack around if needed. 431 * 432 * @param inOutBounds the bounds of the docked stack to adjust 433 */ repositionDockedStackAfterRotation(Rect inOutBounds)434 private void repositionDockedStackAfterRotation(Rect inOutBounds) { 435 int dockSide = getDockSide(inOutBounds); 436 if (mService.mPolicy.isDockSideAllowed(dockSide)) { 437 return; 438 } 439 mDisplayContent.getLogicalDisplayRect(mTmpRect); 440 dockSide = DockedDividerUtils.invertDockSide(dockSide); 441 switch (dockSide) { 442 case DOCKED_LEFT: 443 int movement = inOutBounds.left; 444 inOutBounds.left -= movement; 445 inOutBounds.right -= movement; 446 break; 447 case DOCKED_RIGHT: 448 movement = mTmpRect.right - inOutBounds.right; 449 inOutBounds.left += movement; 450 inOutBounds.right += movement; 451 break; 452 case DOCKED_TOP: 453 movement = inOutBounds.top; 454 inOutBounds.top -= movement; 455 inOutBounds.bottom -= movement; 456 break; 457 case DOCKED_BOTTOM: 458 movement = mTmpRect.bottom - inOutBounds.bottom; 459 inOutBounds.top += movement; 460 inOutBounds.bottom += movement; 461 break; 462 } 463 } 464 465 /** 466 * Snaps the bounds after rotation to the closest snap target for the docked stack. 467 */ snapDockedStackAfterRotation(Rect outBounds)468 private void snapDockedStackAfterRotation(Rect outBounds) { 469 470 // Calculate the current position. 471 final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); 472 final int dividerSize = mService.getDefaultDisplayContentLocked() 473 .getDockedDividerController().getContentWidth(); 474 final int dockSide = getDockSide(outBounds); 475 final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds, 476 dockSide, dividerSize); 477 final int displayWidth = mDisplayContent.getDisplayInfo().logicalWidth; 478 final int displayHeight = mDisplayContent.getDisplayInfo().logicalHeight; 479 480 // Snap the position to a target. 481 final int rotation = displayInfo.rotation; 482 final int orientation = mService.mCurConfiguration.orientation; 483 mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds); 484 final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm( 485 mService.mContext.getResources(), displayWidth, displayHeight, 486 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds); 487 final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition); 488 489 // Recalculate the bounds based on the position of the target. 490 DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide, 491 outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight, 492 dividerSize); 493 } 494 isAnimating()495 boolean isAnimating() { 496 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 497 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; 498 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 499 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; 500 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 501 final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator; 502 if (winAnimator.isAnimationSet() || winAnimator.mWin.mAnimatingExit) { 503 return true; 504 } 505 } 506 } 507 } 508 return false; 509 } 510 addTask(Task task, boolean toTop)511 void addTask(Task task, boolean toTop) { 512 addTask(task, toTop, task.showForAllUsers()); 513 } 514 515 /** 516 * Put a Task in this stack. Used for adding and moving. 517 * @param task The task to add. 518 * @param toTop Whether to add it to the top or bottom. 519 * @param showForAllUsers Whether to show the task regardless of the current user. 520 */ addTask(Task task, boolean toTop, boolean showForAllUsers)521 void addTask(Task task, boolean toTop, boolean showForAllUsers) { 522 positionTask(task, toTop ? mTasks.size() : 0, showForAllUsers); 523 } 524 positionTask(Task task, int position, boolean showForAllUsers)525 void positionTask(Task task, int position, boolean showForAllUsers) { 526 final boolean canShowTask = 527 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId); 528 mTasks.remove(task); 529 int stackSize = mTasks.size(); 530 int minPosition = 0; 531 int maxPosition = stackSize; 532 533 if (canShowTask) { 534 minPosition = computeMinPosition(minPosition, stackSize); 535 } else { 536 maxPosition = computeMaxPosition(maxPosition); 537 } 538 // Reset position based on minimum/maximum possible positions. 539 position = Math.min(Math.max(position, minPosition), maxPosition); 540 541 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, 542 "positionTask: task=" + task + " position=" + position); 543 mTasks.add(position, task); 544 545 // If we are moving the task across stacks, the scroll is no longer valid. 546 if (task.mStack != this) { 547 task.resetScrollLocked(); 548 } 549 task.mStack = this; 550 task.updateDisplayInfo(mDisplayContent); 551 boolean toTop = position == mTasks.size() - 1; 552 if (toTop) { 553 mDisplayContent.moveStack(this, true); 554 } 555 556 if (StackId.windowsAreScaleable(mStackId)) { 557 // We force windows out of SCALING_MODE_FREEZE 558 // so that we can continue to animate them 559 // while a resize is pending. 560 forceWindowsScaleable(task, true); 561 } else { 562 forceWindowsScaleable(task, false); 563 } 564 EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, position); 565 } 566 567 /** Calculate the minimum possible position for a task that can be shown to the user. 568 * The minimum position will be above all other tasks that can't be shown. 569 * @param minPosition The minimum position the caller is suggesting. 570 * We will start adjusting up from here. 571 * @param size The size of the current task list. 572 */ computeMinPosition(int minPosition, int size)573 private int computeMinPosition(int minPosition, int size) { 574 while (minPosition < size) { 575 final Task tmpTask = mTasks.get(minPosition); 576 final boolean canShowTmpTask = 577 tmpTask.showForAllUsers() 578 || mService.isCurrentProfileLocked(tmpTask.mUserId); 579 if (canShowTmpTask) { 580 break; 581 } 582 minPosition++; 583 } 584 return minPosition; 585 } 586 587 /** Calculate the maximum possible position for a task that can't be shown to the user. 588 * The maximum position will be below all other tasks that can be shown. 589 * @param maxPosition The maximum position the caller is suggesting. 590 * We will start adjusting down from here. 591 */ computeMaxPosition(int maxPosition)592 private int computeMaxPosition(int maxPosition) { 593 while (maxPosition > 0) { 594 final Task tmpTask = mTasks.get(maxPosition - 1); 595 final boolean canShowTmpTask = 596 tmpTask.showForAllUsers() 597 || mService.isCurrentProfileLocked(tmpTask.mUserId); 598 if (!canShowTmpTask) { 599 break; 600 } 601 maxPosition--; 602 } 603 return maxPosition; 604 } 605 moveTaskToTop(Task task)606 void moveTaskToTop(Task task) { 607 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToTop: task=" + task + " Callers=" 608 + Debug.getCallers(6)); 609 mTasks.remove(task); 610 addTask(task, true); 611 } 612 moveTaskToBottom(Task task)613 void moveTaskToBottom(Task task) { 614 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToBottom: task=" + task); 615 mTasks.remove(task); 616 addTask(task, false); 617 } 618 619 /** 620 * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the 621 * back. 622 * @param task The Task to delete. 623 */ removeTask(Task task)624 void removeTask(Task task) { 625 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeTask: task=" + task); 626 mTasks.remove(task); 627 if (mDisplayContent != null) { 628 if (mTasks.isEmpty()) { 629 mDisplayContent.moveStack(this, false); 630 } 631 mDisplayContent.layoutNeeded = true; 632 } 633 for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) { 634 final AppWindowToken wtoken = mExitingAppTokens.get(appNdx); 635 if (wtoken.mTask == task) { 636 wtoken.mIsExiting = false; 637 mExitingAppTokens.remove(appNdx); 638 } 639 } 640 } 641 attachDisplayContent(DisplayContent displayContent)642 void attachDisplayContent(DisplayContent displayContent) { 643 if (mDisplayContent != null) { 644 throw new IllegalStateException("attachDisplayContent: Already attached"); 645 } 646 647 mDisplayContent = displayContent; 648 mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(), 649 "animation background stackId=" + mStackId); 650 651 Rect bounds = null; 652 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID); 653 if (mStackId == DOCKED_STACK_ID 654 || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId) 655 && !dockedStack.isFullscreen())) { 656 // The existence of a docked stack affects the size of other static stack created since 657 // the docked stack occupies a dedicated region on screen, but only if the dock stack is 658 // not fullscreen. If it's fullscreen, it means that we are in the transition of 659 // dismissing it, so we must not resize this stack. 660 bounds = new Rect(); 661 displayContent.getLogicalDisplayRect(mTmpRect); 662 mTmpRect2.setEmpty(); 663 if (dockedStack != null) { 664 dockedStack.getRawBounds(mTmpRect2); 665 } 666 final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode 667 == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; 668 getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2, 669 mDisplayContent.mDividerControllerLocked.getContentWidth(), 670 dockedOnTopOrLeft); 671 } 672 673 updateDisplayInfo(bounds); 674 } 675 getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility)676 void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) { 677 if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) 678 || mDisplayContent == null) { 679 outBounds.set(mBounds); 680 return; 681 } 682 683 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID); 684 if (dockedStack == null) { 685 // Not sure why you are calling this method when there is no docked stack... 686 throw new IllegalStateException( 687 "Calling getStackDockedModeBoundsLocked() when there is no docked stack."); 688 } 689 if (!ignoreVisibility && !dockedStack.isVisibleLocked()) { 690 // The docked stack is being dismissed, but we caught before it finished being 691 // dismissed. In that case we want to treat it as if it is not occupying any space and 692 // let others occupy the whole display. 693 mDisplayContent.getLogicalDisplayRect(outBounds); 694 return; 695 } 696 697 final int dockedSide = dockedStack.getDockSide(); 698 if (dockedSide == DOCKED_INVALID) { 699 // Not sure how you got here...Only thing we can do is return current bounds. 700 Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack); 701 outBounds.set(mBounds); 702 return; 703 } 704 705 mDisplayContent.getLogicalDisplayRect(mTmpRect); 706 dockedStack.getRawBounds(mTmpRect2); 707 final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT; 708 getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2, 709 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft); 710 711 } 712 713 /** 714 * Outputs the bounds a stack should be given the presence of a docked stack on the display. 715 * @param displayRect The bounds of the display the docked stack is on. 716 * @param outBounds Output bounds that should be used for the stack. 717 * @param stackId Id of stack we are calculating the bounds for. 718 * @param dockedBounds Bounds of the docked stack. 719 * @param dockDividerWidth We need to know the width of the divider make to the output bounds 720 * close to the side of the dock. 721 * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen. 722 */ getStackDockedModeBounds( Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth, boolean dockOnTopOrLeft)723 private void getStackDockedModeBounds( 724 Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth, 725 boolean dockOnTopOrLeft) { 726 final boolean dockedStack = stackId == DOCKED_STACK_ID; 727 final boolean splitHorizontally = displayRect.width() > displayRect.height(); 728 729 outBounds.set(displayRect); 730 if (dockedStack) { 731 if (mService.mDockedStackCreateBounds != null) { 732 outBounds.set(mService.mDockedStackCreateBounds); 733 return; 734 } 735 736 // The initial bounds of the docked stack when it is created about half the screen space 737 // and its bounds can be adjusted after that. The bounds of all other stacks are 738 // adjusted to occupy whatever screen space the docked stack isn't occupying. 739 final DisplayInfo di = mDisplayContent.getDisplayInfo(); 740 mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, 741 mTmpRect2); 742 final int position = new DividerSnapAlgorithm(mService.mContext.getResources(), 743 di.logicalWidth, 744 di.logicalHeight, 745 dockDividerWidth, 746 mService.mCurConfiguration.orientation == ORIENTATION_PORTRAIT, 747 mTmpRect2).getMiddleTarget().position; 748 749 if (dockOnTopOrLeft) { 750 if (splitHorizontally) { 751 outBounds.right = position; 752 } else { 753 outBounds.bottom = position; 754 } 755 } else { 756 if (splitHorizontally) { 757 outBounds.left = position + dockDividerWidth; 758 } else { 759 outBounds.top = position + dockDividerWidth; 760 } 761 } 762 return; 763 } 764 765 // Other stacks occupy whatever space is left by the docked stack. 766 if (!dockOnTopOrLeft) { 767 if (splitHorizontally) { 768 outBounds.right = dockedBounds.left - dockDividerWidth; 769 } else { 770 outBounds.bottom = dockedBounds.top - dockDividerWidth; 771 } 772 } else { 773 if (splitHorizontally) { 774 outBounds.left = dockedBounds.right + dockDividerWidth; 775 } else { 776 outBounds.top = dockedBounds.bottom + dockDividerWidth; 777 } 778 } 779 DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft); 780 } 781 resetDockedStackToMiddle()782 void resetDockedStackToMiddle() { 783 if (mStackId != DOCKED_STACK_ID) { 784 throw new IllegalStateException("Not a docked stack=" + this); 785 } 786 787 mService.mDockedStackCreateBounds = null; 788 789 final Rect bounds = new Rect(); 790 getStackDockedModeBoundsLocked(bounds, true /*ignoreVisibility*/); 791 mService.mH.obtainMessage(RESIZE_STACK, DOCKED_STACK_ID, 792 1 /*allowResizeInDockedMode*/, bounds).sendToTarget(); 793 } 794 detachDisplay()795 void detachDisplay() { 796 EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); 797 798 boolean doAnotherLayoutPass = false; 799 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 800 final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens; 801 for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) { 802 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows; 803 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) { 804 // We are in the middle of changing the state of displays/stacks/tasks. We need 805 // to finish that, before we let layout interfere with it. 806 mService.removeWindowLocked(appWindows.get(winNdx)); 807 doAnotherLayoutPass = true; 808 } 809 } 810 } 811 if (doAnotherLayoutPass) { 812 mService.mWindowPlacerLocked.requestTraversal(); 813 } 814 815 close(); 816 } 817 resetAnimationBackgroundAnimator()818 void resetAnimationBackgroundAnimator() { 819 mAnimationBackgroundAnimator = null; 820 mAnimationBackgroundSurface.hide(); 821 } 822 setAnimationBackground(WindowStateAnimator winAnimator, int color)823 void setAnimationBackground(WindowStateAnimator winAnimator, int color) { 824 int animLayer = winAnimator.mAnimLayer; 825 if (mAnimationBackgroundAnimator == null 826 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) { 827 mAnimationBackgroundAnimator = winAnimator; 828 animLayer = mService.adjustAnimationBackground(winAnimator); 829 mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM, 830 ((color >> 24) & 0xff) / 255f, 0); 831 } 832 } 833 switchUser()834 void switchUser() { 835 int top = mTasks.size(); 836 for (int taskNdx = 0; taskNdx < top; ++taskNdx) { 837 Task task = mTasks.get(taskNdx); 838 if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) { 839 mTasks.remove(taskNdx); 840 mTasks.add(task); 841 --top; 842 } 843 } 844 } 845 close()846 void close() { 847 if (mAnimationBackgroundSurface != null) { 848 mAnimationBackgroundSurface.destroySurface(); 849 mAnimationBackgroundSurface = null; 850 } 851 mDisplayContent = null; 852 } 853 854 /** 855 * Adjusts the stack bounds if the IME is visible. 856 * 857 * @param imeWin The IME window. 858 */ setAdjustedForIme(WindowState imeWin, boolean forceUpdate)859 void setAdjustedForIme(WindowState imeWin, boolean forceUpdate) { 860 mImeWin = imeWin; 861 mImeGoingAway = false; 862 if (!mAdjustedForIme || forceUpdate) { 863 mAdjustedForIme = true; 864 mAdjustImeAmount = 0f; 865 mAdjustDividerAmount = 0f; 866 updateAdjustForIme(0f, 0f, true /* force */); 867 } 868 } 869 isAdjustedForIme()870 boolean isAdjustedForIme() { 871 return mAdjustedForIme; 872 } 873 isAnimatingForIme()874 boolean isAnimatingForIme() { 875 return mImeWin != null && mImeWin.isAnimatingLw(); 876 } 877 878 /** 879 * Update the stack's bounds (crop or position) according to the IME window's 880 * current position. When IME window is animated, the bottom stack is animated 881 * together to track the IME window's current position, and the top stack is 882 * cropped as necessary. 883 * 884 * @return true if a traversal should be performed after the adjustment. 885 */ updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force)886 boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) { 887 if (adjustAmount != mAdjustImeAmount 888 || adjustDividerAmount != mAdjustDividerAmount || force) { 889 mAdjustImeAmount = adjustAmount; 890 mAdjustDividerAmount = adjustDividerAmount; 891 updateAdjustedBounds(); 892 return isVisibleLocked(true /* ignoreKeyguard */); 893 } else { 894 return false; 895 } 896 } 897 898 /** 899 * Resets the adjustment after it got adjusted for the IME. 900 * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about 901 * animations; otherwise, set flag and animates the window away together 902 * with IME window. 903 */ resetAdjustedForIme(boolean adjustBoundsNow)904 void resetAdjustedForIme(boolean adjustBoundsNow) { 905 if (adjustBoundsNow) { 906 mImeWin = null; 907 mAdjustedForIme = false; 908 mImeGoingAway = false; 909 mAdjustImeAmount = 0f; 910 mAdjustDividerAmount = 0f; 911 updateAdjustedBounds(); 912 mService.setResizeDimLayer(false, mStackId, 1.0f); 913 } else { 914 mImeGoingAway |= mAdjustedForIme; 915 } 916 } 917 918 /** 919 * Sets the amount how much we currently minimize our stack. 920 * 921 * @param minimizeAmount The amount, between 0 and 1. 922 * @return Whether the amount has changed and a layout is needed. 923 */ setAdjustedForMinimizedDock(float minimizeAmount)924 boolean setAdjustedForMinimizedDock(float minimizeAmount) { 925 if (minimizeAmount != mMinimizeAmount) { 926 mMinimizeAmount = minimizeAmount; 927 updateAdjustedBounds(); 928 return isVisibleLocked(true /* ignoreKeyguard*/); 929 } else { 930 return false; 931 } 932 } 933 isAdjustedForMinimizedDock()934 boolean isAdjustedForMinimizedDock() { 935 return mMinimizeAmount != 0f; 936 } 937 938 /** 939 * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows 940 * to the list of to be drawn windows the service is waiting for. 941 */ beginImeAdjustAnimation()942 void beginImeAdjustAnimation() { 943 for (int j = mTasks.size() - 1; j >= 0; j--) { 944 final Task task = mTasks.get(j); 945 if (task.isVisible()) { 946 task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER); 947 task.addWindowsWaitingForDrawnIfResizingChanged(); 948 } 949 } 950 } 951 952 /** 953 * Resets the resizing state of all windows. 954 */ endImeAdjustAnimation()955 void endImeAdjustAnimation() { 956 for (int j = mTasks.size() - 1; j >= 0; j--) { 957 mTasks.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER); 958 } 959 } 960 getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom)961 int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) { 962 return displayContentRect.top + (int) 963 ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN); 964 } 965 adjustForIME(final WindowState imeWin)966 private boolean adjustForIME(final WindowState imeWin) { 967 final int dockedSide = getDockSide(); 968 final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM; 969 if (imeWin == null || !dockedTopOrBottom) { 970 return false; 971 } 972 973 final Rect displayContentRect = mTmpRect; 974 final Rect contentBounds = mTmpRect2; 975 976 // Calculate the content bounds excluding the area occupied by IME 977 getDisplayContent().getContentRect(displayContentRect); 978 contentBounds.set(displayContentRect); 979 int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top); 980 981 imeTop += imeWin.getGivenContentInsetsLw().top; 982 if (contentBounds.bottom > imeTop) { 983 contentBounds.bottom = imeTop; 984 } 985 986 final int yOffset = displayContentRect.bottom - contentBounds.bottom; 987 988 final int dividerWidth = 989 getDisplayContent().mDividerControllerLocked.getContentWidth(); 990 final int dividerWidthInactive = 991 getDisplayContent().mDividerControllerLocked.getContentWidthInactive(); 992 993 if (dockedSide == DOCKED_TOP) { 994 // If this stack is docked on top, we make it smaller so the bottom stack is not 995 // occluded by IME. We shift its bottom up by the height of the IME, but 996 // leaves at least 30% of the top stack visible. 997 final int minTopStackBottom = 998 getMinTopStackBottom(displayContentRect, mBounds.bottom); 999 final int bottom = Math.max( 1000 mBounds.bottom - yOffset + dividerWidth - dividerWidthInactive, 1001 minTopStackBottom); 1002 mTmpAdjustedBounds.set(mBounds); 1003 mTmpAdjustedBounds.bottom = 1004 (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom); 1005 mFullyAdjustedImeBounds.set(mBounds); 1006 } else { 1007 // When the stack is on bottom and has no focus, it's only adjusted for divider width. 1008 final int dividerWidthDelta = dividerWidthInactive - dividerWidth; 1009 1010 // When the stack is on bottom and has focus, it needs to be moved up so as to 1011 // not occluded by IME, and at the same time adjusted for divider width. 1012 // We try to move it up by the height of the IME window, but only to the extent 1013 // that leaves at least 30% of the top stack visible. 1014 // 'top' is where the top of bottom stack will move to in this case. 1015 final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive; 1016 final int minTopStackBottom = 1017 getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth); 1018 final int top = Math.max( 1019 mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive); 1020 1021 mTmpAdjustedBounds.set(mBounds); 1022 // Account for the adjustment for IME and divider width separately. 1023 // (top - topBeforeImeAdjust) is the amount of movement due to IME only, 1024 // and dividerWidthDelta is due to divider width change only. 1025 mTmpAdjustedBounds.top = mBounds.top + 1026 (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) + 1027 mAdjustDividerAmount * dividerWidthDelta); 1028 mFullyAdjustedImeBounds.set(mBounds); 1029 mFullyAdjustedImeBounds.top = top; 1030 mFullyAdjustedImeBounds.bottom = top + mBounds.height(); 1031 } 1032 return true; 1033 } 1034 adjustForMinimizedDockedStack(float minimizeAmount)1035 private boolean adjustForMinimizedDockedStack(float minimizeAmount) { 1036 final int dockSide = getDockSide(); 1037 if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) { 1038 return false; 1039 } 1040 1041 if (dockSide == DOCKED_TOP) { 1042 mService.getStableInsetsLocked(mTmpRect); 1043 int topInset = mTmpRect.top; 1044 mTmpAdjustedBounds.set(mBounds); 1045 mTmpAdjustedBounds.bottom = 1046 (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom); 1047 } else if (dockSide == DOCKED_LEFT) { 1048 mTmpAdjustedBounds.set(mBounds); 1049 final int width = mBounds.width(); 1050 mTmpAdjustedBounds.right = 1051 (int) (minimizeAmount * mDockedStackMinimizeThickness 1052 + (1 - minimizeAmount) * mBounds.right); 1053 mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width; 1054 } else if (dockSide == DOCKED_RIGHT) { 1055 mTmpAdjustedBounds.set(mBounds); 1056 mTmpAdjustedBounds.left = 1057 (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness) 1058 + (1 - minimizeAmount) * mBounds.left); 1059 } 1060 return true; 1061 } 1062 1063 /** 1064 * @return the distance in pixels how much the stack gets minimized from it's original size 1065 */ getMinimizeDistance()1066 int getMinimizeDistance() { 1067 final int dockSide = getDockSide(); 1068 if (dockSide == DOCKED_INVALID) { 1069 return 0; 1070 } 1071 1072 if (dockSide == DOCKED_TOP) { 1073 mService.getStableInsetsLocked(mTmpRect); 1074 int topInset = mTmpRect.top; 1075 return mBounds.bottom - topInset; 1076 } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) { 1077 return mBounds.width() - mDockedStackMinimizeThickness; 1078 } else { 1079 return 0; 1080 } 1081 } 1082 1083 /** 1084 * Updates the adjustment depending on it's current state. 1085 */ updateAdjustedBounds()1086 private void updateAdjustedBounds() { 1087 boolean adjust = false; 1088 if (mMinimizeAmount != 0f) { 1089 adjust = adjustForMinimizedDockedStack(mMinimizeAmount); 1090 } else if (mAdjustedForIme) { 1091 adjust = adjustForIME(mImeWin); 1092 } 1093 if (!adjust) { 1094 mTmpAdjustedBounds.setEmpty(); 1095 } 1096 setAdjustedBounds(mTmpAdjustedBounds); 1097 1098 final boolean isImeTarget = (mService.getImeFocusStackLocked() == this); 1099 if (mAdjustedForIme && adjust && !isImeTarget) { 1100 final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount) 1101 * IME_ADJUST_DIM_AMOUNT; 1102 mService.setResizeDimLayer(true, mStackId, alpha); 1103 } 1104 } 1105 applyAdjustForImeIfNeeded(Task task)1106 void applyAdjustForImeIfNeeded(Task task) { 1107 if (mMinimizeAmount != 0f || !mAdjustedForIme || mAdjustedBounds.isEmpty()) { 1108 return; 1109 } 1110 1111 final Rect insetBounds = mImeGoingAway ? mBounds : mFullyAdjustedImeBounds; 1112 task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP); 1113 mDisplayContent.layoutNeeded = true; 1114 } 1115 isAdjustedForMinimizedDockedStack()1116 boolean isAdjustedForMinimizedDockedStack() { 1117 return mMinimizeAmount != 0f; 1118 } 1119 dump(String prefix, PrintWriter pw)1120 public void dump(String prefix, PrintWriter pw) { 1121 pw.println(prefix + "mStackId=" + mStackId); 1122 pw.println(prefix + "mDeferDetach=" + mDeferDetach); 1123 pw.println(prefix + "mFullscreen=" + mFullscreen); 1124 pw.println(prefix + "mBounds=" + mBounds.toShortString()); 1125 if (mMinimizeAmount != 0f) { 1126 pw.println(prefix + "mMinimizeAmout=" + mMinimizeAmount); 1127 } 1128 if (mAdjustedForIme) { 1129 pw.println(prefix + "mAdjustedForIme=true"); 1130 pw.println(prefix + "mAdjustImeAmount=" + mAdjustImeAmount); 1131 pw.println(prefix + "mAdjustDividerAmount=" + mAdjustDividerAmount); 1132 } 1133 if (!mAdjustedBounds.isEmpty()) { 1134 pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString()); 1135 } 1136 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) { 1137 mTasks.get(taskNdx).dump(prefix + " ", pw); 1138 } 1139 if (mAnimationBackgroundSurface.isDimming()) { 1140 pw.println(prefix + "mWindowAnimationBackgroundSurface:"); 1141 mAnimationBackgroundSurface.printTo(prefix + " ", pw); 1142 } 1143 if (!mExitingAppTokens.isEmpty()) { 1144 pw.println(); 1145 pw.println(" Exiting application tokens:"); 1146 for (int i = mExitingAppTokens.size() - 1; i >= 0; i--) { 1147 WindowToken token = mExitingAppTokens.get(i); 1148 pw.print(" Exiting App #"); pw.print(i); 1149 pw.print(' '); pw.print(token); 1150 pw.println(':'); 1151 token.dump(pw, " "); 1152 } 1153 } 1154 } 1155 1156 /** Fullscreen status of the stack without adjusting for other factors in the system like 1157 * visibility of docked stack. 1158 * Most callers should be using {@link #isFullscreen} as it take into consideration other 1159 * system factors. */ getRawFullscreen()1160 boolean getRawFullscreen() { 1161 return mFullscreen; 1162 } 1163 1164 @Override dimFullscreen()1165 public boolean dimFullscreen() { 1166 return mStackId == HOME_STACK_ID || isFullscreen(); 1167 } 1168 isFullscreen()1169 boolean isFullscreen() { 1170 if (useCurrentBounds()) { 1171 return mFullscreen; 1172 } 1173 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack 1174 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the 1175 // system. 1176 return true; 1177 } 1178 1179 @Override getDisplayInfo()1180 public DisplayInfo getDisplayInfo() { 1181 return mDisplayContent.getDisplayInfo(); 1182 } 1183 1184 @Override toString()1185 public String toString() { 1186 return "{stackId=" + mStackId + " tasks=" + mTasks + "}"; 1187 } 1188 1189 @Override toShortString()1190 public String toShortString() { 1191 return "Stack=" + mStackId; 1192 } 1193 1194 /** 1195 * For docked workspace (or workspace that's side-by-side to the docked), provides 1196 * information which side of the screen was the dock anchored. 1197 */ getDockSide()1198 int getDockSide() { 1199 return getDockSide(mBounds); 1200 } 1201 getDockSide(Rect bounds)1202 int getDockSide(Rect bounds) { 1203 if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) { 1204 return DOCKED_INVALID; 1205 } 1206 if (mDisplayContent == null) { 1207 return DOCKED_INVALID; 1208 } 1209 mDisplayContent.getLogicalDisplayRect(mTmpRect); 1210 final int orientation = mService.mCurConfiguration.orientation; 1211 return getDockSideUnchecked(bounds, mTmpRect, orientation); 1212 } 1213 getDockSideUnchecked(Rect bounds, Rect displayRect, int orientation)1214 static int getDockSideUnchecked(Rect bounds, Rect displayRect, int orientation) { 1215 if (orientation == Configuration.ORIENTATION_PORTRAIT) { 1216 // Portrait mode, docked either at the top or the bottom. 1217 if (bounds.top - displayRect.top <= displayRect.bottom - bounds.bottom) { 1218 return DOCKED_TOP; 1219 } else { 1220 return DOCKED_BOTTOM; 1221 } 1222 } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 1223 // Landscape mode, docked either on the left or on the right. 1224 if (bounds.left - displayRect.left <= displayRect.right - bounds.right) { 1225 return DOCKED_LEFT; 1226 } else { 1227 return DOCKED_RIGHT; 1228 } 1229 } else { 1230 return DOCKED_INVALID; 1231 } 1232 } 1233 isVisibleLocked()1234 boolean isVisibleLocked() { 1235 return isVisibleLocked(false /* ignoreKeyguard */); 1236 } 1237 isVisibleLocked(boolean ignoreKeyguard)1238 boolean isVisibleLocked(boolean ignoreKeyguard) { 1239 final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded() 1240 && !mService.mAnimator.mKeyguardGoingAway; 1241 if (!ignoreKeyguard && keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) { 1242 // The keyguard is showing and the stack shouldn't show on top of the keyguard. 1243 return false; 1244 } 1245 1246 for (int i = mTasks.size() - 1; i >= 0; i--) { 1247 final Task task = mTasks.get(i); 1248 for (int j = task.mAppTokens.size() - 1; j >= 0; j--) { 1249 if (!task.mAppTokens.get(j).hidden) { 1250 return true; 1251 } 1252 } 1253 } 1254 1255 return false; 1256 } 1257 isDragResizing()1258 boolean isDragResizing() { 1259 return mDragResizing; 1260 } 1261 setDragResizingLocked(boolean resizing)1262 void setDragResizingLocked(boolean resizing) { 1263 if (mDragResizing == resizing) { 1264 return; 1265 } 1266 mDragResizing = resizing; 1267 for (int i = mTasks.size() - 1; i >= 0 ; i--) { 1268 mTasks.get(i).resetDragResizingChangeReported(); 1269 } 1270 } 1271 1272 @Override // AnimatesBounds setSize(Rect bounds)1273 public boolean setSize(Rect bounds) { 1274 synchronized (mService.mWindowMap) { 1275 if (mDisplayContent == null) { 1276 return false; 1277 } 1278 } 1279 try { 1280 mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false, -1); 1281 } catch (RemoteException e) { 1282 } 1283 return true; 1284 } 1285 setPinnedStackSize(Rect bounds, Rect tempTaskBounds)1286 public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) { 1287 synchronized (mService.mWindowMap) { 1288 if (mDisplayContent == null) { 1289 return false; 1290 } 1291 if (mStackId != PINNED_STACK_ID) { 1292 Slog.w(TAG_WM, "Attempt to use pinned stack resize animation helper on" 1293 + "non pinned stack"); 1294 return false; 1295 } 1296 } 1297 try { 1298 mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds); 1299 } catch (RemoteException e) { 1300 // I don't believe you. 1301 } 1302 return true; 1303 } 1304 forceWindowsScaleable(Task task, boolean force)1305 void forceWindowsScaleable(Task task, boolean force) { 1306 SurfaceControl.openTransaction(); 1307 try { 1308 final ArrayList<AppWindowToken> activities = task.mAppTokens; 1309 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 1310 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; 1311 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 1312 final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator; 1313 if (winAnimator == null || !winAnimator.hasSurface()) { 1314 continue; 1315 } 1316 winAnimator.mSurfaceController.forceScaleableInTransaction(force); 1317 } 1318 } 1319 } finally { 1320 SurfaceControl.closeTransaction(); 1321 } 1322 } 1323 1324 @Override // AnimatesBounds onAnimationStart()1325 public void onAnimationStart() { 1326 synchronized (mService.mWindowMap) { 1327 mBoundsAnimating = true; 1328 } 1329 } 1330 1331 @Override // AnimatesBounds onAnimationEnd()1332 public void onAnimationEnd() { 1333 synchronized (mService.mWindowMap) { 1334 mBoundsAnimating = false; 1335 mService.requestTraversal(); 1336 } 1337 if (mStackId == PINNED_STACK_ID) { 1338 try { 1339 mService.mActivityManager.notifyPinnedStackAnimationEnded(); 1340 } catch (RemoteException e) { 1341 // I don't believe you... 1342 } 1343 } 1344 } 1345 1346 @Override moveToFullscreen()1347 public void moveToFullscreen() { 1348 try { 1349 mService.mActivityManager.moveTasksToFullscreenStack(mStackId, true); 1350 } catch (RemoteException e) { 1351 e.printStackTrace(); 1352 } 1353 } 1354 1355 @Override getFullScreenBounds(Rect bounds)1356 public void getFullScreenBounds(Rect bounds) { 1357 getDisplayContent().getContentRect(bounds); 1358 } 1359 hasMovementAnimations()1360 public boolean hasMovementAnimations() { 1361 return StackId.hasMovementAnimations(mStackId); 1362 } 1363 getForceScaleToCrop()1364 public boolean getForceScaleToCrop() { 1365 return mBoundsAnimating; 1366 } 1367 getBoundsAnimating()1368 public boolean getBoundsAnimating() { 1369 return mBoundsAnimating; 1370 } 1371 1372 /** 1373 * See {@link WindowManagerService#overridePlayingAppAnimationsLw} 1374 */ overridePlayingAppAnimations(Animation a)1375 void overridePlayingAppAnimations(Animation a) { 1376 for (int i = mTasks.size() - 1; i >= 0; --i) { 1377 mTasks.get(i).overridePlayingAppAnimations(a); 1378 } 1379 } 1380 } 1381