TaskStack.java revision b1193ade255385d899d81e8d62ceaa97c7d6aeb6
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 com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT; 20import static com.android.server.wm.WindowManagerService.TAG; 21 22import android.content.res.Configuration; 23import android.graphics.Rect; 24import android.os.Debug; 25import android.util.DisplayMetrics; 26import android.util.EventLog; 27import android.util.Slog; 28import android.util.TypedValue; 29import android.view.Display; 30import android.view.Surface; 31 32import com.android.server.EventLogTags; 33 34import java.io.PrintWriter; 35import java.util.ArrayList; 36 37public class TaskStack { 38 /** Amount of time in milliseconds to animate the dim surface from one value to another, 39 * when no window animation is driving it. */ 40 private static final int DEFAULT_DIM_DURATION = 200; 41 42 /** Unique identifier */ 43 final int mStackId; 44 45 /** The service */ 46 private final WindowManagerService mService; 47 48 /** The display this stack sits under. */ 49 private DisplayContent mDisplayContent; 50 51 /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match 52 * mTaskHistory in the ActivityStack with the same mStackId */ 53 private final ArrayList<Task> mTasks = new ArrayList<Task>(); 54 55 /** For comparison with DisplayContent bounds. */ 56 private Rect mTmpRect = new Rect(); 57 /** For handling display rotations. */ 58 private Rect mTmpRect2 = new Rect(); 59 60 /** Content limits relative to the DisplayContent this sits in. */ 61 private Rect mBounds = new Rect(); 62 63 /** Whether mBounds is fullscreen */ 64 private boolean mFullscreen = true; 65 66 /** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */ 67 private DimLayer mDimLayer; 68 69 /** The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. */ 70 WindowStateAnimator mDimWinAnimator; 71 72 /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */ 73 DimLayer mAnimationBackgroundSurface; 74 75 /** The particular window with an Animation with non-zero background color. */ 76 WindowStateAnimator mAnimationBackgroundAnimator; 77 78 /** Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the end 79 * then stop any dimming. */ 80 boolean mDimmingTag; 81 82 /** Application tokens that are exiting, but still on screen for animations. */ 83 final AppTokenList mExitingAppTokens = new AppTokenList(); 84 85 /** Detach this stack from its display when animation completes. */ 86 boolean mDeferDetach; 87 88 // Contains configurations settings that are different from the global configuration due to 89 // stack specific operations. E.g. {@link #setBounds}. 90 Configuration mOverrideConfig; 91 // True if the stack was forced to fullscreen disregarding the override configuration. 92 private boolean mForceFullscreen; 93 // The {@link #mBounds} before the stack was forced to fullscreen. Will be restored as the 94 // stack bounds once the stack is no longer forced to fullscreen. 95 final private Rect mPreForceFullscreenBounds; 96 97 // When true this stack is at the top of the screen and should be layed out to extend under 98 // the status bar. 99 boolean mUnderStatusBar; 100 101 // Device rotation as of the last time {@link #mBounds} was set. 102 int mRotation; 103 104 TaskStack(WindowManagerService service, int stackId) { 105 mService = service; 106 mStackId = stackId; 107 mOverrideConfig = Configuration.EMPTY; 108 mForceFullscreen = false; 109 mPreForceFullscreenBounds = new Rect(); 110 mUnderStatusBar = true; 111 // TODO: remove bounds from log, they are always 0. 112 EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top, 113 mBounds.right, mBounds.bottom); 114 } 115 116 DisplayContent getDisplayContent() { 117 return mDisplayContent; 118 } 119 120 ArrayList<Task> getTasks() { 121 return mTasks; 122 } 123 124 void resizeWindows() { 125 final ArrayList<WindowState> resizingWindows = mService.mResizingWindows; 126 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 127 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; 128 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 129 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; 130 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 131 final WindowState win = windows.get(winNdx); 132 if (!resizingWindows.contains(win)) { 133 if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG, 134 "setBounds: Resizing " + win); 135 resizingWindows.add(win); 136 } 137 } 138 } 139 } 140 } 141 142 /** Set the stack bounds. Passing in null sets the bounds to fullscreen. */ 143 boolean setBounds(Rect bounds) { 144 boolean oldFullscreen = mFullscreen; 145 int rotation = Surface.ROTATION_0; 146 if (mDisplayContent != null) { 147 mDisplayContent.getLogicalDisplayRect(mTmpRect); 148 rotation = mDisplayContent.getDisplayInfo().rotation; 149 if (bounds == null) { 150 bounds = mTmpRect; 151 mFullscreen = true; 152 } else { 153 bounds.intersect(mTmpRect); // ensure bounds are entirely within the display rect 154 mFullscreen = mTmpRect.equals(bounds); 155 } 156 } 157 158 if (bounds == null) { 159 // Can't set to fullscreen if we don't have a display to get bounds from... 160 return false; 161 } 162 if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) { 163 return false; 164 } 165 166 mDimLayer.setBounds(bounds); 167 mAnimationBackgroundSurface.setBounds(bounds); 168 mBounds.set(bounds); 169 mUnderStatusBar = (mBounds.top == 0); 170 mRotation = rotation; 171 updateOverrideConfiguration(); 172 return true; 173 } 174 175 void getBounds(Rect out) { 176 out.set(mBounds); 177 } 178 179 private void updateOverrideConfiguration() { 180 final Configuration serviceConfig = mService.mCurConfiguration; 181 if (mFullscreen) { 182 mOverrideConfig = Configuration.EMPTY; 183 return; 184 } 185 186 if (mOverrideConfig == Configuration.EMPTY) { 187 mOverrideConfig = new Configuration(); 188 } 189 190 // TODO(multidisplay): Update Dp to that of display stack is on. 191 final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; 192 mOverrideConfig.screenWidthDp = 193 Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp); 194 mOverrideConfig.screenHeightDp = 195 Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp); 196 mOverrideConfig.smallestScreenWidthDp = 197 Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp); 198 mOverrideConfig.orientation = 199 (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp) 200 ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; 201 } 202 203 void updateDisplayInfo() { 204 if (mFullscreen) { 205 setBounds(null); 206 } else if (mDisplayContent != null) { 207 final int newRotation = mDisplayContent.getDisplayInfo().rotation; 208 if (mRotation == newRotation) { 209 return; 210 } 211 212 // Device rotation changed. We don't want the stack to move around on the screen when 213 // this happens, so update the stack bounds so it stays in the same place. 214 final int rotationDelta = DisplayContent.deltaRotation(mRotation, newRotation); 215 mDisplayContent.getLogicalDisplayRect(mTmpRect); 216 switch (rotationDelta) { 217 case Surface.ROTATION_0: 218 mTmpRect2.set(mBounds); 219 break; 220 case Surface.ROTATION_90: 221 mTmpRect2.top = mTmpRect.bottom - mBounds.right; 222 mTmpRect2.left = mBounds.top; 223 mTmpRect2.right = mTmpRect2.left + mBounds.height(); 224 mTmpRect2.bottom = mTmpRect2.top + mBounds.width(); 225 break; 226 case Surface.ROTATION_180: 227 mTmpRect2.top = mTmpRect.bottom - mBounds.bottom; 228 mTmpRect2.left = mTmpRect.right - mBounds.right; 229 mTmpRect2.right = mTmpRect2.left + mBounds.width(); 230 mTmpRect2.bottom = mTmpRect2.top + mBounds.height(); 231 break; 232 case Surface.ROTATION_270: 233 mTmpRect2.top = mBounds.left; 234 mTmpRect2.left = mTmpRect.right - mBounds.bottom; 235 mTmpRect2.right = mTmpRect2.left + mBounds.height(); 236 mTmpRect2.bottom = mTmpRect2.top + mBounds.width(); 237 break; 238 } 239 setBounds(mTmpRect2); 240 } 241 } 242 243 boolean isFullscreen() { 244 return mFullscreen; 245 } 246 247 /** Forces the stack to fullscreen if input is true, else un-forces the stack from fullscreen. 248 * Returns true if something happened. 249 */ 250 boolean forceFullscreen(boolean forceFullscreen) { 251 if (mForceFullscreen == forceFullscreen) { 252 return false; 253 } 254 mForceFullscreen = forceFullscreen; 255 if (forceFullscreen) { 256 if (mFullscreen) { 257 return false; 258 } 259 mPreForceFullscreenBounds.set(mBounds); 260 return setBounds(null); 261 } else { 262 if (!mFullscreen || mPreForceFullscreenBounds.isEmpty()) { 263 return false; 264 } 265 return setBounds(mPreForceFullscreenBounds); 266 } 267 } 268 269 boolean isAnimating() { 270 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 271 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; 272 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 273 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; 274 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 275 final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator; 276 if (winAnimator.isAnimating() || winAnimator.mWin.mExiting) { 277 return true; 278 } 279 } 280 } 281 } 282 return false; 283 } 284 285 /** 286 * Put a Task in this stack. Used for adding and moving. 287 * @param task The task to add. 288 * @param toTop Whether to add it to the top or bottom. 289 */ 290 void addTask(Task task, boolean toTop) { 291 int stackNdx; 292 if (!toTop) { 293 stackNdx = 0; 294 } else { 295 stackNdx = mTasks.size(); 296 if (!mService.isCurrentProfileLocked(task.mUserId)) { 297 // Place the task below all current user tasks. 298 while (--stackNdx >= 0) { 299 if (!mService.isCurrentProfileLocked(mTasks.get(stackNdx).mUserId)) { 300 break; 301 } 302 } 303 // Put it above first non-current user task. 304 ++stackNdx; 305 } 306 } 307 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "addTask: task=" + task + " toTop=" + toTop 308 + " pos=" + stackNdx); 309 mTasks.add(stackNdx, task); 310 311 task.mStack = this; 312 if (toTop) { 313 mDisplayContent.moveStack(this, true); 314 } 315 EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, stackNdx); 316 } 317 318 void moveTaskToTop(Task task) { 319 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToTop: task=" + task + " Callers=" 320 + Debug.getCallers(6)); 321 mTasks.remove(task); 322 addTask(task, true); 323 } 324 325 void moveTaskToBottom(Task task) { 326 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToBottom: task=" + task); 327 mTasks.remove(task); 328 addTask(task, false); 329 } 330 331 /** 332 * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the 333 * back. 334 * @param task The Task to delete. 335 */ 336 void removeTask(Task task) { 337 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task); 338 mTasks.remove(task); 339 if (mDisplayContent != null) { 340 if (mTasks.isEmpty()) { 341 mDisplayContent.moveStack(this, false); 342 } 343 mDisplayContent.layoutNeeded = true; 344 } 345 for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) { 346 final AppWindowToken wtoken = mExitingAppTokens.get(appNdx); 347 if (wtoken.mTask == task) { 348 wtoken.mIsExiting = false; 349 mExitingAppTokens.remove(appNdx); 350 } 351 } 352 } 353 354 void attachDisplayContent(DisplayContent displayContent) { 355 if (mDisplayContent != null) { 356 throw new IllegalStateException("attachDisplayContent: Already attached"); 357 } 358 359 mDisplayContent = displayContent; 360 mDimLayer = new DimLayer(mService, this, displayContent); 361 mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent); 362 updateDisplayInfo(); 363 } 364 365 void detachDisplay() { 366 EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); 367 368 boolean doAnotherLayoutPass = false; 369 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 370 final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens; 371 for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) { 372 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows; 373 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) { 374 mService.removeWindowInnerLocked(null, appWindows.get(winNdx)); 375 doAnotherLayoutPass = true; 376 } 377 } 378 } 379 if (doAnotherLayoutPass) { 380 mService.requestTraversalLocked(); 381 } 382 383 mAnimationBackgroundSurface.destroySurface(); 384 mAnimationBackgroundSurface = null; 385 mDimLayer.destroySurface(); 386 mDimLayer = null; 387 mDisplayContent = null; 388 } 389 390 void resetAnimationBackgroundAnimator() { 391 mAnimationBackgroundAnimator = null; 392 mAnimationBackgroundSurface.hide(); 393 } 394 395 private long getDimBehindFadeDuration(long duration) { 396 TypedValue tv = new TypedValue(); 397 mService.mContext.getResources().getValue( 398 com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true); 399 if (tv.type == TypedValue.TYPE_FRACTION) { 400 duration = (long)tv.getFraction(duration, duration); 401 } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) { 402 duration = tv.data; 403 } 404 return duration; 405 } 406 407 boolean animateDimLayers() { 408 final int dimLayer; 409 final float dimAmount; 410 if (mDimWinAnimator == null) { 411 dimLayer = mDimLayer.getLayer(); 412 dimAmount = 0; 413 } else { 414 dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM; 415 dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount; 416 } 417 final float targetAlpha = mDimLayer.getTargetAlpha(); 418 if (targetAlpha != dimAmount) { 419 if (mDimWinAnimator == null) { 420 mDimLayer.hide(DEFAULT_DIM_DURATION); 421 } else { 422 long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null) 423 ? mDimWinAnimator.mAnimation.computeDurationHint() 424 : DEFAULT_DIM_DURATION; 425 if (targetAlpha > dimAmount) { 426 duration = getDimBehindFadeDuration(duration); 427 } 428 mDimLayer.show(dimLayer, dimAmount, duration); 429 } 430 } else if (mDimLayer.getLayer() != dimLayer) { 431 mDimLayer.setLayer(dimLayer); 432 } 433 if (mDimLayer.isAnimating()) { 434 if (!mService.okToDisplay()) { 435 // Jump to the end of the animation. 436 mDimLayer.show(); 437 } else { 438 return mDimLayer.stepAnimation(); 439 } 440 } 441 return false; 442 } 443 444 void resetDimmingTag() { 445 mDimmingTag = false; 446 } 447 448 void setDimmingTag() { 449 mDimmingTag = true; 450 } 451 452 boolean testDimmingTag() { 453 return mDimmingTag; 454 } 455 456 boolean isDimming() { 457 return mDimLayer.isDimming(); 458 } 459 460 boolean isDimming(WindowStateAnimator winAnimator) { 461 return mDimWinAnimator == winAnimator && mDimLayer.isDimming(); 462 } 463 464 void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) { 465 // Only set dim params on the highest dimmed layer. 466 // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer. 467 if (newWinAnimator.mSurfaceShown && (mDimWinAnimator == null 468 || !mDimWinAnimator.mSurfaceShown 469 || mDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) { 470 mDimWinAnimator = newWinAnimator; 471 if (mDimWinAnimator.mWin.mAppToken == null 472 && !mFullscreen && mDisplayContent != null) { 473 // Dim should cover the entire screen for system windows. 474 mDisplayContent.getLogicalDisplayRect(mTmpRect); 475 mDimLayer.setBounds(mTmpRect); 476 } 477 } 478 } 479 480 void stopDimmingIfNeeded() { 481 if (!mDimmingTag && isDimming()) { 482 mDimWinAnimator = null; 483 mDimLayer.setBounds(mBounds); 484 } 485 } 486 487 void setAnimationBackground(WindowStateAnimator winAnimator, int color) { 488 int animLayer = winAnimator.mAnimLayer; 489 if (mAnimationBackgroundAnimator == null 490 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) { 491 mAnimationBackgroundAnimator = winAnimator; 492 animLayer = mService.adjustAnimationBackground(winAnimator); 493 mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM, 494 ((color >> 24) & 0xff) / 255f, 0); 495 } 496 } 497 498 void switchUser() { 499 int top = mTasks.size(); 500 for (int taskNdx = 0; taskNdx < top; ++taskNdx) { 501 Task task = mTasks.get(taskNdx); 502 if (mService.isCurrentProfileLocked(task.mUserId)) { 503 mTasks.remove(taskNdx); 504 mTasks.add(task); 505 --top; 506 } 507 } 508 } 509 510 void close() { 511 mDimLayer.mDimSurface.destroy(); 512 mAnimationBackgroundSurface.mDimSurface.destroy(); 513 } 514 515 public void dump(String prefix, PrintWriter pw) { 516 pw.print(prefix); pw.print("mStackId="); pw.println(mStackId); 517 pw.print(prefix); pw.print("mDeferDetach="); pw.println(mDeferDetach); 518 for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) { 519 pw.print(prefix); pw.println(mTasks.get(taskNdx)); 520 } 521 if (mAnimationBackgroundSurface.isDimming()) { 522 pw.print(prefix); pw.println("mWindowAnimationBackgroundSurface:"); 523 mAnimationBackgroundSurface.printTo(prefix + " ", pw); 524 } 525 if (mDimLayer.isDimming()) { 526 pw.print(prefix); pw.println("mDimLayer:"); 527 mDimLayer.printTo(prefix + " ", pw); 528 pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator); 529 } 530 if (!mExitingAppTokens.isEmpty()) { 531 pw.println(); 532 pw.println(" Exiting application tokens:"); 533 for (int i=mExitingAppTokens.size()-1; i>=0; i--) { 534 WindowToken token = mExitingAppTokens.get(i); 535 pw.print(" Exiting App #"); pw.print(i); 536 pw.print(' '); pw.print(token); 537 pw.println(':'); 538 token.dump(pw, " "); 539 } 540 } 541 } 542 543 @Override 544 public String toString() { 545 return "{stackId=" + mStackId + " tasks=" + mTasks + "}"; 546 } 547} 548