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