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