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