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