blob: 2c83e6752e2c5e5d68619278cbe34b4940bc0546 [file] [log] [blame]
Wale Ogunwalee8069dc2015-08-18 09:52:01 -07001/*
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 static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
20import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
21import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
22import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
23import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
24import static com.android.server.wm.WindowManagerService.DEBUG_ADD_REMOVE;
25import static com.android.server.wm.WindowManagerService.DEBUG_APP_TRANSITIONS;
26import static com.android.server.wm.WindowManagerService.DEBUG_LAYERS;
27import static com.android.server.wm.WindowManagerService.DEBUG_WINDOW_MOVEMENT;
28import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
29import static com.android.server.wm.WindowManagerService.DEBUG_WALLPAPER;
30import static com.android.server.wm.WindowManagerService.DEBUG_WALLPAPER_LIGHT;
31import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT;
32import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
33import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
34
35import android.os.Bundle;
36import android.os.Debug;
37import android.os.IBinder;
38import android.os.RemoteException;
39import android.os.SystemClock;
40import android.util.Slog;
41import android.view.DisplayInfo;
42import android.view.WindowManager;
43import android.view.WindowManagerPolicy;
44
45import java.io.PrintWriter;
46import java.util.ArrayList;
47
48/**
49 * Controls wallpaper windows visibility, ordering, and so on.
50 * NOTE: All methods in this class must be called with the window manager service lock held.
51 */
52class WallpaperController {
53 private static final String TAG = com.android.server.wm.WindowManagerService.TAG;
54 final private WindowManagerService mService;
55
56 private final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<>();
57
58 // If non-null, this is the currently visible window that is associated
59 // with the wallpaper.
60 private WindowState mWallpaperTarget = null;
61 // If non-null, we are in the middle of animating from one wallpaper target
62 // to another, and this is the lower one in Z-order.
63 private WindowState mLowerWallpaperTarget = null;
64 // If non-null, we are in the middle of animating from one wallpaper target
65 // to another, and this is the higher one in Z-order.
66 private WindowState mUpperWallpaperTarget = null;
67
68 private int mWallpaperAnimLayerAdjustment;
69
70 private float mLastWallpaperX = -1;
71 private float mLastWallpaperY = -1;
72 private float mLastWallpaperXStep = -1;
73 private float mLastWallpaperYStep = -1;
74 private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
75 private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
76
77 // This is set when we are waiting for a wallpaper to tell us it is done
78 // changing its scroll position.
79 WindowState mWaitingOnWallpaper;
80
81 // The last time we had a timeout when waiting for a wallpaper.
82 private long mLastWallpaperTimeoutTime;
83 // We give a wallpaper up to 150ms to finish scrolling.
84 private static final long WALLPAPER_TIMEOUT = 150;
85 // Time we wait after a timeout before trying to wait again.
86 private static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
87
88 // Set to the wallpaper window we would like to hide once the transition animations are done.
89 // This is useful in cases where we don't want the wallpaper to be hidden when the close app
90 // is a wallpaper target and is done animating out, but the opening app isn't a wallpaper
91 // target and isn't done animating in.
92 private WindowState mDeferredHideWallpaper = null;
93
94 // We give a wallpaper up to 500ms to finish drawing before playing app transitions.
95 private static final long WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION = 500;
96 private static final int WALLPAPER_DRAW_NORMAL = 0;
97 private static final int WALLPAPER_DRAW_PENDING = 1;
98 private static final int WALLPAPER_DRAW_TIMEOUT = 2;
99 private int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
100
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700101 private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult();
102
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700103 public WallpaperController(WindowManagerService service) {
104 mService = service;
105 }
106
107 WindowState getWallpaperTarget() {
108 return mWallpaperTarget;
109 }
110
111 WindowState getLowerWallpaperTarget() {
112 return mLowerWallpaperTarget;
113 }
114
115 WindowState getUpperWallpaperTarget() {
116 return mUpperWallpaperTarget;
117 }
118
119 boolean isWallpaperTarget(WindowState win) {
120 return win == mWallpaperTarget;
121 }
122
123 boolean isBelowWallpaperTarget(WindowState win) {
124 return mWallpaperTarget != null && mWallpaperTarget.mLayer >= win.mBaseLayer;
125 }
126
127 boolean isWallpaperVisible() {
128 return isWallpaperVisible(mWallpaperTarget);
129 }
130
131 private boolean isWallpaperVisible(WindowState wallpaperTarget) {
132 if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
133 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
134 + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
135 ? wallpaperTarget.mAppToken.mAppAnimator.animation : null)
136 + " upper=" + mUpperWallpaperTarget
137 + " lower=" + mLowerWallpaperTarget);
138 return (wallpaperTarget != null
139 && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null
140 && wallpaperTarget.mAppToken.mAppAnimator.animation != null)))
141 || mUpperWallpaperTarget != null
142 || mLowerWallpaperTarget != null;
143 }
144
145 boolean isWallpaperTargetAnimating() {
146 return mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
147 && !mWallpaperTarget.mWinAnimator.isDummyAnimation();
148 }
149
150 void updateWallpaperVisibility() {
151 final boolean visible = isWallpaperVisible(mWallpaperTarget);
152 final DisplayContent displayContent = mWallpaperTarget.getDisplayContent();
153 if (displayContent == null) {
154 return;
155 }
156 final DisplayInfo displayInfo = displayContent.getDisplayInfo();
157 final int dw = displayInfo.logicalWidth;
158 final int dh = displayInfo.logicalHeight;
159
160 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
161 WindowToken token = mWallpaperTokens.get(curTokenNdx);
162 if (token.hidden == visible) {
163 token.hidden = !visible;
164 // Need to do a layout to ensure the wallpaper now has the
165 // correct size.
166 displayContent.layoutNeeded = true;
167 }
168
169 final WindowList windows = token.windows;
170 for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
171 WindowState wallpaper = windows.get(wallpaperNdx);
172 if (visible) {
173 updateWallpaperOffset(wallpaper, dw, dh, false);
174 }
175
176 dispatchWallpaperVisibility(wallpaper, visible);
177 }
178 }
179 }
180
181 void hideDeferredWallpapersIfNeeded() {
182 if (mDeferredHideWallpaper != null) {
183 hideWallpapers(mDeferredHideWallpaper);
184 mDeferredHideWallpaper = null;
185 }
186 }
187
188 void hideWallpapers(final WindowState winGoingAway) {
189 if (mWallpaperTarget != null
190 && (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) {
191 return;
192 }
193 if (mService.mAppTransition.isRunning()) {
194 // Defer hiding the wallpaper when app transition is running until the animations
195 // are done.
196 mDeferredHideWallpaper = winGoingAway;
197 return;
198 }
199
200 final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway);
201 for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
202 final WindowToken token = mWallpaperTokens.get(i);
203 for (int j = token.windows.size() - 1; j >= 0; j--) {
204 final WindowState wallpaper = token.windows.get(j);
205 final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
206 if (!winAnimator.mLastHidden || wasDeferred) {
207 winAnimator.hide();
208 dispatchWallpaperVisibility(wallpaper, false);
209 final DisplayContent displayContent = wallpaper.getDisplayContent();
210 if (displayContent != null) {
211 displayContent.pendingLayoutChanges |=
212 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
213 }
214 }
215 }
216 if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token
217 + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower="
218 + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, " "));
219 token.hidden = true;
220 }
221 }
222
223 /**
224 * Check wallpaper for visibility change and notify window if so.
225 * @param wallpaper The wallpaper to test and notify.
226 * @param visible Current visibility.
227 */
228 void dispatchWallpaperVisibility(final WindowState wallpaper, final boolean visible) {
229 // Only send notification if the visibility actually changed and we are not trying to hide
230 // the wallpaper when we are deferring hiding of the wallpaper.
231 if (wallpaper.mWallpaperVisible != visible
232 && (mDeferredHideWallpaper == null || visible)) {
233 wallpaper.mWallpaperVisible = visible;
234 try {
235 if (DEBUG_VISIBILITY || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
236 "Updating vis of wallpaper " + wallpaper
237 + ": " + visible + " from:\n" + Debug.getCallers(4, " "));
238 wallpaper.mClient.dispatchAppVisibility(visible);
239 } catch (RemoteException e) {
240 }
241 }
242 }
243
244 boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) {
245 boolean rawChanged = false;
246 float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f;
247 float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
248 int availw = wallpaperWin.mFrame.right - wallpaperWin.mFrame.left - dw;
249 int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
250 if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
251 offset += mLastWallpaperDisplayOffsetX;
252 }
253 boolean changed = wallpaperWin.mXOffset != offset;
254 if (changed) {
255 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset);
256 wallpaperWin.mXOffset = offset;
257 }
258 if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
259 wallpaperWin.mWallpaperX = wpx;
260 wallpaperWin.mWallpaperXStep = wpxs;
261 rawChanged = true;
262 }
263
264 float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
265 float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
266 int availh = wallpaperWin.mFrame.bottom - wallpaperWin.mFrame.top - dh;
267 offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0;
268 if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
269 offset += mLastWallpaperDisplayOffsetY;
270 }
271 if (wallpaperWin.mYOffset != offset) {
272 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset);
273 changed = true;
274 wallpaperWin.mYOffset = offset;
275 }
276 if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
277 wallpaperWin.mWallpaperY = wpy;
278 wallpaperWin.mWallpaperYStep = wpys;
279 rawChanged = true;
280 }
281
282 if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
283 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
284 try {
285 if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset "
286 + wallpaperWin + " x=" + wallpaperWin.mWallpaperX
287 + " y=" + wallpaperWin.mWallpaperY);
288 if (sync) {
289 mWaitingOnWallpaper = wallpaperWin;
290 }
291 wallpaperWin.mClient.dispatchWallpaperOffsets(
292 wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY,
293 wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync);
294 if (sync) {
295 if (mWaitingOnWallpaper != null) {
296 long start = SystemClock.uptimeMillis();
297 if ((mLastWallpaperTimeoutTime + WALLPAPER_TIMEOUT_RECOVERY)
298 < start) {
299 try {
300 if (DEBUG_WALLPAPER) Slog.v(TAG,
301 "Waiting for offset complete...");
302 mService.mWindowMap.wait(WALLPAPER_TIMEOUT);
303 } catch (InterruptedException e) {
304 }
305 if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!");
306 if ((start + WALLPAPER_TIMEOUT) < SystemClock.uptimeMillis()) {
307 Slog.i(TAG, "Timeout waiting for wallpaper to offset: "
308 + wallpaperWin);
309 mLastWallpaperTimeoutTime = start;
310 }
311 }
312 mWaitingOnWallpaper = null;
313 }
314 }
315 } catch (RemoteException e) {
316 }
317 }
318
319 return changed;
320 }
321
322 void setWindowWallpaperPosition(
323 WindowState window, float x, float y, float xStep, float yStep) {
324 if (window.mWallpaperX != x || window.mWallpaperY != y) {
325 window.mWallpaperX = x;
326 window.mWallpaperY = y;
327 window.mWallpaperXStep = xStep;
328 window.mWallpaperYStep = yStep;
329 updateWallpaperOffsetLocked(window, true);
330 }
331 }
332
333 void setWindowWallpaperDisplayOffset(WindowState window, int x, int y) {
334 if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y) {
335 window.mWallpaperDisplayOffsetX = x;
336 window.mWallpaperDisplayOffsetY = y;
337 updateWallpaperOffsetLocked(window, true);
338 }
339 }
340
341 Bundle sendWindowWallpaperCommand(
342 WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) {
343 if (window == mWallpaperTarget
344 || window == mLowerWallpaperTarget
345 || window == mUpperWallpaperTarget) {
346 boolean doWait = sync;
347 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
348 final WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
349 for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
350 WindowState wallpaper = windows.get(wallpaperNdx);
351 try {
352 wallpaper.mClient.dispatchWallpaperCommand(action,
353 x, y, z, extras, sync);
354 // We only want to be synchronous with one wallpaper.
355 sync = false;
356 } catch (RemoteException e) {
357 }
358 }
359 }
360
361 if (doWait) {
362 // TODO: Need to wait for result.
363 }
364 }
365
366 return null;
367 }
368
369 void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
370 final DisplayContent displayContent = changingTarget.getDisplayContent();
371 if (displayContent == null) {
372 return;
373 }
374 final DisplayInfo displayInfo = displayContent.getDisplayInfo();
375 final int dw = displayInfo.logicalWidth;
376 final int dh = displayInfo.logicalHeight;
377
378 WindowState target = mWallpaperTarget;
379 if (target != null) {
380 if (target.mWallpaperX >= 0) {
381 mLastWallpaperX = target.mWallpaperX;
382 } else if (changingTarget.mWallpaperX >= 0) {
383 mLastWallpaperX = changingTarget.mWallpaperX;
384 }
385 if (target.mWallpaperY >= 0) {
386 mLastWallpaperY = target.mWallpaperY;
387 } else if (changingTarget.mWallpaperY >= 0) {
388 mLastWallpaperY = changingTarget.mWallpaperY;
389 }
390 if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
391 mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX;
392 } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
393 mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX;
394 }
395 if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
396 mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY;
397 } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
398 mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY;
399 }
400 if (target.mWallpaperXStep >= 0) {
401 mLastWallpaperXStep = target.mWallpaperXStep;
402 } else if (changingTarget.mWallpaperXStep >= 0) {
403 mLastWallpaperXStep = changingTarget.mWallpaperXStep;
404 }
405 if (target.mWallpaperYStep >= 0) {
406 mLastWallpaperYStep = target.mWallpaperYStep;
407 } else if (changingTarget.mWallpaperYStep >= 0) {
408 mLastWallpaperYStep = changingTarget.mWallpaperYStep;
409 }
410 }
411
412 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
413 WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
414 for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
415 WindowState wallpaper = windows.get(wallpaperNdx);
416 if (updateWallpaperOffset(wallpaper, dw, dh, sync)) {
417 WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
418 winAnimator.computeShownFrameLocked();
419 // No need to lay out the windows - we can just set the wallpaper position
420 // directly.
421 winAnimator.setWallpaperOffset(wallpaper.mShownFrame);
422 // We only want to be synchronous with one wallpaper.
423 sync = false;
424 }
425 }
426 }
427 }
428
429 void clearLastWallpaperTimeoutTime() {
430 mLastWallpaperTimeoutTime = 0;
431 }
432
433 void wallpaperCommandComplete(IBinder window) {
434 if (mWaitingOnWallpaper != null &&
435 mWaitingOnWallpaper.mClient.asBinder() == window) {
436 mWaitingOnWallpaper = null;
437 mService.mWindowMap.notifyAll();
438 }
439 }
440
441 void wallpaperOffsetsComplete(IBinder window) {
442 if (mWaitingOnWallpaper != null &&
443 mWaitingOnWallpaper.mClient.asBinder() == window) {
444 mWaitingOnWallpaper = null;
445 mService.mWindowMap.notifyAll();
446 }
447 }
448
449 int getAnimLayerAdjustment() {
450 return mWallpaperAnimLayerAdjustment;
451 }
452
453 void setAnimLayerAdjustment(WindowState win, int adj) {
454 if (win != mWallpaperTarget || mLowerWallpaperTarget != null) {
455 return;
456 }
457
458 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Setting wallpaper layer adj to " + adj);
459 mWallpaperAnimLayerAdjustment = adj;
460 for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
461 WindowList windows = mWallpaperTokens.get(i).windows;
462 for (int j = windows.size() - 1; j >= 0; j--) {
463 WindowState wallpaper = windows.get(j);
464 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj;
465 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win "
466 + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
467 }
468 }
469 }
470
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700471 private void findWallpaperTarget(WindowList windows, FindWallpaperTargetResult result) {
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700472
473 final WindowAnimator winAnimator = mService.mAnimator;
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700474 result.reset();
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700475 WindowState w = null;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700476 int windowDetachedI = -1;
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700477 for (int i = windows.size() - 1; i >= 0; i--) {
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700478 w = windows.get(i);
479 if ((w.mAttrs.type == TYPE_WALLPAPER)) {
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700480 if (result.topWallpaper == null) {
481 result.setTopWallpaper(w, i);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700482 }
483 continue;
484 }
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700485 result.topWallpaper = null;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700486 if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
487 // If this window's app token is hidden and not animating,
488 // it is of no interest to us.
489 if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) {
490 if (DEBUG_WALLPAPER) Slog.v(TAG,
491 "Skipping hidden and not animating token: " + w);
492 continue;
493 }
494 }
495 if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen="
496 + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState);
497
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700498 // If the app is executing an animation because the keyguard is going away,
499 // keep the wallpaper during the animation so it doesn't flicker out.
500 final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
501 || (w.mAppToken != null && w.mWinAnimator.mKeyguardGoingAwayAnimation);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700502 if (hasWallpaper && w.isOnScreen()
503 && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700504 if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w);
505 result.setWallpaperTarget(w, i);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700506 if (w == mWallpaperTarget && w.mWinAnimator.isAnimating()) {
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700507 // The current wallpaper target is animating, so we'll look behind it for
508 // another possible target and figure out what is going on later.
509 if (DEBUG_WALLPAPER) Slog.v(TAG,
510 "Win " + w + ": token animating, looking behind.");
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700511 continue;
512 }
513 break;
514 } else if (w == winAnimator.mWindowDetachedWallpaper) {
515 windowDetachedI = i;
516 }
517 }
518
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700519 if (result.wallpaperTarget == null && windowDetachedI >= 0) {
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700520 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700521 "Found animating detached wallpaper activity: #" + windowDetachedI + "=" + w);
522 result.setWallpaperTarget(w, windowDetachedI);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700523 }
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700524 }
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700525
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700526 private boolean updateWallpaperWindowsTarget(
527 WindowList windows, FindWallpaperTargetResult result) {
528
529 boolean targetChanged = false;
530 WindowState wallpaperTarget = result.wallpaperTarget;
531 int wallpaperTargetIndex = result.wallpaperTargetIndex;
532
533 if (mWallpaperTarget != wallpaperTarget
534 && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != wallpaperTarget)) {
535 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
536 "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700537
538 mLowerWallpaperTarget = null;
539 mUpperWallpaperTarget = null;
540
541 WindowState oldW = mWallpaperTarget;
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700542 mWallpaperTarget = wallpaperTarget;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700543 targetChanged = true;
544
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700545 // Now what is happening... if the current and new targets are animating,
546 // then we are in our super special mode!
547 if (wallpaperTarget != null && oldW != null) {
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700548 boolean oldAnim = oldW.isAnimatingLw();
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700549 boolean foundAnim = wallpaperTarget.isAnimatingLw();
550 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
551 "New animation: " + foundAnim + " old animation: " + oldAnim);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700552 if (foundAnim && oldAnim) {
553 int oldI = windows.indexOf(oldW);
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700554 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
555 "New i: " + wallpaperTargetIndex + " old i: " + oldI);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700556 if (oldI >= 0) {
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700557 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
558 "Animating wallpapers: old#" + oldI + "=" + oldW + "; new#"
559 + wallpaperTargetIndex + "=" + wallpaperTarget);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700560
561 // Set the new target correctly.
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700562 if (wallpaperTarget.mAppToken != null
563 && wallpaperTarget.mAppToken.hiddenRequested) {
564 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
565 "Old wallpaper still the target.");
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700566 mWallpaperTarget = oldW;
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700567 wallpaperTarget = oldW;
568 wallpaperTargetIndex = oldI;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700569 }
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700570 // Now set the upper and lower wallpaper targets correctly,
571 // and make sure that we are positioning the wallpaper below the lower.
572 else if (wallpaperTargetIndex > oldI) {
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700573 // The new target is on top of the old one.
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700574 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
575 "Found target above old target.");
576 mUpperWallpaperTarget = wallpaperTarget;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700577 mLowerWallpaperTarget = oldW;
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700578 wallpaperTarget = oldW;
579 wallpaperTargetIndex = oldI;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700580 } else {
581 // The new target is below the old one.
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700582 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
583 "Found target below old target.");
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700584 mUpperWallpaperTarget = oldW;
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700585 mLowerWallpaperTarget = wallpaperTarget;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700586 }
587 }
588 }
589 }
590
591 } else if (mLowerWallpaperTarget != null) {
592 // Is it time to stop animating?
593 if (!mLowerWallpaperTarget.isAnimatingLw() || !mUpperWallpaperTarget.isAnimatingLw()) {
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700594 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!");
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700595 mLowerWallpaperTarget = null;
596 mUpperWallpaperTarget = null;
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700597 mWallpaperTarget = wallpaperTarget;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700598 targetChanged = true;
599 }
600 }
601
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700602 result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
603 return targetChanged;
604 }
605
606 boolean updateWallpaperWindowsTargetByLayer(
607 WindowList windows, FindWallpaperTargetResult result) {
608
609 WindowState wallpaperTarget = result.wallpaperTarget;
610 int wallpaperTargetIndex = result.wallpaperTargetIndex;
611 boolean visible = wallpaperTarget != null;
612
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700613 if (visible) {
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700614 // The window is visible to the compositor...but is it visible to the user?
615 // That is what the wallpaper cares about.
616 visible = isWallpaperVisible(wallpaperTarget);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700617 if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
618
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700619 // If the wallpaper target is animating, we may need to copy its layer adjustment.
620 // Only do this if we are not transferring between two wallpaper targets.
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700621 mWallpaperAnimLayerAdjustment =
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700622 (mLowerWallpaperTarget == null && wallpaperTarget.mAppToken != null)
623 ? wallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700624
625 final int maxLayer = (mService.mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER)
626 + TYPE_LAYER_OFFSET;
627
628 // Now w is the window we are supposed to be behind... but we
629 // need to be sure to also be behind any of its attached windows,
630 // AND any starting window associated with it, AND below the
631 // maximum layer the policy allows for wallpapers.
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700632 while (wallpaperTargetIndex > 0) {
633 WindowState wb = windows.get(wallpaperTargetIndex - 1);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700634 if (wb.mBaseLayer < maxLayer &&
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700635 wb.mAttachedWindow != wallpaperTarget &&
636 (wallpaperTarget.mAttachedWindow == null ||
637 wb.mAttachedWindow != wallpaperTarget.mAttachedWindow) &&
638 (wb.mAttrs.type != TYPE_APPLICATION_STARTING
639 || wallpaperTarget.mToken == null
640 || wb.mToken != wallpaperTarget.mToken)) {
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700641 // This window is not related to the previous one in any
642 // interesting way, so stop here.
643 break;
644 }
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700645 wallpaperTarget = wb;
646 wallpaperTargetIndex--;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700647 }
648 } else {
649 if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target");
650 }
651
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700652 result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
653 return visible;
654 }
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700655
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700656 boolean updateWallpaperWindowsPlacement(WindowList windows,
657 WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) {
658
659 // TODO(multidisplay): Wallpapers on main screen only.
660 final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo();
661 final int dw = displayInfo.logicalWidth;
662 final int dh = displayInfo.logicalHeight;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700663
664 // Start stepping backwards from here, ensuring that our wallpaper windows
665 // are correctly placed.
666 boolean changed = false;
667 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
668 WindowToken token = mWallpaperTokens.get(curTokenNdx);
669 if (token.hidden == visible) {
670 if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
671 "Wallpaper token " + token + " hidden=" + !visible);
672 token.hidden = !visible;
673 // Need to do a layout to ensure the wallpaper now has the correct size.
674 mService.getDefaultDisplayContentLocked().layoutNeeded = true;
675 }
676
677 final WindowList tokenWindows = token.windows;
678 for (int wallpaperNdx = tokenWindows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
679 WindowState wallpaper = tokenWindows.get(wallpaperNdx);
680
681 if (visible) {
682 updateWallpaperOffset(wallpaper, dw, dh, false);
683 }
684
685 // First, make sure the client has the current visibility state.
686 dispatchWallpaperVisibility(wallpaper, visible);
687
688 wallpaper.mWinAnimator.mAnimLayer =
689 wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
690 if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
691 + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
692
693 // First, if this window is at the current index, then all is well.
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700694 if (wallpaper == wallpaperTarget) {
695 wallpaperTargetIndex--;
696 wallpaperTarget = wallpaperTargetIndex > 0
697 ? windows.get(wallpaperTargetIndex - 1) : null;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700698 continue;
699 }
700
701 // The window didn't match... the current wallpaper window,
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700702 // wherever it is, is in the wrong place, so make sure it is not in the list.
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700703 int oldIndex = windows.indexOf(wallpaper);
704 if (oldIndex >= 0) {
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700705 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
706 "Wallpaper removing at " + oldIndex + ": " + wallpaper);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700707 windows.remove(oldIndex);
708 mService.mWindowsChanged = true;
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700709 if (oldIndex < wallpaperTargetIndex) {
710 wallpaperTargetIndex--;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700711 }
712 }
713
714 // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
715 // layer. For keyguard over wallpaper put the wallpaper under the keyguard.
716 int insertionIndex = 0;
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700717 if (visible && wallpaperTarget != null) {
718 final int type = wallpaperTarget.mAttrs.type;
719 final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700720 if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0
721 || type == TYPE_KEYGUARD_SCRIM) {
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700722 insertionIndex = windows.indexOf(wallpaperTarget);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700723 }
724 }
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700725 if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
726 "Moving wallpaper " + wallpaper
727 + " from " + oldIndex + " to " + insertionIndex);
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700728
729 windows.add(insertionIndex, wallpaper);
730 mService.mWindowsChanged = true;
731 changed = true;
732 }
733 }
734
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700735 return changed;
736 }
737
738 boolean adjustWallpaperWindows() {
739 mService.mInnerFields.mWallpaperMayChange = false;
740
741 final WindowList windows = mService.getDefaultWindowListLocked();
742 // First find top-most window that has asked to be on top of the wallpaper;
743 // all wallpapers go behind it.
744 findWallpaperTarget(windows, mFindResults);
745 final boolean targetChanged = updateWallpaperWindowsTarget(windows, mFindResults);
746 final boolean visible = updateWallpaperWindowsTargetByLayer(windows, mFindResults);
747 WindowState wallpaperTarget = mFindResults.wallpaperTarget;
748 int wallpaperTargetIndex = mFindResults.wallpaperTargetIndex;
749
750 if (wallpaperTarget == null && mFindResults.topWallpaper != null) {
751 // There is no wallpaper target, so it goes at the bottom.
752 // We will assume it is the same place as last time, if known.
753 wallpaperTarget = mFindResults.topWallpaper;
754 wallpaperTargetIndex = mFindResults.topWallpaperIndex + 1;
755 } else {
756 // Okay i is the position immediately above the wallpaper.
757 // Look at what is below it for later.
758 wallpaperTarget = wallpaperTargetIndex > 0
759 ? windows.get(wallpaperTargetIndex - 1) : null;
760 }
761
762 if (visible) {
763 if (mWallpaperTarget.mWallpaperX >= 0) {
764 mLastWallpaperX = mWallpaperTarget.mWallpaperX;
765 mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
766 }
767 if (mWallpaperTarget.mWallpaperY >= 0) {
768 mLastWallpaperY = mWallpaperTarget.mWallpaperY;
769 mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
770 }
771 if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
772 mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
773 }
774 if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
775 mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
776 }
777 }
778
779 final boolean changed = updateWallpaperWindowsPlacement(
780 windows, wallpaperTarget, wallpaperTargetIndex, visible);
781
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700782 if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target="
783 + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
784 + mUpperWallpaperTarget);
785
786 return changed;
787 }
788
789 boolean processWallpaperDrawPendingTimeout() {
790 if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) {
791 mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT;
792 if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
793 "*** WALLPAPER DRAW TIMEOUT");
794 return true;
795 }
796 return false;
797 }
798
799 boolean wallpaperTransitionReady() {
800 boolean transitionReady = true;
801 boolean wallpaperReady = true;
802 for (int curTokenIndex = mWallpaperTokens.size() - 1;
803 curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) {
804 WindowToken token = mWallpaperTokens.get(curTokenIndex);
805 for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0;
806 curWallpaperIndex--) {
807 WindowState wallpaper = token.windows.get(curWallpaperIndex);
808 if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
809 // We've told this wallpaper to be visible, but it is not drawn yet
810 wallpaperReady = false;
811 if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
812 // wait for this wallpaper until it is drawn or timeout
813 transitionReady = false;
814 }
815 if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
816 mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
817 mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
818 mService.mH.sendEmptyMessageDelayed(WALLPAPER_DRAW_PENDING_TIMEOUT,
819 WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
820 }
821 if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
822 "Wallpaper should be visible but has not been drawn yet. " +
823 "mWallpaperDrawState=" + mWallpaperDrawState);
824 break;
825 }
826 }
827 }
828 if (wallpaperReady) {
829 mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
830 mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
831 }
832
833 return transitionReady;
834 }
835
836 void addWallpaperToken(WindowToken token) {
837 mWallpaperTokens.add(token);
838 }
839
840 void removeWallpaperToken(WindowToken token) {
841 mWallpaperTokens.remove(token);
842 }
843
844 void dump(PrintWriter pw, String prefix) {
845 pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
846 if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
847 pw.print(prefix); pw.print("mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
848 pw.print(prefix); pw.print("mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
849 }
850 pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX);
851 pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
852 if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE
853 || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
854 pw.print(prefix);
855 pw.print("mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX);
856 pw.print(" mLastWallpaperDisplayOffsetY="); pw.println(mLastWallpaperDisplayOffsetY);
857 }
858 }
859
860 void dumpTokens(PrintWriter pw, String prefix, boolean dumpAll) {
861 if (!mWallpaperTokens.isEmpty()) {
862 pw.println();
863 pw.print(prefix); pw.println("Wallpaper tokens:");
864 for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
865 WindowToken token = mWallpaperTokens.get(i);
866 pw.print(prefix); pw.print("Wallpaper #"); pw.print(i);
867 pw.print(' '); pw.print(token);
868 if (dumpAll) {
869 pw.println(':');
870 token.dump(pw, " ");
871 } else {
872 pw.println();
873 }
874 }
875 }
876 }
Wale Ogunwale5f61d042015-08-20 10:09:47 -0700877
878 /** Helper class for storing the results of a wallpaper target find operation. */
879 final private static class FindWallpaperTargetResult {
880 int topWallpaperIndex = 0;
881 WindowState topWallpaper = null;
882 int wallpaperTargetIndex = 0;
883 WindowState wallpaperTarget = null;
884
885 void setTopWallpaper(WindowState win, int index) {
886 topWallpaper = win;
887 topWallpaperIndex = index;
888 }
889
890 void setWallpaperTarget(WindowState win, int index) {
891 wallpaperTarget = win;
892 wallpaperTargetIndex = index;
893 }
894
895 void reset() {
896 topWallpaperIndex = 0;
897 topWallpaper = null;
898 wallpaperTargetIndex = 0;
899 wallpaperTarget = null;
900 }
901 }
Wale Ogunwalee8069dc2015-08-18 09:52:01 -0700902}