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