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