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