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