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_STACK;
     21 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
     22 import static com.android.server.wm.WindowManagerService.TAG;
     23 
     24 import android.app.ActivityManager.StackBoxInfo;
     25 import android.graphics.Rect;
     26 import android.graphics.Region;
     27 import android.os.Debug;
     28 import android.util.EventLog;
     29 import android.util.Slog;
     30 import android.view.Display;
     31 import android.view.DisplayInfo;
     32 import com.android.server.EventLogTags;
     33 
     34 import java.io.PrintWriter;
     35 import java.util.ArrayList;
     36 
     37 class DisplayContentList extends ArrayList<DisplayContent> {
     38 }
     39 
     40 /**
     41  * Utility class for keeping track of the WindowStates and other pertinent contents of a
     42  * particular Display.
     43  *
     44  * IMPORTANT: No method from this class should ever be used without holding
     45  * WindowManagerService.mWindowMap.
     46  */
     47 class DisplayContent {
     48 
     49     /** Unique identifier of this stack. */
     50     private final int mDisplayId;
     51 
     52     /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
     53      * from mDisplayWindows; */
     54     private WindowList mWindows = new WindowList();
     55 
     56     // This protects the following display size properties, so that
     57     // getDisplaySize() doesn't need to acquire the global lock.  This is
     58     // needed because the window manager sometimes needs to use ActivityThread
     59     // while it has its global state locked (for example to load animation
     60     // resources), but the ActivityThread also needs get the current display
     61     // size sometimes when it has its package lock held.
     62     //
     63     // These will only be modified with both mWindowMap and mDisplaySizeLock
     64     // held (in that order) so the window manager doesn't need to acquire this
     65     // lock when needing these values in its normal operation.
     66     final Object mDisplaySizeLock = new Object();
     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     private final DisplayInfo mDisplayInfo = new DisplayInfo();
     74     private final Display mDisplay;
     75 
     76     Rect mBaseDisplayRect = new Rect();
     77 
     78     // Accessed directly by all users.
     79     boolean layoutNeeded;
     80     int pendingLayoutChanges;
     81     final boolean isDefaultDisplay;
     82 
     83     /**
     84      * Window tokens that are in the process of exiting, but still
     85      * on screen for animations.
     86      */
     87     final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
     88 
     89     /**
     90      * Application tokens that are in the process of exiting, but still
     91      * on screen for animations.
     92      */
     93     final AppTokenList mExitingAppTokens = new AppTokenList();
     94 
     95     /** Array containing the home StackBox and possibly one more which would contain apps. Array
     96      * is stored in display order with the current bottom stack at 0. */
     97     private ArrayList<StackBox> mStackBoxes = new ArrayList<StackBox>();
     98 
     99     /** True when the home StackBox is at the top of mStackBoxes, false otherwise. */
    100     private TaskStack mHomeStack = null;
    101 
    102     /** Detect user tapping outside of current focused stack bounds .*/
    103     StackTapPointerEventListener mTapDetector;
    104 
    105     /** Detect user tapping outside of current focused stack bounds .*/
    106     Region mTouchExcludeRegion = new Region();
    107 
    108     /** Save allocating when retrieving tasks */
    109     private ArrayList<Task> mTaskHistory = new ArrayList<Task>();
    110 
    111     /** Save allocating when calculating rects */
    112     Rect mTmpRect = new Rect();
    113 
    114     final WindowManagerService mService;
    115 
    116     /**
    117      * @param display May not be null.
    118      * @param service TODO(cmautner):
    119      */
    120     DisplayContent(Display display, WindowManagerService service) {
    121         mDisplay = display;
    122         mDisplayId = display.getDisplayId();
    123         display.getDisplayInfo(mDisplayInfo);
    124         isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
    125         mService = service;
    126 
    127         StackBox newBox = new StackBox(service, this, null);
    128         mStackBoxes.add(newBox);
    129         TaskStack newStack = new TaskStack(service, HOME_STACK_ID, this);
    130         newStack.mStackBox = newBox;
    131         newBox.mStack = newStack;
    132         mHomeStack = newStack;
    133     }
    134 
    135     int getDisplayId() {
    136         return mDisplayId;
    137     }
    138 
    139     WindowList getWindowList() {
    140         return mWindows;
    141     }
    142 
    143     Display getDisplay() {
    144         return mDisplay;
    145     }
    146 
    147     DisplayInfo getDisplayInfo() {
    148         return mDisplayInfo;
    149     }
    150 
    151     /**
    152      * Returns true if the specified UID has access to this display.
    153      */
    154     public boolean hasAccess(int uid) {
    155         return mDisplay.hasAccess(uid);
    156     }
    157 
    158     boolean homeOnTop() {
    159         return mStackBoxes.get(0).mStack != mHomeStack;
    160     }
    161 
    162     public boolean isPrivate() {
    163         return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
    164     }
    165 
    166     /**
    167      * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
    168      * @return All the Tasks, in order, on this display.
    169      */
    170     ArrayList<Task> getTasks() {
    171         return mTaskHistory;
    172     }
    173 
    174     void addTask(Task task, boolean toTop) {
    175         mTaskHistory.remove(task);
    176 
    177         final int userId = task.mUserId;
    178         int taskNdx;
    179         final int numTasks = mTaskHistory.size();
    180         if (toTop) {
    181             for (taskNdx = numTasks - 1; taskNdx >= 0; --taskNdx) {
    182                 if (mTaskHistory.get(taskNdx).mUserId == userId) {
    183                     break;
    184                 }
    185             }
    186             ++taskNdx;
    187         } else {
    188             for (taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
    189                 if (mTaskHistory.get(taskNdx).mUserId == userId) {
    190                     break;
    191                 }
    192             }
    193         }
    194 
    195         mTaskHistory.add(taskNdx, task);
    196         EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx);
    197     }
    198 
    199     void removeTask(Task task) {
    200         mTaskHistory.remove(task);
    201     }
    202 
    203     TaskStack getHomeStack() {
    204         return mHomeStack;
    205     }
    206 
    207     void updateDisplayInfo() {
    208         mDisplay.getDisplayInfo(mDisplayInfo);
    209     }
    210 
    211     void getLogicalDisplayRect(Rect out) {
    212         updateDisplayInfo();
    213         // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
    214         int width = mDisplayInfo.logicalWidth;
    215         int left = (mBaseDisplayWidth - width) / 2;
    216         int height = mDisplayInfo.logicalHeight;
    217         int top = (mBaseDisplayHeight - height) / 2;
    218         out.set(left, top, left + width, top + height);
    219     }
    220 
    221     /** @return The number of tokens in all of the Tasks on this display. */
    222     int numTokens() {
    223         int count = 0;
    224         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
    225             count += mTaskHistory.get(taskNdx).mAppTokens.size();
    226         }
    227         return count;
    228     }
    229 
    230     /** Refer to {@link WindowManagerService#createStack(int, int, int, float)} */
    231     TaskStack createStack(int stackId, int relativeStackBoxId, int position, float weight) {
    232         TaskStack newStack = null;
    233         if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId + " relativeStackBoxId="
    234                 + relativeStackBoxId + " position=" + position + " weight=" + weight);
    235         if (stackId == HOME_STACK_ID) {
    236             if (mStackBoxes.size() != 1) {
    237                 throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");
    238             }
    239             newStack = mHomeStack;
    240         } else {
    241             int stackBoxNdx;
    242             for (stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    243                 final StackBox box = mStackBoxes.get(stackBoxNdx);
    244                 if (position == StackBox.TASK_STACK_GOES_OVER
    245                         || position == StackBox.TASK_STACK_GOES_UNDER) {
    246                     // Position indicates a new box is added at top level only.
    247                     if (box.contains(relativeStackBoxId)) {
    248                         StackBox newBox = new StackBox(mService, this, null);
    249                         newStack = new TaskStack(mService, stackId, this);
    250                         newStack.mStackBox = newBox;
    251                         newBox.mStack = newStack;
    252                         final int offset = position == StackBox.TASK_STACK_GOES_OVER ? 1 : 0;
    253                         if (DEBUG_STACK) Slog.d(TAG, "createStack: inserting stack at " +
    254                                 (stackBoxNdx + offset));
    255                         mStackBoxes.add(stackBoxNdx + offset, newBox);
    256                         break;
    257                     }
    258                 } else {
    259                     // Remaining position values indicate a box must be split.
    260                     newStack = box.split(stackId, relativeStackBoxId, position, weight);
    261                     if (newStack != null) {
    262                         break;
    263                     }
    264                 }
    265             }
    266             if (stackBoxNdx < 0) {
    267                 throw new IllegalArgumentException("createStack: stackBoxId " + relativeStackBoxId
    268                         + " not found.");
    269             }
    270         }
    271         if (newStack != null) {
    272             layoutNeeded = true;
    273         }
    274         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, relativeStackBoxId, position,
    275                 (int)(weight * 100 + 0.5));
    276         return newStack;
    277     }
    278 
    279     /** Refer to {@link WindowManagerService#resizeStackBox(int, float)} */
    280     boolean resizeStack(int stackBoxId, float weight) {
    281         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    282             final StackBox box = mStackBoxes.get(stackBoxNdx);
    283             if (box.resize(stackBoxId, weight)) {
    284                 layoutNeeded = true;
    285                 return true;
    286             }
    287         }
    288         return false;
    289     }
    290 
    291     void addStackBox(StackBox box, boolean toTop) {
    292         if (mStackBoxes.size() >= 2) {
    293             throw new RuntimeException("addStackBox: Too many toplevel StackBoxes!");
    294         }
    295         mStackBoxes.add(toTop ? mStackBoxes.size() : 0, box);
    296     }
    297 
    298     void removeStackBox(StackBox box) {
    299         if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: box=" + box);
    300         final TaskStack stack = box.mStack;
    301         if (stack != null && stack.mStackId == HOME_STACK_ID) {
    302             // Never delete the home stack, even if it is empty.
    303             if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: Not deleting home stack.");
    304             return;
    305         }
    306         mStackBoxes.remove(box);
    307     }
    308 
    309     StackBoxInfo getStackBoxInfo(StackBox box) {
    310         StackBoxInfo info = new StackBoxInfo();
    311         info.stackBoxId = box.mStackBoxId;
    312         info.weight = box.mWeight;
    313         info.vertical = box.mVertical;
    314         info.bounds = new Rect(box.mBounds);
    315         if (box.mStack != null) {
    316             info.stackId = box.mStack.mStackId;
    317             // ActivityManagerService will fill in the StackInfo.
    318         } else {
    319             info.stackId = -1;
    320             info.children = new StackBoxInfo[2];
    321             info.children[0] = getStackBoxInfo(box.mFirst);
    322             info.children[1] = getStackBoxInfo(box.mSecond);
    323         }
    324         return info;
    325     }
    326 
    327     ArrayList<StackBoxInfo> getStackBoxInfos() {
    328         ArrayList<StackBoxInfo> list = new ArrayList<StackBoxInfo>();
    329         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    330             list.add(getStackBoxInfo(mStackBoxes.get(stackBoxNdx)));
    331         }
    332         return list;
    333     }
    334 
    335     /**
    336      * Move the home StackBox to the top or bottom of mStackBoxes. That is the only place
    337      * it is allowed to be. This is a nop if the home StackBox is already in the correct position.
    338      * @param toTop Move home to the top of mStackBoxes if true, to the bottom if false.
    339      * @return true if a change was made, false otherwise.
    340      */
    341     boolean moveHomeStackBox(boolean toTop) {
    342         if (DEBUG_STACK) Slog.d(TAG, "moveHomeStackBox: toTop=" + toTop + " Callers=" +
    343                 Debug.getCallers(4));
    344         EventLog.writeEvent(EventLogTags.WM_HOME_STACK_MOVED, toTop ? 1 : 0);
    345         switch (mStackBoxes.size()) {
    346             case 0: throw new RuntimeException("moveHomeStackBox: No home StackBox!");
    347             case 1: return false; // Only the home StackBox exists.
    348             case 2:
    349                 if (homeOnTop() ^ toTop) {
    350                     mStackBoxes.add(mStackBoxes.remove(0));
    351                     return true;
    352                 }
    353                 return false;
    354             default: throw new RuntimeException("moveHomeStackBox: Too many toplevel StackBoxes!");
    355         }
    356     }
    357 
    358     /**
    359      * Propagate the new bounds to all child stack boxes, applying weights as we move down.
    360      * @param contentRect The bounds to apply at the top level.
    361      */
    362     boolean setStackBoxSize(Rect contentRect) {
    363         boolean change = false;
    364         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    365             change |= mStackBoxes.get(stackBoxNdx).setStackBoxSizes(contentRect, true);
    366         }
    367         return change;
    368     }
    369 
    370     Rect getStackBounds(int stackId) {
    371         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    372             Rect bounds = mStackBoxes.get(stackBoxNdx).getStackBounds(stackId);
    373             if (bounds != null) {
    374                 return bounds;
    375             }
    376         }
    377         return null;
    378     }
    379 
    380     int stackIdFromPoint(int x, int y) {
    381         StackBox topBox = mStackBoxes.get(mStackBoxes.size() - 1);
    382         return topBox.stackIdFromPoint(x, y);
    383     }
    384 
    385     void setTouchExcludeRegion(TaskStack focusedStack) {
    386         mTouchExcludeRegion.set(mBaseDisplayRect);
    387         WindowList windows = getWindowList();
    388         for (int i = windows.size() - 1; i >= 0; --i) {
    389             final WindowState win = windows.get(i);
    390             final TaskStack stack = win.getStack();
    391             if (win.isVisibleLw() && stack != null && stack != focusedStack) {
    392                 mTmpRect.set(win.mVisibleFrame);
    393                 mTmpRect.intersect(win.mVisibleInsets);
    394                 mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
    395             }
    396         }
    397     }
    398 
    399     void switchUserStacks(int oldUserId, int newUserId) {
    400         final WindowList windows = getWindowList();
    401         for (int i = 0; i < windows.size(); i++) {
    402             final WindowState win = windows.get(i);
    403             if (win.isHiddenFromUserLocked()) {
    404                 if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "
    405                         + win + ", attrs=" + win.mAttrs.type + ", belonging to "
    406                         + win.mOwnerUid);
    407                 win.hideLw(false);
    408             }
    409         }
    410 
    411         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    412             mStackBoxes.get(stackBoxNdx).switchUserStacks(newUserId);
    413         }
    414     }
    415 
    416     void resetAnimationBackgroundAnimator() {
    417         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    418             mStackBoxes.get(stackBoxNdx).resetAnimationBackgroundAnimator();
    419         }
    420     }
    421 
    422     boolean animateDimLayers() {
    423         boolean result = false;
    424         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    425             result |= mStackBoxes.get(stackBoxNdx).animateDimLayers();
    426         }
    427         return result;
    428     }
    429 
    430     void resetDimming() {
    431         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    432             mStackBoxes.get(stackBoxNdx).resetDimming();
    433         }
    434     }
    435 
    436     boolean isDimming() {
    437         boolean result = false;
    438         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    439             result |= mStackBoxes.get(stackBoxNdx).isDimming();
    440         }
    441         return result;
    442     }
    443 
    444     void stopDimmingIfNeeded() {
    445         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    446             mStackBoxes.get(stackBoxNdx).stopDimmingIfNeeded();
    447         }
    448     }
    449 
    450     void close() {
    451         for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
    452             mStackBoxes.get(stackBoxNdx).close();
    453         }
    454     }
    455 
    456     public void dump(String prefix, PrintWriter pw) {
    457         pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
    458         final String subPrefix = "  " + prefix;
    459         pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
    460             pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
    461             pw.print("dpi");
    462             if (mInitialDisplayWidth != mBaseDisplayWidth
    463                     || mInitialDisplayHeight != mBaseDisplayHeight
    464                     || mInitialDisplayDensity != mBaseDisplayDensity) {
    465                 pw.print(" base=");
    466                 pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
    467                 pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
    468             }
    469             pw.print(" cur=");
    470             pw.print(mDisplayInfo.logicalWidth);
    471             pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
    472             pw.print(" app=");
    473             pw.print(mDisplayInfo.appWidth);
    474             pw.print("x"); pw.print(mDisplayInfo.appHeight);
    475             pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
    476             pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
    477             pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
    478             pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
    479             pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
    480         for (int boxNdx = 0; boxNdx < mStackBoxes.size(); ++boxNdx) {
    481             pw.print(prefix); pw.print("StackBox #"); pw.println(boxNdx);
    482             mStackBoxes.get(boxNdx).dump(prefix + "  ", pw);
    483         }
    484         int ndx = numTokens();
    485         if (ndx > 0) {
    486             pw.println();
    487             pw.println("  Application tokens in Z order:");
    488             getTasks();
    489             for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
    490                 AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens;
    491                 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
    492                     final AppWindowToken wtoken = tokens.get(tokenNdx);
    493                     pw.print("  App #"); pw.print(ndx--);
    494                             pw.print(' '); pw.print(wtoken); pw.println(":");
    495                     wtoken.dump(pw, "    ");
    496                 }
    497             }
    498         }
    499         if (mExitingTokens.size() > 0) {
    500             pw.println();
    501             pw.println("  Exiting tokens:");
    502             for (int i=mExitingTokens.size()-1; i>=0; i--) {
    503                 WindowToken token = mExitingTokens.get(i);
    504                 pw.print("  Exiting #"); pw.print(i);
    505                 pw.print(' '); pw.print(token);
    506                 pw.println(':');
    507                 token.dump(pw, "    ");
    508             }
    509         }
    510         if (mExitingAppTokens.size() > 0) {
    511             pw.println();
    512             pw.println("  Exiting application tokens:");
    513             for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
    514                 WindowToken token = mExitingAppTokens.get(i);
    515                 pw.print("  Exiting App #"); pw.print(i);
    516                   pw.print(' '); pw.print(token);
    517                   pw.println(':');
    518                   token.dump(pw, "    ");
    519             }
    520         }
    521         pw.println();
    522     }
    523 }
    524