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 com.android.server.EventLogTags.WM_TASK_REMOVED; 27 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; 28 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 29 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 30 31 import android.app.ActivityManager.StackId; 32 import android.app.ActivityManager.TaskDescription; 33 import android.content.pm.ActivityInfo; 34 import android.content.res.Configuration; 35 import android.graphics.Rect; 36 import android.util.EventLog; 37 import android.util.Slog; 38 import android.view.DisplayInfo; 39 import android.view.Surface; 40 41 import com.android.internal.annotations.VisibleForTesting; 42 43 import java.io.PrintWriter; 44 import java.util.function.Consumer; 45 46 class 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 Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, boolean homeTask, TaskDescription taskDescription, TaskWindowContainerController controller)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 getDisplayContent()121 DisplayContent getDisplayContent() { 122 return mStack != null ? mStack.getDisplayContent() : null; 123 } 124 getAdjustedAddPosition(int suggestedPosition)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 addChild(AppWindowToken wtoken, int position)142 void addChild(AppWindowToken wtoken, int position) { 143 position = getAdjustedAddPosition(position); 144 super.addChild(wtoken, position); 145 mDeferRemoval = false; 146 } 147 148 @Override positionChildAt(int position, AppWindowToken child, boolean includingParents)149 void positionChildAt(int position, AppWindowToken child, boolean includingParents) { 150 position = getAdjustedAddPosition(position); 151 super.positionChildAt(position, child, includingParents); 152 mDeferRemoval = false; 153 } 154 hasWindowsAlive()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 shouldDeferRemoval()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 removeIfPossible()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 removeImmediately()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 reparent(TaskStack stack, int position, boolean moveParents)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). */ positionAt(int position, Rect bounds, Configuration overrideConfig)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 onParentSet()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 removeChild(AppWindowToken token)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 setSendingToBottom(boolean toBottom)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. */ setBounds(Rect bounds, Configuration overrideConfig)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 */ setTempInsetBounds(Rect tempInsetBounds)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 */ getTempInsetBounds(Rect out)337 void getTempInsetBounds(Rect out) { 338 out.set(mTempInsetBounds); 339 } 340 setResizeable(int resizeMode)341 void setResizeable(int resizeMode) { 342 mResizeMode = resizeMode; 343 } 344 isResizeable()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 */ preserveOrientationOnResize()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 cropWindowsToStackBounds()361 boolean cropWindowsToStackBounds() { 362 return isResizeable(); 363 } 364 isHomeTask()365 boolean isHomeTask() { 366 return mHomeTask; 367 } 368 resizeLocked(Rect bounds, Configuration overrideConfig, boolean forced)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 */ prepareFreezingBounds()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 */ alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom)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. */ useCurrentBounds()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. */ getBounds(Rect out)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 */ getMaxVisibleBounds(Rect out)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 getDimBounds(Rect out)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 setDragResizing(boolean dragResizing, int dragResizeMode)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 isDragResizing()539 boolean isDragResizing() { 540 return mDragResizing; 541 } 542 getDragResizeMode()543 int getDragResizeMode() { 544 return mDragResizeMode; 545 } 546 updateDisplayInfo(final DisplayContent displayContent)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. */ cancelTaskWindowTransition()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. */ cancelTaskThumbnailTransition()589 void cancelTaskThumbnailTransition() { 590 for (int i = mChildren.size() - 1; i >= 0; --i) { 591 mChildren.get(i).mAppAnimator.clearThumbnail(); 592 } 593 } 594 showForAllUsers()595 boolean showForAllUsers() { 596 final int tokensCount = mChildren.size(); 597 return (tokensCount != 0) && mChildren.get(tokensCount - 1).mShowForAllUsers; 598 } 599 inFreeformWorkspace()600 boolean inFreeformWorkspace() { 601 return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID; 602 } 603 inPinnedWorkspace()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 */ isFloating()614 boolean isFloating() { 615 return StackId.tasksAreFloating(mStack.mStackId) 616 && !mStack.isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState; 617 } 618 getTopVisibleAppMainWindow()619 WindowState getTopVisibleAppMainWindow() { 620 final AppWindowToken token = getTopVisibleAppToken(); 621 return token != null ? token.findMainWindow() : null; 622 } 623 getTopVisibleAppToken()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 dimFullscreen()636 public boolean dimFullscreen() { 637 return isFullscreen(); 638 } 639 isFullscreen()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 getDisplayInfo()651 public DisplayInfo getDisplayInfo() { 652 return getDisplayContent().getDisplayInfo(); 653 } 654 655 @Override isAttachedToDisplay()656 public boolean isAttachedToDisplay() { 657 return getDisplayContent() != null; 658 } 659 forceWindowsScaleable(boolean force)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 setTaskDescription(TaskDescription taskDescription)671 void setTaskDescription(TaskDescription taskDescription) { 672 mTaskDescription = taskDescription; 673 } 674 getTaskDescription()675 TaskDescription getTaskDescription() { 676 return mTaskDescription; 677 } 678 679 @Override fillsParent()680 boolean fillsParent() { 681 return mFillsParent || !StackId.isTaskResizeAllowed(mStack.mStackId); 682 } 683 684 @Override getController()685 TaskWindowContainerController getController() { 686 return (TaskWindowContainerController) super.getController(); 687 } 688 689 @Override forAllTasks(Consumer<Task> callback)690 void forAllTasks(Consumer<Task> callback) { 691 callback.accept(this); 692 } 693 694 @Override toString()695 public String toString() { 696 return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}"; 697 } 698 getName()699 String getName() { 700 return toShortString(); 701 } 702 clearPreserveNonFloatingState()703 void clearPreserveNonFloatingState() { 704 mPreserveNonFloatingState = false; 705 } 706 707 @Override toShortString()708 public String toShortString() { 709 return "Task=" + mTaskId; 710 } 711 dump(String prefix, PrintWriter pw)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