WallpaperController.java revision f4ebe2e2ccfcbce9de7ad0c3b5399971201f66fd
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.ViewGroup.LayoutParams.MATCH_PARENT;
21import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
22import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
23import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
24import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
25
26import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
27import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
28import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
29import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
30import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
31import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
32import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT;
33
34import android.os.Bundle;
35import android.os.Debug;
36import android.os.IBinder;
37import android.os.RemoteException;
38import android.os.SystemClock;
39import android.util.ArraySet;
40import android.util.Slog;
41import android.view.DisplayInfo;
42import android.view.WindowManager;
43import android.view.animation.Animation;
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 = TAG_WITH_CLASS_NAME ? "WallpaperController" : TAG_WM;
54    final private WindowManagerService mService;
55
56    private final ArrayList<WallpaperWindowToken> 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 previous wallpaper target.
63    private WindowState mPrevWallpaperTarget = null;
64
65    private int mWallpaperAnimLayerAdjustment;
66
67    private float mLastWallpaperX = -1;
68    private float mLastWallpaperY = -1;
69    private float mLastWallpaperXStep = -1;
70    private float mLastWallpaperYStep = -1;
71    private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
72    private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
73
74    // This is set when we are waiting for a wallpaper to tell us it is done
75    // changing its scroll position.
76    private WindowState mWaitingOnWallpaper;
77
78    // The last time we had a timeout when waiting for a wallpaper.
79    private long mLastWallpaperTimeoutTime;
80    // We give a wallpaper up to 150ms to finish scrolling.
81    private static final long WALLPAPER_TIMEOUT = 150;
82    // Time we wait after a timeout before trying to wait again.
83    private static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
84
85    // Set to the wallpaper window we would like to hide once the transition animations are done.
86    // This is useful in cases where we don't want the wallpaper to be hidden when the close app
87    // is a wallpaper target and is done animating out, but the opening app isn't a wallpaper
88    // target and isn't done animating in.
89    WindowState mDeferredHideWallpaper = null;
90
91    // We give a wallpaper up to 500ms to finish drawing before playing app transitions.
92    private static final long WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION = 500;
93    private static final int WALLPAPER_DRAW_NORMAL = 0;
94    private static final int WALLPAPER_DRAW_PENDING = 1;
95    private static final int WALLPAPER_DRAW_TIMEOUT = 2;
96    private int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
97
98    private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult();
99
100    public WallpaperController(WindowManagerService service) {
101        mService = service;
102    }
103
104    WindowState getWallpaperTarget() {
105        return mWallpaperTarget;
106    }
107
108    boolean isWallpaperTarget(WindowState win) {
109        return win == mWallpaperTarget;
110    }
111
112    boolean isBelowWallpaperTarget(WindowState win) {
113        return mWallpaperTarget != null && mWallpaperTarget.mLayer >= win.mBaseLayer;
114    }
115
116    boolean isWallpaperVisible() {
117        return isWallpaperVisible(mWallpaperTarget);
118    }
119
120    /**
121     * Starts {@param a} on all wallpaper windows.
122     */
123    void startWallpaperAnimation(Animation a) {
124        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
125            final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
126            token.startAnimation(a);
127        }
128    }
129
130    private boolean isWallpaperVisible(WindowState wallpaperTarget) {
131        if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
132                + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
133                + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
134                ? wallpaperTarget.mAppToken.mAppAnimator.animation : null)
135                + " prev=" + mPrevWallpaperTarget);
136        return (wallpaperTarget != null
137                && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null
138                && wallpaperTarget.mAppToken.mAppAnimator.animation != null)))
139                || mPrevWallpaperTarget != null;
140    }
141
142    boolean isWallpaperTargetAnimating() {
143        return mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimationSet()
144                && !mWallpaperTarget.mWinAnimator.isDummyAnimation();
145    }
146
147    void updateWallpaperVisibility() {
148        final boolean visible = isWallpaperVisible(mWallpaperTarget);
149
150        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
151            final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
152            token.updateWallpaperVisibility(visible);
153        }
154    }
155
156    void hideDeferredWallpapersIfNeeded() {
157        if (mDeferredHideWallpaper != null) {
158            hideWallpapers(mDeferredHideWallpaper);
159            mDeferredHideWallpaper = null;
160        }
161    }
162
163    void hideWallpapers(final WindowState winGoingAway) {
164        if (mWallpaperTarget != null
165                && (mWallpaperTarget != winGoingAway || mPrevWallpaperTarget != null)) {
166            return;
167        }
168        if (mService.mAppTransition.isRunning()) {
169            // Defer hiding the wallpaper when app transition is running until the animations
170            // are done.
171            mDeferredHideWallpaper = winGoingAway;
172            return;
173        }
174
175        final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway);
176        for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
177            final WallpaperWindowToken token = mWallpaperTokens.get(i);
178            token.hideWallpaperToken(wasDeferred, "hideWallpapers");
179            if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token
180                    + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev="
181                    + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, "  "));
182        }
183    }
184
185    boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) {
186        boolean rawChanged = false;
187        // Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to
188        // match the behavior of most Launchers
189        float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f;
190        float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX;
191        float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
192        int availw = wallpaperWin.mFrame.right - wallpaperWin.mFrame.left - dw;
193        int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
194        if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
195            offset += mLastWallpaperDisplayOffsetX;
196        }
197        boolean changed = wallpaperWin.mXOffset != offset;
198        if (changed) {
199            if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset);
200            wallpaperWin.mXOffset = offset;
201        }
202        if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
203            wallpaperWin.mWallpaperX = wpx;
204            wallpaperWin.mWallpaperXStep = wpxs;
205            rawChanged = true;
206        }
207
208        float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
209        float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
210        int availh = wallpaperWin.mFrame.bottom - wallpaperWin.mFrame.top - dh;
211        offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0;
212        if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
213            offset += mLastWallpaperDisplayOffsetY;
214        }
215        if (wallpaperWin.mYOffset != offset) {
216            if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset);
217            changed = true;
218            wallpaperWin.mYOffset = offset;
219        }
220        if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
221            wallpaperWin.mWallpaperY = wpy;
222            wallpaperWin.mWallpaperYStep = wpys;
223            rawChanged = true;
224        }
225
226        if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
227                WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
228            try {
229                if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset "
230                        + wallpaperWin + " x=" + wallpaperWin.mWallpaperX
231                        + " y=" + wallpaperWin.mWallpaperY);
232                if (sync) {
233                    mWaitingOnWallpaper = wallpaperWin;
234                }
235                wallpaperWin.mClient.dispatchWallpaperOffsets(
236                        wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY,
237                        wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync);
238                if (sync) {
239                    if (mWaitingOnWallpaper != null) {
240                        long start = SystemClock.uptimeMillis();
241                        if ((mLastWallpaperTimeoutTime + WALLPAPER_TIMEOUT_RECOVERY)
242                                < start) {
243                            try {
244                                if (DEBUG_WALLPAPER) Slog.v(TAG,
245                                        "Waiting for offset complete...");
246                                mService.mWindowMap.wait(WALLPAPER_TIMEOUT);
247                            } catch (InterruptedException e) {
248                            }
249                            if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!");
250                            if ((start + WALLPAPER_TIMEOUT) < SystemClock.uptimeMillis()) {
251                                Slog.i(TAG, "Timeout waiting for wallpaper to offset: "
252                                        + wallpaperWin);
253                                mLastWallpaperTimeoutTime = start;
254                            }
255                        }
256                        mWaitingOnWallpaper = null;
257                    }
258                }
259            } catch (RemoteException e) {
260            }
261        }
262
263        return changed;
264    }
265
266    void setWindowWallpaperPosition(
267            WindowState window, float x, float y, float xStep, float yStep) {
268        if (window.mWallpaperX != x || window.mWallpaperY != y)  {
269            window.mWallpaperX = x;
270            window.mWallpaperY = y;
271            window.mWallpaperXStep = xStep;
272            window.mWallpaperYStep = yStep;
273            updateWallpaperOffsetLocked(window, true);
274        }
275    }
276
277    void setWindowWallpaperDisplayOffset(WindowState window, int x, int y) {
278        if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y)  {
279            window.mWallpaperDisplayOffsetX = x;
280            window.mWallpaperDisplayOffsetY = y;
281            updateWallpaperOffsetLocked(window, true);
282        }
283    }
284
285    Bundle sendWindowWallpaperCommand(
286            WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) {
287        if (window == mWallpaperTarget || window == mPrevWallpaperTarget) {
288            boolean doWait = sync;
289            for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
290                final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
291                token.sendWindowWallpaperCommand(action, x, y, z, extras, sync);
292            }
293
294            if (doWait) {
295                // TODO: Need to wait for result.
296            }
297        }
298
299        return null;
300    }
301
302    private void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
303        final DisplayContent displayContent = changingTarget.getDisplayContent();
304        if (displayContent == null) {
305            return;
306        }
307        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
308        final int dw = displayInfo.logicalWidth;
309        final int dh = displayInfo.logicalHeight;
310
311        WindowState target = mWallpaperTarget;
312        if (target != null) {
313            if (target.mWallpaperX >= 0) {
314                mLastWallpaperX = target.mWallpaperX;
315            } else if (changingTarget.mWallpaperX >= 0) {
316                mLastWallpaperX = changingTarget.mWallpaperX;
317            }
318            if (target.mWallpaperY >= 0) {
319                mLastWallpaperY = target.mWallpaperY;
320            } else if (changingTarget.mWallpaperY >= 0) {
321                mLastWallpaperY = changingTarget.mWallpaperY;
322            }
323            if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
324                mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX;
325            } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
326                mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX;
327            }
328            if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
329                mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY;
330            } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
331                mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY;
332            }
333            if (target.mWallpaperXStep >= 0) {
334                mLastWallpaperXStep = target.mWallpaperXStep;
335            } else if (changingTarget.mWallpaperXStep >= 0) {
336                mLastWallpaperXStep = changingTarget.mWallpaperXStep;
337            }
338            if (target.mWallpaperYStep >= 0) {
339                mLastWallpaperYStep = target.mWallpaperYStep;
340            } else if (changingTarget.mWallpaperYStep >= 0) {
341                mLastWallpaperYStep = changingTarget.mWallpaperYStep;
342            }
343        }
344
345        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
346            mWallpaperTokens.get(curTokenNdx).updateWallpaperOffset(dw, dh, sync);
347        }
348    }
349
350    void clearLastWallpaperTimeoutTime() {
351        mLastWallpaperTimeoutTime = 0;
352    }
353
354    void wallpaperCommandComplete(IBinder window) {
355        if (mWaitingOnWallpaper != null &&
356                mWaitingOnWallpaper.mClient.asBinder() == window) {
357            mWaitingOnWallpaper = null;
358            mService.mWindowMap.notifyAll();
359        }
360    }
361
362    void wallpaperOffsetsComplete(IBinder window) {
363        if (mWaitingOnWallpaper != null &&
364                mWaitingOnWallpaper.mClient.asBinder() == window) {
365            mWaitingOnWallpaper = null;
366            mService.mWindowMap.notifyAll();
367        }
368    }
369
370    int getAnimLayerAdjustment() {
371        return mWallpaperAnimLayerAdjustment;
372    }
373
374    private void findWallpaperTarget(DisplayContent dc , FindWallpaperTargetResult result) {
375        final WindowAnimator winAnimator = mService.mAnimator;
376        result.reset();
377        if (mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
378            // In freeform mode we set the wallpaper as its own target, so we don't need an
379            // additional window to make it visible.
380            result.setUseTopWallpaperAsTarget(true);
381        }
382
383        dc.forAllWindows(w -> {
384            if ((w.mAttrs.type == TYPE_WALLPAPER)) {
385                if (result.topWallpaper == null || result.resetTopWallpaper) {
386                    result.setTopWallpaper(w);
387                    result.resetTopWallpaper = false;
388                }
389                return false;
390            }
391
392            result.resetTopWallpaper = true;
393            if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
394                // If this window's app token is hidden and not animating,
395                // it is of no interest to us.
396                if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) {
397                    if (DEBUG_WALLPAPER) Slog.v(TAG,
398                            "Skipping hidden and not animating token: " + w);
399                    return false;
400                }
401            }
402            if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen()
403                    + " mDrawState=" + w.mWinAnimator.mDrawState);
404
405            if (w.mWillReplaceWindow && mWallpaperTarget == null
406                    && !result.useTopWallpaperAsTarget) {
407                // When we are replacing a window and there was wallpaper before replacement, we
408                // want to keep the window until the new windows fully appear and can determine the
409                // visibility, to avoid flickering.
410                result.setUseTopWallpaperAsTarget(true);
411            }
412
413            final boolean keyguardGoingAwayWithWallpaper = (w.mAppToken != null
414                    && AppTransition.isKeyguardGoingAwayTransit(
415                            w.mAppToken.mAppAnimator.getTransit())
416                    && (w.mAppToken.mAppAnimator.getTransitFlags()
417                            & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
418
419            boolean needsShowWhenLockedWallpaper = false;
420            if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
421                    && mService.mPolicy.isKeyguardLocked()
422                    && mService.mPolicy.isKeyguardOccluded()) {
423                // The lowest show when locked window decides whether we need to put the wallpaper
424                // behind.
425                needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
426                        || (w.mAppToken != null && !w.mAppToken.fillsParent());
427            }
428
429            if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) {
430                // Keep the wallpaper during Keyguard exit but also when it's needed for a
431                // non-fullscreen show when locked activity.
432                result.setUseTopWallpaperAsTarget(true);
433            }
434
435            final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
436            if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
437                if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w);
438                result.setWallpaperTarget(w);
439                if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) {
440                    // The current wallpaper target is animating, so we'll look behind it for
441                    // another possible target and figure out what is going on later.
442                    if (DEBUG_WALLPAPER) Slog.v(TAG,
443                            "Win " + w + ": token animating, looking behind.");
444                }
445                // Found a target! End search.
446                return true;
447            } else if (w == winAnimator.mWindowDetachedWallpaper) {
448                if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
449                        "Found animating detached wallpaper target win: " + w);
450                result.setUseTopWallpaperAsTarget(true);
451            }
452            return false;
453        }, true /* traverseTopToBottom */);
454
455        if (result.wallpaperTarget == null && result.useTopWallpaperAsTarget) {
456            result.setWallpaperTarget(result.topWallpaper);
457        }
458    }
459
460    private boolean isFullscreen(WindowManager.LayoutParams attrs) {
461        return attrs.x == 0 && attrs.y == 0
462                && attrs.width == MATCH_PARENT && attrs.height == MATCH_PARENT;
463    }
464
465    /** Updates the target wallpaper if needed and returns true if an update happened. */
466    private void updateWallpaperWindowsTarget(DisplayContent dc,
467            FindWallpaperTargetResult result) {
468
469        WindowState wallpaperTarget = result.wallpaperTarget;
470
471        if (mWallpaperTarget == wallpaperTarget
472                || (mPrevWallpaperTarget != null && mPrevWallpaperTarget == wallpaperTarget)) {
473
474            if (mPrevWallpaperTarget == null) {
475                return;
476            }
477
478            // Is it time to stop animating?
479            if (!mPrevWallpaperTarget.isAnimatingLw()) {
480                if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!");
481                mPrevWallpaperTarget = null;
482                mWallpaperTarget = wallpaperTarget;
483            }
484            return;
485        }
486
487        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
488                "New wallpaper target: " + wallpaperTarget + " prevTarget: " + mWallpaperTarget);
489
490        mPrevWallpaperTarget = null;
491
492        final WindowState prevWallpaperTarget = mWallpaperTarget;
493        mWallpaperTarget = wallpaperTarget;
494
495        if (wallpaperTarget == null || prevWallpaperTarget == null) {
496            return;
497        }
498
499        // Now what is happening...  if the current and new targets are animating,
500        // then we are in our super special mode!
501        boolean oldAnim = prevWallpaperTarget.isAnimatingLw();
502        boolean foundAnim = wallpaperTarget.isAnimatingLw();
503        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
504                "New animation: " + foundAnim + " old animation: " + oldAnim);
505
506        if (!foundAnim || !oldAnim) {
507            return;
508        }
509
510        if (dc.getWindow(w -> w == prevWallpaperTarget) == null) {
511            return;
512        }
513
514        final boolean newTargetHidden = wallpaperTarget.mAppToken != null
515                && wallpaperTarget.mAppToken.hiddenRequested;
516        final boolean oldTargetHidden = prevWallpaperTarget.mAppToken != null
517                && prevWallpaperTarget.mAppToken.hiddenRequested;
518
519        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: "
520                + prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + wallpaperTarget
521                + " hidden=" + newTargetHidden);
522
523        mPrevWallpaperTarget = prevWallpaperTarget;
524
525        if (newTargetHidden && !oldTargetHidden) {
526            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Old wallpaper still the target.");
527            // Use the old target if new target is hidden but old target
528            // is not. If they're both hidden, still use the new target.
529            mWallpaperTarget = prevWallpaperTarget;
530        } else if (newTargetHidden == oldTargetHidden
531                && !mService.mOpeningApps.contains(wallpaperTarget.mAppToken)
532                && (mService.mOpeningApps.contains(prevWallpaperTarget.mAppToken)
533                || mService.mClosingApps.contains(prevWallpaperTarget.mAppToken))) {
534            // If they're both hidden (or both not hidden), prefer the one that's currently in
535            // opening or closing app list, this allows transition selection logic to better
536            // determine the wallpaper status of opening/closing apps.
537            mWallpaperTarget = prevWallpaperTarget;
538        }
539
540        result.setWallpaperTarget(wallpaperTarget);
541    }
542
543    private void updateWallpaperTokens(boolean visible) {
544        for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
545            final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
546            token.updateWallpaperWindows(visible, mWallpaperAnimLayerAdjustment);
547        }
548    }
549
550    void adjustWallpaperWindows(DisplayContent dc) {
551        mService.mRoot.mWallpaperMayChange = false;
552
553        // First find top-most window that has asked to be on top of the wallpaper;
554        // all wallpapers go behind it.
555        findWallpaperTarget(dc, mFindResults);
556        updateWallpaperWindowsTarget(dc, mFindResults);
557
558        // The window is visible to the compositor...but is it visible to the user?
559        // That is what the wallpaper cares about.
560        final boolean visible = mWallpaperTarget != null && isWallpaperVisible(mWallpaperTarget);
561        if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
562
563        if (visible) {
564            // If the wallpaper target is animating, we may need to copy its layer adjustment.
565            // Only do this if we are not transferring between two wallpaper targets.
566            mWallpaperAnimLayerAdjustment =
567                    (mPrevWallpaperTarget == null && mWallpaperTarget.mAppToken != null)
568                            ? mWallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0;
569
570            if (mWallpaperTarget.mWallpaperX >= 0) {
571                mLastWallpaperX = mWallpaperTarget.mWallpaperX;
572                mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
573            }
574            if (mWallpaperTarget.mWallpaperY >= 0) {
575                mLastWallpaperY = mWallpaperTarget.mWallpaperY;
576                mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
577            }
578            if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
579                mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
580            }
581            if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
582                mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
583            }
584        }
585
586        updateWallpaperTokens(visible);
587
588        if (DEBUG_WALLPAPER_LIGHT)  Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
589                + " prev=" + mPrevWallpaperTarget);
590    }
591
592    boolean processWallpaperDrawPendingTimeout() {
593        if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) {
594            mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT;
595            if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
596                    "*** WALLPAPER DRAW TIMEOUT");
597            return true;
598        }
599        return false;
600    }
601
602    boolean wallpaperTransitionReady() {
603        boolean transitionReady = true;
604        boolean wallpaperReady = true;
605        for (int curTokenIndex = mWallpaperTokens.size() - 1;
606                curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) {
607            final WallpaperWindowToken token = mWallpaperTokens.get(curTokenIndex);
608            if (token.hasVisibleNotDrawnWallpaper()) {
609                // We've told this wallpaper to be visible, but it is not drawn yet
610                wallpaperReady = false;
611                if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
612                    // wait for this wallpaper until it is drawn or timeout
613                    transitionReady = false;
614                }
615                if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
616                    mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
617                    mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
618                    mService.mH.sendEmptyMessageDelayed(WALLPAPER_DRAW_PENDING_TIMEOUT,
619                            WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
620                }
621                if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
622                        "Wallpaper should be visible but has not been drawn yet. " +
623                                "mWallpaperDrawState=" + mWallpaperDrawState);
624                break;
625            }
626        }
627        if (wallpaperReady) {
628            mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
629            mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
630        }
631
632        return transitionReady;
633    }
634
635    /**
636     * Adjusts the wallpaper windows if the input display has a pending wallpaper layout or one of
637     * the opening apps should be a wallpaper target.
638     */
639    void adjustWallpaperWindowsForAppTransitionIfNeeded(DisplayContent dc,
640            ArraySet<AppWindowToken> openingApps) {
641        boolean adjust = false;
642        if ((dc.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
643            adjust = true;
644        } else {
645            for (int i = openingApps.size() - 1; i >= 0; --i) {
646                final AppWindowToken token = openingApps.valueAt(i);
647                if (token.windowsCanBeWallpaperTarget()) {
648                    adjust = true;
649                    break;
650                }
651            }
652        }
653
654        if (adjust) {
655            adjustWallpaperWindows(dc);
656        }
657    }
658
659    void addWallpaperToken(WallpaperWindowToken token) {
660        mWallpaperTokens.add(token);
661    }
662
663    void removeWallpaperToken(WallpaperWindowToken token) {
664        mWallpaperTokens.remove(token);
665    }
666
667    void dump(PrintWriter pw, String prefix) {
668        pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
669        if (mPrevWallpaperTarget != null) {
670            pw.print(prefix); pw.print("mPrevWallpaperTarget="); pw.println(mPrevWallpaperTarget);
671        }
672        pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX);
673        pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
674        if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE
675                || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
676            pw.print(prefix);
677            pw.print("mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX);
678            pw.print(" mLastWallpaperDisplayOffsetY="); pw.println(mLastWallpaperDisplayOffsetY);
679        }
680
681        if (mWallpaperAnimLayerAdjustment != 0) {
682            pw.println(prefix + "mWallpaperAnimLayerAdjustment=" + mWallpaperAnimLayerAdjustment);
683        }
684    }
685
686    void dumpTokens(PrintWriter pw, String prefix, boolean dumpAll) {
687        if (!mWallpaperTokens.isEmpty()) {
688            pw.println();
689            pw.print(prefix); pw.println("Wallpaper tokens:");
690            for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
691                WindowToken token = mWallpaperTokens.get(i);
692                pw.print(prefix); pw.print("Wallpaper #"); pw.print(i);
693                pw.print(' '); pw.print(token);
694                if (dumpAll) {
695                    pw.println(':');
696                    token.dump(pw, "    ");
697                } else {
698                    pw.println();
699                }
700            }
701        }
702    }
703
704    /** Helper class for storing the results of a wallpaper target find operation. */
705    final private static class FindWallpaperTargetResult {
706        WindowState topWallpaper = null;
707        boolean useTopWallpaperAsTarget = false;
708        WindowState wallpaperTarget = null;
709        boolean resetTopWallpaper = false;
710
711        void setTopWallpaper(WindowState win) {
712            topWallpaper = win;
713        }
714
715        void setWallpaperTarget(WindowState win) {
716            wallpaperTarget = win;
717        }
718
719        void setUseTopWallpaperAsTarget(boolean topWallpaperAsTarget) {
720            useTopWallpaperAsTarget = topWallpaperAsTarget;
721        }
722
723        void reset() {
724            topWallpaper = null;
725            wallpaperTarget = null;
726            useTopWallpaperAsTarget = false;
727            resetTopWallpaper = false;
728        }
729    }
730}
731