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 17 package com.android.server.wm; 18 19 import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT; 20 import static com.android.server.wm.WindowManagerService.TAG; 21 22 import android.graphics.Rect; 23 import android.os.Debug; 24 import android.util.Slog; 25 import android.util.TypedValue; 26 27 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; 28 29 import java.io.PrintWriter; 30 import java.util.ArrayList; 31 32 public 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 final 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 ArrayList<Task> mTasks = new ArrayList<Task>(); 49 50 /** The StackBox this sits in. */ 51 StackBox mStackBox; 52 53 /** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */ 54 final DimLayer mDimLayer; 55 56 /** The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. */ 57 WindowStateAnimator mDimWinAnimator; 58 59 /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */ 60 final DimLayer mAnimationBackgroundSurface; 61 62 /** The particular window with an Animation with non-zero background color. */ 63 WindowStateAnimator mAnimationBackgroundAnimator; 64 65 /** Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the end 66 * then stop any dimming. */ 67 boolean mDimmingTag; 68 69 TaskStack(WindowManagerService service, int stackId, DisplayContent displayContent) { 70 mService = service; 71 mStackId = stackId; 72 mDisplayContent = displayContent; 73 final int displayId = displayContent.getDisplayId(); 74 mDimLayer = new DimLayer(service, this); 75 mAnimationBackgroundSurface = new DimLayer(service, this); 76 } 77 78 DisplayContent getDisplayContent() { 79 return mDisplayContent; 80 } 81 82 ArrayList<Task> getTasks() { 83 return mTasks; 84 } 85 86 boolean isHomeStack() { 87 return mStackId == HOME_STACK_ID; 88 } 89 90 boolean hasSibling() { 91 return mStackBox.mParent != null; 92 } 93 94 /** 95 * Put a Task in this stack. Used for adding and moving. 96 * @param task The task to add. 97 * @param toTop Whether to add it to the top or bottom. 98 */ 99 boolean addTask(Task task, boolean toTop) { 100 mStackBox.makeDirty(); 101 102 int stackNdx; 103 if (!toTop) { 104 stackNdx = 0; 105 } else { 106 stackNdx = mTasks.size(); 107 final int currentUserId = mService.mCurrentUserId; 108 if (task.mUserId != currentUserId) { 109 // Place the task below all current user tasks. 110 while (--stackNdx >= 0) { 111 if (currentUserId != mTasks.get(stackNdx).mUserId) { 112 break; 113 } 114 } 115 ++stackNdx; 116 } 117 } 118 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "addTask: task=" + task + " toTop=" + toTop 119 + " pos=" + stackNdx); 120 mTasks.add(stackNdx, task); 121 122 task.mStack = this; 123 return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID); 124 } 125 126 boolean moveTaskToTop(Task task) { 127 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToTop: task=" + task + " Callers=" 128 + Debug.getCallers(6)); 129 mTasks.remove(task); 130 return addTask(task, true); 131 } 132 133 boolean moveTaskToBottom(Task task) { 134 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToBottom: task=" + task); 135 mTasks.remove(task); 136 return addTask(task, false); 137 } 138 139 /** 140 * Delete a Task from this stack. If it is the last Task in the stack, remove this stack from 141 * its parent StackBox and merge the parent. 142 * @param task The Task to delete. 143 */ 144 void removeTask(Task task) { 145 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task); 146 mStackBox.makeDirty(); 147 mTasks.remove(task); 148 } 149 150 int remove() { 151 mAnimationBackgroundSurface.destroySurface(); 152 mDimLayer.destroySurface(); 153 return mStackBox.remove(); 154 } 155 156 void resetAnimationBackgroundAnimator() { 157 mAnimationBackgroundAnimator = null; 158 mAnimationBackgroundSurface.hide(); 159 } 160 161 private long getDimBehindFadeDuration(long duration) { 162 TypedValue tv = new TypedValue(); 163 mService.mContext.getResources().getValue( 164 com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true); 165 if (tv.type == TypedValue.TYPE_FRACTION) { 166 duration = (long)tv.getFraction(duration, duration); 167 } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) { 168 duration = tv.data; 169 } 170 return duration; 171 } 172 173 boolean animateDimLayers() { 174 final int dimLayer; 175 final float dimAmount; 176 if (mDimWinAnimator == null) { 177 dimLayer = mDimLayer.getLayer(); 178 dimAmount = 0; 179 } else { 180 dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM; 181 dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount; 182 } 183 final float targetAlpha = mDimLayer.getTargetAlpha(); 184 if (targetAlpha != dimAmount) { 185 if (mDimWinAnimator == null) { 186 mDimLayer.hide(DEFAULT_DIM_DURATION); 187 } else { 188 long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null) 189 ? mDimWinAnimator.mAnimation.computeDurationHint() 190 : DEFAULT_DIM_DURATION; 191 if (targetAlpha > dimAmount) { 192 duration = getDimBehindFadeDuration(duration); 193 } 194 mDimLayer.show(dimLayer, dimAmount, duration); 195 } 196 } else if (mDimLayer.getLayer() != dimLayer) { 197 mDimLayer.setLayer(dimLayer); 198 } 199 if (mDimLayer.isAnimating()) { 200 if (!mService.okToDisplay()) { 201 // Jump to the end of the animation. 202 mDimLayer.show(); 203 } else { 204 return mDimLayer.stepAnimation(); 205 } 206 } 207 return false; 208 } 209 210 void resetDimmingTag() { 211 mDimmingTag = false; 212 } 213 214 void setDimmingTag() { 215 mDimmingTag = true; 216 } 217 218 boolean testDimmingTag() { 219 return mDimmingTag; 220 } 221 222 boolean isDimming() { 223 return mDimLayer.isDimming(); 224 } 225 226 boolean isDimming(WindowStateAnimator winAnimator) { 227 return mDimWinAnimator == winAnimator && mDimLayer.isDimming(); 228 } 229 230 void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) { 231 // Only set dim params on the highest dimmed layer. 232 final WindowStateAnimator existingDimWinAnimator = mDimWinAnimator; 233 // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer. 234 if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null 235 || !existingDimWinAnimator.mSurfaceShown 236 || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) { 237 mDimWinAnimator = newWinAnimator; 238 } 239 } 240 241 void stopDimmingIfNeeded() { 242 if (!mDimmingTag && isDimming()) { 243 mDimWinAnimator = null; 244 } 245 } 246 247 void setAnimationBackground(WindowStateAnimator winAnimator, int color) { 248 int animLayer = winAnimator.mAnimLayer; 249 if (mAnimationBackgroundAnimator == null 250 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) { 251 mAnimationBackgroundAnimator = winAnimator; 252 animLayer = mService.adjustAnimationBackground(winAnimator); 253 mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM, 254 ((color >> 24) & 0xff) / 255f, 0); 255 } 256 } 257 258 void setBounds(Rect bounds, boolean underStatusBar) { 259 mDimLayer.setBounds(bounds); 260 mAnimationBackgroundSurface.setBounds(bounds); 261 262 final ArrayList<WindowState> resizingWindows = mService.mResizingWindows; 263 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { 264 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens; 265 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { 266 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows; 267 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 268 final WindowState win = windows.get(winNdx); 269 if (!resizingWindows.contains(win)) { 270 resizingWindows.add(win); 271 } 272 win.mUnderStatusBar = underStatusBar; 273 } 274 } 275 } 276 } 277 278 void switchUser(int userId) { 279 int top = mTasks.size(); 280 for (int taskNdx = 0; taskNdx < top; ++taskNdx) { 281 Task task = mTasks.get(taskNdx); 282 if (task.mUserId == userId) { 283 mTasks.remove(taskNdx); 284 mTasks.add(task); 285 --top; 286 } 287 } 288 } 289 290 public void dump(String prefix, PrintWriter pw) { 291 pw.print(prefix); pw.print("mStackId="); pw.println(mStackId); 292 for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) { 293 pw.print(prefix); pw.println(mTasks.get(taskNdx)); 294 } 295 if (mAnimationBackgroundSurface.isDimming()) { 296 pw.print(prefix); pw.println("mWindowAnimationBackgroundSurface:"); 297 mAnimationBackgroundSurface.printTo(prefix + " ", pw); 298 } 299 if (mDimLayer.isDimming()) { 300 pw.print(prefix); pw.println("mDimLayer:"); 301 mDimLayer.printTo(prefix, pw); 302 pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator); 303 } 304 } 305 306 @Override 307 public String toString() { 308 return "{stackId=" + mStackId + " tasks=" + mTasks + "}"; 309 } 310 } 311