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