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