TaskStack.java revision b660b9d8cf6b951b85a35599d636c470795e9a1a
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.graphics.Rect; 23import android.os.Debug; 24import android.util.EventLog; 25import android.util.Slog; 26import android.util.TypedValue; 27import com.android.server.EventLogTags; 28 29import java.io.PrintWriter; 30import java.util.ArrayList; 31 32public class TaskStack { 33 /** Amount of time in milliseconds to animate the dim surface from one value to another, 34 * when no window animation is driving it. */ 35 private static final int DEFAULT_DIM_DURATION = 200; 36 37 /** Unique identifier */ 38 final int mStackId; 39 40 /** The service */ 41 private final WindowManagerService mService; 42 43 /** The display this stack sits under. */ 44 private DisplayContent mDisplayContent; 45 46 /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match 47 * mTaskHistory in the ActivityStack with the same mStackId */ 48 private final ArrayList<Task> mTasks = new ArrayList<Task>(); 49 50 /** For comparison with DisplayContent bounds. */ 51 private Rect mTmpRect = new Rect(); 52 53 /** Content limits relative to the DisplayContent this sits in. */ 54 private Rect mBounds = new Rect(); 55 56 /** Whether mBounds is fullscreen */ 57 private boolean mFullscreen = true; 58 59 /** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */ 60 private DimLayer mDimLayer; 61 62 /** The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. */ 63 WindowStateAnimator mDimWinAnimator; 64 65 /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */ 66 DimLayer mAnimationBackgroundSurface; 67 68 /** The particular window with an Animation with non-zero background color. */ 69 WindowStateAnimator mAnimationBackgroundAnimator; 70 71 /** Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the end 72 * then stop any dimming. */ 73 boolean mDimmingTag; 74 75 /** Application tokens that are exiting, but still on screen for animations. */ 76 final AppTokenList mExitingAppTokens = new AppTokenList(); 77 78 TaskStack(WindowManagerService service, int stackId) { 79 mService = service; 80 mStackId = stackId; 81 // TODO: remove bounds from log, they are always 0. 82 EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top, 83 mBounds.right, mBounds.bottom); 84 } 85 86 DisplayContent getDisplayContent() { 87 return mDisplayContent; 88 } 89 90 ArrayList<Task> getTasks() { 91 return mTasks; 92 } 93 94 void resizeWindows() { 95 final boolean underStatusBar = mBounds.top == 0; 96 97 final ArrayList<WindowState> resizingWindows = mService.mResizingWindows; 98 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 99 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; 100 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 101 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; 102 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 103 final WindowState win = windows.get(winNdx); 104 if (!resizingWindows.contains(win)) { 105 if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG, 106 "setBounds: Resizing " + win); 107 resizingWindows.add(win); 108 } 109 win.mUnderStatusBar = underStatusBar; 110 } 111 } 112 } 113 } 114 115 boolean setBounds(Rect bounds) { 116 boolean oldFullscreen = mFullscreen; 117 if (mDisplayContent != null) { 118 mDisplayContent.getLogicalDisplayRect(mTmpRect); 119 mFullscreen = mTmpRect.equals(bounds); 120 } 121 122 if (mBounds.equals(bounds) && oldFullscreen == mFullscreen) { 123 return false; 124 } 125 126 mDimLayer.setBounds(bounds); 127 mAnimationBackgroundSurface.setBounds(bounds); 128 mBounds.set(bounds); 129 130 return true; 131 } 132 133 void getBounds(Rect out) { 134 out.set(mBounds); 135 } 136 137 void updateDisplayInfo() { 138 if (mFullscreen && mDisplayContent != null) { 139 mDisplayContent.getLogicalDisplayRect(mTmpRect); 140 setBounds(mTmpRect); 141 } 142 } 143 144 boolean isFullscreen() { 145 return mFullscreen; 146 } 147 148 boolean isAnimating() { 149 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 150 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; 151 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 152 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; 153 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 154 if (windows.get(winNdx).mWinAnimator.isAnimating()) { 155 return true; 156 } 157 } 158 } 159 } 160 return false; 161 } 162 163 /** 164 * Put a Task in this stack. Used for adding and moving. 165 * @param task The task to add. 166 * @param toTop Whether to add it to the top or bottom. 167 */ 168 void addTask(Task task, boolean toTop) { 169 int stackNdx; 170 if (!toTop) { 171 stackNdx = 0; 172 } else { 173 stackNdx = mTasks.size(); 174 final int currentUserId = mService.mCurrentUserId; 175 if (task.mUserId != currentUserId) { 176 // Place the task below all current user tasks. 177 while (--stackNdx >= 0) { 178 if (currentUserId != mTasks.get(stackNdx).mUserId) { 179 break; 180 } 181 } 182 ++stackNdx; 183 } 184 } 185 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "addTask: task=" + task + " toTop=" + toTop 186 + " pos=" + stackNdx); 187 mTasks.add(stackNdx, task); 188 189 task.mStack = this; 190 mDisplayContent.moveStack(this, true); 191 EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, stackNdx); 192 } 193 194 void moveTaskToTop(Task task) { 195 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToTop: task=" + task + " Callers=" 196 + Debug.getCallers(6)); 197 mTasks.remove(task); 198 addTask(task, true); 199 } 200 201 void moveTaskToBottom(Task task) { 202 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToBottom: task=" + task); 203 mTasks.remove(task); 204 addTask(task, false); 205 } 206 207 /** 208 * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the 209 * back. 210 * @param task The Task to delete. 211 */ 212 void removeTask(Task task) { 213 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task); 214 mTasks.remove(task); 215 if (mDisplayContent != null) { 216 if (mTasks.isEmpty()) { 217 mDisplayContent.moveStack(this, false); 218 } 219 mDisplayContent.layoutNeeded = true; 220 } 221 } 222 223 void attachDisplayContent(DisplayContent displayContent) { 224 if (mDisplayContent != null) { 225 throw new IllegalStateException("attachDisplayContent: Already attached"); 226 } 227 228 mDisplayContent = displayContent; 229 mDimLayer = new DimLayer(mService, this, displayContent); 230 mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent); 231 updateDisplayInfo(); 232 } 233 234 void detachDisplay() { 235 EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); 236 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 237 mService.tmpRemoveTaskWindowsLocked(mTasks.get(taskNdx)); 238 } 239 mAnimationBackgroundSurface.destroySurface(); 240 mAnimationBackgroundSurface = null; 241 mDimLayer.destroySurface(); 242 mDimLayer = null; 243 mDisplayContent = null; 244 } 245 246 void resetAnimationBackgroundAnimator() { 247 mAnimationBackgroundAnimator = null; 248 mAnimationBackgroundSurface.hide(); 249 } 250 251 private long getDimBehindFadeDuration(long duration) { 252 TypedValue tv = new TypedValue(); 253 mService.mContext.getResources().getValue( 254 com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true); 255 if (tv.type == TypedValue.TYPE_FRACTION) { 256 duration = (long)tv.getFraction(duration, duration); 257 } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) { 258 duration = tv.data; 259 } 260 return duration; 261 } 262 263 boolean animateDimLayers() { 264 final int dimLayer; 265 final float dimAmount; 266 if (mDimWinAnimator == null) { 267 dimLayer = mDimLayer.getLayer(); 268 dimAmount = 0; 269 } else { 270 dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM; 271 dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount; 272 } 273 final float targetAlpha = mDimLayer.getTargetAlpha(); 274 if (targetAlpha != dimAmount) { 275 if (mDimWinAnimator == null) { 276 mDimLayer.hide(DEFAULT_DIM_DURATION); 277 } else { 278 long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null) 279 ? mDimWinAnimator.mAnimation.computeDurationHint() 280 : DEFAULT_DIM_DURATION; 281 if (targetAlpha > dimAmount) { 282 duration = getDimBehindFadeDuration(duration); 283 } 284 mDimLayer.show(dimLayer, dimAmount, duration); 285 } 286 } else if (mDimLayer.getLayer() != dimLayer) { 287 mDimLayer.setLayer(dimLayer); 288 } 289 if (mDimLayer.isAnimating()) { 290 if (!mService.okToDisplay()) { 291 // Jump to the end of the animation. 292 mDimLayer.show(); 293 } else { 294 return mDimLayer.stepAnimation(); 295 } 296 } 297 return false; 298 } 299 300 void resetDimmingTag() { 301 mDimmingTag = false; 302 } 303 304 void setDimmingTag() { 305 mDimmingTag = true; 306 } 307 308 boolean testDimmingTag() { 309 return mDimmingTag; 310 } 311 312 boolean isDimming() { 313 return mDimLayer.isDimming(); 314 } 315 316 boolean isDimming(WindowStateAnimator winAnimator) { 317 return mDimWinAnimator == winAnimator && mDimLayer.isDimming(); 318 } 319 320 void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) { 321 // Only set dim params on the highest dimmed layer. 322 final WindowStateAnimator existingDimWinAnimator = mDimWinAnimator; 323 // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer. 324 if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null 325 || !existingDimWinAnimator.mSurfaceShown 326 || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) { 327 mDimWinAnimator = newWinAnimator; 328 } 329 } 330 331 void stopDimmingIfNeeded() { 332 if (!mDimmingTag && isDimming()) { 333 mDimWinAnimator = null; 334 } 335 } 336 337 void setAnimationBackground(WindowStateAnimator winAnimator, int color) { 338 int animLayer = winAnimator.mAnimLayer; 339 if (mAnimationBackgroundAnimator == null 340 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) { 341 mAnimationBackgroundAnimator = winAnimator; 342 animLayer = mService.adjustAnimationBackground(winAnimator); 343 mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM, 344 ((color >> 24) & 0xff) / 255f, 0); 345 } 346 } 347 348 void switchUser(int userId) { 349 int top = mTasks.size(); 350 for (int taskNdx = 0; taskNdx < top; ++taskNdx) { 351 Task task = mTasks.get(taskNdx); 352 if (task.mUserId == userId) { 353 mTasks.remove(taskNdx); 354 mTasks.add(task); 355 --top; 356 } 357 } 358 } 359 360 void close() { 361 mDimLayer.mDimSurface.destroy(); 362 mAnimationBackgroundSurface.mDimSurface.destroy(); 363 } 364 365 void checkForDeferredActions() { 366 if (mDisplayContent != null && 367 (mDisplayContent.mDeferredActions & DisplayContent.DEFER_DETACH) != 0 && 368 !isAnimating()) { 369 mDisplayContent.mDeferredActions &= ~DisplayContent.DEFER_DETACH; 370 mService.detachStack(mStackId); 371 if ((mDisplayContent.mDeferredActions & DisplayContent.DEFER_REMOVAL) != 0) { 372 mDisplayContent.mDeferredActions &= ~DisplayContent.DEFER_REMOVAL; 373 mService.onDisplayRemoved(mDisplayContent.getDisplayId()); 374 } 375 } 376 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 377 final Task task = mTasks.get(taskNdx); 378 AppTokenList tokens = task.mAppTokens; 379 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { 380 AppWindowToken wtoken = tokens.get(tokenNdx); 381 if (wtoken.mDeferRemoval) { 382 wtoken.mDeferRemoval = false; 383 mService.removeAppFromTaskLocked(wtoken); 384 } 385 } 386 if (task.mDeferRemoval) { 387 task.mDeferRemoval = false; 388 mService.removeTaskLocked(task); 389 } 390 } 391 } 392 393 public void dump(String prefix, PrintWriter pw) { 394 pw.print(prefix); pw.print("mStackId="); pw.println(mStackId); 395 for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) { 396 pw.print(prefix); pw.println(mTasks.get(taskNdx)); 397 } 398 if (mAnimationBackgroundSurface.isDimming()) { 399 pw.print(prefix); pw.println("mWindowAnimationBackgroundSurface:"); 400 mAnimationBackgroundSurface.printTo(prefix + " ", pw); 401 } 402 if (mDimLayer.isDimming()) { 403 pw.print(prefix); pw.println("mDimLayer:"); 404 mDimLayer.printTo(prefix, pw); 405 pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator); 406 } 407 if (!mExitingAppTokens.isEmpty()) { 408 pw.println(); 409 pw.println(" Exiting application tokens:"); 410 for (int i=mExitingAppTokens.size()-1; i>=0; i--) { 411 WindowToken token = mExitingAppTokens.get(i); 412 pw.print(" Exiting App #"); pw.print(i); 413 pw.print(' '); pw.print(token); 414 pw.println(':'); 415 token.dump(pw, " "); 416 } 417 } 418 } 419 420 @Override 421 public String toString() { 422 return "{stackId=" + mStackId + " tasks=" + mTasks + "}"; 423 } 424} 425