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