blob: 97d0ae0f8546d4dbf688b88249db9bf280f4df1a [file] [log] [blame]
Filip Gruszczynski0689ae92015-10-01 12:30:31 -07001package com.android.server.wm;
2
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -08003import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DIM_LAYER;
4import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
5import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Chong Zhang112eb8c2015-11-02 11:17:00 -08006import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
Filip Gruszczynski0689ae92015-10-01 12:30:31 -07007
8import android.graphics.Rect;
9import android.util.ArrayMap;
10import android.util.Slog;
11import android.util.TypedValue;
12
Jorim Jaggibc5425c2016-03-01 13:51:16 +010013import com.android.server.wm.DimLayer.DimLayerUser;
14
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070015import java.io.PrintWriter;
16
17/**
18 * Centralizes the control of dim layers used for
Chong Zhang112eb8c2015-11-02 11:17:00 -080019 * {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND}
20 * as well as other use cases (such as dimming above a dead window).
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070021 */
Chong Zhang112eb8c2015-11-02 11:17:00 -080022class DimLayerController {
Jorim Jaggibc5425c2016-03-01 13:51:16 +010023 private static final String TAG_LOCAL = "DimLayerController";
24 private static final String TAG = TAG_WITH_CLASS_NAME ? TAG_LOCAL : TAG_WM;
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070025
26 /** Amount of time in milliseconds to animate the dim surface from one value to another,
27 * when no window animation is driving it. */
28 private static final int DEFAULT_DIM_DURATION = 200;
29
Chong Zhang112eb8c2015-11-02 11:17:00 -080030 /**
31 * The default amount of dim applied over a dead window
32 */
33 private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
34
35 // Shared dim layer for fullscreen users. {@link DimLayerState#dimLayer} will point to this
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070036 // instead of creating a new object per fullscreen task on a display.
37 private DimLayer mSharedFullScreenDimLayer;
38
Chong Zhang112eb8c2015-11-02 11:17:00 -080039 private ArrayMap<DimLayer.DimLayerUser, DimLayerState> mState = new ArrayMap<>();
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070040
41 private DisplayContent mDisplayContent;
42
43 private Rect mTmpBounds = new Rect();
44
Chong Zhang112eb8c2015-11-02 11:17:00 -080045 DimLayerController(DisplayContent displayContent) {
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070046 mDisplayContent = displayContent;
47 }
48
49 /** Updates the dim layer bounds, recreating it if needed. */
50 void updateDimLayer(DimLayer.DimLayerUser dimLayerUser) {
Chong Zhang4c9ba52a2015-11-10 18:36:33 -080051 DimLayerState state = getOrCreateDimLayerState(dimLayerUser);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070052 final boolean previousFullscreen = state.dimLayer != null
53 && state.dimLayer == mSharedFullScreenDimLayer;
54 DimLayer newDimLayer;
55 final int displayId = mDisplayContent.getDisplayId();
56 if (dimLayerUser.isFullscreen()) {
57 if (previousFullscreen) {
58 // Nothing to do here...
59 return;
60 }
61 // Use shared fullscreen dim layer
62 newDimLayer = mSharedFullScreenDimLayer;
63 if (newDimLayer == null) {
64 if (state.dimLayer != null) {
65 // Re-purpose the previous dim layer.
66 newDimLayer = state.dimLayer;
67 } else {
68 // Create new full screen dim layer.
Jorim Jaggibc5425c2016-03-01 13:51:16 +010069 newDimLayer = new DimLayer(mDisplayContent.mService, dimLayerUser, displayId,
70 getDimLayerTag(dimLayerUser));
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070071 }
Chong Zhang4c9ba52a2015-11-10 18:36:33 -080072 dimLayerUser.getDimBounds(mTmpBounds);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070073 newDimLayer.setBounds(mTmpBounds);
74 mSharedFullScreenDimLayer = newDimLayer;
75 } else if (state.dimLayer != null) {
Chong Zhang112eb8c2015-11-02 11:17:00 -080076 state.dimLayer.destroySurface();
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070077 }
78 } else {
79 newDimLayer = (state.dimLayer == null || previousFullscreen)
Jorim Jaggibc5425c2016-03-01 13:51:16 +010080 ? new DimLayer(mDisplayContent.mService, dimLayerUser, displayId,
81 getDimLayerTag(dimLayerUser))
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070082 : state.dimLayer;
Chong Zhang4c9ba52a2015-11-10 18:36:33 -080083 dimLayerUser.getDimBounds(mTmpBounds);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070084 newDimLayer.setBounds(mTmpBounds);
85 }
86 state.dimLayer = newDimLayer;
87 }
88
Jorim Jaggibc5425c2016-03-01 13:51:16 +010089 private static String getDimLayerTag(DimLayerUser dimLayerUser) {
90 return TAG_LOCAL + "/" + dimLayerUser.toShortString();
91 }
92
Chong Zhang4c9ba52a2015-11-10 18:36:33 -080093 private DimLayerState getOrCreateDimLayerState(DimLayer.DimLayerUser dimLayerUser) {
Chong Zhang112eb8c2015-11-02 11:17:00 -080094 if (DEBUG_DIM_LAYER) Slog.v(TAG, "getOrCreateDimLayerState, dimLayerUser="
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070095 + dimLayerUser.toShortString());
Chong Zhang112eb8c2015-11-02 11:17:00 -080096 DimLayerState state = mState.get(dimLayerUser);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070097 if (state == null) {
Chong Zhang112eb8c2015-11-02 11:17:00 -080098 state = new DimLayerState();
Filip Gruszczynski0689ae92015-10-01 12:30:31 -070099 mState.put(dimLayerUser, state);
100 }
101 return state;
102 }
103
104 private void setContinueDimming(DimLayer.DimLayerUser dimLayerUser) {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800105 DimLayerState state = mState.get(dimLayerUser);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700106 if (state == null) {
107 if (DEBUG_DIM_LAYER) Slog.w(TAG, "setContinueDimming, no state for: "
108 + dimLayerUser.toShortString());
109 return;
110 }
111 state.continueDimming = true;
112 }
113
114 boolean isDimming() {
115 for (int i = mState.size() - 1; i >= 0; i--) {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800116 DimLayerState state = mState.valueAt(i);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700117 if (state.dimLayer != null && state.dimLayer.isDimming()) {
118 return true;
119 }
120 }
121 return false;
122 }
123
124 void resetDimming() {
125 for (int i = mState.size() - 1; i >= 0; i--) {
126 mState.valueAt(i).continueDimming = false;
127 }
128 }
129
130 private boolean getContinueDimming(DimLayer.DimLayerUser dimLayerUser) {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800131 DimLayerState state = mState.get(dimLayerUser);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700132 return state != null && state.continueDimming;
133 }
134
135 void startDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser,
Chong Zhang112eb8c2015-11-02 11:17:00 -0800136 WindowStateAnimator newWinAnimator, boolean aboveApp) {
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700137 // Only set dim params on the highest dimmed layer.
138 // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800139 DimLayerState state = getOrCreateDimLayerState(dimLayerUser);
140 state.dimAbove = aboveApp;
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700141 if (DEBUG_DIM_LAYER) Slog.v(TAG, "startDimmingIfNeeded,"
142 + " dimLayerUser=" + dimLayerUser.toShortString()
143 + " newWinAnimator=" + newWinAnimator
144 + " state.animator=" + state.animator);
Robert Carre6a83512015-11-03 16:09:21 -0800145 if (newWinAnimator.getShown() && (state.animator == null
146 || !state.animator.getShown()
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700147 || state.animator.mAnimLayer <= newWinAnimator.mAnimLayer)) {
148 state.animator = newWinAnimator;
149 if (state.animator.mWin.mAppToken == null && !dimLayerUser.isFullscreen()) {
150 // Dim should cover the entire screen for system windows.
151 mDisplayContent.getLogicalDisplayRect(mTmpBounds);
152 state.dimLayer.setBounds(mTmpBounds);
153 }
154 }
155 }
156
157 void stopDimmingIfNeeded() {
158 if (DEBUG_DIM_LAYER) Slog.v(TAG, "stopDimmingIfNeeded, mState.size()=" + mState.size());
159 for (int i = mState.size() - 1; i >= 0; i--) {
160 DimLayer.DimLayerUser dimLayerUser = mState.keyAt(i);
161 stopDimmingIfNeeded(dimLayerUser);
162 }
163 }
164
165 private void stopDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser) {
166 // No need to check if state is null, we know the key has a value.
Chong Zhang112eb8c2015-11-02 11:17:00 -0800167 DimLayerState state = mState.get(dimLayerUser);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700168 if (DEBUG_DIM_LAYER) Slog.v(TAG, "stopDimmingIfNeeded,"
169 + " dimLayerUser=" + dimLayerUser.toShortString()
170 + " state.continueDimming=" + state.continueDimming
171 + " state.dimLayer.isDimming=" + state.dimLayer.isDimming());
172 if (!state.continueDimming && state.dimLayer.isDimming()) {
173 state.animator = null;
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800174 dimLayerUser.getDimBounds(mTmpBounds);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700175 state.dimLayer.setBounds(mTmpBounds);
176 }
177 }
178
179 boolean animateDimLayers() {
180 int fullScreen = -1;
Filip Gruszczynskib1fa0442015-10-05 12:40:28 -0700181 int fullScreenAndDimming = -1;
182 boolean result = false;
183
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700184 for (int i = mState.size() - 1; i >= 0; i--) {
Filip Gruszczynskib1fa0442015-10-05 12:40:28 -0700185 DimLayer.DimLayerUser user = mState.keyAt(i);
186 if (user.isFullscreen()) {
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700187 fullScreen = i;
188 if (mState.valueAt(i).continueDimming) {
Filip Gruszczynskib1fa0442015-10-05 12:40:28 -0700189 fullScreenAndDimming = i;
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700190 }
Filip Gruszczynskib1fa0442015-10-05 12:40:28 -0700191 } else {
192 // We always want to animate the non fullscreen windows, they don't share their
193 // dim layers.
194 result |= animateDimLayers(user);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700195 }
196 }
Filip Gruszczynskib1fa0442015-10-05 12:40:28 -0700197 // For the shared, full screen dim layer, we prefer the animation that is causing it to
198 // appear.
199 if (fullScreenAndDimming != -1) {
200 result |= animateDimLayers(mState.keyAt(fullScreenAndDimming));
201 } else if (fullScreen != -1) {
202 // If there is no animation for the full screen dim layer to appear, we can use any of
203 // the animators that will cause it to disappear.
204 result |= animateDimLayers(mState.keyAt(fullScreen));
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700205 }
Filip Gruszczynskib1fa0442015-10-05 12:40:28 -0700206 return result;
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700207 }
208
209 private boolean animateDimLayers(DimLayer.DimLayerUser dimLayerUser) {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800210 DimLayerState state = mState.get(dimLayerUser);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700211 if (DEBUG_DIM_LAYER) Slog.v(TAG, "animateDimLayers,"
212 + " dimLayerUser=" + dimLayerUser.toShortString()
213 + " state.animator=" + state.animator
214 + " state.continueDimming=" + state.continueDimming);
215 final int dimLayer;
216 final float dimAmount;
217 if (state.animator == null) {
218 dimLayer = state.dimLayer.getLayer();
219 dimAmount = 0;
220 } else {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800221 if (state.dimAbove) {
222 dimLayer = state.animator.mAnimLayer + LAYER_OFFSET_DIM;
223 dimAmount = DEFAULT_DIM_AMOUNT_DEAD_WINDOW;
224 } else {
225 dimLayer = state.animator.mAnimLayer - LAYER_OFFSET_DIM;
226 dimAmount = state.animator.mWin.mAttrs.dimAmount;
227 }
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700228 }
229 final float targetAlpha = state.dimLayer.getTargetAlpha();
230 if (targetAlpha != dimAmount) {
231 if (state.animator == null) {
232 state.dimLayer.hide(DEFAULT_DIM_DURATION);
233 } else {
234 long duration = (state.animator.mAnimating && state.animator.mAnimation != null)
235 ? state.animator.mAnimation.computeDurationHint()
236 : DEFAULT_DIM_DURATION;
237 if (targetAlpha > dimAmount) {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800238 duration = getDimLayerFadeDuration(duration);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700239 }
240 state.dimLayer.show(dimLayer, dimAmount, duration);
241 }
242 } else if (state.dimLayer.getLayer() != dimLayer) {
243 state.dimLayer.setLayer(dimLayer);
244 }
245 if (state.dimLayer.isAnimating()) {
246 if (!mDisplayContent.mService.okToDisplay()) {
247 // Jump to the end of the animation.
248 state.dimLayer.show();
249 } else {
250 return state.dimLayer.stepAnimation();
251 }
252 }
253 return false;
254 }
255
256 boolean isDimming(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator winAnimator) {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800257 DimLayerState state = mState.get(dimLayerUser);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700258 return state != null && state.animator == winAnimator && state.dimLayer.isDimming();
259 }
260
Chong Zhang112eb8c2015-11-02 11:17:00 -0800261 private long getDimLayerFadeDuration(long duration) {
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700262 TypedValue tv = new TypedValue();
263 mDisplayContent.mService.mContext.getResources().getValue(
264 com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
265 if (tv.type == TypedValue.TYPE_FRACTION) {
266 duration = (long) tv.getFraction(duration, duration);
267 } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) {
268 duration = tv.data;
269 }
270 return duration;
271 }
272
273 void close() {
274 for (int i = mState.size() - 1; i >= 0; i--) {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800275 DimLayerState state = mState.valueAt(i);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700276 state.dimLayer.destroySurface();
277 }
278 mState.clear();
279 mSharedFullScreenDimLayer = null;
280 }
281
282 void removeDimLayerUser(DimLayer.DimLayerUser dimLayerUser) {
Chong Zhangcb1887e2015-11-04 20:59:26 -0800283 DimLayerState state = mState.get(dimLayerUser);
284 if (state != null) {
285 // Destroy the surface, unless it's the shared fullscreen dim.
286 if (state.dimLayer != mSharedFullScreenDimLayer) {
287 state.dimLayer.destroySurface();
288 }
289 mState.remove(dimLayerUser);
290 }
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700291 }
292
293 void applyDimBehind(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator) {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800294 applyDim(dimLayerUser, animator, false /* aboveApp */);
295 }
296
297 void applyDimAbove(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator) {
298 applyDim(dimLayerUser, animator, true /* aboveApp */);
299 }
300
301 private void applyDim(
302 DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator, boolean aboveApp) {
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700303 if (dimLayerUser == null) {
304 Slog.e(TAG, "Trying to apply dim layer for: " + this
305 + ", but no dim layer user found.");
306 return;
307 }
308 if (!getContinueDimming(dimLayerUser)) {
309 setContinueDimming(dimLayerUser);
310 if (!isDimming(dimLayerUser, animator)) {
311 if (DEBUG_DIM_LAYER) Slog.v(TAG, "Win " + this + " start dimming.");
Chong Zhang112eb8c2015-11-02 11:17:00 -0800312 startDimmingIfNeeded(dimLayerUser, animator, aboveApp);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700313 }
314 }
315 }
316
Chong Zhang112eb8c2015-11-02 11:17:00 -0800317 private static class DimLayerState {
318 // The particular window requesting a dim layer. If null, hide dimLayer.
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700319 WindowStateAnimator animator;
320 // Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the
321 // end then stop any dimming.
322 boolean continueDimming;
323 DimLayer dimLayer;
Chong Zhang112eb8c2015-11-02 11:17:00 -0800324 boolean dimAbove;
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700325 }
326
327 void dump(String prefix, PrintWriter pw) {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800328 pw.println(prefix + "DimLayerController");
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700329 for (int i = 0, n = mState.size(); i < n; i++) {
330 pw.println(prefix + " " + mState.keyAt(i).toShortString());
331 pw.print(prefix + " ");
Chong Zhang112eb8c2015-11-02 11:17:00 -0800332 DimLayerState state = mState.valueAt(i);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700333 pw.print("dimLayer=" + (state.dimLayer == mSharedFullScreenDimLayer ? "shared" :
334 state.dimLayer));
335 pw.print(", animator=" + state.animator);
336 pw.println(", continueDimming=" + state.continueDimming + "}");
337
338 }
339 }
340}