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     boolean mDisplayScalingDisabled;
70     private final DisplayInfo mDisplayInfo = new DisplayInfo();
71     private final Display mDisplay;
72 
73     Rect mBaseDisplayRect = new Rect();
74     Rect mContentRect = new Rect();
75 
76     // Accessed directly by all users.
77     boolean layoutNeeded;
78     int pendingLayoutChanges;
79     final boolean isDefaultDisplay;
80 
81     /** Window tokens that are in the process of exiting, but still on screen for animations. */
82     final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
83 
84     /** Array containing all TaskStacks on this display.  Array
85      * is stored in display order with the current bottom stack at 0. */
86     private final ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>();
87 
88     /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
89      * (except a future lockscreen TaskStack) moves to the top. */
90     private TaskStack mHomeStack = null;
91 
92     /** Detect user tapping outside of current focused stack bounds .*/
93     StackTapPointerEventListener mTapDetector;
94 
95     /** Detect user tapping outside of current focused stack bounds .*/
96     Region mTouchExcludeRegion = new Region();
97 
98     /** Save allocating when calculating rects */
99     Rect mTmpRect = new Rect();
100 
101     /** For gathering Task objects in order. */
102     final ArrayList<Task> mTmpTaskHistory = new ArrayList<Task>();
103 
104     final WindowManagerService mService;
105 
106     /** Remove this display when animation on it has completed. */
107     boolean mDeferredRemoval;
108 
109     /**
110      * @param display May not be null.
111      * @param service You know.
112      */
DisplayContent(Display display, WindowManagerService service)113     DisplayContent(Display display, WindowManagerService service) {
114         mDisplay = display;
115         mDisplayId = display.getDisplayId();
116         display.getDisplayInfo(mDisplayInfo);
117         isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
118         mService = service;
119     }
120 
getDisplayId()121     int getDisplayId() {
122         return mDisplayId;
123     }
124 
getWindowList()125     WindowList getWindowList() {
126         return mWindows;
127     }
128 
getDisplay()129     Display getDisplay() {
130         return mDisplay;
131     }
132 
getDisplayInfo()133     DisplayInfo getDisplayInfo() {
134         return mDisplayInfo;
135     }
136 
137     /**
138      * Returns true if the specified UID has access to this display.
139      */
hasAccess(int uid)140     public boolean hasAccess(int uid) {
141         return mDisplay.hasAccess(uid);
142     }
143 
isPrivate()144     public boolean isPrivate() {
145         return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
146     }
147 
getStacks()148     ArrayList<TaskStack> getStacks() {
149         return mStacks;
150     }
151 
152     /**
153      * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
154      * @return All the Tasks, in order, on this display.
155      */
getTasks()156     ArrayList<Task> getTasks() {
157         mTmpTaskHistory.clear();
158         final int numStacks = mStacks.size();
159         for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
160             mTmpTaskHistory.addAll(mStacks.get(stackNdx).getTasks());
161         }
162         return mTmpTaskHistory;
163     }
164 
getHomeStack()165     TaskStack getHomeStack() {
166         if (mHomeStack == null && mDisplayId == Display.DEFAULT_DISPLAY) {
167             Slog.e(TAG, "getHomeStack: Returning null from this=" + this);
168         }
169         return mHomeStack;
170     }
171 
updateDisplayInfo()172     void updateDisplayInfo() {
173         mDisplay.getDisplayInfo(mDisplayInfo);
174         for (int i = mStacks.size() - 1; i >= 0; --i) {
175             mStacks.get(i).updateDisplayInfo();
176         }
177     }
178 
getLogicalDisplayRect(Rect out)179     void getLogicalDisplayRect(Rect out) {
180         // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
181         final int orientation = mDisplayInfo.rotation;
182         boolean rotated = (orientation == Surface.ROTATION_90
183                 || orientation == Surface.ROTATION_270);
184         final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
185         final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
186         int width = mDisplayInfo.logicalWidth;
187         int left = (physWidth - width) / 2;
188         int height = mDisplayInfo.logicalHeight;
189         int top = (physHeight - height) / 2;
190         out.set(left, top, left + width, top + height);
191     }
192 
193     /** Refer to {@link WindowManagerService#attachStack(int, int)} */
attachStack(TaskStack stack)194     void attachStack(TaskStack stack) {
195         if (stack.mStackId == HOME_STACK_ID) {
196             if (mHomeStack != null) {
197                 throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
198             }
199             mHomeStack = stack;
200         }
201         mStacks.add(stack);
202         layoutNeeded = true;
203     }
204 
moveStack(TaskStack stack, boolean toTop)205     void moveStack(TaskStack stack, boolean toTop) {
206         if (!mStacks.remove(stack)) {
207             Slog.wtf(TAG, "moving stack that was not added: " + stack, new Throwable());
208         }
209         mStacks.add(toTop ? mStacks.size() : 0, stack);
210     }
211 
detachStack(TaskStack stack)212     void detachStack(TaskStack stack) {
213         mStacks.remove(stack);
214     }
215 
216     /**
217      * Propagate the new bounds to all child stacks.
218      * @param contentRect The bounds to apply at the top level.
219      */
resize(Rect contentRect)220     void resize(Rect contentRect) {
221         mContentRect.set(contentRect);
222     }
223 
stackIdFromPoint(int x, int y)224     int stackIdFromPoint(int x, int y) {
225         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
226             final TaskStack stack = mStacks.get(stackNdx);
227             stack.getBounds(mTmpRect);
228             if (mTmpRect.contains(x, y)) {
229                 return stack.mStackId;
230             }
231         }
232         return -1;
233     }
234 
setTouchExcludeRegion(TaskStack focusedStack)235     void setTouchExcludeRegion(TaskStack focusedStack) {
236         mTouchExcludeRegion.set(mBaseDisplayRect);
237         WindowList windows = getWindowList();
238         for (int i = windows.size() - 1; i >= 0; --i) {
239             final WindowState win = windows.get(i);
240             final TaskStack stack = win.getStack();
241             if (win.isVisibleLw() && stack != null && stack != focusedStack) {
242                 mTmpRect.set(win.mVisibleFrame);
243                 // If no intersection, we need mTmpRect to be unmodified.
244                 mTmpRect.intersect(win.mVisibleInsets);
245                 mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
246             }
247         }
248         if (mTapDetector != null) {
249             mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion);
250         }
251     }
252 
switchUserStacks()253     void switchUserStacks() {
254         final WindowList windows = getWindowList();
255         for (int i = 0; i < windows.size(); i++) {
256             final WindowState win = windows.get(i);
257             if (win.isHiddenFromUserLocked()) {
258                 if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing, hiding " + win
259                         + ", attrs=" + win.mAttrs.type + ", belonging to " + win.mOwnerUid);
260                 win.hideLw(false);
261             }
262         }
263 
264         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
265             mStacks.get(stackNdx).switchUser();
266         }
267     }
268 
resetAnimationBackgroundAnimator()269     void resetAnimationBackgroundAnimator() {
270         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
271             mStacks.get(stackNdx).resetAnimationBackgroundAnimator();
272         }
273     }
274 
animateDimLayers()275     boolean animateDimLayers() {
276         boolean result = false;
277         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
278             result |= mStacks.get(stackNdx).animateDimLayers();
279         }
280         return result;
281     }
282 
resetDimming()283     void resetDimming() {
284         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
285             mStacks.get(stackNdx).resetDimmingTag();
286         }
287     }
288 
isDimming()289     boolean isDimming() {
290         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
291             if (mStacks.get(stackNdx).isDimming()) {
292                 return true;
293             }
294         }
295         return false;
296     }
297 
stopDimmingIfNeeded()298     void stopDimmingIfNeeded() {
299         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
300             mStacks.get(stackNdx).stopDimmingIfNeeded();
301         }
302     }
303 
close()304     void close() {
305         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
306             mStacks.get(stackNdx).close();
307         }
308     }
309 
isAnimating()310     boolean isAnimating() {
311         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
312             final TaskStack stack = mStacks.get(stackNdx);
313             if (stack.isAnimating()) {
314                 return true;
315             }
316         }
317         return false;
318     }
319 
checkForDeferredActions()320     void checkForDeferredActions() {
321         boolean animating = false;
322         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
323             final TaskStack stack = mStacks.get(stackNdx);
324             if (stack.isAnimating()) {
325                 animating = true;
326             } else {
327                 if (stack.mDeferDetach) {
328                     mService.detachStackLocked(this, stack);
329                 }
330                 final ArrayList<Task> tasks = stack.getTasks();
331                 for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
332                     final Task task = tasks.get(taskNdx);
333                     AppTokenList tokens = task.mAppTokens;
334                     for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
335                         AppWindowToken wtoken = tokens.get(tokenNdx);
336                         if (wtoken.mIsExiting) {
337                             wtoken.removeAppFromTaskLocked();
338                         }
339                     }
340                 }
341             }
342         }
343         if (!animating && mDeferredRemoval) {
344             mService.onDisplayRemoved(mDisplayId);
345         }
346     }
347 
deltaRotation(int oldRotation, int newRotation)348     static int deltaRotation(int oldRotation, int newRotation) {
349         int delta = newRotation - oldRotation;
350         if (delta < 0) delta += 4;
351         return delta;
352     }
353 
dump(String prefix, PrintWriter pw)354     public void dump(String prefix, PrintWriter pw) {
355         pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
356         final String subPrefix = "  " + prefix;
357         pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
358             pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
359             pw.print("dpi");
360             if (mInitialDisplayWidth != mBaseDisplayWidth
361                     || mInitialDisplayHeight != mBaseDisplayHeight
362                     || mInitialDisplayDensity != mBaseDisplayDensity) {
363                 pw.print(" base=");
364                 pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
365                 pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
366             }
367             if (mDisplayScalingDisabled) {
368                 pw.println(" noscale");
369             }
370             pw.print(" cur=");
371             pw.print(mDisplayInfo.logicalWidth);
372             pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
373             pw.print(" app=");
374             pw.print(mDisplayInfo.appWidth);
375             pw.print("x"); pw.print(mDisplayInfo.appHeight);
376             pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
377             pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
378             pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
379             pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
380             pw.print(subPrefix); pw.print("deferred="); pw.print(mDeferredRemoval);
381                 pw.print(" layoutNeeded="); pw.println(layoutNeeded);
382         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
383             final TaskStack stack = mStacks.get(stackNdx);
384             pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
385             stack.dump(prefix + "  ", pw);
386         }
387         pw.println();
388         pw.println("  Application tokens in top down Z order:");
389         int ndx = 0;
390         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
391             final TaskStack stack = mStacks.get(stackNdx);
392             pw.print("  mStackId="); pw.println(stack.mStackId);
393             ArrayList<Task> tasks = stack.getTasks();
394             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
395                 final Task task = tasks.get(taskNdx);
396                 pw.print("    mTaskId="); pw.println(task.mTaskId);
397                 AppTokenList tokens = task.mAppTokens;
398                 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx, ++ndx) {
399                     final AppWindowToken wtoken = tokens.get(tokenNdx);
400                     pw.print("    Activity #"); pw.print(tokenNdx);
401                             pw.print(' '); pw.print(wtoken); pw.println(":");
402                     wtoken.dump(pw, "      ");
403                 }
404             }
405         }
406         if (ndx == 0) {
407             pw.println("    None");
408         }
409         pw.println();
410         if (!mExitingTokens.isEmpty()) {
411             pw.println();
412             pw.println("  Exiting tokens:");
413             for (int i=mExitingTokens.size()-1; i>=0; i--) {
414                 WindowToken token = mExitingTokens.get(i);
415                 pw.print("  Exiting #"); pw.print(i);
416                 pw.print(' '); pw.print(token);
417                 pw.println(':');
418                 token.dump(pw, "    ");
419             }
420         }
421         pw.println();
422     }
423 
424     @Override
toString()425     public String toString() {
426         return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks;
427     }
428 }
429