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