1 /*
2  * Copyright (C) 2014 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.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
20 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
21 
22 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
23 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
24 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
25 import static com.android.server.wm.WindowManagerService.DEBUG_KEYGUARD;
26 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION;
27 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
28 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
29 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
30 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_ACTION_PENDING;
31 
32 import android.content.Context;
33 import android.os.RemoteException;
34 import android.util.Slog;
35 import android.util.SparseArray;
36 import android.util.TimeUtils;
37 import android.view.Display;
38 import android.view.SurfaceControl;
39 import android.view.WindowManagerPolicy;
40 import android.view.animation.AlphaAnimation;
41 import android.view.animation.Animation;
42 import android.view.Choreographer;
43 
44 import com.android.server.wm.WindowManagerService.LayoutFields;
45 
46 import java.io.PrintWriter;
47 import java.util.ArrayList;
48 
49 /**
50  * Singleton class that carries out the animations and Surface operations in a separate task
51  * on behalf of WindowManagerService.
52  */
53 public class WindowAnimator {
54     private static final String TAG = "WindowAnimator";
55 
56     /** How long to give statusbar to clear the private keyguard flag when animating out */
57     private static final long KEYGUARD_ANIM_TIMEOUT_MS = 1000;
58 
59     final WindowManagerService mService;
60     final Context mContext;
61     final WindowManagerPolicy mPolicy;
62 
63     /** Is any window animating? */
64     boolean mAnimating;
65 
66     /** Is any app window animating? */
67     boolean mAppWindowAnimating;
68 
69     final Choreographer.FrameCallback mAnimationFrameCallback;
70 
71     /** Time of current animation step. Reset on each iteration */
72     long mCurrentTime;
73 
74     /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
75      * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
76     private int mAnimTransactionSequence;
77 
78     /** Window currently running an animation that has requested it be detached
79      * from the wallpaper.  This means we need to ensure the wallpaper is
80      * visible behind it in case it animates in a way that would allow it to be
81      * seen. If multiple windows satisfy this, use the lowest window. */
82     WindowState mWindowDetachedWallpaper = null;
83 
84     int mBulkUpdateParams = 0;
85     Object mLastWindowFreezeSource;
86 
87     SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
88             new SparseArray<DisplayContentsAnimator>(2);
89 
90     boolean mInitialized = false;
91 
92     boolean mKeyguardGoingAway;
93     boolean mKeyguardGoingAwayToNotificationShade;
94     boolean mKeyguardGoingAwayDisableWindowAnimations;
95 
96     /** Use one animation for all entering activities after keyguard is dismissed. */
97     Animation mPostKeyguardExitAnimation;
98 
99     // forceHiding states.
100     static final int KEYGUARD_NOT_SHOWN     = 0;
101     static final int KEYGUARD_SHOWN         = 1;
102     static final int KEYGUARD_ANIMATING_OUT = 2;
103     int mForceHiding = KEYGUARD_NOT_SHOWN;
104 
forceHidingToString()105     private String forceHidingToString() {
106         switch (mForceHiding) {
107             case KEYGUARD_NOT_SHOWN:    return "KEYGUARD_NOT_SHOWN";
108             case KEYGUARD_SHOWN:        return "KEYGUARD_SHOWN";
109             case KEYGUARD_ANIMATING_OUT:return "KEYGUARD_ANIMATING_OUT";
110             default: return "KEYGUARD STATE UNKNOWN " + mForceHiding;
111         }
112     }
113 
WindowAnimator(final WindowManagerService service)114     WindowAnimator(final WindowManagerService service) {
115         mService = service;
116         mContext = service.mContext;
117         mPolicy = service.mPolicy;
118 
119         mAnimationFrameCallback = new Choreographer.FrameCallback() {
120             public void doFrame(long frameTimeNs) {
121                 synchronized (mService.mWindowMap) {
122                     mService.mAnimationScheduled = false;
123                     animateLocked(frameTimeNs);
124                 }
125             }
126         };
127     }
128 
addDisplayLocked(final int displayId)129     void addDisplayLocked(final int displayId) {
130         // Create the DisplayContentsAnimator object by retrieving it.
131         getDisplayContentsAnimatorLocked(displayId);
132         if (displayId == Display.DEFAULT_DISPLAY) {
133             mInitialized = true;
134         }
135     }
136 
removeDisplayLocked(final int displayId)137     void removeDisplayLocked(final int displayId) {
138         final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
139         if (displayAnimator != null) {
140             if (displayAnimator.mScreenRotationAnimation != null) {
141                 displayAnimator.mScreenRotationAnimation.kill();
142                 displayAnimator.mScreenRotationAnimation = null;
143             }
144         }
145 
146         mDisplayContentsAnimators.delete(displayId);
147     }
148 
updateAppWindowsLocked(int displayId)149     private void updateAppWindowsLocked(int displayId) {
150         ArrayList<TaskStack> stacks = mService.getDisplayContentLocked(displayId).getStacks();
151         for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
152             final TaskStack stack = stacks.get(stackNdx);
153             final ArrayList<Task> tasks = stack.getTasks();
154             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
155                 final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
156                 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
157                     final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
158                     appAnimator.wasAnimating = appAnimator.animating;
159                     if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
160                         appAnimator.animating = true;
161                         mAnimating = mAppWindowAnimating = true;
162                     } else if (appAnimator.wasAnimating) {
163                         // stopped animating, do one more pass through the layout
164                         setAppLayoutChanges(appAnimator,
165                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
166                                 "appToken " + appAnimator.mAppToken + " done", displayId);
167                         if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
168                                 "updateWindowsApps...: done animating " + appAnimator.mAppToken);
169                     }
170                 }
171             }
172 
173             final AppTokenList exitingAppTokens = stack.mExitingAppTokens;
174             final int exitingCount = exitingAppTokens.size();
175             for (int i = 0; i < exitingCount; i++) {
176                 final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
177                 appAnimator.wasAnimating = appAnimator.animating;
178                 if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
179                     mAnimating = mAppWindowAnimating = true;
180                 } else if (appAnimator.wasAnimating) {
181                     // stopped animating, do one more pass through the layout
182                     setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
183                         "exiting appToken " + appAnimator.mAppToken + " done", displayId);
184                     if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
185                             "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
186                 }
187             }
188         }
189     }
190 
shouldForceHide(WindowState win)191     private boolean shouldForceHide(WindowState win) {
192         final WindowState imeTarget = mService.mInputMethodTarget;
193         final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleNow() &&
194                 ((imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0
195                         || !mPolicy.canBeForceHidden(imeTarget, imeTarget.mAttrs));
196 
197         final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
198         final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
199                 null : winShowWhenLocked.mAppToken;
200 
201         boolean allowWhenLocked = false;
202         // Show IME over the keyguard if the target allows it
203         allowWhenLocked |= (win.mIsImWindow || imeTarget == win) && showImeOverKeyguard;
204         // Show SHOW_WHEN_LOCKED windows that turn on the screen
205         allowWhenLocked |= (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && win.mTurnOnScreen;
206 
207         if (appShowWhenLocked != null) {
208             allowWhenLocked |= appShowWhenLocked == win.mAppToken
209                     // Show all SHOW_WHEN_LOCKED windows while they're animating
210                     || (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && win.isAnimatingLw()
211                     // Show error dialogs over apps that dismiss keyguard.
212                     || (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
213         }
214 
215         // Only hide windows if the keyguard is active and not animating away.
216         boolean keyguardOn = mPolicy.isKeyguardShowingOrOccluded()
217                 && mForceHiding != KEYGUARD_ANIMATING_OUT;
218         return keyguardOn && !allowWhenLocked && (win.getDisplayId() == Display.DEFAULT_DISPLAY);
219     }
220 
updateWindowsLocked(final int displayId)221     private void updateWindowsLocked(final int displayId) {
222         ++mAnimTransactionSequence;
223 
224         final WindowList windows = mService.getWindowListLocked(displayId);
225 
226         if (mKeyguardGoingAway) {
227             for (int i = windows.size() - 1; i >= 0; i--) {
228                 WindowState win = windows.get(i);
229                 if (!mPolicy.isKeyguardHostWindow(win.mAttrs)) {
230                     continue;
231                 }
232                 final WindowStateAnimator winAnimator = win.mWinAnimator;
233                 if ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
234                     if (!winAnimator.mAnimating) {
235                         if (DEBUG_KEYGUARD) Slog.d(TAG,
236                                 "updateWindowsLocked: creating delay animation");
237 
238                         // Create a new animation to delay until keyguard is gone on its own.
239                         winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
240                         winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS);
241                         winAnimator.mAnimationIsEntrance = false;
242                         winAnimator.mAnimationStartTime = -1;
243                         winAnimator.mKeyguardGoingAwayAnimation = true;
244                     }
245                 } else {
246                     if (DEBUG_KEYGUARD) Slog.d(TAG,
247                             "updateWindowsLocked: StatusBar is no longer keyguard");
248                     mKeyguardGoingAway = false;
249                     winAnimator.clearAnimation();
250                 }
251                 break;
252             }
253         }
254 
255         mForceHiding = KEYGUARD_NOT_SHOWN;
256 
257         boolean wallpaperInUnForceHiding = false;
258         boolean startingInUnForceHiding = false;
259         ArrayList<WindowStateAnimator> unForceHiding = null;
260         WindowState wallpaper = null;
261         for (int i = windows.size() - 1; i >= 0; i--) {
262             WindowState win = windows.get(i);
263             WindowStateAnimator winAnimator = win.mWinAnimator;
264             final int flags = win.mAttrs.flags;
265             boolean canBeForceHidden = mPolicy.canBeForceHidden(win, win.mAttrs);
266             boolean shouldBeForceHidden = shouldForceHide(win);
267             if (winAnimator.mSurfaceControl != null) {
268                 final boolean wasAnimating = winAnimator.mWasAnimating;
269                 final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);
270                 winAnimator.mWasAnimating = nowAnimating;
271                 mAnimating |= nowAnimating;
272 
273                 boolean appWindowAnimating = winAnimator.mAppAnimator != null
274                         && winAnimator.mAppAnimator.animating;
275                 boolean wasAppWindowAnimating = winAnimator.mAppAnimator != null
276                         && winAnimator.mAppAnimator.wasAnimating;
277                 boolean anyAnimating = appWindowAnimating || nowAnimating;
278                 boolean anyWasAnimating = wasAppWindowAnimating || wasAnimating;
279 
280                 try {
281                     if (anyAnimating && !anyWasAnimating) {
282                         win.mClient.onAnimationStarted(winAnimator.mAnimatingMove ? -1
283                                 : winAnimator.mKeyguardGoingAwayAnimation ? 1
284                                 : 0);
285                     } else if (!anyAnimating && anyWasAnimating) {
286                         win.mClient.onAnimationStopped();
287                     }
288                 } catch (RemoteException e) {
289                     Slog.w(TAG, "Failed to dispatch window animation state change.", e);
290                 }
291 
292                 if (WindowManagerService.DEBUG_WALLPAPER) {
293                     Slog.v(TAG, win + ": wasAnimating=" + wasAnimating +
294                             ", nowAnimating=" + nowAnimating);
295                 }
296 
297                 if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == win) {
298                     mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
299                     setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
300                             WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
301                     if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
302                         mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2",
303                                 getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
304                     }
305                 }
306 
307                 if (mPolicy.isForceHiding(win.mAttrs)) {
308                     if (!wasAnimating && nowAnimating) {
309                         if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_ANIM ||
310                                 WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
311                                 "Animation started that could impact force hide: " + win);
312                         mBulkUpdateParams |= SET_FORCE_HIDING_CHANGED;
313                         setPendingLayoutChanges(displayId,
314                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
315                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
316                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3",
317                                     getPendingLayoutChanges(displayId));
318                         }
319                         mService.mFocusMayChange = true;
320                     } else if (mKeyguardGoingAway && !nowAnimating) {
321                         // Timeout!!
322                         Slog.e(TAG, "Timeout waiting for animation to startup");
323                         mPolicy.startKeyguardExitAnimation(0, 0);
324                         mKeyguardGoingAway = false;
325                     }
326                     if (win.isReadyForDisplay()) {
327                         if (nowAnimating && win.mWinAnimator.mKeyguardGoingAwayAnimation) {
328                             mForceHiding = KEYGUARD_ANIMATING_OUT;
329                         } else {
330                             mForceHiding = win.isDrawnLw() ? KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN;
331                         }
332                     }
333                     if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
334                             "Force hide " + forceHidingToString()
335                             + " hasSurface=" + win.mHasSurface
336                             + " policyVis=" + win.mPolicyVisibility
337                             + " destroying=" + win.mDestroying
338                             + " attHidden=" + win.mAttachedHidden
339                             + " vis=" + win.mViewVisibility
340                             + " hidden=" + win.mRootToken.hidden
341                             + " anim=" + win.mWinAnimator.mAnimation);
342                 } else if (canBeForceHidden) {
343                     if (shouldBeForceHidden) {
344                         if (!win.hideLw(false, false)) {
345                             // Was already hidden
346                             continue;
347                         }
348                         if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
349                                 "Now policy hidden: " + win);
350                     } else {
351                         boolean applyExistingExitAnimation = mPostKeyguardExitAnimation != null
352                                 && !mPostKeyguardExitAnimation.hasEnded()
353                                 && !winAnimator.mKeyguardGoingAwayAnimation
354                                 && win.hasDrawnLw()
355                                 && win.mAttachedWindow == null
356                                 && !win.mIsImWindow
357                                 && displayId == Display.DEFAULT_DISPLAY;
358 
359                         // If the window is already showing and we don't need to apply an existing
360                         // Keyguard exit animation, skip.
361                         if (!win.showLw(false, false) && !applyExistingExitAnimation) {
362                             continue;
363                         }
364                         final boolean visibleNow = win.isVisibleNow();
365                         if (!visibleNow) {
366                             // Couldn't really show, must showLw() again when win becomes visible.
367                             win.hideLw(false, false);
368                             continue;
369                         }
370                         if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
371                                 "Now policy shown: " + win);
372                         if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
373                                 && win.mAttachedWindow == null) {
374                             if (unForceHiding == null) {
375                                 unForceHiding = new ArrayList<>();
376                             }
377                             unForceHiding.add(winAnimator);
378                             if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
379                                 wallpaperInUnForceHiding = true;
380                             }
381                             if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
382                                 startingInUnForceHiding = true;
383                             }
384                         } else if (applyExistingExitAnimation) {
385                             // We're already in the middle of an animation. Use the existing
386                             // animation to bring in this window.
387                             if (DEBUG_KEYGUARD) Slog.v(TAG,
388                                     "Applying existing Keyguard exit animation to new window: win="
389                                             + win);
390                             Animation a = mPolicy.createForceHideEnterAnimation(
391                                     false, mKeyguardGoingAwayToNotificationShade);
392                             winAnimator.setAnimation(a, mPostKeyguardExitAnimation.getStartTime());
393                             winAnimator.mKeyguardGoingAwayAnimation = true;
394                         }
395                         final WindowState currentFocus = mService.mCurrentFocus;
396                         if (currentFocus == null || currentFocus.mLayer < win.mLayer) {
397                             // We are showing on top of the current
398                             // focus, so re-evaluate focus to make
399                             // sure it is correct.
400                             if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.v(TAG,
401                                     "updateWindowsLocked: setting mFocusMayChange true");
402                             mService.mFocusMayChange = true;
403                         }
404                     }
405                     if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
406                         mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
407                         setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
408                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
409                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
410                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 4",
411                                     getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
412                         }
413                     }
414                 }
415             }
416 
417             // If the window doesn't have a surface, the only thing we care about is the correct
418             // policy visibility.
419             else if (canBeForceHidden) {
420                 if (shouldBeForceHidden) {
421                     win.hideLw(false, false);
422                 } else {
423                     win.showLw(false, false);
424                 }
425             }
426 
427             final AppWindowToken atoken = win.mAppToken;
428             if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
429                 if (atoken == null || atoken.allDrawn) {
430                     if (winAnimator.performShowLocked()) {
431                         setPendingLayoutChanges(displayId,
432                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
433                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
434                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 5",
435                                     getPendingLayoutChanges(displayId));
436                         }
437                     }
438                 }
439             }
440             final AppWindowAnimator appAnimator = winAnimator.mAppAnimator;
441             if (appAnimator != null && appAnimator.thumbnail != null) {
442                 if (appAnimator.thumbnailTransactionSeq != mAnimTransactionSequence) {
443                     appAnimator.thumbnailTransactionSeq = mAnimTransactionSequence;
444                     appAnimator.thumbnailLayer = 0;
445                 }
446                 if (appAnimator.thumbnailLayer < winAnimator.mAnimLayer) {
447                     appAnimator.thumbnailLayer = winAnimator.mAnimLayer;
448                 }
449             }
450             if (win.mIsWallpaper) {
451                 wallpaper = win;
452             }
453         } // end forall windows
454 
455         // If we have windows that are being show due to them no longer
456         // being force-hidden, apply the appropriate animation to them if animations are not
457         // disabled.
458         if (unForceHiding != null) {
459             if (!mKeyguardGoingAwayDisableWindowAnimations) {
460                 boolean first = true;
461                 for (int i=unForceHiding.size()-1; i>=0; i--) {
462                     final WindowStateAnimator winAnimator = unForceHiding.get(i);
463                     Animation a = mPolicy.createForceHideEnterAnimation(
464                             wallpaperInUnForceHiding && !startingInUnForceHiding,
465                             mKeyguardGoingAwayToNotificationShade);
466                     if (a != null) {
467                         if (DEBUG_KEYGUARD) Slog.v(TAG,
468                                 "Starting keyguard exit animation on window " + winAnimator.mWin);
469                         winAnimator.setAnimation(a);
470                         winAnimator.mKeyguardGoingAwayAnimation = true;
471                         if (first) {
472                             mPostKeyguardExitAnimation = a;
473                             mPostKeyguardExitAnimation.setStartTime(mCurrentTime);
474                             first = false;
475                         }
476                     }
477                 }
478             } else if (mKeyguardGoingAway) {
479                 mPolicy.startKeyguardExitAnimation(mCurrentTime, 0 /* duration */);
480                 mKeyguardGoingAway = false;
481             }
482 
483 
484             // Wallpaper is going away in un-force-hide motion, animate it as well.
485             if (!wallpaperInUnForceHiding && wallpaper != null
486                     && !mKeyguardGoingAwayDisableWindowAnimations) {
487                 if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: wallpaper animating away");
488                 Animation a = mPolicy.createForceHideWallpaperExitAnimation(
489                         mKeyguardGoingAwayToNotificationShade);
490                 if (a != null) {
491                     wallpaper.mWinAnimator.setAnimation(a);
492                 }
493             }
494         }
495 
496         if (mPostKeyguardExitAnimation != null) {
497             // We're in the midst of a keyguard exit animation.
498             if (mKeyguardGoingAway) {
499                 mPolicy.startKeyguardExitAnimation(mCurrentTime +
500                         mPostKeyguardExitAnimation.getStartOffset(),
501                         mPostKeyguardExitAnimation.getDuration());
502                 mKeyguardGoingAway = false;
503             }
504             // mPostKeyguardExitAnimation might either be ended normally, cancelled, or "orphaned",
505             // meaning that the window it was running on was removed. We check for hasEnded() for
506             // ended normally and cancelled case, and check the time for the "orphaned" case.
507             else if (mPostKeyguardExitAnimation.hasEnded()
508                     || mCurrentTime - mPostKeyguardExitAnimation.getStartTime()
509                             > mPostKeyguardExitAnimation.getDuration()) {
510                 // Done with the animation, reset.
511                 if (DEBUG_KEYGUARD) Slog.v(TAG, "Done with Keyguard exit animations.");
512                 mPostKeyguardExitAnimation = null;
513             }
514         }
515     }
516 
updateWallpaperLocked(int displayId)517     private void updateWallpaperLocked(int displayId) {
518         mService.getDisplayContentLocked(displayId).resetAnimationBackgroundAnimator();
519 
520         final WindowList windows = mService.getWindowListLocked(displayId);
521         WindowState detachedWallpaper = null;
522 
523         for (int i = windows.size() - 1; i >= 0; i--) {
524             final WindowState win = windows.get(i);
525             WindowStateAnimator winAnimator = win.mWinAnimator;
526             if (winAnimator.mSurfaceControl == null) {
527                 continue;
528             }
529 
530             final int flags = win.mAttrs.flags;
531 
532             // If this window is animating, make a note that we have
533             // an animating window and take care of a request to run
534             // a detached wallpaper animation.
535             if (winAnimator.mAnimating) {
536                 if (winAnimator.mAnimation != null) {
537                     if ((flags & FLAG_SHOW_WALLPAPER) != 0
538                             && winAnimator.mAnimation.getDetachWallpaper()) {
539                         detachedWallpaper = win;
540                     }
541                     final int color = winAnimator.mAnimation.getBackgroundColor();
542                     if (color != 0) {
543                         final TaskStack stack = win.getStack();
544                         if (stack != null) {
545                             stack.setAnimationBackground(winAnimator, color);
546                         }
547                     }
548                 }
549                 mAnimating = true;
550             }
551 
552             // If this window's app token is running a detached wallpaper
553             // animation, make a note so we can ensure the wallpaper is
554             // displayed behind it.
555             final AppWindowAnimator appAnimator = winAnimator.mAppAnimator;
556             if (appAnimator != null && appAnimator.animation != null
557                     && appAnimator.animating) {
558                 if ((flags & FLAG_SHOW_WALLPAPER) != 0
559                         && appAnimator.animation.getDetachWallpaper()) {
560                     detachedWallpaper = win;
561                 }
562 
563                 final int color = appAnimator.animation.getBackgroundColor();
564                 if (color != 0) {
565                     final TaskStack stack = win.getStack();
566                     if (stack != null) {
567                         stack.setAnimationBackground(winAnimator, color);
568                     }
569                 }
570             }
571         } // end forall windows
572 
573         if (mWindowDetachedWallpaper != detachedWallpaper) {
574             if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
575                     "Detached wallpaper changed from " + mWindowDetachedWallpaper
576                     + " to " + detachedWallpaper);
577             mWindowDetachedWallpaper = detachedWallpaper;
578             mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
579         }
580     }
581 
582     /** See if any windows have been drawn, so they (and others associated with them) can now be
583      *  shown. */
testTokenMayBeDrawnLocked(int displayId)584     private void testTokenMayBeDrawnLocked(int displayId) {
585         // See if any windows have been drawn, so they (and others
586         // associated with them) can now be shown.
587         final ArrayList<Task> tasks = mService.getDisplayContentLocked(displayId).getTasks();
588         final int numTasks = tasks.size();
589         for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
590             final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
591             final int numTokens = tokens.size();
592             for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
593                 final AppWindowToken wtoken = tokens.get(tokenNdx);
594                 AppWindowAnimator appAnimator = wtoken.mAppAnimator;
595                 final boolean allDrawn = wtoken.allDrawn;
596                 if (allDrawn != appAnimator.allDrawn) {
597                     appAnimator.allDrawn = allDrawn;
598                     if (allDrawn) {
599                         // The token has now changed state to having all
600                         // windows shown...  what to do, what to do?
601                         if (appAnimator.freezingScreen) {
602                             appAnimator.showAllWindowsLocked();
603                             mService.unsetAppFreezingScreenLocked(wtoken, false, true);
604                             if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
605                                     "Setting mOrientationChangeComplete=true because wtoken "
606                                     + wtoken + " numInteresting=" + wtoken.numInterestingWindows
607                                     + " numDrawn=" + wtoken.numDrawnWindows);
608                             // This will set mOrientationChangeComplete and cause a pass through layout.
609                             setAppLayoutChanges(appAnimator,
610                                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
611                                     "testTokenMayBeDrawnLocked: freezingScreen", displayId);
612                         } else {
613                             setAppLayoutChanges(appAnimator,
614                                     WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
615                                     "testTokenMayBeDrawnLocked", displayId);
616 
617                             // We can now show all of the drawn windows!
618                             if (!mService.mOpeningApps.contains(wtoken)) {
619                                 mAnimating |= appAnimator.showAllWindowsLocked();
620                             }
621                         }
622                     }
623                 }
624             }
625         }
626     }
627 
628 
629     /** Locked on mService.mWindowMap. */
animateLocked(long frameTimeNs)630     private void animateLocked(long frameTimeNs) {
631         if (!mInitialized) {
632             return;
633         }
634 
635         mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
636         mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
637         boolean wasAnimating = mAnimating;
638         mAnimating = false;
639         mAppWindowAnimating = false;
640         if (WindowManagerService.DEBUG_WINDOW_TRACE) {
641             Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
642         }
643 
644         if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
645                 TAG, ">>> OPEN TRANSACTION animateLocked");
646         SurfaceControl.openTransaction();
647         SurfaceControl.setAnimationTransaction();
648         try {
649             final int numDisplays = mDisplayContentsAnimators.size();
650             for (int i = 0; i < numDisplays; i++) {
651                 final int displayId = mDisplayContentsAnimators.keyAt(i);
652                 updateAppWindowsLocked(displayId);
653                 DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
654 
655                 final ScreenRotationAnimation screenRotationAnimation =
656                         displayAnimator.mScreenRotationAnimation;
657                 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
658                     if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
659                         mAnimating = true;
660                     } else {
661                         mBulkUpdateParams |= SET_UPDATE_ROTATION;
662                         screenRotationAnimation.kill();
663                         displayAnimator.mScreenRotationAnimation = null;
664 
665                         //TODO (multidisplay): Accessibility supported only for the default display.
666                         if (mService.mAccessibilityController != null
667                                 && displayId == Display.DEFAULT_DISPLAY) {
668                             // We just finished rotation animation which means we did not
669                             // anounce the rotation and waited for it to end, announce now.
670                             mService.mAccessibilityController.onRotationChangedLocked(
671                                     mService.getDefaultDisplayContentLocked(), mService.mRotation);
672                         }
673                     }
674                 }
675 
676                 // Update animations of all applications, including those
677                 // associated with exiting/removed apps
678                 updateWindowsLocked(displayId);
679                 updateWallpaperLocked(displayId);
680 
681                 final WindowList windows = mService.getWindowListLocked(displayId);
682                 final int N = windows.size();
683                 for (int j = 0; j < N; j++) {
684                     windows.get(j).mWinAnimator.prepareSurfaceLocked(true);
685                 }
686             }
687 
688             for (int i = 0; i < numDisplays; i++) {
689                 final int displayId = mDisplayContentsAnimators.keyAt(i);
690 
691                 testTokenMayBeDrawnLocked(displayId);
692 
693                 final ScreenRotationAnimation screenRotationAnimation =
694                         mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
695                 if (screenRotationAnimation != null) {
696                     screenRotationAnimation.updateSurfacesInTransaction();
697                 }
698 
699                 mAnimating |= mService.getDisplayContentLocked(displayId).animateDimLayers();
700 
701                 //TODO (multidisplay): Magnification is supported only for the default display.
702                 if (mService.mAccessibilityController != null
703                         && displayId == Display.DEFAULT_DISPLAY) {
704                     mService.mAccessibilityController.drawMagnifiedRegionBorderIfNeededLocked();
705                 }
706             }
707 
708             if (mAnimating) {
709                 mService.scheduleAnimationLocked();
710             }
711 
712             mService.setFocusedStackLayer();
713 
714             if (mService.mWatermark != null) {
715                 mService.mWatermark.drawIfNeeded();
716             }
717         } catch (RuntimeException e) {
718             Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
719         } finally {
720             SurfaceControl.closeTransaction();
721             if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
722                     TAG, "<<< CLOSE TRANSACTION animateLocked");
723         }
724 
725         boolean hasPendingLayoutChanges = false;
726         final int numDisplays = mService.mDisplayContents.size();
727         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
728             final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
729             final int pendingChanges = getPendingLayoutChanges(displayContent.getDisplayId());
730             if ((pendingChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
731                 mBulkUpdateParams |= SET_WALLPAPER_ACTION_PENDING;
732             }
733             if (pendingChanges != 0) {
734                 hasPendingLayoutChanges = true;
735             }
736         }
737 
738         boolean doRequest = false;
739         if (mBulkUpdateParams != 0) {
740             doRequest = mService.copyAnimToLayoutParamsLocked();
741         }
742 
743         if (hasPendingLayoutChanges || doRequest) {
744             mService.requestTraversalLocked();
745         }
746 
747         if (!mAnimating && wasAnimating) {
748             mService.requestTraversalLocked();
749         }
750         if (WindowManagerService.DEBUG_WINDOW_TRACE) {
751             Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
752                 + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
753                 + " mPendingLayoutChanges(DEFAULT_DISPLAY)="
754                 + Integer.toHexString(getPendingLayoutChanges(Display.DEFAULT_DISPLAY)));
755         }
756     }
757 
bulkUpdateParamsToString(int bulkUpdateParams)758     static String bulkUpdateParamsToString(int bulkUpdateParams) {
759         StringBuilder builder = new StringBuilder(128);
760         if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
761             builder.append(" UPDATE_ROTATION");
762         }
763         if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
764             builder.append(" WALLPAPER_MAY_CHANGE");
765         }
766         if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
767             builder.append(" FORCE_HIDING_CHANGED");
768         }
769         if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
770             builder.append(" ORIENTATION_CHANGE_COMPLETE");
771         }
772         if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
773             builder.append(" TURN_ON_SCREEN");
774         }
775         return builder.toString();
776     }
777 
dumpLocked(PrintWriter pw, String prefix, boolean dumpAll)778     public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
779         final String subPrefix = "  " + prefix;
780         final String subSubPrefix = "  " + subPrefix;
781 
782         for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
783             pw.print(prefix); pw.print("DisplayContentsAnimator #");
784                     pw.print(mDisplayContentsAnimators.keyAt(i));
785                     pw.println(":");
786             DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
787             final WindowList windows =
788                     mService.getWindowListLocked(mDisplayContentsAnimators.keyAt(i));
789             final int N = windows.size();
790             for (int j = 0; j < N; j++) {
791                 WindowStateAnimator wanim = windows.get(j).mWinAnimator;
792                 pw.print(subPrefix); pw.print("Window #"); pw.print(j);
793                         pw.print(": "); pw.println(wanim);
794             }
795             if (displayAnimator.mScreenRotationAnimation != null) {
796                 pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
797                 displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw);
798             } else if (dumpAll) {
799                 pw.print(subPrefix); pw.println("no ScreenRotationAnimation ");
800             }
801             pw.println();
802         }
803 
804         pw.println();
805 
806         if (dumpAll) {
807             pw.print(prefix); pw.print("mAnimTransactionSequence=");
808                     pw.print(mAnimTransactionSequence);
809                     pw.print(" mForceHiding="); pw.println(forceHidingToString());
810             pw.print(prefix); pw.print("mCurrentTime=");
811                     pw.println(TimeUtils.formatUptime(mCurrentTime));
812         }
813         if (mBulkUpdateParams != 0) {
814             pw.print(prefix); pw.print("mBulkUpdateParams=0x");
815                     pw.print(Integer.toHexString(mBulkUpdateParams));
816                     pw.println(bulkUpdateParamsToString(mBulkUpdateParams));
817         }
818         if (mWindowDetachedWallpaper != null) {
819             pw.print(prefix); pw.print("mWindowDetachedWallpaper=");
820                 pw.println(mWindowDetachedWallpaper);
821         }
822     }
823 
getPendingLayoutChanges(final int displayId)824     int getPendingLayoutChanges(final int displayId) {
825         if (displayId < 0) {
826             return 0;
827         }
828         final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
829         return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
830     }
831 
setPendingLayoutChanges(final int displayId, final int changes)832     void setPendingLayoutChanges(final int displayId, final int changes) {
833         if (displayId < 0) {
834             return;
835         }
836         final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
837         if (displayContent != null) {
838             displayContent.pendingLayoutChanges |= changes;
839         }
840     }
841 
setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String reason, final int displayId)842     void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String reason,
843             final int displayId) {
844         WindowList windows = appAnimator.mAppToken.allAppWindows;
845         for (int i = windows.size() - 1; i >= 0; i--) {
846             if (displayId == windows.get(i).getDisplayId()) {
847                 setPendingLayoutChanges(displayId, changes);
848                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
849                     mService.debugLayoutRepeats(reason, getPendingLayoutChanges(displayId));
850                 }
851                 break;
852             }
853         }
854     }
855 
getDisplayContentsAnimatorLocked(int displayId)856     private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
857         DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
858         if (displayAnimator == null) {
859             displayAnimator = new DisplayContentsAnimator();
860             mDisplayContentsAnimators.put(displayId, displayAnimator);
861         }
862         return displayAnimator;
863     }
864 
setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation)865     void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
866         if (displayId >= 0) {
867             getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
868         }
869     }
870 
getScreenRotationAnimationLocked(int displayId)871     ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) {
872         if (displayId < 0) {
873             return null;
874         }
875         return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation;
876     }
877 
878     private class DisplayContentsAnimator {
879         ScreenRotationAnimation mScreenRotationAnimation = null;
880     }
881 }
882