blob: b871d7f0f5018cbac2a9484b2ef2dc663856129a [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
101 public WallpaperController(WindowManagerService service) {
102 mService = service;
103 }
104
105 WindowState getWallpaperTarget() {
106 return mWallpaperTarget;
107 }
108
109 WindowState getLowerWallpaperTarget() {
110 return mLowerWallpaperTarget;
111 }
112
113 WindowState getUpperWallpaperTarget() {
114 return mUpperWallpaperTarget;
115 }
116
117 boolean isWallpaperTarget(WindowState win) {
118 return win == mWallpaperTarget;
119 }
120
121 boolean isBelowWallpaperTarget(WindowState win) {
122 return mWallpaperTarget != null && mWallpaperTarget.mLayer >= win.mBaseLayer;
123 }
124
125 boolean isWallpaperVisible() {
126 return isWallpaperVisible(mWallpaperTarget);
127 }
128
129 private boolean isWallpaperVisible(WindowState wallpaperTarget) {
130 if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
131 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
132 + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
133 ? wallpaperTarget.mAppToken.mAppAnimator.animation : null)
134 + " upper=" + mUpperWallpaperTarget
135 + " lower=" + mLowerWallpaperTarget);
136 return (wallpaperTarget != null
137 && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null
138 && wallpaperTarget.mAppToken.mAppAnimator.animation != null)))
139 || mUpperWallpaperTarget != null
140 || mLowerWallpaperTarget != null;
141 }
142
143 boolean isWallpaperTargetAnimating() {
144 return mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
145 && !mWallpaperTarget.mWinAnimator.isDummyAnimation();
146 }
147
148 void updateWallpaperVisibility() {
149 final boolean visible = isWallpaperVisible(mWallpaperTarget);
150 final DisplayContent displayContent = mWallpaperTarget.getDisplayContent();
151 if (displayContent == null) {
152 return;
153 }
154 final DisplayInfo displayInfo = displayContent.getDisplayInfo();
155 final int dw = displayInfo.logicalWidth;
156 final int dh = displayInfo.logicalHeight;
157
158 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
159 WindowToken token = mWallpaperTokens.get(curTokenNdx);
160 if (token.hidden == visible) {
161 token.hidden = !visible;
162 // Need to do a layout to ensure the wallpaper now has the
163 // correct size.
164 displayContent.layoutNeeded = true;
165 }
166
167 final WindowList windows = token.windows;
168 for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
169 WindowState wallpaper = windows.get(wallpaperNdx);
170 if (visible) {
171 updateWallpaperOffset(wallpaper, dw, dh, false);
172 }
173
174 dispatchWallpaperVisibility(wallpaper, visible);
175 }
176 }
177 }
178
179 void hideDeferredWallpapersIfNeeded() {
180 if (mDeferredHideWallpaper != null) {
181 hideWallpapers(mDeferredHideWallpaper);
182 mDeferredHideWallpaper = null;
183 }
184 }
185
186 void hideWallpapers(final WindowState winGoingAway) {
187 if (mWallpaperTarget != null
188 && (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) {
189 return;
190 }
191 if (mService.mAppTransition.isRunning()) {
192 // Defer hiding the wallpaper when app transition is running until the animations
193 // are done.
194 mDeferredHideWallpaper = winGoingAway;
195 return;
196 }
197
198 final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway);
199 for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
200 final WindowToken token = mWallpaperTokens.get(i);
201 for (int j = token.windows.size() - 1; j >= 0; j--) {
202 final WindowState wallpaper = token.windows.get(j);
203 final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
204 if (!winAnimator.mLastHidden || wasDeferred) {
205 winAnimator.hide();
206 dispatchWallpaperVisibility(wallpaper, false);
207 final DisplayContent displayContent = wallpaper.getDisplayContent();
208 if (displayContent != null) {
209 displayContent.pendingLayoutChanges |=
210 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
211 }
212 }
213 }
214 if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token
215 + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower="
216 + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, " "));
217 token.hidden = true;
218 }
219 }
220
221 /**
222 * Check wallpaper for visibility change and notify window if so.
223 * @param wallpaper The wallpaper to test and notify.
224 * @param visible Current visibility.
225 */
226 void dispatchWallpaperVisibility(final WindowState wallpaper, final boolean visible) {
227 // Only send notification if the visibility actually changed and we are not trying to hide
228 // the wallpaper when we are deferring hiding of the wallpaper.
229 if (wallpaper.mWallpaperVisible != visible
230 && (mDeferredHideWallpaper == null || visible)) {
231 wallpaper.mWallpaperVisible = visible;
232 try {
233 if (DEBUG_VISIBILITY || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
234 "Updating vis of wallpaper " + wallpaper
235 + ": " + visible + " from:\n" + Debug.getCallers(4, " "));
236 wallpaper.mClient.dispatchAppVisibility(visible);
237 } catch (RemoteException e) {
238 }
239 }
240 }
241
242 boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) {
243 boolean rawChanged = false;
244 float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f;
245 float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
246 int availw = wallpaperWin.mFrame.right - wallpaperWin.mFrame.left - dw;
247 int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
248 if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
249 offset += mLastWallpaperDisplayOffsetX;
250 }
251 boolean changed = wallpaperWin.mXOffset != offset;
252 if (changed) {
253 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset);
254 wallpaperWin.mXOffset = offset;
255 }
256 if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
257 wallpaperWin.mWallpaperX = wpx;
258 wallpaperWin.mWallpaperXStep = wpxs;
259 rawChanged = true;
260 }
261
262 float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
263 float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
264 int availh = wallpaperWin.mFrame.bottom - wallpaperWin.mFrame.top - dh;
265 offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0;
266 if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
267 offset += mLastWallpaperDisplayOffsetY;
268 }
269 if (wallpaperWin.mYOffset != offset) {
270 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset);
271 changed = true;
272 wallpaperWin.mYOffset = offset;
273 }
274 if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
275 wallpaperWin.mWallpaperY = wpy;
276 wallpaperWin.mWallpaperYStep = wpys;
277 rawChanged = true;
278 }
279
280 if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
281 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
282 try {
283 if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset "
284 + wallpaperWin + " x=" + wallpaperWin.mWallpaperX
285 + " y=" + wallpaperWin.mWallpaperY);
286 if (sync) {
287 mWaitingOnWallpaper = wallpaperWin;
288 }
289 wallpaperWin.mClient.dispatchWallpaperOffsets(
290 wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY,
291 wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync);
292 if (sync) {
293 if (mWaitingOnWallpaper != null) {
294 long start = SystemClock.uptimeMillis();
295 if ((mLastWallpaperTimeoutTime + WALLPAPER_TIMEOUT_RECOVERY)
296 < start) {
297 try {
298 if (DEBUG_WALLPAPER) Slog.v(TAG,
299 "Waiting for offset complete...");
300 mService.mWindowMap.wait(WALLPAPER_TIMEOUT);
301 } catch (InterruptedException e) {
302 }
303 if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!");
304 if ((start + WALLPAPER_TIMEOUT) < SystemClock.uptimeMillis()) {
305 Slog.i(TAG, "Timeout waiting for wallpaper to offset: "
306 + wallpaperWin);
307 mLastWallpaperTimeoutTime = start;
308 }
309 }
310 mWaitingOnWallpaper = null;
311 }
312 }
313 } catch (RemoteException e) {
314 }
315 }
316
317 return changed;
318 }
319
320 void setWindowWallpaperPosition(
321 WindowState window, float x, float y, float xStep, float yStep) {
322 if (window.mWallpaperX != x || window.mWallpaperY != y) {
323 window.mWallpaperX = x;
324 window.mWallpaperY = y;
325 window.mWallpaperXStep = xStep;
326 window.mWallpaperYStep = yStep;
327 updateWallpaperOffsetLocked(window, true);
328 }
329 }
330
331 void setWindowWallpaperDisplayOffset(WindowState window, int x, int y) {
332 if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y) {
333 window.mWallpaperDisplayOffsetX = x;
334 window.mWallpaperDisplayOffsetY = y;
335 updateWallpaperOffsetLocked(window, true);
336 }
337 }
338
339 Bundle sendWindowWallpaperCommand(
340 WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) {
341 if (window == mWallpaperTarget
342 || window == mLowerWallpaperTarget
343 || window == mUpperWallpaperTarget) {
344 boolean doWait = sync;
345 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
346 final WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
347 for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
348 WindowState wallpaper = windows.get(wallpaperNdx);
349 try {
350 wallpaper.mClient.dispatchWallpaperCommand(action,
351 x, y, z, extras, sync);
352 // We only want to be synchronous with one wallpaper.
353 sync = false;
354 } catch (RemoteException e) {
355 }
356 }
357 }
358
359 if (doWait) {
360 // TODO: Need to wait for result.
361 }
362 }
363
364 return null;
365 }
366
367 void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
368 final DisplayContent displayContent = changingTarget.getDisplayContent();
369 if (displayContent == null) {
370 return;
371 }
372 final DisplayInfo displayInfo = displayContent.getDisplayInfo();
373 final int dw = displayInfo.logicalWidth;
374 final int dh = displayInfo.logicalHeight;
375
376 WindowState target = mWallpaperTarget;
377 if (target != null) {
378 if (target.mWallpaperX >= 0) {
379 mLastWallpaperX = target.mWallpaperX;
380 } else if (changingTarget.mWallpaperX >= 0) {
381 mLastWallpaperX = changingTarget.mWallpaperX;
382 }
383 if (target.mWallpaperY >= 0) {
384 mLastWallpaperY = target.mWallpaperY;
385 } else if (changingTarget.mWallpaperY >= 0) {
386 mLastWallpaperY = changingTarget.mWallpaperY;
387 }
388 if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
389 mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX;
390 } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
391 mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX;
392 }
393 if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
394 mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY;
395 } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
396 mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY;
397 }
398 if (target.mWallpaperXStep >= 0) {
399 mLastWallpaperXStep = target.mWallpaperXStep;
400 } else if (changingTarget.mWallpaperXStep >= 0) {
401 mLastWallpaperXStep = changingTarget.mWallpaperXStep;
402 }
403 if (target.mWallpaperYStep >= 0) {
404 mLastWallpaperYStep = target.mWallpaperYStep;
405 } else if (changingTarget.mWallpaperYStep >= 0) {
406 mLastWallpaperYStep = changingTarget.mWallpaperYStep;
407 }
408 }
409
410 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
411 WindowList windows = mWallpaperTokens.get(curTokenNdx).windows;
412 for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
413 WindowState wallpaper = windows.get(wallpaperNdx);
414 if (updateWallpaperOffset(wallpaper, dw, dh, sync)) {
415 WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
416 winAnimator.computeShownFrameLocked();
417 // No need to lay out the windows - we can just set the wallpaper position
418 // directly.
419 winAnimator.setWallpaperOffset(wallpaper.mShownFrame);
420 // We only want to be synchronous with one wallpaper.
421 sync = false;
422 }
423 }
424 }
425 }
426
427 void clearLastWallpaperTimeoutTime() {
428 mLastWallpaperTimeoutTime = 0;
429 }
430
431 void wallpaperCommandComplete(IBinder window) {
432 if (mWaitingOnWallpaper != null &&
433 mWaitingOnWallpaper.mClient.asBinder() == window) {
434 mWaitingOnWallpaper = null;
435 mService.mWindowMap.notifyAll();
436 }
437 }
438
439 void wallpaperOffsetsComplete(IBinder window) {
440 if (mWaitingOnWallpaper != null &&
441 mWaitingOnWallpaper.mClient.asBinder() == window) {
442 mWaitingOnWallpaper = null;
443 mService.mWindowMap.notifyAll();
444 }
445 }
446
447 int getAnimLayerAdjustment() {
448 return mWallpaperAnimLayerAdjustment;
449 }
450
451 void setAnimLayerAdjustment(WindowState win, int adj) {
452 if (win != mWallpaperTarget || mLowerWallpaperTarget != null) {
453 return;
454 }
455
456 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Setting wallpaper layer adj to " + adj);
457 mWallpaperAnimLayerAdjustment = adj;
458 for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
459 WindowList windows = mWallpaperTokens.get(i).windows;
460 for (int j = windows.size() - 1; j >= 0; j--) {
461 WindowState wallpaper = windows.get(j);
462 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj;
463 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win "
464 + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
465 }
466 }
467 }
468
469 boolean adjustWallpaperWindows() {
470 mService.mInnerFields.mWallpaperMayChange = false;
471 boolean targetChanged = false;
472
473 // TODO(multidisplay): Wallpapers on main screen only.
474 final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo();
475 final int dw = displayInfo.logicalWidth;
476 final int dh = displayInfo.logicalHeight;
477
478 final WindowAnimator winAnimator = mService.mAnimator;
479
480 // First find top-most window that has asked to be on top of the
481 // wallpaper; all wallpapers go behind it.
482 final WindowList windows = mService.getDefaultWindowListLocked();
483 int N = windows.size();
484 WindowState w = null;
485 WindowState foundW = null;
486 int foundI = 0;
487 WindowState topCurW = null;
488 int topCurI = 0;
489 int windowDetachedI = -1;
490 int i = N;
491 while (i > 0) {
492 i--;
493 w = windows.get(i);
494 if ((w.mAttrs.type == TYPE_WALLPAPER)) {
495 if (topCurW == null) {
496 topCurW = w;
497 topCurI = i;
498 }
499 continue;
500 }
501 topCurW = null;
502 if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
503 // If this window's app token is hidden and not animating,
504 // it is of no interest to us.
505 if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) {
506 if (DEBUG_WALLPAPER) Slog.v(TAG,
507 "Skipping hidden and not animating token: " + w);
508 continue;
509 }
510 }
511 if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen="
512 + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState);
513
514 // If the app is executing an animation because the keyguard is going away, keep the
515 // wallpaper during the animation so it doesn't flicker out.
516 final boolean hasWallpaper = (w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
517 || (w.mAppToken != null
518 && w.mWinAnimator.mKeyguardGoingAwayAnimation);
519 if (hasWallpaper && w.isOnScreen()
520 && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
521 if (DEBUG_WALLPAPER) Slog.v(TAG,
522 "Found wallpaper target: #" + i + "=" + w);
523 foundW = w;
524 foundI = i;
525 if (w == mWallpaperTarget && w.mWinAnimator.isAnimating()) {
526 // The current wallpaper target is animating, so we'll
527 // look behind it for another possible target and figure
528 // out what is going on below.
529 if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w
530 + ": token animating, looking behind.");
531 continue;
532 }
533 break;
534 } else if (w == winAnimator.mWindowDetachedWallpaper) {
535 windowDetachedI = i;
536 }
537 }
538
539 if (foundW == null && windowDetachedI >= 0) {
540 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
541 "Found animating detached wallpaper activity: #" + i + "=" + w);
542 foundW = w;
543 foundI = windowDetachedI;
544 }
545
546 if (mWallpaperTarget != foundW
547 && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != foundW)) {
548 if (DEBUG_WALLPAPER_LIGHT) {
549 Slog.v(TAG, "New wallpaper target: " + foundW
550 + " oldTarget: " + mWallpaperTarget);
551 }
552
553 mLowerWallpaperTarget = null;
554 mUpperWallpaperTarget = null;
555
556 WindowState oldW = mWallpaperTarget;
557 mWallpaperTarget = foundW;
558 targetChanged = true;
559
560 // Now what is happening... if the current and new targets are
561 // animating, then we are in our super special mode!
562 if (foundW != null && oldW != null) {
563 boolean oldAnim = oldW.isAnimatingLw();
564 boolean foundAnim = foundW.isAnimatingLw();
565 if (DEBUG_WALLPAPER_LIGHT) {
566 Slog.v(TAG, "New animation: " + foundAnim
567 + " old animation: " + oldAnim);
568 }
569 if (foundAnim && oldAnim) {
570 int oldI = windows.indexOf(oldW);
571 if (DEBUG_WALLPAPER_LIGHT) {
572 Slog.v(TAG, "New i: " + foundI + " old i: " + oldI);
573 }
574 if (oldI >= 0) {
575 if (DEBUG_WALLPAPER_LIGHT) {
576 Slog.v(TAG, "Animating wallpapers: old#" + oldI
577 + "=" + oldW + "; new#" + foundI
578 + "=" + foundW);
579 }
580
581 // Set the new target correctly.
582 if (foundW.mAppToken != null && foundW.mAppToken.hiddenRequested) {
583 if (DEBUG_WALLPAPER_LIGHT) {
584 Slog.v(TAG, "Old wallpaper still the target.");
585 }
586 mWallpaperTarget = oldW;
587 foundW = oldW;
588 foundI = oldI;
589 }
590 // Now set the upper and lower wallpaper targets
591 // correctly, and make sure that we are positioning
592 // the wallpaper below the lower.
593 else if (foundI > oldI) {
594 // The new target is on top of the old one.
595 if (DEBUG_WALLPAPER_LIGHT) {
596 Slog.v(TAG, "Found target above old target.");
597 }
598 mUpperWallpaperTarget = foundW;
599 mLowerWallpaperTarget = oldW;
600 foundW = oldW;
601 foundI = oldI;
602 } else {
603 // The new target is below the old one.
604 if (DEBUG_WALLPAPER_LIGHT) {
605 Slog.v(TAG, "Found target below old target.");
606 }
607 mUpperWallpaperTarget = oldW;
608 mLowerWallpaperTarget = foundW;
609 }
610 }
611 }
612 }
613
614 } else if (mLowerWallpaperTarget != null) {
615 // Is it time to stop animating?
616 if (!mLowerWallpaperTarget.isAnimatingLw() || !mUpperWallpaperTarget.isAnimatingLw()) {
617 if (DEBUG_WALLPAPER_LIGHT) {
618 Slog.v(TAG, "No longer animating wallpaper targets!");
619 }
620 mLowerWallpaperTarget = null;
621 mUpperWallpaperTarget = null;
622 mWallpaperTarget = foundW;
623 targetChanged = true;
624 }
625 }
626
627 boolean visible = foundW != null;
628 if (visible) {
629 // The window is visible to the compositor... but is it visible
630 // to the user? That is what the wallpaper cares about.
631 visible = isWallpaperVisible(foundW);
632 if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
633
634 // If the wallpaper target is animating, we may need to copy
635 // its layer adjustment. Only do this if we are not transfering
636 // between two wallpaper targets.
637 mWallpaperAnimLayerAdjustment =
638 (mLowerWallpaperTarget == null && foundW.mAppToken != null)
639 ? foundW.mAppToken.mAppAnimator.animLayerAdjustment : 0;
640
641 final int maxLayer = (mService.mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER)
642 + TYPE_LAYER_OFFSET;
643
644 // Now w is the window we are supposed to be behind... but we
645 // need to be sure to also be behind any of its attached windows,
646 // AND any starting window associated with it, AND below the
647 // maximum layer the policy allows for wallpapers.
648 while (foundI > 0) {
649 WindowState wb = windows.get(foundI - 1);
650 if (wb.mBaseLayer < maxLayer &&
651 wb.mAttachedWindow != foundW &&
652 (foundW.mAttachedWindow == null ||
653 wb.mAttachedWindow != foundW.mAttachedWindow) &&
654 (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
655 foundW.mToken == null || wb.mToken != foundW.mToken)) {
656 // This window is not related to the previous one in any
657 // interesting way, so stop here.
658 break;
659 }
660 foundW = wb;
661 foundI--;
662 }
663 } else {
664 if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target");
665 }
666
667 if (foundW == null && topCurW != null) {
668 // There is no wallpaper target, so it goes at the bottom.
669 // We will assume it is the same place as last time, if known.
670 foundW = topCurW;
671 foundI = topCurI+1;
672 } else {
673 // Okay i is the position immediately above the wallpaper. Look at
674 // what is below it for later.
675 foundW = foundI > 0 ? windows.get(foundI - 1) : null;
676 }
677
678 if (visible) {
679 if (mWallpaperTarget.mWallpaperX >= 0) {
680 mLastWallpaperX = mWallpaperTarget.mWallpaperX;
681 mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
682 }
683 if (mWallpaperTarget.mWallpaperY >= 0) {
684 mLastWallpaperY = mWallpaperTarget.mWallpaperY;
685 mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
686 }
687 if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
688 mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
689 }
690 if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
691 mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
692 }
693 }
694
695 // Start stepping backwards from here, ensuring that our wallpaper windows
696 // are correctly placed.
697 boolean changed = false;
698 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
699 WindowToken token = mWallpaperTokens.get(curTokenNdx);
700 if (token.hidden == visible) {
701 if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
702 "Wallpaper token " + token + " hidden=" + !visible);
703 token.hidden = !visible;
704 // Need to do a layout to ensure the wallpaper now has the correct size.
705 mService.getDefaultDisplayContentLocked().layoutNeeded = true;
706 }
707
708 final WindowList tokenWindows = token.windows;
709 for (int wallpaperNdx = tokenWindows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) {
710 WindowState wallpaper = tokenWindows.get(wallpaperNdx);
711
712 if (visible) {
713 updateWallpaperOffset(wallpaper, dw, dh, false);
714 }
715
716 // First, make sure the client has the current visibility state.
717 dispatchWallpaperVisibility(wallpaper, visible);
718
719 wallpaper.mWinAnimator.mAnimLayer =
720 wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
721 if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win "
722 + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
723
724 // First, if this window is at the current index, then all is well.
725 if (wallpaper == foundW) {
726 foundI--;
727 foundW = foundI > 0 ? windows.get(foundI - 1) : null;
728 continue;
729 }
730
731 // The window didn't match... the current wallpaper window,
732 // wherever it is, is in the wrong place, so make sure it is
733 // not in the list.
734 int oldIndex = windows.indexOf(wallpaper);
735 if (oldIndex >= 0) {
736 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Wallpaper removing at "
737 + oldIndex + ": " + wallpaper);
738 windows.remove(oldIndex);
739 mService.mWindowsChanged = true;
740 if (oldIndex < foundI) {
741 foundI--;
742 }
743 }
744
745 // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
746 // layer. For keyguard over wallpaper put the wallpaper under the keyguard.
747 int insertionIndex = 0;
748 if (visible && foundW != null) {
749 final int type = foundW.mAttrs.type;
750 final int privateFlags = foundW.mAttrs.privateFlags;
751 if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0
752 || type == TYPE_KEYGUARD_SCRIM) {
753 insertionIndex = windows.indexOf(foundW);
754 }
755 }
756 if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
757 Slog.v(TAG, "Moving wallpaper " + wallpaper
758 + " from " + oldIndex + " to " + insertionIndex);
759 }
760
761 windows.add(insertionIndex, wallpaper);
762 mService.mWindowsChanged = true;
763 changed = true;
764 }
765 }
766
767 if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target="
768 + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
769 + mUpperWallpaperTarget);
770
771 return changed;
772 }
773
774 boolean processWallpaperDrawPendingTimeout() {
775 if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) {
776 mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT;
777 if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
778 "*** WALLPAPER DRAW TIMEOUT");
779 return true;
780 }
781 return false;
782 }
783
784 boolean wallpaperTransitionReady() {
785 boolean transitionReady = true;
786 boolean wallpaperReady = true;
787 for (int curTokenIndex = mWallpaperTokens.size() - 1;
788 curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) {
789 WindowToken token = mWallpaperTokens.get(curTokenIndex);
790 for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0;
791 curWallpaperIndex--) {
792 WindowState wallpaper = token.windows.get(curWallpaperIndex);
793 if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
794 // We've told this wallpaper to be visible, but it is not drawn yet
795 wallpaperReady = false;
796 if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
797 // wait for this wallpaper until it is drawn or timeout
798 transitionReady = false;
799 }
800 if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
801 mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
802 mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
803 mService.mH.sendEmptyMessageDelayed(WALLPAPER_DRAW_PENDING_TIMEOUT,
804 WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
805 }
806 if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
807 "Wallpaper should be visible but has not been drawn yet. " +
808 "mWallpaperDrawState=" + mWallpaperDrawState);
809 break;
810 }
811 }
812 }
813 if (wallpaperReady) {
814 mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
815 mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
816 }
817
818 return transitionReady;
819 }
820
821 void addWallpaperToken(WindowToken token) {
822 mWallpaperTokens.add(token);
823 }
824
825 void removeWallpaperToken(WindowToken token) {
826 mWallpaperTokens.remove(token);
827 }
828
829 void dump(PrintWriter pw, String prefix) {
830 pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
831 if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
832 pw.print(prefix); pw.print("mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
833 pw.print(prefix); pw.print("mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
834 }
835 pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX);
836 pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
837 if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE
838 || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
839 pw.print(prefix);
840 pw.print("mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX);
841 pw.print(" mLastWallpaperDisplayOffsetY="); pw.println(mLastWallpaperDisplayOffsetY);
842 }
843 }
844
845 void dumpTokens(PrintWriter pw, String prefix, boolean dumpAll) {
846 if (!mWallpaperTokens.isEmpty()) {
847 pw.println();
848 pw.print(prefix); pw.println("Wallpaper tokens:");
849 for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
850 WindowToken token = mWallpaperTokens.get(i);
851 pw.print(prefix); pw.print("Wallpaper #"); pw.print(i);
852 pw.print(' '); pw.print(token);
853 if (dumpAll) {
854 pw.println(':');
855 token.dump(pw, " ");
856 } else {
857 pw.println();
858 }
859 }
860 }
861 }
862}