Task.java revision e42d0e102dbdf5287703389183a69019b64fc35e
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 17package com.android.server.wm; 18 19import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION; 20import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; 21import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; 22import static android.app.ActivityManager.StackId.HOME_STACK_ID; 23import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS; 24import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 25import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE; 26import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; 27import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 28import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 29import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK; 30import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 31 32import android.app.ActivityManager.StackId; 33import android.content.pm.ActivityInfo; 34import android.content.res.Configuration; 35import android.graphics.Rect; 36import android.util.EventLog; 37import android.util.Slog; 38import android.view.DisplayInfo; 39import android.view.Surface; 40 41import com.android.server.EventLogTags; 42 43import java.io.PrintWriter; 44import java.util.ArrayList; 45 46class Task 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 static final int BOUNDS_CHANGE_NONE = 0; 50 // Return value from {@link setBounds} indicating the position of the Task bounds changed. 51 static final int BOUNDS_CHANGE_POSITION = 1; 52 // Return value from {@link setBounds} indicating the size of the Task bounds changed. 53 static final int BOUNDS_CHANGE_SIZE = 1 << 1; 54 55 TaskStack mStack; 56 final AppTokenList mAppTokens = new AppTokenList(); 57 final int mTaskId; 58 final int mUserId; 59 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 66 private Rect mPreScrollBounds = new Rect(); 67 private boolean mScrollValid; 68 69 // Bounds used to calculate the insets. 70 private final Rect mTempInsetBounds = new Rect(); 71 72 // Device rotation as of the last time {@link #mBounds} was set. 73 int mRotation; 74 75 // Whether mBounds is fullscreen 76 private boolean mFullscreen = true; 77 78 // Contains configurations settings that are different from the global configuration due to 79 // stack specific operations. E.g. {@link #setBounds}. 80 Configuration mOverrideConfig; 81 82 // For comparison with DisplayContent bounds. 83 private Rect mTmpRect = new Rect(); 84 // For handling display rotations. 85 private Rect mTmpRect2 = new Rect(); 86 87 // Resize mode of the task. See {@link ActivityInfo#resizeMode} 88 private int mResizeMode; 89 90 // Whether the task is currently being drag-resized 91 private boolean mDragResizing; 92 private int mDragResizeMode; 93 94 private boolean mHomeTask; 95 96 Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, 97 Configuration config) { 98 mTaskId = taskId; 99 mStack = stack; 100 mUserId = userId; 101 mService = service; 102 setBounds(bounds, config); 103 } 104 105 DisplayContent getDisplayContent() { 106 return mStack.getDisplayContent(); 107 } 108 109 void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) { 110 final int lastPos = mAppTokens.size(); 111 if (addPos >= lastPos) { 112 addPos = lastPos; 113 } else { 114 for (int pos = 0; pos < lastPos && pos < addPos; ++pos) { 115 if (mAppTokens.get(pos).removed) { 116 // addPos assumes removed tokens are actually gone. 117 ++addPos; 118 } 119 } 120 } 121 mAppTokens.add(addPos, wtoken); 122 wtoken.mTask = this; 123 mDeferRemoval = false; 124 mResizeMode = resizeMode; 125 mHomeTask = homeTask; 126 } 127 128 private boolean hasWindowsAlive() { 129 for (int i = mAppTokens.size() - 1; i >= 0; i--) { 130 if (mAppTokens.get(i).hasWindowsAlive()) { 131 return true; 132 } 133 } 134 return false; 135 } 136 137 void removeLocked() { 138 if (hasWindowsAlive() && mStack.isAnimating()) { 139 if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId); 140 mDeferRemoval = true; 141 return; 142 } 143 if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId); 144 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask"); 145 mDeferRemoval = false; 146 DisplayContent content = getDisplayContent(); 147 if (content != null) { 148 content.mDimLayerController.removeDimLayerUser(this); 149 } 150 mStack.removeTask(this); 151 mService.mTaskIdToTask.delete(mTaskId); 152 } 153 154 void moveTaskToStack(TaskStack stack, boolean toTop) { 155 if (stack == mStack) { 156 return; 157 } 158 if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId 159 + " from stack=" + mStack); 160 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask"); 161 if (mStack != null) { 162 mStack.removeTask(this); 163 } 164 stack.addTask(this, toTop); 165 } 166 167 void positionTaskInStack(TaskStack stack, int position, Rect bounds, Configuration config) { 168 if (mStack != null && stack != mStack) { 169 if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId 170 + " from stack=" + mStack); 171 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask"); 172 mStack.removeTask(this); 173 } 174 stack.positionTask(this, position, showForAllUsers()); 175 resizeLocked(bounds, config, false /* force */); 176 177 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { 178 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows; 179 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 180 final WindowState win = windows.get(winNdx); 181 win.notifyMovedInStack(); 182 } 183 } 184 } 185 186 boolean removeAppToken(AppWindowToken wtoken) { 187 boolean removed = mAppTokens.remove(wtoken); 188 if (mAppTokens.size() == 0) { 189 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token"); 190 if (mDeferRemoval) { 191 removeLocked(); 192 } 193 } 194 wtoken.mTask = null; 195 /* Leave mTaskId for now, it might be useful for debug 196 wtoken.mTaskId = -1; 197 */ 198 return removed; 199 } 200 201 void setSendingToBottom(boolean toBottom) { 202 for (int appTokenNdx = 0; appTokenNdx < mAppTokens.size(); appTokenNdx++) { 203 mAppTokens.get(appTokenNdx).sendingToBottom = toBottom; 204 } 205 } 206 207 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */ 208 private int setBounds(Rect bounds, Configuration config) { 209 if (config == null) { 210 config = Configuration.EMPTY; 211 } 212 if (bounds == null && !Configuration.EMPTY.equals(config)) { 213 throw new IllegalArgumentException("null bounds but non empty configuration: " 214 + config); 215 } 216 if (bounds != null && Configuration.EMPTY.equals(config)) { 217 throw new IllegalArgumentException("non null bounds, but empty configuration"); 218 } 219 boolean oldFullscreen = mFullscreen; 220 int rotation = Surface.ROTATION_0; 221 final DisplayContent displayContent = mStack.getDisplayContent(); 222 if (displayContent != null) { 223 displayContent.getLogicalDisplayRect(mTmpRect); 224 rotation = displayContent.getDisplayInfo().rotation; 225 mFullscreen = bounds == null; 226 if (mFullscreen) { 227 bounds = mTmpRect; 228 } 229 } 230 231 if (bounds == null) { 232 // Can't set to fullscreen if we don't have a display to get bounds from... 233 return BOUNDS_CHANGE_NONE; 234 } 235 if (mPreScrollBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) { 236 return BOUNDS_CHANGE_NONE; 237 } 238 239 int boundsChange = BOUNDS_CHANGE_NONE; 240 if (mPreScrollBounds.left != bounds.left || mPreScrollBounds.top != bounds.top) { 241 boundsChange |= BOUNDS_CHANGE_POSITION; 242 } 243 if (mPreScrollBounds.width() != bounds.width() || mPreScrollBounds.height() != bounds.height()) { 244 boundsChange |= BOUNDS_CHANGE_SIZE; 245 } 246 247 248 mPreScrollBounds.set(bounds); 249 250 resetScrollLocked(); 251 252 mRotation = rotation; 253 if (displayContent != null) { 254 displayContent.mDimLayerController.updateDimLayer(this); 255 } 256 mOverrideConfig = mFullscreen ? Configuration.EMPTY : config; 257 return boundsChange; 258 } 259 260 /** 261 * Sets the bounds used to calculate the insets. See 262 * {@link android.app.IActivityManager#resizeDockedStack} why this is needed. 263 */ 264 void setTempInsetBounds(Rect tempInsetBounds) { 265 if (tempInsetBounds != null) { 266 mTempInsetBounds.set(tempInsetBounds); 267 } else { 268 mTempInsetBounds.setEmpty(); 269 } 270 } 271 272 /** 273 * Gets the bounds used to calculate the insets. See 274 * {@link android.app.IActivityManager#resizeDockedStack} why this is needed. 275 */ 276 void getTempInsetBounds(Rect out) { 277 out.set(mTempInsetBounds); 278 } 279 280 void setResizeable(int resizeMode) { 281 mResizeMode = resizeMode; 282 } 283 284 boolean isResizeable() { 285 return !mHomeTask 286 && (ActivityInfo.isResizeableMode(mResizeMode) || mService.mForceResizableTasks); 287 } 288 289 boolean cropWindowsToStackBounds() { 290 return !mHomeTask && (isResizeable() || mResizeMode == RESIZE_MODE_CROP_WINDOWS); 291 } 292 293 boolean isHomeTask() { 294 return mHomeTask; 295 } 296 297 private boolean inCropWindowsResizeMode() { 298 return !mHomeTask && !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS; 299 } 300 301 boolean resizeLocked(Rect bounds, Configuration configuration, boolean forced) { 302 int boundsChanged = setBounds(bounds, configuration); 303 if (forced) { 304 boundsChanged |= BOUNDS_CHANGE_SIZE; 305 } 306 if (boundsChanged == BOUNDS_CHANGE_NONE) { 307 return false; 308 } 309 if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) { 310 resizeWindows(); 311 } else { 312 moveWindows(); 313 } 314 return true; 315 } 316 317 /** 318 * Prepares the task bounds to be frozen with the current size. See 319 * {@link AppWindowToken#freezeBounds}. 320 */ 321 void prepareFreezingBounds() { 322 mPreparedFrozenBounds.set(mBounds); 323 } 324 325 void resetScrollLocked() { 326 if (mScrollValid) { 327 mScrollValid = false; 328 applyScrollToAllWindows(0, 0); 329 } 330 mBounds.set(mPreScrollBounds); 331 } 332 333 void applyScrollToAllWindows(final int xOffset, final int yOffset) { 334 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { 335 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows; 336 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 337 final WindowState win = windows.get(winNdx); 338 win.mXOffset = xOffset; 339 win.mYOffset = yOffset; 340 } 341 } 342 } 343 344 void applyScrollToWindowIfNeeded(final WindowState win) { 345 if (mScrollValid) { 346 win.mXOffset = mBounds.left; 347 win.mYOffset = mBounds.top; 348 } 349 } 350 351 boolean scrollLocked(Rect bounds) { 352 // shift the task bound if it doesn't fully cover the stack area 353 mStack.getDimBounds(mTmpRect); 354 if (mService.mCurConfiguration.orientation == ORIENTATION_LANDSCAPE) { 355 if (bounds.left > mTmpRect.left) { 356 bounds.left = mTmpRect.left; 357 bounds.right = mTmpRect.left + mBounds.width(); 358 } else if (bounds.right < mTmpRect.right) { 359 bounds.left = mTmpRect.right - mBounds.width(); 360 bounds.right = mTmpRect.right; 361 } 362 } else { 363 if (bounds.top > mTmpRect.top) { 364 bounds.top = mTmpRect.top; 365 bounds.bottom = mTmpRect.top + mBounds.height(); 366 } else if (bounds.bottom < mTmpRect.bottom) { 367 bounds.top = mTmpRect.bottom - mBounds.height(); 368 bounds.bottom = mTmpRect.bottom; 369 } 370 } 371 372 // We can stop here if we're already scrolling and the scrolled bounds not changed. 373 if (mScrollValid && bounds.equals(mBounds)) { 374 return false; 375 } 376 377 // Normal setBounds() does not allow non-null bounds for fullscreen apps. 378 // We only change bounds for the scrolling case without change it size, 379 // on resizing path we should still want the validation. 380 mBounds.set(bounds); 381 mScrollValid = true; 382 applyScrollToAllWindows(bounds.left, bounds.top); 383 return true; 384 } 385 386 /** Return true if the current bound can get outputted to the rest of the system as-is. */ 387 private boolean useCurrentBounds() { 388 final DisplayContent displayContent = mStack.getDisplayContent(); 389 if (mFullscreen 390 || !StackId.isTaskResizeableByDockedStack(mStack.mStackId) 391 || displayContent == null 392 || displayContent.getDockedStackVisibleForUserLocked() != null) { 393 return true; 394 } 395 return false; 396 } 397 398 /** Original bounds of the task if applicable, otherwise fullscreen rect. */ 399 void getBounds(Rect out) { 400 if (useCurrentBounds()) { 401 // No need to adjust the output bounds if fullscreen or the docked stack is visible 402 // since it is already what we want to represent to the rest of the system. 403 out.set(mBounds); 404 return; 405 } 406 407 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is 408 // not currently visible. Go ahead a represent it as fullscreen to the rest of the system. 409 mStack.getDisplayContent().getLogicalDisplayRect(out); 410 } 411 412 /** 413 * Calculate the maximum visible area of this task. If the task has only one app, 414 * the result will be visible frame of that app. If the task has more than one apps, 415 * we search from top down if the next app got different visible area. 416 * 417 * This effort is to handle the case where some task (eg. GMail composer) might pop up 418 * a dialog that's different in size from the activity below, in which case we should 419 * be dimming the entire task area behind the dialog. 420 * 421 * @param out Rect containing the max visible bounds. 422 * @return true if the task has some visible app windows; false otherwise. 423 */ 424 boolean getMaxVisibleBounds(Rect out) { 425 boolean foundTop = false; 426 for (int i = mAppTokens.size() - 1; i >= 0; i--) { 427 final AppWindowToken token = mAppTokens.get(i); 428 // skip hidden (or about to hide) apps 429 if (token.mIsExiting || token.clientHidden || token.hiddenRequested) { 430 continue; 431 } 432 final WindowState win = token.findMainWindow(); 433 if (win == null) { 434 continue; 435 } 436 if (!foundTop) { 437 out.set(win.mVisibleFrame); 438 foundTop = true; 439 continue; 440 } 441 if (win.mVisibleFrame.left < out.left) { 442 out.left = win.mVisibleFrame.left; 443 } 444 if (win.mVisibleFrame.top < out.top) { 445 out.top = win.mVisibleFrame.top; 446 } 447 if (win.mVisibleFrame.right > out.right) { 448 out.right = win.mVisibleFrame.right; 449 } 450 if (win.mVisibleFrame.bottom > out.bottom) { 451 out.bottom = win.mVisibleFrame.bottom; 452 } 453 } 454 return foundTop; 455 } 456 457 /** Bounds of the task to be used for dimming, as well as touch related tests. */ 458 @Override 459 public void getDimBounds(Rect out) { 460 final DisplayContent displayContent = mStack.getDisplayContent(); 461 // It doesn't matter if we in particular are part of the resize, since we couldn't have 462 // a DimLayer anyway if we weren't visible. 463 final boolean dockedResizing = displayContent != null ? 464 displayContent.mDividerControllerLocked.isResizing() : false; 465 if (useCurrentBounds()) { 466 if (inFreeformWorkspace() && getMaxVisibleBounds(out)) { 467 return; 468 } 469 470 if (!mFullscreen) { 471 // When minimizing the docked stack when going home, we don't adjust the task bounds 472 // so we need to intersect the task bounds with the stack bounds here. 473 // 474 // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack 475 // bounds and so we don't even want to use them. Even if the app should not be resized the Dim 476 // should keep up with the divider. 477 if (dockedResizing) { 478 mStack.getBounds(out); 479 } else { 480 mStack.getBounds(mTmpRect); 481 mTmpRect.intersect(mBounds); 482 } 483 out.set(mTmpRect); 484 } else { 485 out.set(mBounds); 486 } 487 return; 488 } 489 490 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack 491 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the 492 // system. 493 displayContent.getLogicalDisplayRect(out); 494 } 495 496 void setDragResizing(boolean dragResizing, int dragResizeMode) { 497 if (mDragResizing != dragResizing) { 498 if (!DragResizeMode.isModeAllowedForStack(mStack.mStackId, dragResizeMode)) { 499 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId=" 500 + mStack.mStackId + " dragResizeMode=" + dragResizeMode); 501 } 502 mDragResizing = dragResizing; 503 mDragResizeMode = dragResizeMode; 504 resetDragResizingChangeReported(); 505 } 506 } 507 508 void resetDragResizingChangeReported() { 509 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { 510 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows; 511 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 512 final WindowState win = windows.get(winNdx); 513 win.resetDragResizingChangeReported(); 514 } 515 } 516 } 517 518 boolean isDragResizing() { 519 return mDragResizing || (mStack != null && mStack.isDragResizing()); 520 } 521 522 int getDragResizeMode() { 523 return mDragResizeMode; 524 } 525 526 /** 527 * Adds all of the tasks windows to {@link WindowManagerService#mWaitingForDrawn} if drag 528 * resizing state of the window has been changed. 529 */ 530 void addWindowsWaitingForDrawnIfResizingChanged() { 531 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { 532 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows; 533 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 534 final WindowState win = windows.get(winNdx); 535 if (win.isDragResizeChanged()) { 536 mService.mWaitingForDrawn.add(win); 537 } 538 } 539 } 540 } 541 542 void updateDisplayInfo(final DisplayContent displayContent) { 543 if (displayContent == null) { 544 return; 545 } 546 if (mFullscreen) { 547 setBounds(null, Configuration.EMPTY); 548 return; 549 } 550 final int newRotation = displayContent.getDisplayInfo().rotation; 551 if (mRotation == newRotation) { 552 return; 553 } 554 555 // Device rotation changed. 556 // - Reset the bounds to the pre-scroll bounds as whatever scrolling was done is no longer 557 // valid. 558 // - Rotate the bounds and notify activity manager if the task can be resized independently 559 // from its stack. The stack will take care of task rotation for the other case. 560 mTmpRect2.set(mPreScrollBounds); 561 562 if (!StackId.isTaskResizeAllowed(mStack.mStackId)) { 563 setBounds(mTmpRect2, mOverrideConfig); 564 return; 565 } 566 567 displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); 568 if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) { 569 // Post message to inform activity manager of the bounds change simulating a one-way 570 // call. We do this to prevent a deadlock between window manager lock and activity 571 // manager lock been held. 572 mService.mH.obtainMessage(RESIZE_TASK, mTaskId, 573 RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mPreScrollBounds).sendToTarget(); 574 } 575 } 576 577 void resizeWindows() { 578 final ArrayList<WindowState> resizingWindows = mService.mResizingWindows; 579 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { 580 final AppWindowToken atoken = mAppTokens.get(activityNdx); 581 582 // Some windows won't go through the resizing process, if they don't have a surface, so 583 // destroy all saved surfaces here. 584 atoken.destroySavedSurfaces(); 585 final ArrayList<WindowState> windows = atoken.allAppWindows; 586 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 587 final WindowState win = windows.get(winNdx); 588 if (win.mHasSurface && !resizingWindows.contains(win)) { 589 if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win); 590 resizingWindows.add(win); 591 592 // If we are not drag resizing, force recreating of a new surface so updating 593 // the content and positioning that surface will be in sync. 594 // 595 // As we use this flag as a hint to freeze surface boundary updates, 596 // we'd like to only apply this to TYPE_BASE_APPLICATION, 597 // windows of TYPE_APPLICATION like dialogs, could appear 598 // to not be drag resizing while they resize, but we'd 599 // still like to manipulate their frame to update crop, etc... 600 // 601 // Anyway we don't need to synchronize position and content updates for these 602 // windows since they aren't at the base layer and could be moved around anyway. 603 if (!win.computeDragResizing() && win.mAttrs.type == TYPE_BASE_APPLICATION && 604 !mStack.getBoundsAnimating() && !win.isGoneForLayoutLw()) { 605 win.mResizedWhileNotDragResizing = true; 606 } 607 } 608 if (win.isGoneForLayoutLw()) { 609 win.mResizedWhileGone = true; 610 } 611 } 612 } 613 } 614 615 void moveWindows() { 616 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { 617 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows; 618 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 619 final WindowState win = windows.get(winNdx); 620 if (DEBUG_RESIZE) Slog.d(TAG, "moveWindows: Moving " + win); 621 win.mMovedByResize = true; 622 } 623 } 624 } 625 626 /** 627 * Cancels any running app transitions associated with the task. 628 */ 629 void cancelTaskWindowTransition() { 630 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { 631 mAppTokens.get(activityNdx).mAppAnimator.clearAnimation(); 632 } 633 } 634 635 /** 636 * Cancels any running thumbnail transitions associated with the task. 637 */ 638 void cancelTaskThumbnailTransition() { 639 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { 640 mAppTokens.get(activityNdx).mAppAnimator.clearThumbnail(); 641 } 642 } 643 644 boolean showForAllUsers() { 645 final int tokensCount = mAppTokens.size(); 646 return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers; 647 } 648 649 boolean isVisibleForUser() { 650 for (int i = mAppTokens.size() - 1; i >= 0; i--) { 651 final AppWindowToken appToken = mAppTokens.get(i); 652 for (int j = appToken.allAppWindows.size() - 1; j >= 0; j--) { 653 WindowState window = appToken.allAppWindows.get(j); 654 if (!window.isHiddenFromUserLocked()) { 655 return true; 656 } 657 } 658 } 659 return false; 660 } 661 662 boolean isVisible() { 663 for (int i = mAppTokens.size() - 1; i >= 0; i--) { 664 final AppWindowToken appToken = mAppTokens.get(i); 665 if (appToken.isVisible()) { 666 return true; 667 } 668 } 669 return false; 670 } 671 672 boolean inHomeStack() { 673 return mStack != null && mStack.mStackId == HOME_STACK_ID; 674 } 675 676 boolean inFreeformWorkspace() { 677 return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID; 678 } 679 680 boolean inDockedWorkspace() { 681 return mStack != null && mStack.mStackId == DOCKED_STACK_ID; 682 } 683 684 boolean isResizeableByDockedStack() { 685 final DisplayContent displayContent = getDisplayContent(); 686 return displayContent != null && displayContent.getDockedStackLocked() != null 687 && mStack != null && StackId.isTaskResizeableByDockedStack(mStack.mStackId); 688 } 689 690 boolean isFloating() { 691 return StackId.tasksAreFloating(mStack.mStackId); 692 } 693 694 /** 695 * Whether the task should be treated as if it's docked. Returns true if the task 696 * is currently in docked workspace, or it's side-by-side to a docked task. 697 */ 698 boolean isDockedInEffect() { 699 return inDockedWorkspace() || isResizeableByDockedStack(); 700 } 701 702 boolean isTwoFingerScrollMode() { 703 return inCropWindowsResizeMode() && isDockedInEffect(); 704 } 705 706 WindowState getTopVisibleAppMainWindow() { 707 final AppWindowToken token = getTopVisibleAppToken(); 708 return token != null ? token.findMainWindow() : null; 709 } 710 711 AppWindowToken getTopVisibleAppToken() { 712 for (int i = mAppTokens.size() - 1; i >= 0; i--) { 713 final AppWindowToken token = mAppTokens.get(i); 714 // skip hidden (or about to hide) apps 715 if (!token.mIsExiting && !token.clientHidden && !token.hiddenRequested) { 716 return token; 717 } 718 } 719 return null; 720 } 721 722 AppWindowToken getTopAppToken() { 723 return mAppTokens.size() > 0 ? mAppTokens.get(mAppTokens.size() - 1) : null; 724 } 725 726 @Override 727 public boolean isFullscreen() { 728 if (useCurrentBounds()) { 729 return mFullscreen; 730 } 731 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack 732 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the 733 // system. 734 return true; 735 } 736 737 @Override 738 public DisplayInfo getDisplayInfo() { 739 return mStack.getDisplayContent().getDisplayInfo(); 740 } 741 742 @Override 743 public String toString() { 744 return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}"; 745 } 746 747 @Override 748 public String toShortString() { 749 return "Task=" + mTaskId; 750 } 751 752 public void dump(String prefix, PrintWriter pw) { 753 final String doublePrefix = prefix + " "; 754 755 pw.println(prefix + "taskId=" + mTaskId); 756 pw.println(doublePrefix + "mFullscreen=" + mFullscreen); 757 pw.println(doublePrefix + "mBounds=" + mBounds.toShortString()); 758 pw.println(doublePrefix + "mdr=" + mDeferRemoval); 759 pw.println(doublePrefix + "appTokens=" + mAppTokens); 760 pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString()); 761 762 final String triplePrefix = doublePrefix + " "; 763 764 for (int i = mAppTokens.size() - 1; i >= 0; i--) { 765 final AppWindowToken wtoken = mAppTokens.get(i); 766 pw.println(triplePrefix + "Activity #" + i + " " + wtoken); 767 wtoken.dump(pw, triplePrefix); 768 } 769 770 } 771} 772