blob: 68c2be93d69e8dbaadff0d61b9e2136942c153bb [file] [log] [blame]
Jorim Jaggi50981592015-12-29 17:54:12 +01001/*
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 */
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080016
Jorim Jaggi50981592015-12-29 17:54:12 +010017package com.android.server.wm;
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080018
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080019import android.util.Slog;
20import android.view.Display;
21
22import java.io.PrintWriter;
Wale Ogunwale26b7b432016-02-03 14:12:08 -080023import java.util.ArrayDeque;
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080024
Wale Ogunwale26b7b432016-02-03 14:12:08 -080025import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
26import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
Jorim Jaggi50981592015-12-29 17:54:12 +010027import 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;
Wale Ogunwale20ec11b2016-04-22 12:11:51 -070030import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
Jorim Jaggi50981592015-12-29 17:54:12 +010031import static com.android.server.wm.WindowManagerService.WINDOW_LAYER_MULTIPLIER;
32
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080033/**
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 */
51public 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;
Wale Ogunwale26b7b432016-02-03 14:12:08 -080061 private ArrayDeque<WindowState> mPinnedWindows = new ArrayDeque<>();
62 private ArrayDeque<WindowState> mDockedWindows = new ArrayDeque<>();
Robert Carrb9768772016-04-19 22:31:09 -070063 private ArrayDeque<WindowState> mInputMethodWindows = new ArrayDeque<>();
Jiaquan He9bc01a82016-07-08 10:29:38 -070064 private ArrayDeque<WindowState> mOnTopLauncherWindows = new ArrayDeque<>();
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080065 private WindowState mDockDivider = null;
Wale Ogunwale26b7b432016-02-03 14:12:08 -080066 private ArrayDeque<WindowState> mReplacingWindows = new ArrayDeque<>();
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080067
68 final void assignLayersLocked(WindowList windows) {
69 if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows,
70 new RuntimeException("here").fillInStackTrace());
71
72 clear();
73 int curBaseLayer = 0;
74 int curLayer = 0;
75 boolean anyLayerChanged = false;
76 for (int i = 0, windowCount = windows.size(); i < windowCount; i++) {
77 final WindowState w = windows.get(i);
78 boolean layerChanged = false;
79
80 int oldLayer = w.mLayer;
81 if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i > 0 && w.mIsWallpaper)) {
82 curLayer += WINDOW_LAYER_MULTIPLIER;
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080083 } else {
84 curBaseLayer = curLayer = w.mBaseLayer;
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080085 }
Robert Carr67eec032016-03-22 16:57:33 -070086 assignAnimLayer(w, curLayer);
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080087
Robert Carr67eec032016-03-22 16:57:33 -070088 // TODO: Preserved old behavior of code here but not sure comparing
89 // oldLayer to mAnimLayer and mLayer makes sense...though the
90 // worst case would be unintentionalp layer reassignment.
91 if (w.mLayer != oldLayer || w.mWinAnimator.mAnimLayer != oldLayer) {
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080092 layerChanged = true;
93 anyLayerChanged = true;
94 }
95
96 if (w.mAppToken != null) {
97 mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
Robert Carr67eec032016-03-22 16:57:33 -070098 w.mWinAnimator.mAnimLayer);
Filip Gruszczynski92e432c2015-12-15 19:17:09 -080099 }
100 collectSpecialWindows(w);
101
102 if (layerChanged) {
103 w.scheduleAnimationIfDimming();
104 }
105 }
106
107 adjustSpecialWindows();
108
109 //TODO (multidisplay): Magnification is supported only for the default display.
110 if (mService.mAccessibilityController != null && anyLayerChanged
111 && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
112 mService.mAccessibilityController.onWindowLayersChangedLocked();
113 }
114
115 if (DEBUG_LAYERS) logDebugLayers(windows);
116 }
117
118 void setInputMethodAnimLayerAdjustment(int adj) {
119 if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj);
120 mInputMethodAnimLayerAdjustment = adj;
121 final WindowState imw = mService.mInputMethodWindow;
122 if (imw != null) {
Wale Ogunwaleadde52e2016-07-16 13:11:55 -0700123 imw.adjustAnimLayer(adj);
Filip Gruszczynski92e432c2015-12-15 19:17:09 -0800124 }
Michael Wright6db8e692015-12-17 17:19:46 -0500125 for (int i = mService.mInputMethodDialogs.size() - 1; i >= 0; i--) {
Filip Gruszczynski92e432c2015-12-15 19:17:09 -0800126 final WindowState dialog = mService.mInputMethodDialogs.get(i);
Wale Ogunwaleadde52e2016-07-16 13:11:55 -0700127 // TODO: This and other places setting mAnimLayer can probably use WS.adjustAnimLayer,
128 // but need to make sure we are not setting things twice for child windows that are
129 // already in the list.
Filip Gruszczynski92e432c2015-12-15 19:17:09 -0800130 dialog.mWinAnimator.mAnimLayer = dialog.mLayer + adj;
131 if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
132 + " anim layer: " + dialog.mWinAnimator.mAnimLayer);
133 }
134 }
135
136 int getSpecialWindowAnimLayerAdjustment(WindowState win) {
137 if (win.mIsImWindow) {
138 return mInputMethodAnimLayerAdjustment;
139 } else if (win.mIsWallpaper) {
140 return mService.mWallpaperControllerLocked.getAnimLayerAdjustment();
141 }
142 return 0;
143 }
144
Jorim Jaggi50981592015-12-29 17:54:12 +0100145 /**
146 * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
147 * above all application surfaces.
148 */
149 int getResizeDimLayer() {
Wale Ogunwale20ec11b2016-04-22 12:11:51 -0700150 return (mDockDivider != null) ? mDockDivider.mLayer - 1 : LAYER_OFFSET_DIM;
Jorim Jaggi50981592015-12-29 17:54:12 +0100151 }
152
Filip Gruszczynski92e432c2015-12-15 19:17:09 -0800153 private void logDebugLayers(WindowList windows) {
154 for (int i = 0, n = windows.size(); i < n; i++) {
155 final WindowState w = windows.get(i);
156 final WindowStateAnimator winAnimator = w.mWinAnimator;
157 Slog.v(TAG_WM, "Assign layer " + w + ": " + "mBase=" + w.mBaseLayer
158 + " mLayer=" + w.mLayer + (w.mAppToken == null
159 ? "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
160 + " =mAnimLayer=" + winAnimator.mAnimLayer);
161 }
162 }
163
164 private void clear() {
165 mHighestApplicationLayer = 0;
Wale Ogunwale26b7b432016-02-03 14:12:08 -0800166 mPinnedWindows.clear();
Robert Carrb9768772016-04-19 22:31:09 -0700167 mInputMethodWindows.clear();
Wale Ogunwale26b7b432016-02-03 14:12:08 -0800168 mDockedWindows.clear();
Jiaquan He9bc01a82016-07-08 10:29:38 -0700169 mOnTopLauncherWindows.clear();
Wale Ogunwale26b7b432016-02-03 14:12:08 -0800170 mReplacingWindows.clear();
Filip Gruszczynski92e432c2015-12-15 19:17:09 -0800171 mDockDivider = null;
172 }
173
174 private void collectSpecialWindows(WindowState w) {
Filip Gruszczynskibedb5662016-01-04 15:56:07 -0800175 if (w.mAttrs.type == TYPE_DOCK_DIVIDER) {
Filip Gruszczynski92e432c2015-12-15 19:17:09 -0800176 mDockDivider = w;
Wale Ogunwale26b7b432016-02-03 14:12:08 -0800177 return;
178 }
179 if (w.mWillReplaceWindow) {
180 mReplacingWindows.add(w);
181 }
Robert Carrb9768772016-04-19 22:31:09 -0700182 if (w.mIsImWindow) {
183 mInputMethodWindows.add(w);
184 return;
185 }
Jiaquan He9bc01a82016-07-08 10:29:38 -0700186 final Task task = w.getTask();
187 if (task == null) {
188 return;
189 }
190 if (task.isOnTopLauncher()) {
191 mOnTopLauncherWindows.add(w);
192 }
193 final TaskStack stack = task.mStack;
Wale Ogunwale26b7b432016-02-03 14:12:08 -0800194 if (stack == null) {
195 return;
196 }
197 if (stack.mStackId == PINNED_STACK_ID) {
198 mPinnedWindows.add(w);
199 } else if (stack.mStackId == DOCKED_STACK_ID) {
200 mDockedWindows.add(w);
Filip Gruszczynski92e432c2015-12-15 19:17:09 -0800201 }
202 }
203
204 private void adjustSpecialWindows() {
Robert Carr6412d752016-03-31 17:23:35 -0700205 int layer = mHighestApplicationLayer + WINDOW_LAYER_MULTIPLIER;
Wale Ogunwale26b7b432016-02-03 14:12:08 -0800206 // For pinned and docked stack window, we want to make them above other windows also when
207 // these windows are animating.
208 while (!mDockedWindows.isEmpty()) {
209 layer = assignAndIncreaseLayerIfNeeded(mDockedWindows.remove(), layer);
210 }
Jorim Jaggi50981592015-12-29 17:54:12 +0100211
Filip Gruszczynski92e432c2015-12-15 19:17:09 -0800212 layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
Robert Carr9da141f2016-04-05 14:24:22 -0700213
Jiaquan He9bc01a82016-07-08 10:29:38 -0700214 boolean onTopLauncherVisible = !mOnTopLauncherWindows.isEmpty();
215 while (!mOnTopLauncherWindows.isEmpty()) {
216 layer = assignAndIncreaseLayerIfNeeded(mOnTopLauncherWindows.remove(), layer);
217 }
218
219 // Make sure IME windows are showing above the dock divider and on-top launcher windows.
220 if ((mDockDivider != null && mDockDivider.isVisibleLw()) || onTopLauncherVisible) {
Robert Carrb9768772016-04-19 22:31:09 -0700221 while (!mInputMethodWindows.isEmpty()) {
Adrian Roosae712e52016-04-21 20:59:47 -0700222 final WindowState w = mInputMethodWindows.remove();
223 // Only ever move IME windows up, else we brake IME for windows above the divider.
224 if (layer > w.mLayer) {
225 layer = assignAndIncreaseLayerIfNeeded(w, layer);
226 }
Robert Carrd82b7482016-04-17 19:45:24 -0700227 }
Robert Carr9da141f2016-04-05 14:24:22 -0700228 }
229
Wale Ogunwale26b7b432016-02-03 14:12:08 -0800230 // We know that we will be animating a relaunching window in the near future, which will
231 // receive a z-order increase. We want the replaced window to immediately receive the same
232 // treatment, e.g. to be above the dock divider.
233 while (!mReplacingWindows.isEmpty()) {
234 layer = assignAndIncreaseLayerIfNeeded(mReplacingWindows.remove(), layer);
235 }
236
237 while (!mPinnedWindows.isEmpty()) {
238 layer = assignAndIncreaseLayerIfNeeded(mPinnedWindows.remove(), layer);
239 }
Filip Gruszczynski92e432c2015-12-15 19:17:09 -0800240 }
241
242 private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
Robert Carr90da5e52016-04-15 10:58:37 -0700243 if (win != null) {
Robert Carr67eec032016-03-22 16:57:33 -0700244 assignAnimLayer(win, layer);
Robert Carr6412d752016-03-31 17:23:35 -0700245 // Make sure we leave space inbetween normal windows for dims and such.
246 layer += WINDOW_LAYER_MULTIPLIER;
Filip Gruszczynski92e432c2015-12-15 19:17:09 -0800247 }
248 return layer;
249 }
Robert Carr6412d752016-03-31 17:23:35 -0700250
Robert Carr67eec032016-03-22 16:57:33 -0700251 private void assignAnimLayer(WindowState w, int layer) {
252 w.mLayer = layer;
253 w.mWinAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
254 getSpecialWindowAnimLayerAdjustment(w);
Jorim Jaggic69bd222016-03-15 14:38:37 +0100255 if (w.mAppToken != null && w.mAppToken.mAppAnimator.thumbnailForceAboveLayer > 0
256 && w.mWinAnimator.mAnimLayer > w.mAppToken.mAppAnimator.thumbnailForceAboveLayer) {
257 w.mAppToken.mAppAnimator.thumbnailForceAboveLayer = w.mWinAnimator.mAnimLayer;
258 }
Robert Carr67eec032016-03-22 16:57:33 -0700259 }
Filip Gruszczynski92e432c2015-12-15 19:17:09 -0800260
261 void dump(PrintWriter pw, String s) {
262 if (mInputMethodAnimLayerAdjustment != 0 ||
263 mService.mWallpaperControllerLocked.getAnimLayerAdjustment() != 0) {
264 pw.print(" mInputMethodAnimLayerAdjustment=");
265 pw.print(mInputMethodAnimLayerAdjustment);
266 pw.print(" mWallpaperAnimLayerAdjustment=");
267 pw.println(mService.mWallpaperControllerLocked.getAnimLayerAdjustment());
268 }
269 }
270}