WallpaperController.java revision 0303c5723edfdb4f2db37543544d7cbe9b14df97
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.wm;
18
19import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
20import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
21import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
22import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
23import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
24import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
25import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
26import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
27import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
28import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
29import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT;
30import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
31import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
32
33import android.os.Bundle;
34import android.os.Debug;
35import android.os.IBinder;
36import android.os.RemoteException;
37import android.os.SystemClock;
38import android.util.ArraySet;
39import android.util.Slog;
40import android.view.DisplayInfo;
41import android.view.WindowManager;
42
43import java.io.PrintWriter;
44import java.util.ArrayList;
45
46/**
47 * Controls wallpaper windows visibility, ordering, and so on.
48 * NOTE: All methods in this class must be called with the window manager service lock held.
49 */
50class WallpaperController {
51    private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperController" : TAG_WM;
52    final private WindowManagerService mService;
53
54    private final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<>();
55
56    // If non-null, this is the currently visible window that is associated
57    // with the wallpaper.
58    private WindowState mWallpaperTarget = null;
59    // If non-null, we are in the middle of animating from one wallpaper target
60    // to another, and this is the lower one in Z-order.
61    private WindowState mLowerWallpaperTarget = null;
62    // If non-null, we are in the middle of animating from one wallpaper target
63    // to another, and this is the higher one in Z-order.
64    private WindowState mUpperWallpaperTarget = null;
65
66    private int mWallpaperAnimLayerAdjustment;
67
68    private float mLastWallpaperX = -1;
69    private float mLastWallpaperY = -1;
70    private float mLastWallpaperXStep = -1;
71    private float mLastWallpaperYStep = -1;
72    private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
73    private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
74
75    // This is set when we are waiting for a wallpaper to tell us it is done
76    // changing its scroll position.
77    WindowState mWaitingOnWallpaper;
78
79    // The last time we had a timeout when waiting for a wallpaper.
80    private long mLastWallpaperTimeoutTime;
81    // We give a wallpaper up to 150ms to finish scrolling.
82    private static final long WALLPAPER_TIMEOUT = 150;
83    // Time we wait after a timeout before trying to wait again.
84    private static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
85
86    // Set to the wallpaper window we would like to hide once the transition animations are done.
87    // This is useful in cases where we don't want the wallpaper to be hidden when the close app
88    // is a wallpaper target and is done animating out, but the opening app isn't a wallpaper
89    // target and isn't done animating in.
90    WindowState mDeferredHideWallpaper = null;
91
92    // We give a wallpaper up to 500ms to finish drawing before playing app transitions.
93    private static final long WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION = 500;
94    private static final int WALLPAPER_DRAW_NORMAL = 0;
95    private static final int WALLPAPER_DRAW_PENDING = 1;
96    private static final int WALLPAPER_DRAW_TIMEOUT = 2;
97    private int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
98
99    private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult();
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.isAnimationSet()
145                && !mWallpaperTarget.mWinAnimator.isDummyAnimation();
146    }
147
148    void updateWallpaperVisibility() {
149        final boolean visible = isWallpaperVisible(mWallpaperTarget);
150
151        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
152            final WindowToken token = mWallpaperTokens.get(curTokenNdx);
153            token.updateWallpaperVisibility(visible);
154        }
155    }
156
157    void hideDeferredWallpapersIfNeeded() {
158        if (mDeferredHideWallpaper != null) {
159            hideWallpapers(mDeferredHideWallpaper);
160            mDeferredHideWallpaper = null;
161        }
162    }
163
164    void hideWallpapers(final WindowState winGoingAway) {
165        if (mWallpaperTarget != null
166                && (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) {
167            return;
168        }
169        if (mService.mAppTransition.isRunning()) {
170            // Defer hiding the wallpaper when app transition is running until the animations
171            // are done.
172            mDeferredHideWallpaper = winGoingAway;
173            return;
174        }
175
176        final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway);
177        for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
178            final WindowToken token = mWallpaperTokens.get(i);
179            token.hideWallpaperToken(wasDeferred, "hideWallpapers");
180            if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token
181                    + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower="
182                    + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, "  "));
183        }
184    }
185
186    boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) {
187        boolean rawChanged = false;
188        // Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to
189        // match the behavior of most Launchers
190        float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f;
191        float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX;
192        float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
193        int availw = wallpaperWin.mFrame.right - wallpaperWin.mFrame.left - dw;
194        int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
195        if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
196            offset += mLastWallpaperDisplayOffsetX;
197        }
198        boolean changed = wallpaperWin.mXOffset != offset;
199        if (changed) {
200            if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset);
201            wallpaperWin.mXOffset = offset;
202        }
203        if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
204            wallpaperWin.mWallpaperX = wpx;
205            wallpaperWin.mWallpaperXStep = wpxs;
206            rawChanged = true;
207        }
208
209        float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
210        float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
211        int availh = wallpaperWin.mFrame.bottom - wallpaperWin.mFrame.top - dh;
212        offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0;
213        if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
214            offset += mLastWallpaperDisplayOffsetY;
215        }
216        if (wallpaperWin.mYOffset != offset) {
217            if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset);
218            changed = true;
219            wallpaperWin.mYOffset = offset;
220        }
221        if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
222            wallpaperWin.mWallpaperY = wpy;
223            wallpaperWin.mWallpaperYStep = wpys;
224            rawChanged = true;
225        }
226
227        if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
228                WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
229            try {
230                if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset "
231                        + wallpaperWin + " x=" + wallpaperWin.mWallpaperX
232                        + " y=" + wallpaperWin.mWallpaperY);
233                if (sync) {
234                    mWaitingOnWallpaper = wallpaperWin;
235                }
236                wallpaperWin.mClient.dispatchWallpaperOffsets(
237                        wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY,
238                        wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync);
239                if (sync) {
240                    if (mWaitingOnWallpaper != null) {
241                        long start = SystemClock.uptimeMillis();
242                        if ((mLastWallpaperTimeoutTime + WALLPAPER_TIMEOUT_RECOVERY)
243                                < start) {
244                            try {
245                                if (DEBUG_WALLPAPER) Slog.v(TAG,
246                                        "Waiting for offset complete...");
247                                mService.mWindowMap.wait(WALLPAPER_TIMEOUT);
248                            } catch (InterruptedException e) {
249                            }
250                            if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!");
251                            if ((start + WALLPAPER_TIMEOUT) < SystemClock.uptimeMillis()) {
252                                Slog.i(TAG, "Timeout waiting for wallpaper to offset: "
253                                        + wallpaperWin);
254                                mLastWallpaperTimeoutTime = start;
255                            }
256                        }
257                        mWaitingOnWallpaper = null;
258                    }
259                }
260            } catch (RemoteException e) {
261            }
262        }
263
264        return changed;
265    }
266
267    void setWindowWallpaperPosition(
268            WindowState window, float x, float y, float xStep, float yStep) {
269        if (window.mWallpaperX != x || window.mWallpaperY != y)  {
270            window.mWallpaperX = x;
271            window.mWallpaperY = y;
272            window.mWallpaperXStep = xStep;
273            window.mWallpaperYStep = yStep;
274            updateWallpaperOffsetLocked(window, true);
275        }
276    }
277
278    void setWindowWallpaperDisplayOffset(WindowState window, int x, int y) {
279        if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y)  {
280            window.mWallpaperDisplayOffsetX = x;
281            window.mWallpaperDisplayOffsetY = y;
282            updateWallpaperOffsetLocked(window, true);
283        }
284    }
285
286    Bundle sendWindowWallpaperCommand(
287            WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) {
288        if (window == mWallpaperTarget
289                || window == mLowerWallpaperTarget
290                || window == mUpperWallpaperTarget) {
291            boolean doWait = sync;
292            for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
293                final WindowToken token = mWallpaperTokens.get(curTokenNdx);
294                token.sendWindowWallpaperCommand(action, x, y, z, extras, sync);
295            }
296
297            if (doWait) {
298                // TODO: Need to wait for result.
299            }
300        }
301
302        return null;
303    }
304
305    private void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
306        final DisplayContent displayContent = changingTarget.getDisplayContent();
307        if (displayContent == null) {
308            return;
309        }
310        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
311        final int dw = displayInfo.logicalWidth;
312        final int dh = displayInfo.logicalHeight;
313
314        WindowState target = mWallpaperTarget;
315        if (target != null) {
316            if (target.mWallpaperX >= 0) {
317                mLastWallpaperX = target.mWallpaperX;
318            } else if (changingTarget.mWallpaperX >= 0) {
319                mLastWallpaperX = changingTarget.mWallpaperX;
320            }
321            if (target.mWallpaperY >= 0) {
322                mLastWallpaperY = target.mWallpaperY;
323            } else if (changingTarget.mWallpaperY >= 0) {
324                mLastWallpaperY = changingTarget.mWallpaperY;
325            }
326            if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
327                mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX;
328            } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
329                mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX;
330            }
331            if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
332                mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY;
333            } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
334                mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY;
335            }
336            if (target.mWallpaperXStep >= 0) {
337                mLastWallpaperXStep = target.mWallpaperXStep;
338            } else if (changingTarget.mWallpaperXStep >= 0) {
339                mLastWallpaperXStep = changingTarget.mWallpaperXStep;
340            }
341            if (target.mWallpaperYStep >= 0) {
342                mLastWallpaperYStep = target.mWallpaperYStep;
343            } else if (changingTarget.mWallpaperYStep >= 0) {
344                mLastWallpaperYStep = changingTarget.mWallpaperYStep;
345            }
346        }
347
348        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
349            mWallpaperTokens.get(curTokenNdx).updateWallpaperOffset(dw, dh, sync);
350        }
351    }
352
353    void clearLastWallpaperTimeoutTime() {
354        mLastWallpaperTimeoutTime = 0;
355    }
356
357    void wallpaperCommandComplete(IBinder window) {
358        if (mWaitingOnWallpaper != null &&
359                mWaitingOnWallpaper.mClient.asBinder() == window) {
360            mWaitingOnWallpaper = null;
361            mService.mWindowMap.notifyAll();
362        }
363    }
364
365    void wallpaperOffsetsComplete(IBinder window) {
366        if (mWaitingOnWallpaper != null &&
367                mWaitingOnWallpaper.mClient.asBinder() == window) {
368            mWaitingOnWallpaper = null;
369            mService.mWindowMap.notifyAll();
370        }
371    }
372
373    int getAnimLayerAdjustment() {
374        return mWallpaperAnimLayerAdjustment;
375    }
376
377    private void findWallpaperTarget(WindowList windows, FindWallpaperTargetResult result) {
378        final WindowAnimator winAnimator = mService.mAnimator;
379        result.reset();
380        WindowState w = null;
381        int windowDetachedI = -1;
382        boolean resetTopWallpaper = false;
383        boolean inFreeformSpace = false;
384        boolean replacing = false;
385        boolean keyguardGoingAwayWithWallpaper = false;
386
387        for (int i = windows.size() - 1; i >= 0; i--) {
388            w = windows.get(i);
389            if ((w.mAttrs.type == TYPE_WALLPAPER)) {
390                if (result.topWallpaper == null || resetTopWallpaper) {
391                    result.setTopWallpaper(w, i);
392                    resetTopWallpaper = false;
393                }
394                continue;
395            }
396            resetTopWallpaper = true;
397            if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
398                // If this window's app token is hidden and not animating,
399                // it is of no interest to us.
400                if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) {
401                    if (DEBUG_WALLPAPER) Slog.v(TAG,
402                            "Skipping hidden and not animating token: " + w);
403                    continue;
404                }
405            }
406            if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen="
407                    + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState);
408
409            if (!inFreeformSpace) {
410                TaskStack stack = w.getStack();
411                inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
412            }
413
414            replacing |= w.mWillReplaceWindow;
415            keyguardGoingAwayWithWallpaper |= (w.mAppToken != null
416                    && w.mWinAnimator.mKeyguardGoingAwayWithWallpaper);
417
418            final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
419            if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
420                if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w);
421                result.setWallpaperTarget(w, i);
422                if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) {
423                    // The current wallpaper target is animating, so we'll look behind it for
424                    // another possible target and figure out what is going on later.
425                    if (DEBUG_WALLPAPER) Slog.v(TAG,
426                            "Win " + w + ": token animating, looking behind.");
427                    continue;
428                }
429                break;
430            } else if (w == winAnimator.mWindowDetachedWallpaper) {
431                windowDetachedI = i;
432            }
433        }
434
435        if (result.wallpaperTarget != null) {
436            return;
437        }
438
439        if (windowDetachedI >= 0) {
440            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
441                    "Found animating detached wallpaper activity: #" + windowDetachedI + "=" + w);
442            result.setWallpaperTarget(w, windowDetachedI);
443        } else if (inFreeformSpace || (replacing && mWallpaperTarget != null)) {
444            // In freeform mode we set the wallpaper as its own target, so we don't need an
445            // additional window to make it visible. When we are replacing a window and there was
446            // wallpaper before replacement, we want to keep the window until the new windows fully
447            // appear and can determine the visibility, to avoid flickering.
448            result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex);
449
450        } else if (keyguardGoingAwayWithWallpaper) {
451            // If the app is executing an animation because the keyguard is going away (and the
452            // keyguard was showing the wallpaper) keep the wallpaper during the animation so it
453            // doesn't flicker out by having it be its own target.
454            result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex);
455        }
456    }
457
458    /** Updates the target wallpaper if needed and returns true if an update happened. */
459    private boolean updateWallpaperWindowsTarget(
460            WindowList windows, FindWallpaperTargetResult result) {
461
462        WindowState wallpaperTarget = result.wallpaperTarget;
463        int wallpaperTargetIndex = result.wallpaperTargetIndex;
464
465        if (mWallpaperTarget == wallpaperTarget
466                || (mLowerWallpaperTarget != null && mLowerWallpaperTarget == wallpaperTarget)) {
467
468            if (mLowerWallpaperTarget != null) {
469                // Is it time to stop animating?
470                if (!mLowerWallpaperTarget.isAnimatingLw()
471                        || !mUpperWallpaperTarget.isAnimatingLw()) {
472                    if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
473                            "No longer animating wallpaper targets!");
474                    mLowerWallpaperTarget = null;
475                    mUpperWallpaperTarget = null;
476                    mWallpaperTarget = wallpaperTarget;
477                    return true;
478                }
479            }
480
481            return false;
482        }
483
484        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
485                "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget);
486
487        mLowerWallpaperTarget = null;
488        mUpperWallpaperTarget = null;
489
490        WindowState oldW = mWallpaperTarget;
491        mWallpaperTarget = wallpaperTarget;
492
493        if (wallpaperTarget == null || oldW == null) {
494            return true;
495        }
496
497        // Now what is happening...  if the current and new targets are animating,
498        // then we are in our super special mode!
499        boolean oldAnim = oldW.isAnimatingLw();
500        boolean foundAnim = wallpaperTarget.isAnimatingLw();
501        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
502                "New animation: " + foundAnim + " old animation: " + oldAnim);
503
504        if (!foundAnim || !oldAnim) {
505            return true;
506        }
507
508        int oldI = windows.indexOf(oldW);
509        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
510                "New i: " + wallpaperTargetIndex + " old i: " + oldI);
511
512        if (oldI < 0) {
513            return true;
514        }
515
516        final boolean newTargetHidden = wallpaperTarget.mAppToken != null
517                && wallpaperTarget.mAppToken.hiddenRequested;
518        final boolean oldTargetHidden = oldW.mAppToken != null
519                && oldW.mAppToken.hiddenRequested;
520
521        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old#" + oldI + "="
522                + oldW + " hidden=" + oldTargetHidden + " new#" + wallpaperTargetIndex + "="
523                + wallpaperTarget + " hidden=" + newTargetHidden);
524
525        // Set the upper and lower wallpaper targets correctly,
526        // and make sure that we are positioning the wallpaper below the lower.
527        if (wallpaperTargetIndex > oldI) {
528            // The new target is on top of the old one.
529            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target above old target.");
530            mUpperWallpaperTarget = wallpaperTarget;
531            mLowerWallpaperTarget = oldW;
532
533            wallpaperTarget = oldW;
534            wallpaperTargetIndex = oldI;
535        } else {
536            // The new target is below the old one.
537            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target below old target.");
538            mUpperWallpaperTarget = oldW;
539            mLowerWallpaperTarget = wallpaperTarget;
540        }
541
542        if (newTargetHidden && !oldTargetHidden) {
543            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Old wallpaper still the target.");
544            // Use the old target if new target is hidden but old target
545            // is not. If they're both hidden, still use the new target.
546            mWallpaperTarget = oldW;
547        } else if (newTargetHidden == oldTargetHidden
548                && !mService.mOpeningApps.contains(wallpaperTarget.mAppToken)
549                && (mService.mOpeningApps.contains(oldW.mAppToken)
550                || mService.mClosingApps.contains(oldW.mAppToken))) {
551            // If they're both hidden (or both not hidden), prefer the one that's currently in
552            // opening or closing app list, this allows transition selection logic to better
553            // determine the wallpaper status of opening/closing apps.
554            mWallpaperTarget = oldW;
555        }
556
557        result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
558        return true;
559    }
560
561    private boolean updateWallpaperWindowsTargetByLayer(WindowList windows,
562            FindWallpaperTargetResult result) {
563
564        WindowState wallpaperTarget = result.wallpaperTarget;
565        int wallpaperTargetIndex = result.wallpaperTargetIndex;
566        boolean visible = wallpaperTarget != null;
567
568        if (visible) {
569            // The window is visible to the compositor...but is it visible to the user?
570            // That is what the wallpaper cares about.
571            visible = isWallpaperVisible(wallpaperTarget);
572            if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
573
574            // If the wallpaper target is animating, we may need to copy its layer adjustment.
575            // Only do this if we are not transferring between two wallpaper targets.
576            mWallpaperAnimLayerAdjustment =
577                    (mLowerWallpaperTarget == null && wallpaperTarget.mAppToken != null)
578                            ? wallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0;
579
580            final int maxLayer = (mService.mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER)
581                    + TYPE_LAYER_OFFSET;
582
583            // Now w is the window we are supposed to be behind...  but we
584            // need to be sure to also be behind any of its attached windows,
585            // AND any starting window associated with it, AND below the
586            // maximum layer the policy allows for wallpapers.
587            while (wallpaperTargetIndex > 0) {
588                final WindowState wb = windows.get(wallpaperTargetIndex - 1);
589                final WindowState wbParentWindow = wb.getParentWindow();
590                final WindowState wallpaperParentWindow = wallpaperTarget.getParentWindow();
591                if (wb.mBaseLayer < maxLayer
592                        && wbParentWindow != wallpaperTarget
593                        && (wallpaperParentWindow == null || wbParentWindow != wallpaperParentWindow)
594                        && (wb.mAttrs.type != TYPE_APPLICATION_STARTING
595                                || wallpaperTarget.mToken == null
596                                || wb.mToken != wallpaperTarget.mToken)) {
597                    // This window is not related to the previous one in any
598                    // interesting way, so stop here.
599                    break;
600                }
601                wallpaperTarget = wb;
602                wallpaperTargetIndex--;
603            }
604        } else {
605            if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target");
606        }
607
608        result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
609        return visible;
610    }
611
612    private boolean updateWallpaperWindowsPlacement(WindowList windows,
613            WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) {
614
615        // TODO(multidisplay): Wallpapers on main screen only.
616        final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo();
617        final int dw = displayInfo.logicalWidth;
618        final int dh = displayInfo.logicalHeight;
619
620        // Start stepping backwards from here, ensuring that our wallpaper windows are correctly placed.
621        boolean changed = false;
622        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
623            final WindowToken token = mWallpaperTokens.get(curTokenNdx);
624            changed |= token.updateWallpaperWindowsPlacement(windows, wallpaperTarget,
625                    wallpaperTargetIndex, visible, dw, dh, mWallpaperAnimLayerAdjustment);
626        }
627
628        return changed;
629    }
630
631    boolean adjustWallpaperWindows(WindowList windows) {
632        mService.mRoot.mWallpaperMayChange = false;
633
634        // First find top-most window that has asked to be on top of the wallpaper;
635        // all wallpapers go behind it.
636        findWallpaperTarget(windows, mFindResults);
637        final boolean targetChanged = updateWallpaperWindowsTarget(windows, mFindResults);
638        final boolean visible = updateWallpaperWindowsTargetByLayer(windows, mFindResults);
639        WindowState wallpaperTarget = mFindResults.wallpaperTarget;
640        int wallpaperTargetIndex = mFindResults.wallpaperTargetIndex;
641
642        if (wallpaperTarget == null && mFindResults.topWallpaper != null) {
643            // There is no wallpaper target, so it goes at the bottom.
644            // We will assume it is the same place as last time, if known.
645            wallpaperTarget = mFindResults.topWallpaper;
646            wallpaperTargetIndex = mFindResults.topWallpaperIndex + 1;
647        } else {
648            // Okay i is the position immediately above the wallpaper.
649            // Look at what is below it for later.
650            wallpaperTarget = wallpaperTargetIndex > 0
651                    ? windows.get(wallpaperTargetIndex - 1) : null;
652        }
653
654        if (visible) {
655            if (mWallpaperTarget.mWallpaperX >= 0) {
656                mLastWallpaperX = mWallpaperTarget.mWallpaperX;
657                mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
658            }
659            if (mWallpaperTarget.mWallpaperY >= 0) {
660                mLastWallpaperY = mWallpaperTarget.mWallpaperY;
661                mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
662            }
663            if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
664                mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
665            }
666            if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
667                mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
668            }
669        }
670
671        final boolean changed = updateWallpaperWindowsPlacement(
672                windows, wallpaperTarget, wallpaperTargetIndex, visible);
673
674        if (targetChanged && DEBUG_WALLPAPER_LIGHT)  Slog.d(TAG, "New wallpaper: target="
675                + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
676                + mUpperWallpaperTarget);
677
678        return changed;
679    }
680
681    boolean processWallpaperDrawPendingTimeout() {
682        if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) {
683            mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT;
684            if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
685                    "*** WALLPAPER DRAW TIMEOUT");
686            return true;
687        }
688        return false;
689    }
690
691    boolean wallpaperTransitionReady() {
692        boolean transitionReady = true;
693        boolean wallpaperReady = true;
694        for (int curTokenIndex = mWallpaperTokens.size() - 1;
695                curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) {
696            final WindowToken token = mWallpaperTokens.get(curTokenIndex);
697            if (token.hasVisibleNotDrawnWallpaper()) {
698                // We've told this wallpaper to be visible, but it is not drawn yet
699                wallpaperReady = false;
700                if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
701                    // wait for this wallpaper until it is drawn or timeout
702                    transitionReady = false;
703                }
704                if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
705                    mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
706                    mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
707                    mService.mH.sendEmptyMessageDelayed(WALLPAPER_DRAW_PENDING_TIMEOUT,
708                            WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
709                }
710                if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
711                        "Wallpaper should be visible but has not been drawn yet. " +
712                                "mWallpaperDrawState=" + mWallpaperDrawState);
713                break;
714            }
715        }
716        if (wallpaperReady) {
717            mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
718            mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
719        }
720
721        return transitionReady;
722    }
723
724    /**
725     * Adjusts the wallpaper windows if the input display has a pending wallpaper layout or one of
726     * the opening apps should be a wallpaper target.
727     */
728    void adjustWallpaperWindowsForAppTransitionIfNeeded(DisplayContent dc,
729            ArraySet<AppWindowToken> openingApps) {
730        boolean adjust = false;
731        if ((dc.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
732            adjust = true;
733        } else {
734            for (int i = openingApps.size() - 1; i >= 0; --i) {
735                final AppWindowToken token = openingApps.valueAt(i);
736                if (token.windowsCanBeWallpaperTarget()) {
737                    adjust = true;
738                    break;
739                }
740            }
741        }
742
743        if (adjust) {
744            dc.adjustWallpaperWindows();
745        }
746    }
747
748    void addWallpaperToken(WindowToken token) {
749        mWallpaperTokens.add(token);
750    }
751
752    void removeWallpaperToken(WindowToken token) {
753        mWallpaperTokens.remove(token);
754    }
755
756    void dump(PrintWriter pw, String prefix) {
757        pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
758        if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
759            pw.print(prefix); pw.print("mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
760            pw.print(prefix); pw.print("mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
761        }
762        pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX);
763        pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
764        if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE
765                || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
766            pw.print(prefix);
767            pw.print("mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX);
768            pw.print(" mLastWallpaperDisplayOffsetY="); pw.println(mLastWallpaperDisplayOffsetY);
769        }
770
771        if (mWallpaperAnimLayerAdjustment != 0) {
772            pw.println(prefix + "mWallpaperAnimLayerAdjustment=" + mWallpaperAnimLayerAdjustment);
773        }
774    }
775
776    void dumpTokens(PrintWriter pw, String prefix, boolean dumpAll) {
777        if (!mWallpaperTokens.isEmpty()) {
778            pw.println();
779            pw.print(prefix); pw.println("Wallpaper tokens:");
780            for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
781                WindowToken token = mWallpaperTokens.get(i);
782                pw.print(prefix); pw.print("Wallpaper #"); pw.print(i);
783                pw.print(' '); pw.print(token);
784                if (dumpAll) {
785                    pw.println(':');
786                    token.dump(pw, "    ");
787                } else {
788                    pw.println();
789                }
790            }
791        }
792    }
793
794    /** Helper class for storing the results of a wallpaper target find operation. */
795    final private static class FindWallpaperTargetResult {
796        int topWallpaperIndex = 0;
797        WindowState topWallpaper = null;
798        int wallpaperTargetIndex = 0;
799        WindowState wallpaperTarget = null;
800
801        void setTopWallpaper(WindowState win, int index) {
802            topWallpaper = win;
803            topWallpaperIndex = index;
804        }
805
806        void setWallpaperTarget(WindowState win, int index) {
807            wallpaperTarget = win;
808            wallpaperTargetIndex = index;
809        }
810
811        void reset() {
812            topWallpaperIndex = 0;
813            topWallpaper = null;
814            wallpaperTargetIndex = 0;
815            wallpaperTarget = null;
816        }
817    }
818}
819