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