• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_STACK;
21 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
22 import static com.android.server.wm.WindowManagerService.TAG;
23 
24 import android.app.ActivityManager.StackBoxInfo;
25 import android.graphics.Rect;
26 import android.graphics.Region;
27 import android.os.Debug;
28 import android.util.EventLog;
29 import android.util.Slog;
30 import android.view.Display;
31 import android.view.DisplayInfo;
32 import com.android.server.EventLogTags;
33 
34 import java.io.PrintWriter;
35 import java.util.ArrayList;
36 
37 class DisplayContentList extends ArrayList<DisplayContent> {
38 }
39 
40 /**
41  * Utility class for keeping track of the WindowStates and other pertinent contents of a
42  * particular Display.
43  *
44  * IMPORTANT: No method from this class should ever be used without holding
45  * WindowManagerService.mWindowMap.
46  */
47 class DisplayContent {
48 
49     /** Unique identifier of this stack. */
50     private final int mDisplayId;
51 
52     /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
53      * from mDisplayWindows; */
54     private WindowList mWindows = new WindowList();
55 
56     // This protects the following display size properties, so that
57     // getDisplaySize() doesn't need to acquire the global lock.  This is
58     // needed because the window manager sometimes needs to use ActivityThread
59     // while it has its global state locked (for example to load animation
60     // resources), but the ActivityThread also needs get the current display
61     // size sometimes when it has its package lock held.
62     //
63     // These will only be modified with both mWindowMap and mDisplaySizeLock
64     // held (in that order) so the window manager doesn't need to acquire this
65     // lock when needing these values in its normal operation.
66     final Object mDisplaySizeLock = new Object();
67     int mInitialDisplayWidth = 0;
68     int mInitialDisplayHeight = 0;
69     int mInitialDisplayDensity = 0;
70     int mBaseDisplayWidth = 0;
71     int mBaseDisplayHeight = 0;
72     int mBaseDisplayDensity = 0;
73     private final DisplayInfo mDisplayInfo = new DisplayInfo();
74     private final Display mDisplay;
75 
76     Rect mBaseDisplayRect = new Rect();
77 
78     // Accessed directly by all users.
79     boolean layoutNeeded;
80     int pendingLayoutChanges;
81     final boolean isDefaultDisplay;
82 
83     /**
84      * Window tokens that are in the process of exiting, but still
85      * on screen for animations.
86      */
87     final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
88 
89     /**
90      * Application tokens that are in the process of exiting, but still
91      * on screen for animations.
92      */
93     final AppTokenList mExitingAppTokens = new AppTokenList();
94 
95     /** Array containing the home StackBox and possibly one more which would contain apps. Array
96      * is stored in display order with the current bottom stack at 0. */
97     private ArrayList<StackBox> mStackBoxes = new ArrayList<StackBox>();
98 
99     /** True when the home StackBox is at the top of mStackBoxes, false otherwise. */
100     private TaskStack mHomeStack = null;
101 
102     /** Detect user tapping outside of current focused stack bounds .*/
103     StackTapPointerEventListener mTapDetector;
104 
105     /** Detect user tapping outside of current focused stack bounds .*/
106     Region mTouchExcludeRegion = new Region();
107 
108     /** Save allocating when retrieving tasks */
109     private ArrayList<Task> mTaskHistory = new ArrayList<Task>();
110 
111     /** Save allocating when calculating rects */
112     Rect mTmpRect = new Rect();
113 
114     final WindowManagerService mService;
115 
116     /**
117      * @param display May not be null.
118      * @param service TODO(cmautner):
119      */
DisplayContent(Display display, WindowManagerService service)120     DisplayContent(Display display, WindowManagerService service) {
121         mDisplay = display;
122         mDisplayId = display.getDisplayId();
123         display.getDisplayInfo(mDisplayInfo);
124         isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
125         mService = service;
126 
127         StackBox newBox = new StackBox(service, this, null);
128         mStackBoxes.add(newBox);
129         TaskStack newStack = new TaskStack(service, HOME_STACK_ID, this);
130         newStack.mStackBox = newBox;
131         newBox.mStack = newStack;
132         mHomeStack = newStack;
133     }
134 
getDisplayId()135     int getDisplayId() {
136         return mDisplayId;
137     }
138 
getWindowList()139     WindowList getWindowList() {
140         return mWindows;
141     }
142 
getDisplay()143     Display getDisplay() {
144         return mDisplay;
145     }
146 
getDisplayInfo()147     DisplayInfo getDisplayInfo() {
148         return mDisplayInfo;
149     }
150 
151     /**
152      * Returns true if the specified UID has access to this display.
153      */
hasAccess(int uid)154     public boolean hasAccess(int uid) {
155         return mDisplay.hasAccess(uid);
156     }
157 
homeOnTop()158     boolean homeOnTop() {
159         return mStackBoxes.get(0).mStack != mHomeStack;
160     }
161 
isPrivate()162     public boolean isPrivate() {
163         return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
164     }
165 
166     /**
167      * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
168      * @return All the Tasks, in order, on this display.
169      */
getTasks()170     ArrayList<Task> getTasks() {
171         return mTaskHistory;
172     }
173 
addTask(Task task, boolean toTop)174     void addTask(Task task, boolean toTop) {
175         mTaskHistory.remove(task);
176 
177         final int userId = task.mUserId;
178         int taskNdx;
179         final int numTasks = mTaskHistory.size();
180         if (toTop) {
181             for (taskNdx = numTasks - 1; taskNdx >= 0; --taskNdx) {
182                 if (mTaskHistory.get(taskNdx).mUserId == userId) {
183                     break;
184                 }
185             }
186             ++taskNdx;
187         } else {
188             for (taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
189                 if (mTaskHistory.get(taskNdx).mUserId == userId) {
190                     break;
191                 }
192             }
193         }
194 
195         mTaskHistory.add(taskNdx, task);
196         EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx);
197     }
198 
removeTask(Task task)199     void removeTask(Task task) {
200         mTaskHistory.remove(task);
201     }
202 
getHomeStack()203     TaskStack getHomeStack() {
204         return mHomeStack;
205     }
206 
updateDisplayInfo()207     void updateDisplayInfo() {
208         mDisplay.getDisplayInfo(mDisplayInfo);
209     }
210 
getLogicalDisplayRect(Rect out)211     void getLogicalDisplayRect(Rect out) {
212         updateDisplayInfo();
213         // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
214         int width = mDisplayInfo.logicalWidth;
215         int left = (mBaseDisplayWidth - width) / 2;
216         int height = mDisplayInfo.logicalHeight;
217         int top = (mBaseDisplayHeight - height) / 2;
218         out.set(left, top, left + width, top + height);
219     }
220 
221     /** @return The number of tokens in all of the Tasks on this display. */
numTokens()222     int numTokens() {
223         int count = 0;
224         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
225             count += mTaskHistory.get(taskNdx).mAppTokens.size();
226         }
227         return count;
228     }
229 
230     /** Refer to {@link WindowManagerService#createStack(int, int, int, float)} */
createStack(int stackId, int relativeStackBoxId, int position, float weight)231     TaskStack createStack(int stackId, int relativeStackBoxId, int position, float weight) {
232         TaskStack newStack = null;
233         if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId + " relativeStackBoxId="
234                 + relativeStackBoxId + " position=" + position + " weight=" + weight);
235         if (stackId == HOME_STACK_ID) {
236             if (mStackBoxes.size() != 1) {
237                 throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");
238             }
239             newStack = mHomeStack;
240         } else {
241             int stackBoxNdx;
242             for (stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
243                 final StackBox box = mStackBoxes.get(stackBoxNdx);
244                 if (position == StackBox.TASK_STACK_GOES_OVER
245                         || position == StackBox.TASK_STACK_GOES_UNDER) {
246                     // Position indicates a new box is added at top level only.
247                     if (box.contains(relativeStackBoxId)) {
248                         StackBox newBox = new StackBox(mService, this, null);
249                         newStack = new TaskStack(mService, stackId, this);
250                         newStack.mStackBox = newBox;
251                         newBox.mStack = newStack;
252                         final int offset = position == StackBox.TASK_STACK_GOES_OVER ? 1 : 0;
253                         if (DEBUG_STACK) Slog.d(TAG, "createStack: inserting stack at " +
254                                 (stackBoxNdx + offset));
255                         mStackBoxes.add(stackBoxNdx + offset, newBox);
256                         break;
257                     }
258                 } else {
259                     // Remaining position values indicate a box must be split.
260                     newStack = box.split(stackId, relativeStackBoxId, position, weight);
261                     if (newStack != null) {
262                         break;
263                     }
264                 }
265             }
266             if (stackBoxNdx < 0) {
267                 throw new IllegalArgumentException("createStack: stackBoxId " + relativeStackBoxId
268                         + " not found.");
269             }
270         }
271         if (newStack != null) {
272             layoutNeeded = true;
273         }
274         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, relativeStackBoxId, position,
275                 (int)(weight * 100 + 0.5));
276         return newStack;
277     }
278 
279     /** Refer to {@link WindowManagerService#resizeStackBox(int, float)} */
resizeStack(int stackBoxId, float weight)280     boolean resizeStack(int stackBoxId, float weight) {
281         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
282             final StackBox box = mStackBoxes.get(stackBoxNdx);
283             if (box.resize(stackBoxId, weight)) {
284                 layoutNeeded = true;
285                 return true;
286             }
287         }
288         return false;
289     }
290 
addStackBox(StackBox box, boolean toTop)291     void addStackBox(StackBox box, boolean toTop) {
292         if (mStackBoxes.size() >= 2) {
293             throw new RuntimeException("addStackBox: Too many toplevel StackBoxes!");
294         }
295         mStackBoxes.add(toTop ? mStackBoxes.size() : 0, box);
296     }
297 
removeStackBox(StackBox box)298     void removeStackBox(StackBox box) {
299         if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: box=" + box);
300         final TaskStack stack = box.mStack;
301         if (stack != null && stack.mStackId == HOME_STACK_ID) {
302             // Never delete the home stack, even if it is empty.
303             if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: Not deleting home stack.");
304             return;
305         }
306         mStackBoxes.remove(box);
307     }
308 
getStackBoxInfo(StackBox box)309     StackBoxInfo getStackBoxInfo(StackBox box) {
310         StackBoxInfo info = new StackBoxInfo();
311         info.stackBoxId = box.mStackBoxId;
312         info.weight = box.mWeight;
313         info.vertical = box.mVertical;
314         info.bounds = new Rect(box.mBounds);
315         if (box.mStack != null) {
316             info.stackId = box.mStack.mStackId;
317             // ActivityManagerService will fill in the StackInfo.
318         } else {
319             info.stackId = -1;
320             info.children = new StackBoxInfo[2];
321             info.children[0] = getStackBoxInfo(box.mFirst);
322             info.children[1] = getStackBoxInfo(box.mSecond);
323         }
324         return info;
325     }
326 
getStackBoxInfos()327     ArrayList<StackBoxInfo> getStackBoxInfos() {
328         ArrayList<StackBoxInfo> list = new ArrayList<StackBoxInfo>();
329         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
330             list.add(getStackBoxInfo(mStackBoxes.get(stackBoxNdx)));
331         }
332         return list;
333     }
334 
335     /**
336      * Move the home StackBox to the top or bottom of mStackBoxes. That is the only place
337      * it is allowed to be. This is a nop if the home StackBox is already in the correct position.
338      * @param toTop Move home to the top of mStackBoxes if true, to the bottom if false.
339      * @return true if a change was made, false otherwise.
340      */
moveHomeStackBox(boolean toTop)341     boolean moveHomeStackBox(boolean toTop) {
342         if (DEBUG_STACK) Slog.d(TAG, "moveHomeStackBox: toTop=" + toTop + " Callers=" +
343                 Debug.getCallers(4));
344         EventLog.writeEvent(EventLogTags.WM_HOME_STACK_MOVED, toTop ? 1 : 0);
345         switch (mStackBoxes.size()) {
346             case 0: throw new RuntimeException("moveHomeStackBox: No home StackBox!");
347             case 1: return false; // Only the home StackBox exists.
348             case 2:
349                 if (homeOnTop() ^ toTop) {
350                     mStackBoxes.add(mStackBoxes.remove(0));
351                     return true;
352                 }
353                 return false;
354             default: throw new RuntimeException("moveHomeStackBox: Too many toplevel StackBoxes!");
355         }
356     }
357 
358     /**
359      * Propagate the new bounds to all child stack boxes, applying weights as we move down.
360      * @param contentRect The bounds to apply at the top level.
361      */
setStackBoxSize(Rect contentRect)362     boolean setStackBoxSize(Rect contentRect) {
363         boolean change = false;
364         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
365             change |= mStackBoxes.get(stackBoxNdx).setStackBoxSizes(contentRect, true);
366         }
367         return change;
368     }
369 
getStackBounds(int stackId)370     Rect getStackBounds(int stackId) {
371         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
372             Rect bounds = mStackBoxes.get(stackBoxNdx).getStackBounds(stackId);
373             if (bounds != null) {
374                 return bounds;
375             }
376         }
377         return null;
378     }
379 
stackIdFromPoint(int x, int y)380     int stackIdFromPoint(int x, int y) {
381         StackBox topBox = mStackBoxes.get(mStackBoxes.size() - 1);
382         return topBox.stackIdFromPoint(x, y);
383     }
384 
setTouchExcludeRegion(TaskStack focusedStack)385     void setTouchExcludeRegion(TaskStack focusedStack) {
386         mTouchExcludeRegion.set(mBaseDisplayRect);
387         WindowList windows = getWindowList();
388         for (int i = windows.size() - 1; i >= 0; --i) {
389             final WindowState win = windows.get(i);
390             final TaskStack stack = win.getStack();
391             if (win.isVisibleLw() && stack != null && stack != focusedStack) {
392                 mTmpRect.set(win.mVisibleFrame);
393                 mTmpRect.intersect(win.mVisibleInsets);
394                 mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
395             }
396         }
397     }
398 
switchUserStacks(int oldUserId, int newUserId)399     void switchUserStacks(int oldUserId, int newUserId) {
400         final WindowList windows = getWindowList();
401         for (int i = 0; i < windows.size(); i++) {
402             final WindowState win = windows.get(i);
403             if (win.isHiddenFromUserLocked()) {
404                 if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "
405                         + win + ", attrs=" + win.mAttrs.type + ", belonging to "
406                         + win.mOwnerUid);
407                 win.hideLw(false);
408             }
409         }
410 
411         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
412             mStackBoxes.get(stackBoxNdx).switchUserStacks(newUserId);
413         }
414     }
415 
resetAnimationBackgroundAnimator()416     void resetAnimationBackgroundAnimator() {
417         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
418             mStackBoxes.get(stackBoxNdx).resetAnimationBackgroundAnimator();
419         }
420     }
421 
animateDimLayers()422     boolean animateDimLayers() {
423         boolean result = false;
424         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
425             result |= mStackBoxes.get(stackBoxNdx).animateDimLayers();
426         }
427         return result;
428     }
429 
resetDimming()430     void resetDimming() {
431         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
432             mStackBoxes.get(stackBoxNdx).resetDimming();
433         }
434     }
435 
isDimming()436     boolean isDimming() {
437         boolean result = false;
438         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
439             result |= mStackBoxes.get(stackBoxNdx).isDimming();
440         }
441         return result;
442     }
443 
stopDimmingIfNeeded()444     void stopDimmingIfNeeded() {
445         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
446             mStackBoxes.get(stackBoxNdx).stopDimmingIfNeeded();
447         }
448     }
449 
close()450     void close() {
451         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
452             mStackBoxes.get(stackBoxNdx).close();
453         }
454     }
455 
dump(String prefix, PrintWriter pw)456     public void dump(String prefix, PrintWriter pw) {
457         pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
458         final String subPrefix = "  " + prefix;
459         pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
460             pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
461             pw.print("dpi");
462             if (mInitialDisplayWidth != mBaseDisplayWidth
463                     || mInitialDisplayHeight != mBaseDisplayHeight
464                     || mInitialDisplayDensity != mBaseDisplayDensity) {
465                 pw.print(" base=");
466                 pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
467                 pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
468             }
469             pw.print(" cur=");
470             pw.print(mDisplayInfo.logicalWidth);
471             pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
472             pw.print(" app=");
473             pw.print(mDisplayInfo.appWidth);
474             pw.print("x"); pw.print(mDisplayInfo.appHeight);
475             pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
476             pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
477             pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
478             pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
479             pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
480         for (int boxNdx = 0; boxNdx < mStackBoxes.size(); ++boxNdx) {
481             pw.print(prefix); pw.print("StackBox #"); pw.println(boxNdx);
482             mStackBoxes.get(boxNdx).dump(prefix + "  ", pw);
483         }
484         int ndx = numTokens();
485         if (ndx > 0) {
486             pw.println();
487             pw.println("  Application tokens in Z order:");
488             getTasks();
489             for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
490                 AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens;
491                 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
492                     final AppWindowToken wtoken = tokens.get(tokenNdx);
493                     pw.print("  App #"); pw.print(ndx--);
494                             pw.print(' '); pw.print(wtoken); pw.println(":");
495                     wtoken.dump(pw, "    ");
496                 }
497             }
498         }
499         if (mExitingTokens.size() > 0) {
500             pw.println();
501             pw.println("  Exiting tokens:");
502             for (int i=mExitingTokens.size()-1; i>=0; i--) {
503                 WindowToken token = mExitingTokens.get(i);
504                 pw.print("  Exiting #"); pw.print(i);
505                 pw.print(' '); pw.print(token);
506                 pw.println(':');
507                 token.dump(pw, "    ");
508             }
509         }
510         if (mExitingAppTokens.size() > 0) {
511             pw.println();
512             pw.println("  Exiting application tokens:");
513             for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
514                 WindowToken token = mExitingAppTokens.get(i);
515                 pw.print("  Exiting App #"); pw.print(i);
516                   pw.print(' '); pw.print(token);
517                   pw.println(':');
518                   token.dump(pw, "    ");
519             }
520         }
521         pw.println();
522     }
523 }
524