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