OSDN Git Service

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