Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2015 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 android.util.Slog;
     20 import android.view.Display;
     21 
     22 import java.io.PrintWriter;
     23 import java.util.ArrayDeque;
     24 
     25 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
     26 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
     27 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
     28 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
     29 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     30 import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
     31 import static com.android.server.wm.WindowManagerService.WINDOW_LAYER_MULTIPLIER;
     32 
     33 /**
     34  * Controller for assigning layers to windows on the display.
     35  *
     36  * This class encapsulates general algorithm for assigning layers and special rules that we need to
     37  * apply on top. The general algorithm goes through windows from bottom to the top and the higher
     38  * the window is, the higher layer is assigned. The final layer is equal to base layer +
     39  * adjustment from the order. This means that the window list is assumed to be ordered roughly by
     40  * the base layer (there are exceptions, e.g. due to keyguard and wallpaper and they need to be
     41  * handled with care, because they break the algorithm).
     42  *
     43  * On top of the general algorithm we add special rules, that govern such amazing things as:
     44  * <li>IME (which has higher base layer, but will be positioned above application windows)</li>
     45  * <li>docked/pinned windows (that need to be lifted above other application windows, including
     46  * animations)
     47  * <li>dock divider (which needs to live above applications, but below IME)</li>
     48  * <li>replaced windows, which need to live above their normal level, because they anticipate
     49  * an animation</li>.
     50  */
     51 public class WindowLayersController {
     52     private final WindowManagerService mService;
     53 
     54     private int mInputMethodAnimLayerAdjustment;
     55 
     56     public WindowLayersController(WindowManagerService service) {
     57         mService = service;
     58     }
     59 
     60     private int mHighestApplicationLayer = 0;
     61     private ArrayDeque<WindowState> mPinnedWindows = new ArrayDeque<>();
     62     private ArrayDeque<WindowState> mDockedWindows = new ArrayDeque<>();
     63     private ArrayDeque<WindowState> mInputMethodWindows = new ArrayDeque<>();
     64     private WindowState mDockDivider = null;
     65     private ArrayDeque<WindowState> mReplacingWindows = new ArrayDeque<>();
     66 
     67     final void assignLayersLocked(WindowList windows) {
     68         if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows,
     69                 new RuntimeException("here").fillInStackTrace());
     70 
     71         clear();
     72         int curBaseLayer = 0;
     73         int curLayer = 0;
     74         boolean anyLayerChanged = false;
     75         for (int i = 0, windowCount = windows.size(); i < windowCount; i++) {
     76             final WindowState w = windows.get(i);
     77             boolean layerChanged = false;
     78 
     79             int oldLayer = w.mLayer;
     80             if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i > 0 && w.mIsWallpaper)) {
     81                 curLayer += WINDOW_LAYER_MULTIPLIER;
     82             } else {
     83                 curBaseLayer = curLayer = w.mBaseLayer;
     84             }
     85             assignAnimLayer(w, curLayer);
     86 
     87             // TODO: Preserved old behavior of code here but not sure comparing
     88             // oldLayer to mAnimLayer and mLayer makes sense...though the
     89             // worst case would be unintentionalp layer reassignment.
     90             if (w.mLayer != oldLayer || w.mWinAnimator.mAnimLayer != oldLayer) {
     91                 layerChanged = true;
     92                 anyLayerChanged = true;
     93             }
     94 
     95             if (w.mAppToken != null) {
     96                 mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
     97                         w.mWinAnimator.mAnimLayer);
     98             }
     99             collectSpecialWindows(w);
    100 
    101             if (layerChanged) {
    102                 w.scheduleAnimationIfDimming();
    103             }
    104         }
    105 
    106         adjustSpecialWindows();
    107 
    108         //TODO (multidisplay): Magnification is supported only for the default display.
    109         if (mService.mAccessibilityController != null && anyLayerChanged
    110                 && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
    111             mService.mAccessibilityController.onWindowLayersChangedLocked();
    112         }
    113 
    114         if (DEBUG_LAYERS) logDebugLayers(windows);
    115     }
    116 
    117     void setInputMethodAnimLayerAdjustment(int adj) {
    118         if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj);
    119         mInputMethodAnimLayerAdjustment = adj;
    120         final WindowState imw = mService.mInputMethodWindow;
    121         if (imw != null) {
    122             imw.mWinAnimator.mAnimLayer = imw.mLayer + adj;
    123             if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
    124                     + " anim layer: " + imw.mWinAnimator.mAnimLayer);
    125             for (int i = imw.mChildWindows.size() - 1; i >= 0; i--) {
    126                 final WindowState childWindow = imw.mChildWindows.get(i);
    127                 childWindow.mWinAnimator.mAnimLayer = childWindow.mLayer + adj;
    128                 if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + childWindow
    129                         + " anim layer: " + childWindow.mWinAnimator.mAnimLayer);
    130             }
    131         }
    132         for (int i = mService.mInputMethodDialogs.size() - 1; i >= 0; i--) {
    133             final WindowState dialog = mService.mInputMethodDialogs.get(i);
    134             dialog.mWinAnimator.mAnimLayer = dialog.mLayer + adj;
    135             if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
    136                     + " anim layer: " + dialog.mWinAnimator.mAnimLayer);
    137         }
    138     }
    139 
    140     int getSpecialWindowAnimLayerAdjustment(WindowState win) {
    141         if (win.mIsImWindow) {
    142             return mInputMethodAnimLayerAdjustment;
    143         } else if (win.mIsWallpaper) {
    144             return mService.mWallpaperControllerLocked.getAnimLayerAdjustment();
    145         }
    146         return 0;
    147     }
    148 
    149     /**
    150      * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
    151      *         above all application surfaces.
    152      */
    153     int getResizeDimLayer() {
    154         return (mDockDivider != null) ? mDockDivider.mLayer - 1 : LAYER_OFFSET_DIM;
    155     }
    156 
    157     private void logDebugLayers(WindowList windows) {
    158         for (int i = 0, n = windows.size(); i < n; i++) {
    159             final WindowState w = windows.get(i);
    160             final WindowStateAnimator winAnimator = w.mWinAnimator;
    161             Slog.v(TAG_WM, "Assign layer " + w + ": " + "mBase=" + w.mBaseLayer
    162                     + " mLayer=" + w.mLayer + (w.mAppToken == null
    163                     ? "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
    164                     + " =mAnimLayer=" + winAnimator.mAnimLayer);
    165         }
    166     }
    167 
    168     private void clear() {
    169         mHighestApplicationLayer = 0;
    170         mPinnedWindows.clear();
    171         mInputMethodWindows.clear();
    172         mDockedWindows.clear();
    173         mReplacingWindows.clear();
    174         mDockDivider = null;
    175     }
    176 
    177     private void collectSpecialWindows(WindowState w) {
    178         if (w.mAttrs.type == TYPE_DOCK_DIVIDER) {
    179             mDockDivider = w;
    180             return;
    181         }
    182         if (w.mWillReplaceWindow) {
    183             mReplacingWindows.add(w);
    184         }
    185         if (w.mIsImWindow) {
    186             mInputMethodWindows.add(w);
    187             return;
    188         }
    189         final TaskStack stack = w.getStack();
    190         if (stack == null) {
    191             return;
    192         }
    193         if (stack.mStackId == PINNED_STACK_ID) {
    194             mPinnedWindows.add(w);
    195         } else if (stack.mStackId == DOCKED_STACK_ID) {
    196             mDockedWindows.add(w);
    197         }
    198     }
    199 
    200     private void adjustSpecialWindows() {
    201         int layer = mHighestApplicationLayer + WINDOW_LAYER_MULTIPLIER;
    202         // For pinned and docked stack window, we want to make them above other windows also when
    203         // these windows are animating.
    204         while (!mDockedWindows.isEmpty()) {
    205             layer = assignAndIncreaseLayerIfNeeded(mDockedWindows.remove(), layer);
    206         }
    207 
    208         layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
    209 
    210         if (mDockDivider != null && mDockDivider.isVisibleLw()) {
    211             while (!mInputMethodWindows.isEmpty()) {
    212                 final WindowState w = mInputMethodWindows.remove();
    213                 // Only ever move IME windows up, else we brake IME for windows above the divider.
    214                 if (layer > w.mLayer) {
    215                     layer = assignAndIncreaseLayerIfNeeded(w, layer);
    216                 }
    217             }
    218         }
    219 
    220         // We know that we will be animating a relaunching window in the near future, which will
    221         // receive a z-order increase. We want the replaced window to immediately receive the same
    222         // treatment, e.g. to be above the dock divider.
    223         while (!mReplacingWindows.isEmpty()) {
    224             layer = assignAndIncreaseLayerIfNeeded(mReplacingWindows.remove(), layer);
    225         }
    226 
    227         while (!mPinnedWindows.isEmpty()) {
    228             layer = assignAndIncreaseLayerIfNeeded(mPinnedWindows.remove(), layer);
    229         }
    230     }
    231 
    232     private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
    233         if (win != null) {
    234             assignAnimLayer(win, layer);
    235             // Make sure we leave space inbetween normal windows for dims and such.
    236             layer += WINDOW_LAYER_MULTIPLIER;
    237         }
    238         return layer;
    239     }
    240 
    241     private void assignAnimLayer(WindowState w, int layer) {
    242         w.mLayer = layer;
    243         w.mWinAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
    244                     getSpecialWindowAnimLayerAdjustment(w);
    245         if (w.mAppToken != null && w.mAppToken.mAppAnimator.thumbnailForceAboveLayer > 0
    246                 && w.mWinAnimator.mAnimLayer > w.mAppToken.mAppAnimator.thumbnailForceAboveLayer) {
    247             w.mAppToken.mAppAnimator.thumbnailForceAboveLayer = w.mWinAnimator.mAnimLayer;
    248         }
    249     }
    250 
    251     void dump(PrintWriter pw, String s) {
    252         if (mInputMethodAnimLayerAdjustment != 0 ||
    253                 mService.mWallpaperControllerLocked.getAnimLayerAdjustment() != 0) {
    254             pw.print("  mInputMethodAnimLayerAdjustment=");
    255             pw.print(mInputMethodAnimLayerAdjustment);
    256             pw.print("  mWallpaperAnimLayerAdjustment=");
    257             pw.println(mService.mWallpaperControllerLocked.getAnimLayerAdjustment());
    258         }
    259     }
    260 }
    261