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