DisplayContent.java revision e0a3884cb627efc650e19fbe76b1b3343468cf57
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        if (mHomeStack == null) {
195            Slog.e(TAG, "getHomeStack: Returning null from this=" + this);
196        }
197        return mHomeStack;
198    }
199
200    void updateDisplayInfo() {
201        // Save old size.
202        int oldWidth = mDisplayInfo.logicalWidth;
203        int oldHeight = mDisplayInfo.logicalHeight;
204        mDisplay.getDisplayInfo(mDisplayInfo);
205
206        for (int i = mStacks.size() - 1; i >= 0; --i) {
207            final TaskStack stack = mStacks.get(i);
208            if (!stack.isFullscreen()) {
209                stack.resizeBounds(oldWidth, oldHeight, mDisplayInfo.logicalWidth,
210                        mDisplayInfo.logicalHeight);
211            }
212        }
213    }
214
215    void getLogicalDisplayRect(Rect out) {
216        updateDisplayInfo();
217        // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
218        final int orientation = mDisplayInfo.rotation;
219        boolean rotated = (orientation == Surface.ROTATION_90
220                || orientation == Surface.ROTATION_270);
221        final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
222        final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
223        int width = mDisplayInfo.logicalWidth;
224        int left = (physWidth - width) / 2;
225        int height = mDisplayInfo.logicalHeight;
226        int top = (physHeight - height) / 2;
227        out.set(left, top, left + width, top + height);
228    }
229
230    /** @return The number of tokens in all of the Tasks on this display. */
231    int numTokens() {
232        int count = 0;
233        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
234            count += mTaskHistory.get(taskNdx).mAppTokens.size();
235        }
236        return count;
237    }
238
239    /** Refer to {@link WindowManagerService#createStack(int, int)} */
240    TaskStack createStack(int stackId) {
241        if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId);
242        TaskStack newStack = new TaskStack(mService, stackId, this);
243        if (stackId == HOME_STACK_ID) {
244            if (mHomeStack != null) {
245                throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");
246            }
247            mHomeStack = newStack;
248        }
249        mStacks.add(newStack);
250        layoutNeeded = true;
251        return newStack;
252    }
253
254    void moveStack(TaskStack stack, boolean toTop) {
255        mStacks.remove(stack);
256        mStacks.add(toTop ? mStacks.size() : 0, stack);
257    }
258
259    TaskStack removeStack(TaskStack stack) {
260        mStacks.remove(stack);
261        if (!mStacks.isEmpty()) {
262            return mStacks.get(mStacks.size() - 1);
263        }
264        return null;
265    }
266
267    /**
268     * Propagate the new bounds to all child stacks.
269     * @param contentRect The bounds to apply at the top level.
270     */
271    void resize(Rect contentRect) {
272        mContentRect.set(contentRect);
273    }
274
275    boolean getStackBounds(int stackId, Rect bounds) {
276        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
277            final TaskStack stack = mStacks.get(stackNdx);
278            if (stackId == stack.mStackId) {
279                bounds.set(stack.mBounds);
280                return true;
281            }
282        }
283        return false;
284    }
285
286    int stackIdFromPoint(int x, int y) {
287        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
288            final TaskStack stack = mStacks.get(stackNdx);
289            stack.getBounds(mTmpRect);
290            if (mTmpRect.contains(x, y)) {
291                return stack.mStackId;
292            }
293        }
294        return -1;
295    }
296
297    void setTouchExcludeRegion(TaskStack focusedStack) {
298        mTouchExcludeRegion.set(mBaseDisplayRect);
299        WindowList windows = getWindowList();
300        for (int i = windows.size() - 1; i >= 0; --i) {
301            final WindowState win = windows.get(i);
302            final TaskStack stack = win.getStack();
303            if (win.isVisibleLw() && stack != null && stack != focusedStack) {
304                mTmpRect.set(win.mVisibleFrame);
305                mTmpRect.intersect(win.mVisibleInsets);
306                mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
307            }
308        }
309    }
310
311    void switchUserStacks(int oldUserId, int newUserId) {
312        final WindowList windows = getWindowList();
313        for (int i = 0; i < windows.size(); i++) {
314            final WindowState win = windows.get(i);
315            if (win.isHiddenFromUserLocked()) {
316                if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "
317                        + win + ", attrs=" + win.mAttrs.type + ", belonging to "
318                        + win.mOwnerUid);
319                win.hideLw(false);
320            }
321        }
322
323        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
324            mStacks.get(stackNdx).switchUser(newUserId);
325        }
326    }
327
328    void resetAnimationBackgroundAnimator() {
329        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
330            mStacks.get(stackNdx).resetAnimationBackgroundAnimator();
331        }
332    }
333
334    boolean animateDimLayers() {
335        boolean result = false;
336        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
337            result |= mStacks.get(stackNdx).animateDimLayers();
338        }
339        return result;
340    }
341
342    void resetDimming() {
343        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
344            mStacks.get(stackNdx).resetDimmingTag();
345        }
346    }
347
348    boolean isDimming() {
349        boolean result = false;
350        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
351            result |= mStacks.get(stackNdx).isDimming();
352        }
353        return result;
354    }
355
356    void stopDimmingIfNeeded() {
357        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
358            mStacks.get(stackNdx).stopDimmingIfNeeded();
359        }
360    }
361
362    void close() {
363        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
364            mStacks.get(stackNdx).close();
365        }
366    }
367
368    public void dump(String prefix, PrintWriter pw) {
369        pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
370        final String subPrefix = "  " + prefix;
371        pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
372            pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
373            pw.print("dpi");
374            if (mInitialDisplayWidth != mBaseDisplayWidth
375                    || mInitialDisplayHeight != mBaseDisplayHeight
376                    || mInitialDisplayDensity != mBaseDisplayDensity) {
377                pw.print(" base=");
378                pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
379                pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
380            }
381            pw.print(" cur=");
382            pw.print(mDisplayInfo.logicalWidth);
383            pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
384            pw.print(" app=");
385            pw.print(mDisplayInfo.appWidth);
386            pw.print("x"); pw.print(mDisplayInfo.appHeight);
387            pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
388            pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
389            pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
390            pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
391            pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
392        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
393            final TaskStack stack = mStacks.get(stackNdx);
394            pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
395            stack.dump(prefix + "  ", pw);
396        }
397        int ndx = numTokens();
398        if (ndx > 0) {
399            pw.println();
400            pw.println("  Application tokens in Z order:");
401            getTasks();
402            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
403                AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens;
404                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
405                    final AppWindowToken wtoken = tokens.get(tokenNdx);
406                    pw.print("  App #"); pw.print(ndx--);
407                            pw.print(' '); pw.print(wtoken); pw.println(":");
408                    wtoken.dump(pw, "    ");
409                }
410            }
411        }
412        if (mExitingTokens.size() > 0) {
413            pw.println();
414            pw.println("  Exiting tokens:");
415            for (int i=mExitingTokens.size()-1; i>=0; i--) {
416                WindowToken token = mExitingTokens.get(i);
417                pw.print("  Exiting #"); pw.print(i);
418                pw.print(' '); pw.print(token);
419                pw.println(':');
420                token.dump(pw, "    ");
421            }
422        }
423        if (mExitingAppTokens.size() > 0) {
424            pw.println();
425            pw.println("  Exiting application tokens:");
426            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
427                WindowToken token = mExitingAppTokens.get(i);
428                pw.print("  Exiting App #"); pw.print(i);
429                  pw.print(' '); pw.print(token);
430                  pw.println(':');
431                  token.dump(pw, "    ");
432            }
433        }
434        pw.println();
435    }
436
437    @Override
438    public String toString() {
439        return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks;
440    }
441}
442