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 WindowLayersController(WindowManagerService service)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 assignLayersLocked(WindowList windows)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 setInputMethodAnimLayerAdjustment(int adj)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 getSpecialWindowAnimLayerAdjustment(WindowState win)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 */ getResizeDimLayer()153 int getResizeDimLayer() { 154 return (mDockDivider != null) ? mDockDivider.mLayer - 1 : LAYER_OFFSET_DIM; 155 } 156 logDebugLayers(WindowList windows)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 clear()168 private void clear() { 169 mHighestApplicationLayer = 0; 170 mPinnedWindows.clear(); 171 mInputMethodWindows.clear(); 172 mDockedWindows.clear(); 173 mReplacingWindows.clear(); 174 mDockDivider = null; 175 } 176 collectSpecialWindows(WindowState w)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 adjustSpecialWindows()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 assignAndIncreaseLayerIfNeeded(WindowState win, int layer)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 assignAnimLayer(WindowState w, int layer)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 dump(PrintWriter pw, String s)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