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