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