• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TaskStack(WindowManagerService service, int stackId, DisplayContent displayContent)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 
getDisplayContent()79     DisplayContent getDisplayContent() {
80         return mDisplayContent;
81     }
82 
getTasks()83     ArrayList<Task> getTasks() {
84         return mTasks;
85     }
86 
isHomeStack()87     boolean isHomeStack() {
88         return mStackId == HOME_STACK_ID;
89     }
90 
hasSibling()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      */
addTask(Task task, boolean toTop)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 
moveTaskToTop(Task task)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 
moveTaskToBottom(Task task)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      */
removeTask(Task task)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 
remove()153     int remove() {
154         mAnimationBackgroundSurface.destroySurface();
155         mDimLayer.destroySurface();
156         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
157         return mStackBox.remove();
158     }
159 
resetAnimationBackgroundAnimator()160     void resetAnimationBackgroundAnimator() {
161         mAnimationBackgroundAnimator = null;
162         mAnimationBackgroundSurface.hide();
163     }
164 
getDimBehindFadeDuration(long duration)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 
animateDimLayers()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 
resetDimmingTag()214     void resetDimmingTag() {
215         mDimmingTag = false;
216     }
217 
setDimmingTag()218     void setDimmingTag() {
219         mDimmingTag = true;
220     }
221 
testDimmingTag()222     boolean testDimmingTag() {
223         return mDimmingTag;
224     }
225 
isDimming()226     boolean isDimming() {
227         return mDimLayer.isDimming();
228     }
229 
isDimming(WindowStateAnimator winAnimator)230     boolean isDimming(WindowStateAnimator winAnimator) {
231         return mDimWinAnimator == winAnimator && mDimLayer.isDimming();
232     }
233 
startDimmingIfNeeded(WindowStateAnimator newWinAnimator)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 
stopDimmingIfNeeded()245     void stopDimmingIfNeeded() {
246         if (!mDimmingTag && isDimming()) {
247             mDimWinAnimator = null;
248         }
249     }
250 
setAnimationBackground(WindowStateAnimator winAnimator, int color)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 
setBounds(Rect bounds, boolean underStatusBar)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 
switchUser(int userId)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 
dump(String prefix, PrintWriter pw)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
toString()313     public String toString() {
314         return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
315     }
316 }
317