TaskStack.java revision 99db1863a84364339fc5dc9142f15910cdd96ed8
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.DOCKED_STACK_ID; 21import static android.app.ActivityManager.FIRST_STATIC_STACK_ID; 22import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID; 23import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID; 24import static android.app.ActivityManager.LAST_STATIC_STACK_ID; 25import static android.app.ActivityManager.PINNED_STACK_ID; 26import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT; 27import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK; 28import static com.android.server.wm.WindowManagerService.TAG; 29 30import android.annotation.IntDef; 31import android.content.res.Configuration; 32import android.graphics.Rect; 33import android.os.Debug; 34import android.util.EventLog; 35import android.util.Slog; 36import android.util.SparseArray; 37import android.view.DisplayInfo; 38import android.view.Surface; 39 40import com.android.server.EventLogTags; 41 42import java.io.PrintWriter; 43import java.lang.annotation.Retention; 44import java.lang.annotation.RetentionPolicy; 45import java.util.ArrayList; 46 47public class TaskStack implements DimLayer.DimLayerUser { 48 49 // If the stack should be resized to fullscreen. 50 private static final boolean FULLSCREEN = true; 51 52 /** Unique identifier */ 53 final int mStackId; 54 55 /** The service */ 56 private final WindowManagerService mService; 57 58 /** The display this stack sits under. */ 59 private DisplayContent mDisplayContent; 60 61 /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match 62 * mTaskHistory in the ActivityStack with the same mStackId */ 63 private final ArrayList<Task> mTasks = new ArrayList<>(); 64 65 /** For comparison with DisplayContent bounds. */ 66 private Rect mTmpRect = new Rect(); 67 private Rect mTmpRect2 = new Rect(); 68 69 /** Content limits relative to the DisplayContent this sits in. */ 70 private Rect mBounds = new Rect(); 71 72 /** Whether mBounds is fullscreen */ 73 private boolean mFullscreen = true; 74 75 // Device rotation as of the last time {@link #mBounds} was set. 76 int mRotation; 77 78 /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */ 79 DimLayer mAnimationBackgroundSurface; 80 81 /** The particular window with an Animation with non-zero background color. */ 82 WindowStateAnimator mAnimationBackgroundAnimator; 83 84 /** Application tokens that are exiting, but still on screen for animations. */ 85 final AppTokenList mExitingAppTokens = new AppTokenList(); 86 87 /** Detach this stack from its display when animation completes. */ 88 boolean mDeferDetach; 89 90 static final int DOCKED_INVALID = -1; 91 static final int DOCKED_LEFT = 1; 92 static final int DOCKED_TOP = 2; 93 static final int DOCKED_RIGHT = 3; 94 static final int DOCKED_BOTTOM = 4; 95 96 @IntDef({ 97 DOCKED_INVALID, 98 DOCKED_LEFT, 99 DOCKED_TOP, 100 DOCKED_RIGHT, 101 DOCKED_BOTTOM}) 102 @Retention(RetentionPolicy.SOURCE) 103 @interface DockSide {} 104 105 TaskStack(WindowManagerService service, int stackId) { 106 mService = service; 107 mStackId = stackId; 108 EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId); 109 } 110 111 DisplayContent getDisplayContent() { 112 return mDisplayContent; 113 } 114 115 ArrayList<Task> getTasks() { 116 return mTasks; 117 } 118 119 void resizeWindows() { 120 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 121 mTasks.get(taskNdx).resizeWindows(); 122 } 123 } 124 125 boolean allowTaskResize() { 126 return mStackId == FREEFORM_WORKSPACE_STACK_ID 127 || mStackId == DOCKED_STACK_ID 128 || mStackId == PINNED_STACK_ID; 129 } 130 131 /** 132 * Set the bounds of the stack and its containing tasks. 133 * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen. 134 * @param configs Configuration for individual tasks, keyed by task id. 135 * @param taskBounds Bounds for individual tasks, keyed by task id. 136 * @return True if the stack bounds was changed. 137 * */ 138 boolean setBounds( 139 Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) { 140 if (!setBounds(stackBounds)) { 141 return false; 142 } 143 144 // Update bounds of containing tasks. 145 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 146 final Task task = mTasks.get(taskNdx); 147 Configuration config = configs.get(task.mTaskId); 148 if (config != null) { 149 Rect bounds = taskBounds.get(task.mTaskId); 150 task.setBounds(bounds, config); 151 } else { 152 Slog.wtf(TAG, "No config for task: " + task + ", is there a mismatch with AM?"); 153 } 154 } 155 return true; 156 } 157 158 private boolean setBounds(Rect bounds) { 159 boolean oldFullscreen = mFullscreen; 160 int rotation = Surface.ROTATION_0; 161 if (mDisplayContent != null) { 162 mDisplayContent.getLogicalDisplayRect(mTmpRect); 163 rotation = mDisplayContent.getDisplayInfo().rotation; 164 if (bounds == null) { 165 bounds = mTmpRect; 166 mFullscreen = true; 167 } else { 168 // ensure bounds are entirely within the display rect 169 if (!bounds.intersect(mTmpRect)) { 170 // Can't set bounds outside the containing display.. Sorry! 171 return false; 172 } 173 mFullscreen = mTmpRect.equals(bounds); 174 } 175 } 176 177 if (bounds == null) { 178 // Can't set to fullscreen if we don't have a display to get bounds from... 179 return false; 180 } 181 if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) { 182 return false; 183 } 184 185 if (mDisplayContent != null) { 186 mDisplayContent.mDimBehindController.updateDimLayer(this); 187 mAnimationBackgroundSurface.setBounds(bounds); 188 } 189 190 mBounds.set(bounds); 191 mRotation = rotation; 192 return true; 193 } 194 195 /** Bounds of the stack without adjusting for other factors in the system like visibility 196 * of docked stack. 197 * Most callers should be using {@link #getBounds} as it take into consideration other system 198 * factors. */ 199 void getRawBounds(Rect out) { 200 out.set(mBounds); 201 } 202 203 /** Return true if the current bound can get outputted to the rest of the system as-is. */ 204 private boolean useCurrentBounds() { 205 if (mFullscreen 206 || mStackId == DOCKED_STACK_ID 207 || mStackId == PINNED_STACK_ID 208 || mDisplayContent == null 209 || mDisplayContent.getDockedStackLocked() != null) { 210 return true; 211 } 212 return false; 213 } 214 215 /** Bounds of the stack with other system factors taken into consideration. */ 216 @Override 217 public void getBounds(Rect out) { 218 if (useCurrentBounds()) { 219 // No need to adjust the output bounds if fullscreen or the docked stack is visible 220 // since it is already what we want to represent to the rest of the system. 221 out.set(mBounds); 222 return; 223 } 224 225 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack 226 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the 227 // system. 228 mDisplayContent.getLogicalDisplayRect(out); 229 } 230 231 void updateDisplayInfo(Rect bounds) { 232 if (mDisplayContent != null) { 233 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 234 mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent); 235 } 236 if (bounds != null) { 237 setBounds(bounds); 238 } else if (mFullscreen) { 239 setBounds(null); 240 } else { 241 mTmpRect2.set(mBounds); 242 mDisplayContent.rotateBounds( 243 mRotation, mDisplayContent.getDisplayInfo().rotation, mTmpRect2); 244 if (setBounds(mTmpRect2)) { 245 // Post message to inform activity manager of the bounds change simulating 246 // a one-way call. We do this to prevent a deadlock between window manager 247 // lock and activity manager lock been held. 248 mService.mH.sendMessage(mService.mH.obtainMessage( 249 RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mBounds)); 250 } 251 } 252 } 253 } 254 255 boolean isAnimating() { 256 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 257 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; 258 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 259 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; 260 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 261 final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator; 262 if (winAnimator.isAnimating() || winAnimator.mWin.mExiting) { 263 return true; 264 } 265 } 266 } 267 } 268 return false; 269 } 270 271 void addTask(Task task, boolean toTop) { 272 addTask(task, toTop, task.showForAllUsers()); 273 } 274 275 /** 276 * Put a Task in this stack. Used for adding and moving. 277 * @param task The task to add. 278 * @param toTop Whether to add it to the top or bottom. 279 * @param showForAllUsers Whether to show the task regardless of the current user. 280 */ 281 void addTask(Task task, boolean toTop, boolean showForAllUsers) { 282 positionTask(task, toTop ? mTasks.size() : 0, showForAllUsers); 283 } 284 285 void positionTask(Task task, int position, boolean showForAllUsers) { 286 final boolean canShowTask = 287 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId); 288 mTasks.remove(task); 289 int stackSize = mTasks.size(); 290 int minPosition = 0; 291 int maxPosition = stackSize; 292 293 if (canShowTask) { 294 minPosition = computeMinPosition(minPosition, stackSize); 295 } else { 296 maxPosition = computeMaxPosition(maxPosition); 297 } 298 // Reset position based on minimum/maximum possible positions. 299 position = Math.min(Math.max(position, minPosition), maxPosition); 300 301 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, 302 "positionTask: task=" + task + " position=" + position); 303 mTasks.add(position, task); 304 305 task.mStack = this; 306 task.updateDisplayInfo(mDisplayContent); 307 boolean toTop = position == mTasks.size() - 1; 308 if (toTop) { 309 mDisplayContent.moveStack(this, true); 310 } 311 EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, position); 312 } 313 314 /** Calculate the minimum possible position for a task that can be shown to the user. 315 * The minimum position will be above all other tasks that can't be shown. 316 * @param minPosition The minimum position the caller is suggesting. 317 * We will start adjusting up from here. 318 * @param size The size of the current task list. 319 */ 320 private int computeMinPosition(int minPosition, int size) { 321 while (minPosition < size) { 322 final Task tmpTask = mTasks.get(minPosition); 323 final boolean canShowTmpTask = 324 tmpTask.showForAllUsers() 325 || mService.isCurrentProfileLocked(tmpTask.mUserId); 326 if (canShowTmpTask) { 327 break; 328 } 329 minPosition++; 330 } 331 return minPosition; 332 } 333 334 /** Calculate the maximum possible position for a task that can't be shown to the user. 335 * The maximum position will be below all other tasks that can be shown. 336 * @param maxPosition The maximum position the caller is suggesting. 337 * We will start adjusting down from here. 338 */ 339 private int computeMaxPosition(int maxPosition) { 340 while (maxPosition > 0) { 341 final Task tmpTask = mTasks.get(maxPosition - 1); 342 final boolean canShowTmpTask = 343 tmpTask.showForAllUsers() 344 || mService.isCurrentProfileLocked(tmpTask.mUserId); 345 if (!canShowTmpTask) { 346 break; 347 } 348 maxPosition--; 349 } 350 return maxPosition; 351 } 352 353 void moveTaskToTop(Task task) { 354 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToTop: task=" + task + " Callers=" 355 + Debug.getCallers(6)); 356 mTasks.remove(task); 357 addTask(task, true); 358 } 359 360 void moveTaskToBottom(Task task) { 361 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToBottom: task=" + task); 362 mTasks.remove(task); 363 addTask(task, false); 364 } 365 366 /** 367 * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the 368 * back. 369 * @param task The Task to delete. 370 */ 371 void removeTask(Task task) { 372 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task); 373 mTasks.remove(task); 374 if (mDisplayContent != null) { 375 if (mTasks.isEmpty()) { 376 mDisplayContent.moveStack(this, false); 377 } 378 mDisplayContent.layoutNeeded = true; 379 } 380 for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) { 381 final AppWindowToken wtoken = mExitingAppTokens.get(appNdx); 382 if (wtoken.mTask == task) { 383 wtoken.mIsExiting = false; 384 mExitingAppTokens.remove(appNdx); 385 } 386 } 387 } 388 389 void attachDisplayContent(DisplayContent displayContent) { 390 if (mDisplayContent != null) { 391 throw new IllegalStateException("attachDisplayContent: Already attached"); 392 } 393 394 mDisplayContent = displayContent; 395 mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId()); 396 397 Rect bounds = null; 398 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID); 399 if (mStackId == DOCKED_STACK_ID || (dockedStack != null && mStackId != PINNED_STACK_ID 400 && mStackId >= FIRST_STATIC_STACK_ID && mStackId <= LAST_STATIC_STACK_ID)) { 401 // The existence of a docked stack affects the size of any static stack created since 402 // the docked stack occupies a dedicated region on screen. 403 bounds = new Rect(); 404 displayContent.getLogicalDisplayRect(mTmpRect); 405 mTmpRect2.setEmpty(); 406 if (dockedStack != null) { 407 dockedStack.getRawBounds(mTmpRect2); 408 } 409 final boolean dockedOnTopOrLeft = WindowManagerService.sDockedStackCreateMode 410 == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; 411 getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2, 412 mDisplayContent.mDividerControllerLocked.getWidthAdjustment(), 413 dockedOnTopOrLeft); 414 } 415 416 updateDisplayInfo(bounds); 417 418 if (mStackId == DOCKED_STACK_ID) { 419 // Attaching a docked stack to the display affects the size of all other static 420 // stacks since the docked stack occupies a dedicated region on screen. 421 // Resize existing static stacks so they are pushed to the side of the docked stack. 422 resizeNonDockedStacks(!FULLSCREEN, mBounds); 423 } 424 } 425 426 void getStackDockedModeBoundsLocked(Rect outBounds) { 427 if (mStackId == DOCKED_STACK_ID 428 || mStackId == PINNED_STACK_ID 429 || mStackId > LAST_STATIC_STACK_ID 430 || mDisplayContent == null) { 431 outBounds.set(mBounds); 432 return; 433 } 434 435 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID); 436 if (dockedStack == null) { 437 // Not sure why you are calling this method when there is no docked stack... 438 throw new IllegalStateException( 439 "Calling getStackDockedModeBoundsLocked() when there is no docked stack."); 440 } 441 if (!dockedStack.isVisibleLocked()) { 442 // The docked stack is being dismissed, but we caught before it finished being 443 // dismissed. In that case we want to treat it as if it is not occupying any space and 444 // let others occupy the whole display. 445 mDisplayContent.getLogicalDisplayRect(mTmpRect); 446 return; 447 } 448 449 @DockSide 450 final int dockedSide = dockedStack.getDockSide(); 451 if (dockedSide == DOCKED_INVALID) { 452 // Not sure how you got here...Only thing we can do is return current bounds. 453 Slog.e(TAG, "Failed to get valid docked side for docked stack=" + dockedStack); 454 outBounds.set(mBounds); 455 return; 456 } 457 458 mDisplayContent.getLogicalDisplayRect(mTmpRect); 459 dockedStack.getRawBounds(mTmpRect2); 460 final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT; 461 getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2, 462 mDisplayContent.mDividerControllerLocked.getWidthAdjustment(), dockedOnTopOrLeft); 463 464 } 465 466 /** 467 * Outputs the bounds a stack should be given the presence of a docked stack on the display. 468 * @param displayRect The bounds of the display the docked stack is on. 469 * @param outBounds Output bounds that should be used for the stack. 470 * @param stackId Id of stack we are calculating the bounds for. 471 * @param dockedBounds Bounds of the docked stack. 472 * @param adjustment Additional adjustment to make to the output bounds close to the side of the 473 * dock. 474 * @param dockOntopOrLeft If the docked stack is on the top or left side of the screen. 475 */ 476 private static void getStackDockedModeBounds( 477 Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int adjustment, 478 boolean dockOntopOrLeft) { 479 final boolean dockedStack = stackId == DOCKED_STACK_ID; 480 final boolean splitHorizontally = displayRect.width() > displayRect.height(); 481 482 outBounds.set(displayRect); 483 if (dockedStack) { 484 // The initial bounds of the docked stack when it is created half the screen space and 485 // its bounds can be adjusted after that. The bounds of all other stacks are adjusted 486 // to occupy whatever screen space the docked stack isn't occupying. 487 if (dockOntopOrLeft) { 488 if (splitHorizontally) { 489 outBounds.right = displayRect.centerX() - adjustment; 490 } else { 491 outBounds.bottom = displayRect.centerY() - adjustment; 492 } 493 } else { 494 if (splitHorizontally) { 495 outBounds.left = displayRect.centerX() + adjustment; 496 } else { 497 outBounds.top = displayRect.centerY() + adjustment; 498 } 499 } 500 return; 501 } 502 503 // Other stacks occupy whatever space is left by the docked stack. 504 if (!dockOntopOrLeft) { 505 if (splitHorizontally) { 506 outBounds.right = dockedBounds.left - adjustment; 507 } else { 508 outBounds.bottom = dockedBounds.top - adjustment; 509 } 510 } else { 511 if (splitHorizontally) { 512 outBounds.left = dockedBounds.right + adjustment; 513 } else { 514 outBounds.top = dockedBounds.bottom + adjustment; 515 } 516 } 517 } 518 519 /** Resizes all non-docked stacks in the system to either fullscreen or the appropriate size 520 * based on the presence of a docked stack. 521 * @param fullscreen If true the stacks will be resized to fullscreen, else they will be 522 * resized to the appropriate size based on the presence of a docked stack. 523 * @param dockedBounds Bounds of the docked stack. 524 */ 525 private void resizeNonDockedStacks(boolean fullscreen, Rect dockedBounds) { 526 // Not using mTmpRect because we are posting the object in a message. 527 final Rect bounds = new Rect(); 528 mDisplayContent.getLogicalDisplayRect(bounds); 529 if (!fullscreen) { 530 final boolean dockedOnTopOrLeft = WindowManagerService.sDockedStackCreateMode 531 == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; 532 getStackDockedModeBounds(bounds, bounds, FULLSCREEN_WORKSPACE_STACK_ID, dockedBounds, 533 mDisplayContent.mDividerControllerLocked.getWidth(), dockedOnTopOrLeft); 534 } 535 536 final int count = mService.mStackIdToStack.size(); 537 for (int i = 0; i < count; i++) { 538 final TaskStack otherStack = mService.mStackIdToStack.valueAt(i); 539 final int otherStackId = otherStack.mStackId; 540 if (otherStackId != DOCKED_STACK_ID && mStackId != PINNED_STACK_ID 541 && otherStackId >= FIRST_STATIC_STACK_ID 542 && otherStackId <= LAST_STATIC_STACK_ID) { 543 mService.mH.sendMessage( 544 mService.mH.obtainMessage(RESIZE_STACK, otherStackId, 545 1 /*allowResizeInDockedMode*/, bounds)); 546 } 547 } 548 } 549 550 void detachDisplay() { 551 EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); 552 553 boolean doAnotherLayoutPass = false; 554 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 555 final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens; 556 for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) { 557 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows; 558 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) { 559 // We are in the middle of changing the state of displays/stacks/tasks. We need 560 // to finish that, before we let layout interfere with it. 561 mService.removeWindowLocked(appWindows.get(winNdx)); 562 doAnotherLayoutPass = true; 563 } 564 } 565 } 566 if (doAnotherLayoutPass) { 567 mService.mWindowPlacerLocked.requestTraversal(); 568 } 569 570 if (mStackId == DOCKED_STACK_ID) { 571 // Docked stack was detached from the display, so we no longer need to restrict the 572 // region of the screen other static stacks occupy. Go ahead and make them fullscreen. 573 resizeNonDockedStacks(FULLSCREEN, null); 574 } 575 576 close(); 577 } 578 579 void resetAnimationBackgroundAnimator() { 580 mAnimationBackgroundAnimator = null; 581 mAnimationBackgroundSurface.hide(); 582 } 583 584 void setAnimationBackground(WindowStateAnimator winAnimator, int color) { 585 int animLayer = winAnimator.mAnimLayer; 586 if (mAnimationBackgroundAnimator == null 587 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) { 588 mAnimationBackgroundAnimator = winAnimator; 589 animLayer = mService.adjustAnimationBackground(winAnimator); 590 mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM, 591 ((color >> 24) & 0xff) / 255f, 0); 592 } 593 } 594 595 void switchUser() { 596 int top = mTasks.size(); 597 for (int taskNdx = 0; taskNdx < top; ++taskNdx) { 598 Task task = mTasks.get(taskNdx); 599 if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) { 600 mTasks.remove(taskNdx); 601 mTasks.add(task); 602 --top; 603 } 604 } 605 } 606 607 void close() { 608 if (mAnimationBackgroundSurface != null) { 609 mAnimationBackgroundSurface.destroySurface(); 610 mAnimationBackgroundSurface = null; 611 } 612 mDisplayContent = null; 613 } 614 615 public void dump(String prefix, PrintWriter pw) { 616 pw.print(prefix); pw.print("mStackId="); pw.println(mStackId); 617 pw.print(prefix); pw.print("mDeferDetach="); pw.println(mDeferDetach); 618 for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) { 619 pw.print(prefix); 620 mTasks.get(taskNdx).printTo(prefix + " ", pw); 621 } 622 if (mAnimationBackgroundSurface.isDimming()) { 623 pw.print(prefix); pw.println("mWindowAnimationBackgroundSurface:"); 624 mAnimationBackgroundSurface.printTo(prefix + " ", pw); 625 } 626 if (!mExitingAppTokens.isEmpty()) { 627 pw.println(); 628 pw.println(" Exiting application tokens:"); 629 for (int i = mExitingAppTokens.size() - 1; i >= 0; i--) { 630 WindowToken token = mExitingAppTokens.get(i); 631 pw.print(" Exiting App #"); pw.print(i); 632 pw.print(' '); pw.print(token); 633 pw.println(':'); 634 token.dump(pw, " "); 635 } 636 } 637 } 638 639 /** Fullscreen status of the stack without adjusting for other factors in the system like 640 * visibility of docked stack. 641 * Most callers should be using {@link #isFullscreen} as it take into consideration other 642 * system factors. */ 643 boolean getRawFullscreen() { 644 return mFullscreen; 645 } 646 647 @Override 648 public boolean isFullscreen() { 649 if (useCurrentBounds()) { 650 return mFullscreen; 651 } 652 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack 653 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the 654 // system. 655 return true; 656 } 657 658 @Override 659 public DisplayInfo getDisplayInfo() { 660 return mDisplayContent.getDisplayInfo(); 661 } 662 663 @Override 664 public String toString() { 665 return "{stackId=" + mStackId + " tasks=" + mTasks + "}"; 666 } 667 668 @Override 669 public String toShortString() { 670 return "Stack=" + mStackId; 671 } 672 673 /** 674 * For docked workspace provides information which side of the screen was the dock anchored. 675 */ 676 @DockSide 677 int getDockSide() { 678 if (mStackId != DOCKED_STACK_ID) { 679 return DOCKED_INVALID; 680 } 681 if (mDisplayContent == null) { 682 return DOCKED_INVALID; 683 } 684 mDisplayContent.getLogicalDisplayRect(mTmpRect); 685 final int orientation = mService.mCurConfiguration.orientation; 686 if (orientation == Configuration.ORIENTATION_PORTRAIT) { 687 // Portrait mode, docked either at the top or the bottom. 688 if (mBounds.top - mTmpRect.top < mTmpRect.bottom - mBounds.bottom) { 689 return DOCKED_TOP; 690 } else { 691 return DOCKED_BOTTOM; 692 } 693 } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 694 // Landscape mode, docked either on the left or on the right. 695 if (mBounds.left - mTmpRect.left < mTmpRect.right - mBounds.right) { 696 return DOCKED_LEFT; 697 } else { 698 return DOCKED_RIGHT; 699 } 700 } else { 701 return DOCKED_INVALID; 702 } 703 } 704 705 boolean isVisibleLocked() { 706 for (int i = mTasks.size() - 1; i >= 0; i--) { 707 Task task = mTasks.get(i); 708 for (int j = task.mAppTokens.size() - 1; j >= 0; j--) { 709 if (!task.mAppTokens.get(j).hidden) { 710 return true; 711 } 712 } 713 } 714 return false; 715 } 716} 717