Task.java revision 5406e7ade87c33f70c83a283781dcc48fb67cdb9
158d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes/* 21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 2013 The Android Open Source Project 31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * you may not use this file except in compliance with the License. 61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * You may obtain a copy of the License at 71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * See the License for the specific language governing permissions and 141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * limitations under the License. 151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectpackage com.android.server.wm; 181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION; 201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static android.app.ActivityManager.StackId.PINNED_STACK_ID; 211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; 221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static android.app.ActivityManager.StackId.HOME_STACK_ID; 231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; 241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static com.android.server.wm.WindowManagerService.H.RESIZE_TASK; 271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.app.ActivityManager.StackId; 291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.content.pm.ActivityInfo; 301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.content.res.Configuration; 311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.graphics.Rect; 321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.util.EventLog; 331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.util.Slog; 3458d9e280d459225aa8dc4533e883182b08215f7dElliott Hughesimport android.view.DisplayInfo; 351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.view.Surface; 361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport com.android.server.EventLogTags; 381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 3958d9e280d459225aa8dc4533e883182b08215f7dElliott Hughesimport java.io.PrintWriter; 401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4158d9e280d459225aa8dc4533e883182b08215f7dElliott Hughesclass Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerUser { 421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM; 431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // Return value from {@link setBounds} indicating no change was made to the Task bounds. 441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project private static final int BOUNDS_CHANGE_NONE = 0; 451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // Return value from {@link setBounds} indicating the position of the Task bounds changed. 461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project private static final int BOUNDS_CHANGE_POSITION = 1; 4758d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes // Return value from {@link setBounds} indicating the size of the Task bounds changed. 481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project private static final int BOUNDS_CHANGE_SIZE = 1 << 1; 491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 5058d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes // TODO: Track parent marks like this in WindowContainer. 511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project TaskStack mStack; 521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project final int mTaskId; 531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project final int mUserId; 541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project private boolean mDeferRemoval = false; 551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project final WindowManagerService mService; 5658d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes 571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // Content limits relative to the DisplayContent this sits in. 581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project private Rect mBounds = new Rect(); 591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project final Rect mPreparedFrozenBounds = new Rect(); 601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project final Configuration mPreparedFrozenMergedConfig = new Configuration(); 611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // Bounds used to calculate the insets. 63e734769276045c0cb89d4620fdd4ef35a0e6c335André Goddard Rosa private final Rect mTempInsetBounds = new Rect(); 64e734769276045c0cb89d4620fdd4ef35a0e6c335André Goddard Rosa 651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // Device rotation as of the last time {@link #mBounds} was set. 661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project private int mRotation; 671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // Whether mBounds is fullscreen 691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project private boolean mFillsParent = true; 701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // For comparison with DisplayContent bounds. 721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project private Rect mTmpRect = new Rect(); 731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project // For handling display rotations. 741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project private Rect mTmpRect2 = new Rect(); 7558d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes 7658d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes // Resize mode of the task. See {@link ActivityInfo#resizeMode} 771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project private int mResizeMode; 7858d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes 7958d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes // Whether the task is currently being drag-resized 8058d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes private boolean mDragResizing; 811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project private int mDragResizeMode; 82 83 private boolean mHomeTask; 84 85 // Whether this task is an on-top launcher task, which is determined by the root activity. 86 private boolean mIsOnTopLauncher; 87 88 Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, 89 Configuration overrideConfig, boolean isOnTopLauncher) { 90 mTaskId = taskId; 91 mStack = stack; 92 mUserId = userId; 93 mService = service; 94 mIsOnTopLauncher = isOnTopLauncher; 95 setBounds(bounds, overrideConfig); 96 } 97 98 DisplayContent getDisplayContent() { 99 return mStack.getDisplayContent(); 100 } 101 102 void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) { 103 final int lastPos = mChildren.size(); 104 if (addPos >= lastPos) { 105 addPos = lastPos; 106 } else { 107 for (int pos = 0; pos < lastPos && pos < addPos; ++pos) { 108 if (mChildren.get(pos).removed) { 109 // addPos assumes removed tokens are actually gone. 110 ++addPos; 111 } 112 } 113 } 114 115 final WindowContainer parent = wtoken.getParent(); 116 if (parent != null) { 117 parent.removeChild(wtoken); 118 } 119 addChild(wtoken, addPos); 120 wtoken.mTask = this; 121 mDeferRemoval = false; 122 mResizeMode = resizeMode; 123 mHomeTask = homeTask; 124 } 125 126 private boolean hasWindowsAlive() { 127 for (int i = mChildren.size() - 1; i >= 0; i--) { 128 if (mChildren.get(i).hasWindowsAlive()) { 129 return true; 130 } 131 } 132 return false; 133 } 134 135 @Override 136 void removeIfPossible() { 137 if (hasWindowsAlive() && 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 getParent().removeChild(this); 150 mService.mTaskIdToTask.delete(mTaskId); 151 } 152 153 // Change to use reparenting in WC when TaskStack is switched to use WC. 154 void moveTaskToStack(TaskStack stack, boolean toTop) { 155 if (stack == mStack) { 156 return; 157 } 158 if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId 159 + " from stack=" + mStack); 160 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask"); 161 getParent().removeChild(this); 162 stack.addTask(this, toTop); 163 } 164 165 void positionTaskInStack(TaskStack stack, int position, Rect bounds, 166 Configuration overrideConfig) { 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.removeChild(this); 172 } 173 stack.positionTask(this, position, showForAllUsers()); 174 resizeLocked(bounds, overrideConfig, false /* force */); 175 176 for (int activityNdx = mChildren.size() - 1; activityNdx >= 0; --activityNdx) { 177 mChildren.get(activityNdx).notifyMovedInStack(); 178 } 179 } 180 181 @Override 182 void removeChild(AppWindowToken token) { 183 if (!mChildren.contains(token)) { 184 Slog.e(TAG, "removeChild: token=" + this + " not found."); 185 return; 186 } 187 188 super.removeChild(token); 189 190 if (mChildren.isEmpty()) { 191 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token"); 192 if (mDeferRemoval) { 193 removeIfPossible(); 194 } 195 } 196 token.mTask = null; 197 } 198 199 void setSendingToBottom(boolean toBottom) { 200 for (int appTokenNdx = 0; appTokenNdx < mChildren.size(); appTokenNdx++) { 201 mChildren.get(appTokenNdx).sendingToBottom = toBottom; 202 } 203 } 204 205 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */ 206 private int setBounds(Rect bounds, Configuration overrideConfig) { 207 if (overrideConfig == null) { 208 overrideConfig = Configuration.EMPTY; 209 } 210 if (bounds == null && !Configuration.EMPTY.equals(overrideConfig)) { 211 throw new IllegalArgumentException("null bounds but non empty configuration: " 212 + overrideConfig); 213 } 214 if (bounds != null && Configuration.EMPTY.equals(overrideConfig)) { 215 throw new IllegalArgumentException("non null bounds, but empty configuration"); 216 } 217 boolean oldFullscreen = mFillsParent; 218 int rotation = Surface.ROTATION_0; 219 final DisplayContent displayContent = mStack.getDisplayContent(); 220 if (displayContent != null) { 221 displayContent.getLogicalDisplayRect(mTmpRect); 222 rotation = displayContent.getDisplayInfo().rotation; 223 mFillsParent = bounds == null; 224 if (mFillsParent) { 225 bounds = mTmpRect; 226 } 227 } 228 229 if (bounds == null) { 230 // Can't set to fullscreen if we don't have a display to get bounds from... 231 return BOUNDS_CHANGE_NONE; 232 } 233 if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) { 234 return BOUNDS_CHANGE_NONE; 235 } 236 237 int boundsChange = BOUNDS_CHANGE_NONE; 238 if (mBounds.left != bounds.left || mBounds.top != bounds.top) { 239 boundsChange |= BOUNDS_CHANGE_POSITION; 240 } 241 if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) { 242 boundsChange |= BOUNDS_CHANGE_SIZE; 243 } 244 245 mBounds.set(bounds); 246 247 mRotation = rotation; 248 if (displayContent != null) { 249 displayContent.mDimLayerController.updateDimLayer(this); 250 } 251 onOverrideConfigurationChanged(mFillsParent ? Configuration.EMPTY : overrideConfig); 252 return boundsChange; 253 } 254 255 /** 256 * Sets the bounds used to calculate the insets. See 257 * {@link android.app.IActivityManager#resizeDockedStack} why this is needed. 258 */ 259 void setTempInsetBounds(Rect tempInsetBounds) { 260 if (tempInsetBounds != null) { 261 mTempInsetBounds.set(tempInsetBounds); 262 } else { 263 mTempInsetBounds.setEmpty(); 264 } 265 } 266 267 /** 268 * Gets the bounds used to calculate the insets. See 269 * {@link android.app.IActivityManager#resizeDockedStack} why this is needed. 270 */ 271 void getTempInsetBounds(Rect out) { 272 out.set(mTempInsetBounds); 273 } 274 275 void setResizeable(int resizeMode) { 276 mResizeMode = resizeMode; 277 } 278 279 boolean isResizeable() { 280 return ActivityInfo.isResizeableMode(mResizeMode) || mService.mForceResizableTasks; 281 } 282 283 boolean isOnTopLauncher() { 284 return mIsOnTopLauncher; 285 } 286 287 boolean cropWindowsToStackBounds() { 288 return isResizeable(); 289 } 290 291 boolean isHomeTask() { 292 return mHomeTask; 293 } 294 295 boolean resizeLocked(Rect bounds, Configuration overrideConfig, boolean forced) { 296 int boundsChanged = setBounds(bounds, overrideConfig); 297 if (forced) { 298 boundsChanged |= BOUNDS_CHANGE_SIZE; 299 } 300 if (boundsChanged == BOUNDS_CHANGE_NONE) { 301 return false; 302 } 303 if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) { 304 onResize(); 305 } else { 306 onMovedByResize(); 307 } 308 return true; 309 } 310 311 /** 312 * Prepares the task bounds to be frozen with the current size. See 313 * {@link AppWindowToken#freezeBounds}. 314 */ 315 void prepareFreezingBounds() { 316 mPreparedFrozenBounds.set(mBounds); 317 mPreparedFrozenMergedConfig.setTo(getConfiguration()); 318 } 319 320 /** 321 * Align the task to the adjusted bounds. 322 * 323 * @param adjustedBounds Adjusted bounds to which the task should be aligned. 324 * @param tempInsetBounds Insets bounds for the task. 325 * @param alignBottom True if the task's bottom should be aligned to the adjusted 326 * bounds's bottom; false if the task's top should be aligned 327 * the adjusted bounds's top. 328 */ 329 void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) { 330 // Task override config might be empty, while display or stack override config isn't, so 331 // we have to check merged override config here. 332 if (!isResizeable() || Configuration.EMPTY.equals(getMergedOverrideConfiguration())) { 333 return; 334 } 335 336 getBounds(mTmpRect2); 337 if (alignBottom) { 338 int offsetY = adjustedBounds.bottom - mTmpRect2.bottom; 339 mTmpRect2.offset(0, offsetY); 340 } else { 341 mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top); 342 } 343 setTempInsetBounds(tempInsetBounds); 344 resizeLocked(mTmpRect2, getOverrideConfiguration(), false /* forced */); 345 } 346 347 /** Return true if the current bound can get outputted to the rest of the system as-is. */ 348 private boolean useCurrentBounds() { 349 final DisplayContent displayContent = mStack.getDisplayContent(); 350 return mFillsParent 351 || !StackId.isTaskResizeableByDockedStack(mStack.mStackId) 352 || displayContent == null 353 || displayContent.getDockedStackVisibleForUserLocked() != null; 354 } 355 356 /** Original bounds of the task if applicable, otherwise fullscreen rect. */ 357 void getBounds(Rect out) { 358 if (useCurrentBounds()) { 359 // No need to adjust the output bounds if fullscreen or the docked stack is visible 360 // since it is already what we want to represent to the rest of the system. 361 out.set(mBounds); 362 return; 363 } 364 365 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is 366 // not currently visible. Go ahead a represent it as fullscreen to the rest of the system. 367 mStack.getDisplayContent().getLogicalDisplayRect(out); 368 } 369 370 /** 371 * Calculate the maximum visible area of this task. If the task has only one app, 372 * the result will be visible frame of that app. If the task has more than one apps, 373 * we search from top down if the next app got different visible area. 374 * 375 * This effort is to handle the case where some task (eg. GMail composer) might pop up 376 * a dialog that's different in size from the activity below, in which case we should 377 * be dimming the entire task area behind the dialog. 378 * 379 * @param out Rect containing the max visible bounds. 380 * @return true if the task has some visible app windows; false otherwise. 381 */ 382 boolean getMaxVisibleBounds(Rect out) { 383 boolean foundTop = false; 384 for (int i = mChildren.size() - 1; i >= 0; i--) { 385 final AppWindowToken token = mChildren.get(i); 386 // skip hidden (or about to hide) apps 387 if (token.mIsExiting || token.clientHidden || token.hiddenRequested) { 388 continue; 389 } 390 final WindowState win = token.findMainWindow(); 391 if (win == null) { 392 continue; 393 } 394 if (!foundTop) { 395 out.set(win.mVisibleFrame); 396 foundTop = true; 397 continue; 398 } 399 if (win.mVisibleFrame.left < out.left) { 400 out.left = win.mVisibleFrame.left; 401 } 402 if (win.mVisibleFrame.top < out.top) { 403 out.top = win.mVisibleFrame.top; 404 } 405 if (win.mVisibleFrame.right > out.right) { 406 out.right = win.mVisibleFrame.right; 407 } 408 if (win.mVisibleFrame.bottom > out.bottom) { 409 out.bottom = win.mVisibleFrame.bottom; 410 } 411 } 412 return foundTop; 413 } 414 415 /** Bounds of the task to be used for dimming, as well as touch related tests. */ 416 @Override 417 public void getDimBounds(Rect out) { 418 final DisplayContent displayContent = mStack.getDisplayContent(); 419 // It doesn't matter if we in particular are part of the resize, since we couldn't have 420 // a DimLayer anyway if we weren't visible. 421 final boolean dockedResizing = displayContent != null 422 && displayContent.mDividerControllerLocked.isResizing(); 423 if (useCurrentBounds()) { 424 if (inFreeformWorkspace() && getMaxVisibleBounds(out)) { 425 return; 426 } 427 428 if (!mFillsParent) { 429 // When minimizing the docked stack when going home, we don't adjust the task bounds 430 // so we need to intersect the task bounds with the stack bounds here. 431 // 432 // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack 433 // bounds and so we don't even want to use them. Even if the app should not be resized the Dim 434 // should keep up with the divider. 435 if (dockedResizing) { 436 mStack.getBounds(out); 437 } else { 438 mStack.getBounds(mTmpRect); 439 mTmpRect.intersect(mBounds); 440 } 441 out.set(mTmpRect); 442 } else { 443 out.set(mBounds); 444 } 445 return; 446 } 447 448 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is 449 // not currently visible. Go ahead a represent it as fullscreen to the rest of the system. 450 if (displayContent != null) { 451 displayContent.getLogicalDisplayRect(out); 452 } 453 } 454 455 void setDragResizing(boolean dragResizing, int dragResizeMode) { 456 if (mDragResizing != dragResizing) { 457 if (!DragResizeMode.isModeAllowedForStack(mStack.mStackId, dragResizeMode)) { 458 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId=" 459 + mStack.mStackId + " dragResizeMode=" + dragResizeMode); 460 } 461 mDragResizing = dragResizing; 462 mDragResizeMode = dragResizeMode; 463 resetDragResizingChangeReported(); 464 } 465 } 466 467 boolean isDragResizing() { 468 return mDragResizing; 469 } 470 471 int getDragResizeMode() { 472 return mDragResizeMode; 473 } 474 475 void updateDisplayInfo(final DisplayContent displayContent) { 476 if (displayContent == null) { 477 return; 478 } 479 if (mFillsParent) { 480 setBounds(null, Configuration.EMPTY); 481 return; 482 } 483 final int newRotation = displayContent.getDisplayInfo().rotation; 484 if (mRotation == newRotation) { 485 return; 486 } 487 488 // Device rotation changed. 489 // - We don't want the task to move around on the screen when this happens, so update the 490 // task bounds so it stays in the same place. 491 // - Rotate the bounds and notify activity manager if the task can be resized independently 492 // from its stack. The stack will take care of task rotation for the other case. 493 mTmpRect2.set(mBounds); 494 495 if (!StackId.isTaskResizeAllowed(mStack.mStackId)) { 496 setBounds(mTmpRect2, getOverrideConfiguration()); 497 return; 498 } 499 500 displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); 501 if (setBounds(mTmpRect2, getOverrideConfiguration()) != BOUNDS_CHANGE_NONE) { 502 // Post message to inform activity manager of the bounds change simulating a one-way 503 // call. We do this to prevent a deadlock between window manager lock and activity 504 // manager lock been held. 505 mService.mH.obtainMessage(RESIZE_TASK, mTaskId, 506 RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds).sendToTarget(); 507 } 508 } 509 510 /** Cancels any running app transitions associated with the task. */ 511 void cancelTaskWindowTransition() { 512 for (int i = mChildren.size() - 1; i >= 0; --i) { 513 mChildren.get(i).mAppAnimator.clearAnimation(); 514 } 515 } 516 517 /** Cancels any running thumbnail transitions associated with the task. */ 518 void cancelTaskThumbnailTransition() { 519 for (int i = mChildren.size() - 1; i >= 0; --i) { 520 mChildren.get(i).mAppAnimator.clearThumbnail(); 521 } 522 } 523 524 boolean showForAllUsers() { 525 final int tokensCount = mChildren.size(); 526 return (tokensCount != 0) && mChildren.get(tokensCount - 1).showForAllUsers; 527 } 528 529 boolean inHomeStack() { 530 return mStack != null && mStack.mStackId == HOME_STACK_ID; 531 } 532 533 boolean inFreeformWorkspace() { 534 return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID; 535 } 536 537 boolean inPinnedWorkspace() { 538 return mStack != null && mStack.mStackId == PINNED_STACK_ID; 539 } 540 541 boolean isFloating() { 542 return StackId.tasksAreFloating(mStack.mStackId); 543 } 544 545 WindowState getTopVisibleAppMainWindow() { 546 final AppWindowToken token = getTopVisibleAppToken(); 547 return token != null ? token.findMainWindow() : null; 548 } 549 550 AppWindowToken getTopVisibleAppToken() { 551 for (int i = mChildren.size() - 1; i >= 0; i--) { 552 final AppWindowToken token = mChildren.get(i); 553 // skip hidden (or about to hide) apps 554 if (!token.mIsExiting && !token.clientHidden && !token.hiddenRequested) { 555 return token; 556 } 557 } 558 return null; 559 } 560 561 @Override 562 public boolean dimFullscreen() { 563 return isFullscreen(); 564 } 565 566 boolean isFullscreen() { 567 if (useCurrentBounds()) { 568 return mFillsParent; 569 } 570 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack 571 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the 572 // system. 573 return true; 574 } 575 576 @Override 577 public DisplayInfo getDisplayInfo() { 578 return mStack.getDisplayContent().getDisplayInfo(); 579 } 580 581 void forceWindowsScaleable(boolean force) { 582 mService.openSurfaceTransaction(); 583 try { 584 for (int i = mChildren.size() - 1; i >= 0; i--) { 585 mChildren.get(i).forceWindowsScaleableInTransaction(force); 586 } 587 } finally { 588 mService.closeSurfaceTransaction(); 589 } 590 } 591 592 void getWindowOnDisplayBeforeToken(DisplayContent dc, WindowToken token, 593 DisplayContent.GetWindowOnDisplaySearchResult result) { 594 for (int i = mChildren.size() - 1; i >= 0; --i) { 595 final AppWindowToken current = mChildren.get(i); 596 if (current == token) { 597 // We have reach the token we are interested in. End search. 598 result.reachedToken = true; 599 return; 600 } 601 602 // We haven't reached the token yet; if this token is not going to the bottom and 603 // has windows on this display, then it is a candidate for what we are looking for. 604 final WindowList tokenWindowList = dc.getTokenWindowsOnDisplay(current); 605 if (!current.sendingToBottom && tokenWindowList.size() > 0) { 606 result.foundWindow = tokenWindowList.get(0); 607 } 608 } 609 } 610 611 void getWindowOnDisplayAfterToken(DisplayContent dc, WindowToken token, 612 DisplayContent.GetWindowOnDisplaySearchResult result) { 613 for (int i = mChildren.size() - 1; i >= 0; --i) { 614 final AppWindowToken current = mChildren.get(i); 615 if (!result.reachedToken) { 616 if (current == token) { 617 // We have reached the token we are interested in. Get whichever window occurs 618 // after it that is on the same display. 619 result.reachedToken = true; 620 } 621 continue; 622 } 623 624 final WindowList tokenWindowList = dc.getTokenWindowsOnDisplay(current); 625 if (tokenWindowList.size() > 0) { 626 result.foundWindow = tokenWindowList.get(tokenWindowList.size() - 1); 627 return; 628 } 629 } 630 } 631 632 @Override 633 boolean fillsParent() { 634 return mFillsParent || !StackId.isTaskResizeAllowed(mStack.mStackId); 635 } 636 637 @Override 638 public String toString() { 639 return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}"; 640 } 641 642 String getName() { 643 return toShortString(); 644 } 645 646 @Override 647 public String toShortString() { 648 return "Task=" + mTaskId; 649 } 650 651 public void dump(String prefix, PrintWriter pw) { 652 final String doublePrefix = prefix + " "; 653 654 pw.println(prefix + "taskId=" + mTaskId); 655 pw.println(doublePrefix + "mFillsParent=" + mFillsParent); 656 pw.println(doublePrefix + "mBounds=" + mBounds.toShortString()); 657 pw.println(doublePrefix + "mdr=" + mDeferRemoval); 658 pw.println(doublePrefix + "appTokens=" + mChildren); 659 pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString()); 660 661 final String triplePrefix = doublePrefix + " "; 662 663 for (int i = mChildren.size() - 1; i >= 0; i--) { 664 final AppWindowToken wtoken = mChildren.get(i); 665 pw.println(triplePrefix + "Activity #" + i + " " + wtoken); 666 wtoken.dump(pw, triplePrefix); 667 } 668 669 } 670} 671