DisplayContent.java revision 62a40f87b3f45cbd20fea101d977153e9a933891
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 android.app.ActivityManager.StackId.DOCKED_STACK_ID;
20import static android.app.ActivityManager.StackId.HOME_STACK_ID;
21import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
22import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
23import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
24import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
25import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
26import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
27import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
28import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
29
30import android.app.ActivityManager.StackId;
31import android.content.pm.ApplicationInfo;
32import android.content.pm.PackageManager;
33import android.graphics.Rect;
34import android.graphics.Region;
35import android.graphics.Region.Op;
36import android.os.Build;
37import android.os.UserHandle;
38import android.util.DisplayMetrics;
39import android.util.Slog;
40import android.view.Display;
41import android.view.DisplayInfo;
42import android.view.Surface;
43import android.view.animation.Animation;
44
45import java.io.PrintWriter;
46import java.util.ArrayList;
47
48class DisplayContentList extends ArrayList<DisplayContent> {
49}
50
51/**
52 * Utility class for keeping track of the WindowStates and other pertinent contents of a
53 * particular Display.
54 *
55 * IMPORTANT: No method from this class should ever be used without holding
56 * WindowManagerService.mWindowMap.
57 */
58class DisplayContent {
59
60    /** Unique identifier of this stack. */
61    private final int mDisplayId;
62
63    /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
64     * from mDisplayWindows; */
65    private final WindowList mWindows = new WindowList();
66
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    boolean mDisplayScalingDisabled;
74    private final DisplayInfo mDisplayInfo = new DisplayInfo();
75    private final Display mDisplay;
76    private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
77
78    Rect mBaseDisplayRect = new Rect();
79    Rect mContentRect = new Rect();
80
81    // Accessed directly by all users.
82    boolean layoutNeeded;
83    int pendingLayoutChanges;
84    final boolean isDefaultDisplay;
85
86    /** Window tokens that are in the process of exiting, but still on screen for animations. */
87    final ArrayList<WindowToken> mExitingTokens = new ArrayList<>();
88
89    /** Array containing all TaskStacks on this display.  Array
90     * is stored in display order with the current bottom stack at 0. */
91    private final ArrayList<TaskStack> mStacks = new ArrayList<>();
92
93    /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
94     * (except a future lockscreen TaskStack) moves to the top. */
95    private TaskStack mHomeStack = null;
96
97    /** Detect user tapping outside of current focused task bounds .*/
98    TaskTapPointerEventListener mTapDetector;
99
100    /** Detect user tapping outside of current focused stack bounds .*/
101    Region mTouchExcludeRegion = new Region();
102
103    /** Detect user tapping in a non-resizeable task in docked or fullscreen stack .*/
104    Region mNonResizeableRegion = new Region();
105
106    /** Save allocating when calculating rects */
107    private final Rect mTmpRect = new Rect();
108    private final Rect mTmpRect2 = new Rect();
109    private final Region mTmpRegion = new Region();
110
111    /** For gathering Task objects in order. */
112    final ArrayList<Task> mTmpTaskHistory = new ArrayList<Task>();
113
114    final WindowManagerService mService;
115
116    /** Remove this display when animation on it has completed. */
117    boolean mDeferredRemoval;
118
119    final DockedStackDividerController mDividerControllerLocked;
120
121    final DimLayerController mDimLayerController;
122
123    final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>();
124
125    /**
126     * @param display May not be null.
127     * @param service You know.
128     */
129    DisplayContent(Display display, WindowManagerService service) {
130        mDisplay = display;
131        mDisplayId = display.getDisplayId();
132        display.getDisplayInfo(mDisplayInfo);
133        display.getMetrics(mDisplayMetrics);
134        isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
135        mService = service;
136        initializeDisplayBaseInfo();
137        mDividerControllerLocked = new DockedStackDividerController(service, this);
138        mDimLayerController = new DimLayerController(this);
139    }
140
141    int getDisplayId() {
142        return mDisplayId;
143    }
144
145    WindowList getWindowList() {
146        return mWindows;
147    }
148
149    Display getDisplay() {
150        return mDisplay;
151    }
152
153    DisplayInfo getDisplayInfo() {
154        return mDisplayInfo;
155    }
156
157    DisplayMetrics getDisplayMetrics() {
158        return mDisplayMetrics;
159    }
160
161    DockedStackDividerController getDockedDividerController() {
162        return mDividerControllerLocked;
163    }
164
165    /**
166     * Returns true if the specified UID has access to this display.
167     */
168    public boolean hasAccess(int uid) {
169        return mDisplay.hasAccess(uid);
170    }
171
172    public boolean isPrivate() {
173        return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
174    }
175
176    ArrayList<TaskStack> getStacks() {
177        return mStacks;
178    }
179
180    /**
181     * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
182     * @return All the Tasks, in order, on this display.
183     */
184    ArrayList<Task> getTasks() {
185        mTmpTaskHistory.clear();
186        final int numStacks = mStacks.size();
187        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
188            mTmpTaskHistory.addAll(mStacks.get(stackNdx).getTasks());
189        }
190        return mTmpTaskHistory;
191    }
192
193    TaskStack getHomeStack() {
194        if (mHomeStack == null && mDisplayId == Display.DEFAULT_DISPLAY) {
195            Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this);
196        }
197        return mHomeStack;
198    }
199
200    TaskStack getStackById(int stackId) {
201        for (int i = mStacks.size() - 1; i >= 0; --i) {
202            final TaskStack stack = mStacks.get(i);
203            if (stack.mStackId == stackId) {
204                return stack;
205            }
206        }
207        return null;
208    }
209
210    void updateDisplayInfo() {
211        mDisplay.getDisplayInfo(mDisplayInfo);
212        mDisplay.getMetrics(mDisplayMetrics);
213        for (int i = mStacks.size() - 1; i >= 0; --i) {
214            mStacks.get(i).updateDisplayInfo(null);
215        }
216    }
217
218    void initializeDisplayBaseInfo() {
219        // Bootstrap the default logical display from the display manager.
220        final DisplayInfo newDisplayInfo =
221                mService.mDisplayManagerInternal.getDisplayInfo(mDisplayId);
222        if (newDisplayInfo != null) {
223            mDisplayInfo.copyFrom(newDisplayInfo);
224        }
225        mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth;
226        mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight;
227        mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
228        mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
229    }
230
231    void getLogicalDisplayRect(Rect out) {
232        // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
233        final int orientation = mDisplayInfo.rotation;
234        boolean rotated = (orientation == Surface.ROTATION_90
235                || orientation == Surface.ROTATION_270);
236        final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
237        final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
238        int width = mDisplayInfo.logicalWidth;
239        int left = (physWidth - width) / 2;
240        int height = mDisplayInfo.logicalHeight;
241        int top = (physHeight - height) / 2;
242        out.set(left, top, left + width, top + height);
243    }
244
245    void getContentRect(Rect out) {
246        out.set(mContentRect);
247    }
248
249    /** Refer to {@link WindowManagerService#attachStack(int, int, boolean)} */
250    void attachStack(TaskStack stack, boolean onTop) {
251        if (stack.mStackId == HOME_STACK_ID) {
252            if (mHomeStack != null) {
253                throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
254            }
255            mHomeStack = stack;
256        }
257        if (onTop) {
258            mStacks.add(stack);
259        } else {
260            mStacks.add(0, stack);
261        }
262        layoutNeeded = true;
263    }
264
265    void moveStack(TaskStack stack, boolean toTop) {
266        if (StackId.isAlwaysOnTop(stack.mStackId) && !toTop) {
267            // This stack is always-on-top silly...
268            Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + stack + " to bottom");
269            return;
270        }
271
272        if (!mStacks.remove(stack)) {
273            Slog.wtf(TAG_WM, "moving stack that was not added: " + stack, new Throwable());
274        }
275
276        int addIndex = toTop ? mStacks.size() : 0;
277
278        if (toTop
279                && mService.isStackVisibleLocked(PINNED_STACK_ID)
280                && stack.mStackId != PINNED_STACK_ID) {
281            // The pinned stack is always the top most stack (always-on-top) when it is visible.
282            // So, stack is moved just below the pinned stack.
283            addIndex--;
284            TaskStack topStack = mStacks.get(addIndex);
285            if (topStack.mStackId != PINNED_STACK_ID) {
286                throw new IllegalStateException("Pinned stack isn't top stack??? " + mStacks);
287            }
288        }
289        mStacks.add(addIndex, stack);
290    }
291
292    void detachStack(TaskStack stack) {
293        mDimLayerController.removeDimLayerUser(stack);
294        mStacks.remove(stack);
295    }
296
297    /**
298     * Propagate the new bounds to all child stacks.
299     * @param contentRect The bounds to apply at the top level.
300     */
301    void resize(Rect contentRect) {
302        mContentRect.set(contentRect);
303    }
304
305    int taskIdFromPoint(int x, int y) {
306        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
307            TaskStack stack = mStacks.get(stackNdx);
308            stack.getBounds(mTmpRect);
309            if (!mTmpRect.contains(x, y) || stack.isAdjustedForMinimizedDockedStack()) {
310                continue;
311            }
312            final ArrayList<Task> tasks = stack.getTasks();
313            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
314                final Task task = tasks.get(taskNdx);
315                final WindowState win = task.getTopVisibleAppMainWindow();
316                if (win == null) {
317                    continue;
318                }
319                // We need to use the task's dim bounds (which is derived from the visible
320                // bounds of its apps windows) for any touch-related tests. Can't use
321                // the task's original bounds because it might be adjusted to fit the
322                // content frame. For example, the presence of the IME adjusting the
323                // windows frames when the app window is the IME target.
324                task.getDimBounds(mTmpRect);
325                if (mTmpRect.contains(x, y)) {
326                    return task.mTaskId;
327                }
328            }
329        }
330        return -1;
331    }
332
333    /**
334     * Find the task whose outside touch area (for resizing) (x, y) falls within.
335     * Returns null if the touch doesn't fall into a resizing area.
336     */
337    Task findTaskForControlPoint(int x, int y) {
338        final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
339        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
340            TaskStack stack = mStacks.get(stackNdx);
341            if (!StackId.isTaskResizeAllowed(stack.mStackId)) {
342                break;
343            }
344            final ArrayList<Task> tasks = stack.getTasks();
345            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
346                final Task task = tasks.get(taskNdx);
347                if (task.isFullscreen()) {
348                    return null;
349                }
350
351                // We need to use the task's dim bounds (which is derived from the visible
352                // bounds of its apps windows) for any touch-related tests. Can't use
353                // the task's original bounds because it might be adjusted to fit the
354                // content frame. One example is when the task is put to top-left quadrant,
355                // the actual visible area would not start at (0,0) after it's adjusted
356                // for the status bar.
357                task.getDimBounds(mTmpRect);
358                mTmpRect.inset(-delta, -delta);
359                if (mTmpRect.contains(x, y)) {
360                    mTmpRect.inset(delta, delta);
361                    if (!mTmpRect.contains(x, y)) {
362                        return task;
363                    }
364                    // User touched inside the task. No need to look further,
365                    // focus transfer will be handled in ACTION_UP.
366                    return null;
367                }
368            }
369        }
370        return null;
371    }
372
373    void setTouchExcludeRegion(Task focusedTask) {
374        mTouchExcludeRegion.set(mBaseDisplayRect);
375        final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
376        boolean addBackFocusedTask = false;
377        mNonResizeableRegion.setEmpty();
378        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
379            TaskStack stack = mStacks.get(stackNdx);
380            final ArrayList<Task> tasks = stack.getTasks();
381            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
382                final Task task = tasks.get(taskNdx);
383                AppWindowToken token = task.getTopVisibleAppToken();
384                if (token == null || !token.isVisible()) {
385                    continue;
386                }
387
388                /**
389                 * Exclusion region is the region that TapDetector doesn't care about.
390                 * Here we want to remove all non-focused tasks from the exclusion region.
391                 * We also remove the outside touch area for resizing for all freeform
392                 * tasks (including the focused).
393                 *
394                 * We save the focused task region once we find it, and add it back at the end.
395                 */
396
397                task.getDimBounds(mTmpRect);
398
399                if (task == focusedTask) {
400                    addBackFocusedTask = true;
401                    mTmpRect2.set(mTmpRect);
402                }
403
404                final boolean isFreeformed = task.inFreeformWorkspace();
405                if (task != focusedTask || isFreeformed) {
406                    if (isFreeformed) {
407                        // If the task is freeformed, enlarge the area to account for outside
408                        // touch area for resize.
409                        mTmpRect.inset(-delta, -delta);
410                        // Intersect with display content rect. If we have system decor (status bar/
411                        // navigation bar), we want to exclude that from the tap detection.
412                        // Otherwise, if the app is partially placed under some system button (eg.
413                        // Recents, Home), pressing that button would cause a full series of
414                        // unwanted transfer focus/resume/pause, before we could go home.
415                        mTmpRect.intersect(mContentRect);
416                    }
417                    mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
418                }
419                if (task.isTwoFingerScrollMode()) {
420                    stack.getBounds(mTmpRect);
421                    mNonResizeableRegion.op(mTmpRect, Region.Op.UNION);
422                    break;
423                }
424            }
425        }
426        // If we removed the focused task above, add it back and only leave its
427        // outside touch area in the exclusion. TapDectector is not interested in
428        // any touch inside the focused task itself.
429        if (addBackFocusedTask) {
430            mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION);
431        }
432        final WindowState inputMethod = mService.mInputMethodWindow;
433        if (inputMethod != null && inputMethod.isVisibleLw()) {
434            // If the input method is visible and the user is typing, we don't want these touch
435            // events to be intercepted and used to change focus. This would likely cause a
436            // disappearance of the input method.
437            inputMethod.getTouchableRegion(mTmpRegion);
438            mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
439        }
440        for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) {
441            WindowState win = mTapExcludedWindows.get(i);
442            win.getTouchableRegion(mTmpRegion);
443            mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
444        }
445        if (getDockedStackVisibleForUserLocked() != null) {
446            mDividerControllerLocked.getTouchRegion(mTmpRect);
447            mTmpRegion.set(mTmpRect);
448            mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
449        }
450        if (mTapDetector != null) {
451            mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion, mNonResizeableRegion);
452        }
453    }
454
455    void switchUserStacks() {
456        final WindowList windows = getWindowList();
457        for (int i = 0; i < windows.size(); i++) {
458            final WindowState win = windows.get(i);
459            if (win.isHiddenFromUserLocked()) {
460                if (DEBUG_VISIBILITY) Slog.w(TAG_WM, "user changing, hiding " + win
461                        + ", attrs=" + win.mAttrs.type + ", belonging to " + win.mOwnerUid);
462                win.hideLw(false);
463            }
464        }
465
466        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
467            mStacks.get(stackNdx).switchUser();
468        }
469    }
470
471    void resetAnimationBackgroundAnimator() {
472        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
473            mStacks.get(stackNdx).resetAnimationBackgroundAnimator();
474        }
475    }
476
477    boolean animateDimLayers() {
478        return mDimLayerController.animateDimLayers();
479    }
480
481    void resetDimming() {
482        mDimLayerController.resetDimming();
483    }
484
485    boolean isDimming() {
486        return mDimLayerController.isDimming();
487    }
488
489    void stopDimmingIfNeeded() {
490        mDimLayerController.stopDimmingIfNeeded();
491    }
492
493    void close() {
494        mDimLayerController.close();
495        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
496            mStacks.get(stackNdx).close();
497        }
498    }
499
500    boolean isAnimating() {
501        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
502            final TaskStack stack = mStacks.get(stackNdx);
503            if (stack.isAnimating()) {
504                return true;
505            }
506        }
507        return false;
508    }
509
510    void checkForDeferredActions() {
511        boolean animating = false;
512        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
513            final TaskStack stack = mStacks.get(stackNdx);
514            if (stack.isAnimating()) {
515                animating = true;
516            } else {
517                if (stack.mDeferDetach) {
518                    mService.detachStackLocked(this, stack);
519                }
520                final ArrayList<Task> tasks = stack.getTasks();
521                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
522                    final Task task = tasks.get(taskNdx);
523                    AppTokenList tokens = task.mAppTokens;
524                    for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
525                        AppWindowToken wtoken = tokens.get(tokenNdx);
526                        if (wtoken.mIsExiting) {
527                            wtoken.removeAppFromTaskLocked();
528                        }
529                    }
530                }
531            }
532        }
533        if (!animating && mDeferredRemoval) {
534            mService.onDisplayRemoved(mDisplayId);
535        }
536    }
537
538    void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
539        final int rotationDelta = DisplayContent.deltaRotation(oldRotation, newRotation);
540        getLogicalDisplayRect(mTmpRect);
541        switch (rotationDelta) {
542            case Surface.ROTATION_0:
543                mTmpRect2.set(bounds);
544                break;
545            case Surface.ROTATION_90:
546                mTmpRect2.top = mTmpRect.bottom - bounds.right;
547                mTmpRect2.left = bounds.top;
548                mTmpRect2.right = mTmpRect2.left + bounds.height();
549                mTmpRect2.bottom = mTmpRect2.top + bounds.width();
550                break;
551            case Surface.ROTATION_180:
552                mTmpRect2.top = mTmpRect.bottom - bounds.bottom;
553                mTmpRect2.left = mTmpRect.right - bounds.right;
554                mTmpRect2.right = mTmpRect2.left + bounds.width();
555                mTmpRect2.bottom = mTmpRect2.top + bounds.height();
556                break;
557            case Surface.ROTATION_270:
558                mTmpRect2.top = bounds.left;
559                mTmpRect2.left = mTmpRect.right - bounds.bottom;
560                mTmpRect2.right = mTmpRect2.left + bounds.height();
561                mTmpRect2.bottom = mTmpRect2.top + bounds.width();
562                break;
563        }
564        bounds.set(mTmpRect2);
565    }
566
567    static int deltaRotation(int oldRotation, int newRotation) {
568        int delta = newRotation - oldRotation;
569        if (delta < 0) delta += 4;
570        return delta;
571    }
572
573    public void dump(String prefix, PrintWriter pw) {
574        pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
575        final String subPrefix = "  " + prefix;
576        pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
577            pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
578            pw.print("dpi");
579            if (mInitialDisplayWidth != mBaseDisplayWidth
580                    || mInitialDisplayHeight != mBaseDisplayHeight
581                    || mInitialDisplayDensity != mBaseDisplayDensity) {
582                pw.print(" base=");
583                pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
584                pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
585            }
586            if (mDisplayScalingDisabled) {
587                pw.println(" noscale");
588            }
589            pw.print(" cur=");
590            pw.print(mDisplayInfo.logicalWidth);
591            pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
592            pw.print(" app=");
593            pw.print(mDisplayInfo.appWidth);
594            pw.print("x"); pw.print(mDisplayInfo.appHeight);
595            pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
596            pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
597            pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
598            pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
599            pw.print(subPrefix); pw.print("deferred="); pw.print(mDeferredRemoval);
600                pw.print(" layoutNeeded="); pw.println(layoutNeeded);
601
602        pw.println();
603        pw.println("  Application tokens in top down Z order:");
604        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
605            final TaskStack stack = mStacks.get(stackNdx);
606            stack.dump(prefix + "  ", pw);
607        }
608
609        pw.println();
610        if (!mExitingTokens.isEmpty()) {
611            pw.println();
612            pw.println("  Exiting tokens:");
613            for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
614                WindowToken token = mExitingTokens.get(i);
615                pw.print("  Exiting #"); pw.print(i);
616                pw.print(' '); pw.print(token);
617                pw.println(':');
618                token.dump(pw, "    ");
619            }
620        }
621        pw.println();
622        mDimLayerController.dump(prefix + "  ", pw);
623        pw.println();
624        mDividerControllerLocked.dump(prefix + "  ", pw);
625    }
626
627    @Override
628    public String toString() {
629        return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks;
630    }
631
632    /**
633     * @return The docked stack, but only if it is visible, and {@code null} otherwise.
634     */
635    TaskStack getDockedStackLocked() {
636        final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
637        return (stack != null && stack.isVisibleLocked()) ? stack : null;
638    }
639
640    /**
641     * Like {@link #getDockedStackLocked}, but also returns the docked stack if it's currently not
642     * visible, as long as it's not hidden because the current user doesn't have any tasks there.
643     */
644    TaskStack getDockedStackVisibleForUserLocked() {
645        final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
646        return (stack != null && stack.isVisibleLocked(true /* ignoreKeyguard */)) ? stack : null;
647    }
648
649    /**
650     * Find the visible, touch-deliverable window under the given point
651     */
652    WindowState getTouchableWinAtPointLocked(float xf, float yf) {
653        WindowState touchedWin = null;
654        final int x = (int) xf;
655        final int y = (int) yf;
656
657        for (int i = mWindows.size() - 1; i >= 0; i--) {
658            WindowState window = mWindows.get(i);
659            final int flags = window.mAttrs.flags;
660            if (!window.isVisibleLw()) {
661                continue;
662            }
663            if ((flags & FLAG_NOT_TOUCHABLE) != 0) {
664                continue;
665            }
666
667            window.getVisibleBounds(mTmpRect);
668            if (!mTmpRect.contains(x, y)) {
669                continue;
670            }
671
672            window.getTouchableRegion(mTmpRegion);
673
674            final int touchFlags = flags & (FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL);
675            if (mTmpRegion.contains(x, y) || touchFlags == 0) {
676                touchedWin = window;
677                break;
678            }
679        }
680
681        return touchedWin;
682    }
683
684    /**
685     * See {@link WindowManagerService#overridePlayingAppAnimationsLw}.
686     */
687    void overridePlayingAppAnimationsLw(Animation a) {
688        for (int i = mStacks.size() - 1; i >= 0; i--) {
689            mStacks.get(i).overridePlayingAppAnimations(a);
690        }
691    }
692
693    boolean canAddToastWindowForUid(int uid) {
694        // We allow one toast window per UID being shown at a time.
695        WindowList windows = getWindowList();
696        final int windowCount = windows.size();
697        for (int i = 0; i < windowCount; i++) {
698            WindowState window = windows.get(i);
699            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid
700                    && !window.mPermanentlyHidden && !window.mAnimatingExit
701                    && !window.mRemoveOnExit) {
702                return false;
703            }
704        }
705        return true;
706    }
707
708    void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus,
709                                                   WindowState newFocus) {
710        if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) {
711            return;
712        }
713        final int lostFocusUid = oldFocus.mOwnerUid;
714        WindowList windows = getWindowList();
715        final int windowCount = windows.size();
716        for (int i = 0; i < windowCount; i++) {
717            WindowState window = windows.get(i);
718            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == lostFocusUid) {
719                if (!mService.mH.hasMessages(WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window)) {
720                    mService.mH.sendMessageDelayed(
721                            mService.mH.obtainMessage(
722                                    WindowManagerService.H.WINDOW_HIDE_TIMEOUT, window),
723                            window.mAttrs.hideTimeoutMilliseconds);
724                }
725            }
726        }
727    }
728}
729