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