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