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.RESIZE_MODE_SYSTEM_SCREEN_ROTATION; 20import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; 21import static android.app.ActivityManager.StackId.PINNED_STACK_ID; 22import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; 23import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; 24import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 25import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 26import static com.android.server.EventLogTags.WM_TASK_REMOVED; 27import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; 28import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 29import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 30 31import android.app.ActivityManager.StackId; 32import android.app.ActivityManager.TaskDescription; 33import android.content.pm.ActivityInfo; 34import android.content.res.Configuration; 35import android.graphics.Rect; 36import android.util.EventLog; 37import android.util.Slog; 38import android.view.DisplayInfo; 39import android.view.Surface; 40 41import com.android.internal.annotations.VisibleForTesting; 42 43import java.io.PrintWriter; 44import java.util.function.Consumer; 45 46class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerUser { 47 static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM; 48 // Return value from {@link setBounds} indicating no change was made to the Task bounds. 49 private static final int BOUNDS_CHANGE_NONE = 0; 50 // Return value from {@link setBounds} indicating the position of the Task bounds changed. 51 private static final int BOUNDS_CHANGE_POSITION = 1; 52 // Return value from {@link setBounds} indicating the size of the Task bounds changed. 53 private static final int BOUNDS_CHANGE_SIZE = 1 << 1; 54 55 // TODO: Track parent marks like this in WindowContainer. 56 TaskStack mStack; 57 final int mTaskId; 58 final int mUserId; 59 private boolean mDeferRemoval = false; 60 final WindowManagerService mService; 61 62 // Content limits relative to the DisplayContent this sits in. 63 private Rect mBounds = new Rect(); 64 final Rect mPreparedFrozenBounds = new Rect(); 65 final Configuration mPreparedFrozenMergedConfig = new Configuration(); 66 67 // Bounds used to calculate the insets. 68 private final Rect mTempInsetBounds = new Rect(); 69 70 // Device rotation as of the last time {@link #mBounds} was set. 71 private int mRotation; 72 73 // Whether mBounds is fullscreen 74 private boolean mFillsParent = true; 75 76 // For comparison with DisplayContent bounds. 77 private Rect mTmpRect = new Rect(); 78 // For handling display rotations. 79 private Rect mTmpRect2 = new Rect(); 80 81 // Resize mode of the task. See {@link ActivityInfo#resizeMode} 82 private int mResizeMode; 83 84 // Whether the task supports picture-in-picture. 85 // See {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} 86 private boolean mSupportsPictureInPicture; 87 88 // Whether the task is currently being drag-resized 89 private boolean mDragResizing; 90 private int mDragResizeMode; 91 92 private boolean mHomeTask; 93 94 private TaskDescription mTaskDescription; 95 96 // If set to true, the task will report that it is not in the floating 97 // state regardless of it's stack affilation. As the floating state drives 98 // production of content insets this can be used to preserve them across 99 // stack moves and we in fact do so when moving from full screen to pinned. 100 private boolean mPreserveNonFloatingState = false; 101 102 Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, 103 Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, 104 boolean homeTask, TaskDescription taskDescription, 105 TaskWindowContainerController controller) { 106 mTaskId = taskId; 107 mStack = stack; 108 mUserId = userId; 109 mService = service; 110 mResizeMode = resizeMode; 111 mSupportsPictureInPicture = supportsPictureInPicture; 112 mHomeTask = homeTask; 113 setController(controller); 114 setBounds(bounds, overrideConfig); 115 mTaskDescription = taskDescription; 116 117 // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED). 118 setOrientation(SCREEN_ORIENTATION_UNSET); 119 } 120 121 DisplayContent getDisplayContent() { 122 return mStack != null ? mStack.getDisplayContent() : null; 123 } 124 125 private int getAdjustedAddPosition(int suggestedPosition) { 126 final int size = mChildren.size(); 127 if (suggestedPosition >= size) { 128 return Math.min(size, suggestedPosition); 129 } 130 131 for (int pos = 0; pos < size && pos < suggestedPosition; ++pos) { 132 // TODO: Confirm that this is the behavior we want long term. 133 if (mChildren.get(pos).removed) { 134 // suggestedPosition assumes removed tokens are actually gone. 135 ++suggestedPosition; 136 } 137 } 138 return Math.min(size, suggestedPosition); 139 } 140 141 @Override 142 void addChild(AppWindowToken wtoken, int position) { 143 position = getAdjustedAddPosition(position); 144 super.addChild(wtoken, position); 145 mDeferRemoval = false; 146 } 147 148 @Override 149 void positionChildAt(int position, AppWindowToken child, boolean includingParents) { 150 position = getAdjustedAddPosition(position); 151 super.positionChildAt(position, child, includingParents); 152 mDeferRemoval = false; 153 } 154 155 private boolean hasWindowsAlive() { 156 for (int i = mChildren.size() - 1; i >= 0; i--) { 157 if (mChildren.get(i).hasWindowsAlive()) { 158 return true; 159 } 160 } 161 return false; 162 } 163 164 @VisibleForTesting 165 boolean shouldDeferRemoval() { 166 // TODO: This should probably return false if mChildren.isEmpty() regardless if the stack 167 // is animating... 168 return hasWindowsAlive() && mStack.isAnimating(); 169 } 170 171 @Override 172 void removeIfPossible() { 173 if (shouldDeferRemoval()) { 174 if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId); 175 mDeferRemoval = true; 176 return; 177 } 178 removeImmediately(); 179 } 180 181 @Override 182 void removeImmediately() { 183 if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId); 184 EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask"); 185 mDeferRemoval = false; 186 187 // Make sure to remove dim layer user first before removing task its from parent. 188 DisplayContent content = getDisplayContent(); 189 if (content != null) { 190 content.mDimLayerController.removeDimLayerUser(this); 191 } 192 193 super.removeImmediately(); 194 } 195 196 void reparent(TaskStack stack, int position, boolean moveParents) { 197 if (stack == mStack) { 198 throw new IllegalArgumentException( 199 "task=" + this + " already child of stack=" + mStack); 200 } 201 if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId 202 + " from stack=" + mStack); 203 EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask"); 204 final DisplayContent prevDisplayContent = getDisplayContent(); 205 206 // If we are moving from the fullscreen stack to the pinned stack 207 // then we want to preserve our insets so that there will not 208 // be a jump in the area covered by system decorations. We rely 209 // on the pinned animation to later unset this value. 210 if (stack.mStackId == PINNED_STACK_ID) { 211 mPreserveNonFloatingState = true; 212 } else { 213 mPreserveNonFloatingState = false; 214 } 215 216 getParent().removeChild(this); 217 stack.addTask(this, position, showForAllUsers(), moveParents); 218 219 // Relayout display(s). 220 final DisplayContent displayContent = stack.getDisplayContent(); 221 displayContent.setLayoutNeeded(); 222 if (prevDisplayContent != displayContent) { 223 onDisplayChanged(displayContent); 224 prevDisplayContent.setLayoutNeeded(); 225 } 226 } 227 228 /** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */ 229 void positionAt(int position, Rect bounds, Configuration overrideConfig) { 230 mStack.positionChildAt(position, this, false /* includingParents */); 231 resizeLocked(bounds, overrideConfig, false /* force */); 232 } 233 234 @Override 235 void onParentSet() { 236 // Update task bounds if needed. 237 updateDisplayInfo(getDisplayContent()); 238 239 if (StackId.windowsAreScaleable(mStack.mStackId)) { 240 // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them 241 // while a resize is pending. 242 forceWindowsScaleable(true /* force */); 243 } else { 244 forceWindowsScaleable(false /* force */); 245 } 246 } 247 248 @Override 249 void removeChild(AppWindowToken token) { 250 if (!mChildren.contains(token)) { 251 Slog.e(TAG, "removeChild: token=" + this + " not found."); 252 return; 253 } 254 255 super.removeChild(token); 256 257 if (mChildren.isEmpty()) { 258 EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeAppToken: last token"); 259 if (mDeferRemoval) { 260 removeIfPossible(); 261 } 262 } 263 } 264 265 void setSendingToBottom(boolean toBottom) { 266 for (int appTokenNdx = 0; appTokenNdx < mChildren.size(); appTokenNdx++) { 267 mChildren.get(appTokenNdx).sendingToBottom = toBottom; 268 } 269 } 270 271 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */ 272 private int setBounds(Rect bounds, Configuration overrideConfig) { 273 if (overrideConfig == null) { 274 overrideConfig = Configuration.EMPTY; 275 } 276 if (bounds == null && !Configuration.EMPTY.equals(overrideConfig)) { 277 throw new IllegalArgumentException("null bounds but non empty configuration: " 278 + overrideConfig); 279 } 280 if (bounds != null && Configuration.EMPTY.equals(overrideConfig)) { 281 throw new IllegalArgumentException("non null bounds, but empty configuration"); 282 } 283 boolean oldFullscreen = mFillsParent; 284 int rotation = Surface.ROTATION_0; 285 final DisplayContent displayContent = mStack.getDisplayContent(); 286 if (displayContent != null) { 287 displayContent.getLogicalDisplayRect(mTmpRect); 288 rotation = displayContent.getDisplayInfo().rotation; 289 mFillsParent = bounds == null; 290 if (mFillsParent) { 291 bounds = mTmpRect; 292 } 293 } 294 295 if (bounds == null) { 296 // Can't set to fullscreen if we don't have a display to get bounds from... 297 return BOUNDS_CHANGE_NONE; 298 } 299 if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) { 300 return BOUNDS_CHANGE_NONE; 301 } 302 303 int boundsChange = BOUNDS_CHANGE_NONE; 304 if (mBounds.left != bounds.left || mBounds.top != bounds.top) { 305 boundsChange |= BOUNDS_CHANGE_POSITION; 306 } 307 if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) { 308 boundsChange |= BOUNDS_CHANGE_SIZE; 309 } 310 311 mBounds.set(bounds); 312 313 mRotation = rotation; 314 if (displayContent != null) { 315 displayContent.mDimLayerController.updateDimLayer(this); 316 } 317 onOverrideConfigurationChanged(mFillsParent ? Configuration.EMPTY : overrideConfig); 318 return boundsChange; 319 } 320 321 /** 322 * Sets the bounds used to calculate the insets. See 323 * {@link android.app.IActivityManager#resizeDockedStack} why this is needed. 324 */ 325 void setTempInsetBounds(Rect tempInsetBounds) { 326 if (tempInsetBounds != null) { 327 mTempInsetBounds.set(tempInsetBounds); 328 } else { 329 mTempInsetBounds.setEmpty(); 330 } 331 } 332 333 /** 334 * Gets the bounds used to calculate the insets. See 335 * {@link android.app.IActivityManager#resizeDockedStack} why this is needed. 336 */ 337 void getTempInsetBounds(Rect out) { 338 out.set(mTempInsetBounds); 339 } 340 341 void setResizeable(int resizeMode) { 342 mResizeMode = resizeMode; 343 } 344 345 boolean isResizeable() { 346 return ActivityInfo.isResizeableMode(mResizeMode) || mSupportsPictureInPicture 347 || mService.mForceResizableTasks; 348 } 349 350 /** 351 * Tests if the orientation should be preserved upon user interactive resizig operations. 352 353 * @return true if orientation should not get changed upon resizing operation. 354 */ 355 boolean preserveOrientationOnResize() { 356 return mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY 357 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY 358 || mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; 359 } 360 361 boolean cropWindowsToStackBounds() { 362 return isResizeable(); 363 } 364 365 boolean isHomeTask() { 366 return mHomeTask; 367 } 368 369 boolean resizeLocked(Rect bounds, Configuration overrideConfig, boolean forced) { 370 int boundsChanged = setBounds(bounds, overrideConfig); 371 if (forced) { 372 boundsChanged |= BOUNDS_CHANGE_SIZE; 373 } 374 if (boundsChanged == BOUNDS_CHANGE_NONE) { 375 return false; 376 } 377 if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) { 378 onResize(); 379 } else { 380 onMovedByResize(); 381 } 382 return true; 383 } 384 385 /** 386 * Prepares the task bounds to be frozen with the current size. See 387 * {@link AppWindowToken#freezeBounds}. 388 */ 389 void prepareFreezingBounds() { 390 mPreparedFrozenBounds.set(mBounds); 391 mPreparedFrozenMergedConfig.setTo(getConfiguration()); 392 } 393 394 /** 395 * Align the task to the adjusted bounds. 396 * 397 * @param adjustedBounds Adjusted bounds to which the task should be aligned. 398 * @param tempInsetBounds Insets bounds for the task. 399 * @param alignBottom True if the task's bottom should be aligned to the adjusted 400 * bounds's bottom; false if the task's top should be aligned 401 * the adjusted bounds's top. 402 */ 403 void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) { 404 if (!isResizeable() || Configuration.EMPTY.equals(getOverrideConfiguration())) { 405 return; 406 } 407 408 getBounds(mTmpRect2); 409 if (alignBottom) { 410 int offsetY = adjustedBounds.bottom - mTmpRect2.bottom; 411 mTmpRect2.offset(0, offsetY); 412 } else { 413 mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top); 414 } 415 setTempInsetBounds(tempInsetBounds); 416 resizeLocked(mTmpRect2, getOverrideConfiguration(), false /* forced */); 417 } 418 419 /** Return true if the current bound can get outputted to the rest of the system as-is. */ 420 private boolean useCurrentBounds() { 421 final DisplayContent displayContent = mStack.getDisplayContent(); 422 return mFillsParent 423 || !StackId.isTaskResizeableByDockedStack(mStack.mStackId) 424 || displayContent == null 425 || displayContent.getDockedStackIgnoringVisibility() != null; 426 } 427 428 /** Original bounds of the task if applicable, otherwise fullscreen rect. */ 429 void getBounds(Rect out) { 430 if (useCurrentBounds()) { 431 // No need to adjust the output bounds if fullscreen or the docked stack is visible 432 // since it is already what we want to represent to the rest of the system. 433 out.set(mBounds); 434 return; 435 } 436 437 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is 438 // not currently visible. Go ahead a represent it as fullscreen to the rest of the system. 439 mStack.getDisplayContent().getLogicalDisplayRect(out); 440 } 441 442 /** 443 * Calculate the maximum visible area of this task. If the task has only one app, 444 * the result will be visible frame of that app. If the task has more than one apps, 445 * we search from top down if the next app got different visible area. 446 * 447 * This effort is to handle the case where some task (eg. GMail composer) might pop up 448 * a dialog that's different in size from the activity below, in which case we should 449 * be dimming the entire task area behind the dialog. 450 * 451 * @param out Rect containing the max visible bounds. 452 * @return true if the task has some visible app windows; false otherwise. 453 */ 454 boolean getMaxVisibleBounds(Rect out) { 455 boolean foundTop = false; 456 for (int i = mChildren.size() - 1; i >= 0; i--) { 457 final AppWindowToken token = mChildren.get(i); 458 // skip hidden (or about to hide) apps 459 if (token.mIsExiting || token.isClientHidden() || token.hiddenRequested) { 460 continue; 461 } 462 final WindowState win = token.findMainWindow(); 463 if (win == null) { 464 continue; 465 } 466 if (!foundTop) { 467 out.set(win.mVisibleFrame); 468 foundTop = true; 469 continue; 470 } 471 if (win.mVisibleFrame.left < out.left) { 472 out.left = win.mVisibleFrame.left; 473 } 474 if (win.mVisibleFrame.top < out.top) { 475 out.top = win.mVisibleFrame.top; 476 } 477 if (win.mVisibleFrame.right > out.right) { 478 out.right = win.mVisibleFrame.right; 479 } 480 if (win.mVisibleFrame.bottom > out.bottom) { 481 out.bottom = win.mVisibleFrame.bottom; 482 } 483 } 484 return foundTop; 485 } 486 487 /** Bounds of the task to be used for dimming, as well as touch related tests. */ 488 @Override 489 public void getDimBounds(Rect out) { 490 final DisplayContent displayContent = mStack.getDisplayContent(); 491 // It doesn't matter if we in particular are part of the resize, since we couldn't have 492 // a DimLayer anyway if we weren't visible. 493 final boolean dockedResizing = displayContent != null 494 && displayContent.mDividerControllerLocked.isResizing(); 495 if (useCurrentBounds()) { 496 if (inFreeformWorkspace() && getMaxVisibleBounds(out)) { 497 return; 498 } 499 500 if (!mFillsParent) { 501 // When minimizing the docked stack when going home, we don't adjust the task bounds 502 // so we need to intersect the task bounds with the stack bounds here. 503 // 504 // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack 505 // bounds and so we don't even want to use them. Even if the app should not be resized the Dim 506 // should keep up with the divider. 507 if (dockedResizing) { 508 mStack.getBounds(out); 509 } else { 510 mStack.getBounds(mTmpRect); 511 mTmpRect.intersect(mBounds); 512 } 513 out.set(mTmpRect); 514 } else { 515 out.set(mBounds); 516 } 517 return; 518 } 519 520 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is 521 // not currently visible. Go ahead a represent it as fullscreen to the rest of the system. 522 if (displayContent != null) { 523 displayContent.getLogicalDisplayRect(out); 524 } 525 } 526 527 void setDragResizing(boolean dragResizing, int dragResizeMode) { 528 if (mDragResizing != dragResizing) { 529 if (!DragResizeMode.isModeAllowedForStack(mStack.mStackId, dragResizeMode)) { 530 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId=" 531 + mStack.mStackId + " dragResizeMode=" + dragResizeMode); 532 } 533 mDragResizing = dragResizing; 534 mDragResizeMode = dragResizeMode; 535 resetDragResizingChangeReported(); 536 } 537 } 538 539 boolean isDragResizing() { 540 return mDragResizing; 541 } 542 543 int getDragResizeMode() { 544 return mDragResizeMode; 545 } 546 547 void updateDisplayInfo(final DisplayContent displayContent) { 548 if (displayContent == null) { 549 return; 550 } 551 if (mFillsParent) { 552 setBounds(null, Configuration.EMPTY); 553 return; 554 } 555 final int newRotation = displayContent.getDisplayInfo().rotation; 556 if (mRotation == newRotation) { 557 return; 558 } 559 560 // Device rotation changed. 561 // - We don't want the task to move around on the screen when this happens, so update the 562 // task bounds so it stays in the same place. 563 // - Rotate the bounds and notify activity manager if the task can be resized independently 564 // from its stack. The stack will take care of task rotation for the other case. 565 mTmpRect2.set(mBounds); 566 567 if (!StackId.isTaskResizeAllowed(mStack.mStackId)) { 568 setBounds(mTmpRect2, getOverrideConfiguration()); 569 return; 570 } 571 572 displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); 573 if (setBounds(mTmpRect2, getOverrideConfiguration()) != BOUNDS_CHANGE_NONE) { 574 final TaskWindowContainerController controller = getController(); 575 if (controller != null) { 576 controller.requestResize(mBounds, RESIZE_MODE_SYSTEM_SCREEN_ROTATION); 577 } 578 } 579 } 580 581 /** Cancels any running app transitions associated with the task. */ 582 void cancelTaskWindowTransition() { 583 for (int i = mChildren.size() - 1; i >= 0; --i) { 584 mChildren.get(i).mAppAnimator.clearAnimation(); 585 } 586 } 587 588 /** Cancels any running thumbnail transitions associated with the task. */ 589 void cancelTaskThumbnailTransition() { 590 for (int i = mChildren.size() - 1; i >= 0; --i) { 591 mChildren.get(i).mAppAnimator.clearThumbnail(); 592 } 593 } 594 595 boolean showForAllUsers() { 596 final int tokensCount = mChildren.size(); 597 return (tokensCount != 0) && mChildren.get(tokensCount - 1).mShowForAllUsers; 598 } 599 600 boolean inFreeformWorkspace() { 601 return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID; 602 } 603 604 boolean inPinnedWorkspace() { 605 return mStack != null && mStack.mStackId == PINNED_STACK_ID; 606 } 607 608 /** 609 * When we are in a floating stack (Freeform, Pinned, ...) we calculate 610 * insets differently. However if we are animating to the fullscreen stack 611 * we need to begin calculating insets as if we were fullscreen, otherwise 612 * we will have a jump at the end. 613 */ 614 boolean isFloating() { 615 return StackId.tasksAreFloating(mStack.mStackId) 616 && !mStack.isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState; 617 } 618 619 WindowState getTopVisibleAppMainWindow() { 620 final AppWindowToken token = getTopVisibleAppToken(); 621 return token != null ? token.findMainWindow() : null; 622 } 623 624 AppWindowToken getTopVisibleAppToken() { 625 for (int i = mChildren.size() - 1; i >= 0; i--) { 626 final AppWindowToken token = mChildren.get(i); 627 // skip hidden (or about to hide) apps 628 if (!token.mIsExiting && !token.isClientHidden() && !token.hiddenRequested) { 629 return token; 630 } 631 } 632 return null; 633 } 634 635 @Override 636 public boolean dimFullscreen() { 637 return isFullscreen(); 638 } 639 640 boolean isFullscreen() { 641 if (useCurrentBounds()) { 642 return mFillsParent; 643 } 644 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack 645 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the 646 // system. 647 return true; 648 } 649 650 @Override 651 public DisplayInfo getDisplayInfo() { 652 return getDisplayContent().getDisplayInfo(); 653 } 654 655 @Override 656 public boolean isAttachedToDisplay() { 657 return getDisplayContent() != null; 658 } 659 660 void forceWindowsScaleable(boolean force) { 661 mService.openSurfaceTransaction(); 662 try { 663 for (int i = mChildren.size() - 1; i >= 0; i--) { 664 mChildren.get(i).forceWindowsScaleableInTransaction(force); 665 } 666 } finally { 667 mService.closeSurfaceTransaction(); 668 } 669 } 670 671 void setTaskDescription(TaskDescription taskDescription) { 672 mTaskDescription = taskDescription; 673 } 674 675 TaskDescription getTaskDescription() { 676 return mTaskDescription; 677 } 678 679 @Override 680 boolean fillsParent() { 681 return mFillsParent || !StackId.isTaskResizeAllowed(mStack.mStackId); 682 } 683 684 @Override 685 TaskWindowContainerController getController() { 686 return (TaskWindowContainerController) super.getController(); 687 } 688 689 @Override 690 void forAllTasks(Consumer<Task> callback) { 691 callback.accept(this); 692 } 693 694 @Override 695 public String toString() { 696 return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}"; 697 } 698 699 String getName() { 700 return toShortString(); 701 } 702 703 void clearPreserveNonFloatingState() { 704 mPreserveNonFloatingState = false; 705 } 706 707 @Override 708 public String toShortString() { 709 return "Task=" + mTaskId; 710 } 711 712 public void dump(String prefix, PrintWriter pw) { 713 final String doublePrefix = prefix + " "; 714 715 pw.println(prefix + "taskId=" + mTaskId); 716 pw.println(doublePrefix + "mFillsParent=" + mFillsParent); 717 pw.println(doublePrefix + "mBounds=" + mBounds.toShortString()); 718 pw.println(doublePrefix + "mdr=" + mDeferRemoval); 719 pw.println(doublePrefix + "appTokens=" + mChildren); 720 pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString()); 721 722 final String triplePrefix = doublePrefix + " "; 723 724 for (int i = mChildren.size() - 1; i >= 0; i--) { 725 final AppWindowToken wtoken = mChildren.get(i); 726 pw.println(triplePrefix + "Activity #" + i + " " + wtoken); 727 wtoken.dump(pw, triplePrefix); 728 } 729 } 730} 731