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 Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture, boolean homeTask, TaskDescription taskDescription, TaskWindowContainerController controller)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 getDisplayContent()124 DisplayContent getDisplayContent() { 125 return mStack != null ? mStack.getDisplayContent() : null; 126 } 127 getAdjustedAddPosition(int suggestedPosition)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 addChild(AppWindowToken wtoken, int position)145 void addChild(AppWindowToken wtoken, int position) { 146 position = getAdjustedAddPosition(position); 147 super.addChild(wtoken, position); 148 mDeferRemoval = false; 149 } 150 151 @Override positionChildAt(int position, AppWindowToken child, boolean includingParents)152 void positionChildAt(int position, AppWindowToken child, boolean includingParents) { 153 position = getAdjustedAddPosition(position); 154 super.positionChildAt(position, child, includingParents); 155 mDeferRemoval = false; 156 } 157 hasWindowsAlive()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 shouldDeferRemoval()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 removeIfPossible()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 removeImmediately()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 reparent(TaskStack stack, int position, boolean moveParents)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). */ positionAt(int position, Rect bounds, Configuration overrideConfig)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 onParentSet()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 removeChild(AppWindowToken token)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 setSendingToBottom(boolean toBottom)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. */ setBounds(Rect bounds, Configuration overrideConfig)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 */ setTempInsetBounds(Rect tempInsetBounds)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 */ getTempInsetBounds(Rect out)340 void getTempInsetBounds(Rect out) { 341 out.set(mTempInsetBounds); 342 } 343 setResizeable(int resizeMode)344 void setResizeable(int resizeMode) { 345 mResizeMode = resizeMode; 346 } 347 isResizeable()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 */ preserveOrientationOnResize()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 cropWindowsToStackBounds()364 boolean cropWindowsToStackBounds() { 365 return isResizeable(); 366 } 367 isHomeTask()368 boolean isHomeTask() { 369 return mHomeTask; 370 } 371 resizeLocked(Rect bounds, Configuration overrideConfig, boolean forced)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 */ prepareFreezingBounds()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 */ alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom)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. */ useCurrentBounds()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. */ getBounds(Rect out)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 */ getMaxVisibleBounds(Rect out)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 getDimBounds(Rect out)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 setDragResizing(boolean dragResizing, int dragResizeMode)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 isDragResizing()542 boolean isDragResizing() { 543 return mDragResizing; 544 } 545 getDragResizeMode()546 int getDragResizeMode() { 547 return mDragResizeMode; 548 } 549 updateDisplayInfo(final DisplayContent displayContent)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. */ cancelTaskWindowTransition()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. */ cancelTaskThumbnailTransition()592 void cancelTaskThumbnailTransition() { 593 for (int i = mChildren.size() - 1; i >= 0; --i) { 594 mChildren.get(i).mAppAnimator.clearThumbnail(); 595 } 596 } 597 showForAllUsers()598 boolean showForAllUsers() { 599 final int tokensCount = mChildren.size(); 600 return (tokensCount != 0) && mChildren.get(tokensCount - 1).mShowForAllUsers; 601 } 602 inFreeformWorkspace()603 boolean inFreeformWorkspace() { 604 return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID; 605 } 606 inPinnedWorkspace()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 */ isFloating()617 boolean isFloating() { 618 return StackId.tasksAreFloating(mStack.mStackId) 619 && !mStack.isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState; 620 } 621 getTopVisibleAppMainWindow()622 WindowState getTopVisibleAppMainWindow() { 623 final AppWindowToken token = getTopVisibleAppToken(); 624 return token != null ? token.findMainWindow() : null; 625 } 626 getTopFullscreenAppToken()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 getTopVisibleAppToken()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 dimFullscreen()650 public boolean dimFullscreen() { 651 return isFullscreen(); 652 } 653 654 @Override getLayerForDim(WindowStateAnimator animator, int layerOffset, int defaultLayer)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 isFullscreen()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 getDisplayInfo()677 public DisplayInfo getDisplayInfo() { 678 return getDisplayContent().getDisplayInfo(); 679 } 680 681 @Override isAttachedToDisplay()682 public boolean isAttachedToDisplay() { 683 return getDisplayContent() != null; 684 } 685 forceWindowsScaleable(boolean force)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 setTaskDescription(TaskDescription taskDescription)697 void setTaskDescription(TaskDescription taskDescription) { 698 mTaskDescription = taskDescription; 699 } 700 getTaskDescription()701 TaskDescription getTaskDescription() { 702 return mTaskDescription; 703 } 704 705 @Override fillsParent()706 boolean fillsParent() { 707 return mFillsParent || !StackId.isTaskResizeAllowed(mStack.mStackId); 708 } 709 710 @Override getController()711 TaskWindowContainerController getController() { 712 return (TaskWindowContainerController) super.getController(); 713 } 714 715 @Override forAllTasks(Consumer<Task> callback)716 void forAllTasks(Consumer<Task> callback) { 717 callback.accept(this); 718 } 719 720 @Override toString()721 public String toString() { 722 return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}"; 723 } 724 getName()725 String getName() { 726 return toShortString(); 727 } 728 clearPreserveNonFloatingState()729 void clearPreserveNonFloatingState() { 730 mPreserveNonFloatingState = false; 731 } 732 733 @Override toShortString()734 public String toShortString() { 735 return "Task=" + mTaskId; 736 } 737 dump(String prefix, PrintWriter pw)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