1 /*
2  * Copyright (C) 2012 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.am.ActivityStackSupervisor.HOME_STACK_ID;
20 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
21 import static com.android.server.wm.WindowManagerService.TAG;
22 
23 import android.graphics.Rect;
24 import android.graphics.Region;
25 import android.util.Slog;
26 import android.view.Display;
27 import android.view.DisplayInfo;
28 import android.view.Surface;
29 
30 import java.io.PrintWriter;
31 import java.util.ArrayList;
32 
33 class DisplayContentList extends ArrayList<DisplayContent> {
34 }
35 
36 /**
37  * Utility class for keeping track of the WindowStates and other pertinent contents of a
38  * particular Display.
39  *
40  * IMPORTANT: No method from this class should ever be used without holding
41  * WindowManagerService.mWindowMap.
42  */
43 class DisplayContent {
44 
45     /** Unique identifier of this stack. */
46     private final int mDisplayId;
47 
48     /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
49      * from mDisplayWindows; */
50     private final WindowList mWindows = new WindowList();
51 
52     // This protects the following display size properties, so that
53     // getDisplaySize() doesn't need to acquire the global lock.  This is
54     // needed because the window manager sometimes needs to use ActivityThread
55     // while it has its global state locked (for example to load animation
56     // resources), but the ActivityThread also needs get the current display
57     // size sometimes when it has its package lock held.
58     //
59     // These will only be modified with both mWindowMap and mDisplaySizeLock
60     // held (in that order) so the window manager doesn't need to acquire this
61     // lock when needing these values in its normal operation.
62     final Object mDisplaySizeLock = new Object();
63     int mInitialDisplayWidth = 0;
64     int mInitialDisplayHeight = 0;
65     int mInitialDisplayDensity = 0;
66     int mBaseDisplayWidth = 0;
67     int mBaseDisplayHeight = 0;
68     int mBaseDisplayDensity = 0;
69     private final DisplayInfo mDisplayInfo = new DisplayInfo();
70     private final Display mDisplay;
71 
72     Rect mBaseDisplayRect = new Rect();
73     Rect mContentRect = new Rect();
74 
75     // Accessed directly by all users.
76     boolean layoutNeeded;
77     int pendingLayoutChanges;
78     final boolean isDefaultDisplay;
79 
80     /** Window tokens that are in the process of exiting, but still on screen for animations. */
81     final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
82 
83     /** Array containing all TaskStacks on this display.  Array
84      * is stored in display order with the current bottom stack at 0. */
85     private final ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>();
86 
87     /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
88      * (except a future lockscreen TaskStack) moves to the top. */
89     private TaskStack mHomeStack = null;
90 
91     /** Detect user tapping outside of current focused stack bounds .*/
92     StackTapPointerEventListener mTapDetector;
93 
94     /** Detect user tapping outside of current focused stack bounds .*/
95     Region mTouchExcludeRegion = new Region();
96 
97     /** Save allocating when calculating rects */
98     Rect mTmpRect = new Rect();
99 
100     /** For gathering Task objects in order. */
101     final ArrayList<Task> mTmpTaskHistory = new ArrayList<Task>();
102 
103     final WindowManagerService mService;
104 
105     /** Remove this display when animation on it has completed. */
106     boolean mDeferredRemoval;
107 
108     /**
109      * @param display May not be null.
110      * @param service You know.
111      */
DisplayContent(Display display, WindowManagerService service)112     DisplayContent(Display display, WindowManagerService service) {
113         mDisplay = display;
114         mDisplayId = display.getDisplayId();
115         display.getDisplayInfo(mDisplayInfo);
116         isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
117         mService = service;
118     }
119 
getDisplayId()120     int getDisplayId() {
121         return mDisplayId;
122     }
123 
getWindowList()124     WindowList getWindowList() {
125         return mWindows;
126     }
127 
getDisplay()128     Display getDisplay() {
129         return mDisplay;
130     }
131 
getDisplayInfo()132     DisplayInfo getDisplayInfo() {
133         return mDisplayInfo;
134     }
135 
136     /**
137      * Returns true if the specified UID has access to this display.
138      */
hasAccess(int uid)139     public boolean hasAccess(int uid) {
140         return mDisplay.hasAccess(uid);
141     }
142 
isPrivate()143     public boolean isPrivate() {
144         return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
145     }
146 
getStacks()147     ArrayList<TaskStack> getStacks() {
148         return mStacks;
149     }
150 
151     /**
152      * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
153      * @return All the Tasks, in order, on this display.
154      */
getTasks()155     ArrayList<Task> getTasks() {
156         mTmpTaskHistory.clear();
157         final int numStacks = mStacks.size();
158         for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
159             mTmpTaskHistory.addAll(mStacks.get(stackNdx).getTasks());
160         }
161         return mTmpTaskHistory;
162     }
163 
getHomeStack()164     TaskStack getHomeStack() {
165         if (mHomeStack == null && mDisplayId == Display.DEFAULT_DISPLAY) {
166             Slog.e(TAG, "getHomeStack: Returning null from this=" + this);
167         }
168         return mHomeStack;
169     }
170 
updateDisplayInfo()171     void updateDisplayInfo() {
172         mDisplay.getDisplayInfo(mDisplayInfo);
173         for (int i = mStacks.size() - 1; i >= 0; --i) {
174             mStacks.get(i).updateDisplayInfo();
175         }
176     }
177 
getLogicalDisplayRect(Rect out)178     void getLogicalDisplayRect(Rect out) {
179         // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
180         final int orientation = mDisplayInfo.rotation;
181         boolean rotated = (orientation == Surface.ROTATION_90
182                 || orientation == Surface.ROTATION_270);
183         final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
184         final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
185         int width = mDisplayInfo.logicalWidth;
186         int left = (physWidth - width) / 2;
187         int height = mDisplayInfo.logicalHeight;
188         int top = (physHeight - height) / 2;
189         out.set(left, top, left + width, top + height);
190     }
191 
192     /** Refer to {@link WindowManagerService#attachStack(int, int)} */
attachStack(TaskStack stack)193     void attachStack(TaskStack stack) {
194         if (stack.mStackId == HOME_STACK_ID) {
195             if (mHomeStack != null) {
196                 throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
197             }
198             mHomeStack = stack;
199         }
200         mStacks.add(stack);
201         layoutNeeded = true;
202     }
203 
moveStack(TaskStack stack, boolean toTop)204     void moveStack(TaskStack stack, boolean toTop) {
205         mStacks.remove(stack);
206         mStacks.add(toTop ? mStacks.size() : 0, stack);
207     }
208 
detachStack(TaskStack stack)209     void detachStack(TaskStack stack) {
210         mStacks.remove(stack);
211     }
212 
213     /**
214      * Propagate the new bounds to all child stacks.
215      * @param contentRect The bounds to apply at the top level.
216      */
resize(Rect contentRect)217     void resize(Rect contentRect) {
218         mContentRect.set(contentRect);
219     }
220 
stackIdFromPoint(int x, int y)221     int stackIdFromPoint(int x, int y) {
222         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
223             final TaskStack stack = mStacks.get(stackNdx);
224             stack.getBounds(mTmpRect);
225             if (mTmpRect.contains(x, y)) {
226                 return stack.mStackId;
227             }
228         }
229         return -1;
230     }
231 
setTouchExcludeRegion(TaskStack focusedStack)232     void setTouchExcludeRegion(TaskStack focusedStack) {
233         mTouchExcludeRegion.set(mBaseDisplayRect);
234         WindowList windows = getWindowList();
235         for (int i = windows.size() - 1; i >= 0; --i) {
236             final WindowState win = windows.get(i);
237             final TaskStack stack = win.getStack();
238             if (win.isVisibleLw() && stack != null && stack != focusedStack) {
239                 mTmpRect.set(win.mVisibleFrame);
240                 mTmpRect.intersect(win.mVisibleInsets);
241                 mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
242             }
243         }
244     }
245 
switchUserStacks(int newUserId)246     void switchUserStacks(int newUserId) {
247         final WindowList windows = getWindowList();
248         for (int i = 0; i < windows.size(); i++) {
249             final WindowState win = windows.get(i);
250             if (win.isHiddenFromUserLocked()) {
251                 if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "
252                         + win + ", attrs=" + win.mAttrs.type + ", belonging to "
253                         + win.mOwnerUid);
254                 win.hideLw(false);
255             }
256         }
257 
258         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
259             mStacks.get(stackNdx).switchUser(newUserId);
260         }
261     }
262 
resetAnimationBackgroundAnimator()263     void resetAnimationBackgroundAnimator() {
264         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
265             mStacks.get(stackNdx).resetAnimationBackgroundAnimator();
266         }
267     }
268 
animateDimLayers()269     boolean animateDimLayers() {
270         boolean result = false;
271         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
272             result |= mStacks.get(stackNdx).animateDimLayers();
273         }
274         return result;
275     }
276 
resetDimming()277     void resetDimming() {
278         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
279             mStacks.get(stackNdx).resetDimmingTag();
280         }
281     }
282 
isDimming()283     boolean isDimming() {
284         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
285             if (mStacks.get(stackNdx).isDimming()) {
286                 return true;
287             }
288         }
289         return false;
290     }
291 
stopDimmingIfNeeded()292     void stopDimmingIfNeeded() {
293         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
294             mStacks.get(stackNdx).stopDimmingIfNeeded();
295         }
296     }
297 
close()298     void close() {
299         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
300             mStacks.get(stackNdx).close();
301         }
302     }
303 
isAnimating()304     boolean isAnimating() {
305         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
306             final TaskStack stack = mStacks.get(stackNdx);
307             if (stack.isAnimating()) {
308                 return true;
309             }
310         }
311         return false;
312     }
313 
checkForDeferredActions()314     void checkForDeferredActions() {
315         boolean animating = false;
316         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
317             final TaskStack stack = mStacks.get(stackNdx);
318             if (stack.isAnimating()) {
319                 animating = true;
320             } else {
321                 if (stack.mDeferDetach) {
322                     mService.detachStackLocked(this, stack);
323                 }
324                 final ArrayList<Task> tasks = stack.getTasks();
325                 for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
326                     final Task task = tasks.get(taskNdx);
327                     AppTokenList tokens = task.mAppTokens;
328                     for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
329                         AppWindowToken wtoken = tokens.get(tokenNdx);
330                         if (wtoken.mDeferRemoval) {
331                             stack.mExitingAppTokens.remove(wtoken);
332                             wtoken.mDeferRemoval = false;
333                             mService.removeAppFromTaskLocked(wtoken);
334                         }
335                     }
336                     if (task.mDeferRemoval) {
337                         task.mDeferRemoval = false;
338                         mService.removeTaskLocked(task);
339                     }
340                 }
341             }
342         }
343         if (!animating && mDeferredRemoval) {
344             mService.onDisplayRemoved(mDisplayId);
345         }
346     }
347 
dump(String prefix, PrintWriter pw)348     public void dump(String prefix, PrintWriter pw) {
349         pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
350         final String subPrefix = "  " + prefix;
351         pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
352             pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
353             pw.print("dpi");
354             if (mInitialDisplayWidth != mBaseDisplayWidth
355                     || mInitialDisplayHeight != mBaseDisplayHeight
356                     || mInitialDisplayDensity != mBaseDisplayDensity) {
357                 pw.print(" base=");
358                 pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
359                 pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
360             }
361             pw.print(" cur=");
362             pw.print(mDisplayInfo.logicalWidth);
363             pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
364             pw.print(" app=");
365             pw.print(mDisplayInfo.appWidth);
366             pw.print("x"); pw.print(mDisplayInfo.appHeight);
367             pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
368             pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
369             pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
370             pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
371             pw.print(subPrefix); pw.print("deferred="); pw.print(mDeferredRemoval);
372                 pw.print(" layoutNeeded="); pw.println(layoutNeeded);
373         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
374             final TaskStack stack = mStacks.get(stackNdx);
375             pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
376             stack.dump(prefix + "  ", pw);
377         }
378         pw.println();
379         pw.println("  Application tokens in top down Z order:");
380         int ndx = 0;
381         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
382             final TaskStack stack = mStacks.get(stackNdx);
383             pw.print("  mStackId="); pw.println(stack.mStackId);
384             ArrayList<Task> tasks = stack.getTasks();
385             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
386                 final Task task = tasks.get(taskNdx);
387                 pw.print("    mTaskId="); pw.println(task.taskId);
388                 AppTokenList tokens = task.mAppTokens;
389                 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx, ++ndx) {
390                     final AppWindowToken wtoken = tokens.get(tokenNdx);
391                     pw.print("    Activity #"); pw.print(tokenNdx);
392                             pw.print(' '); pw.print(wtoken); pw.println(":");
393                     wtoken.dump(pw, "      ");
394                 }
395             }
396         }
397         if (ndx == 0) {
398             pw.println("    None");
399         }
400         pw.println();
401         if (!mExitingTokens.isEmpty()) {
402             pw.println();
403             pw.println("  Exiting tokens:");
404             for (int i=mExitingTokens.size()-1; i>=0; i--) {
405                 WindowToken token = mExitingTokens.get(i);
406                 pw.print("  Exiting #"); pw.print(i);
407                 pw.print(' '); pw.print(token);
408                 pw.println(':');
409                 token.dump(pw, "    ");
410             }
411         }
412         pw.println();
413     }
414 
415     @Override
toString()416     public String toString() {
417         return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks;
418     }
419 }
420