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