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