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