From 44f60cca7bb31e2f9b4b7bf25bb2e0cfb0e3e1e1 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Fri, 7 Nov 2014 20:33:51 +0100 Subject: [PATCH] Fix lockscreen launch animations once and for all In SysUI, make sure not to dismiss Keyguard multiple times when just waiting for a deferred dismissal, so WindowManager doesn't get multiple calls to keyguardGoingAway. Change heuristics how notifying Keyguard about activity drawn works. Always notify Keyguard after executing an app transition, and notify it also when not doing a transition after a startActivity call. For that to work, update AppWindowToken.startingDisplayed also when the window is displayed, but force hidden because of Keyguard. Further, handle the case correctly when a window gets added during the Keyguard exit animation by overriding the start time for the animation of that new window. Also don't apply a transition animation for a window when executing keyguard exit animation, so by removing a starting window we don't break this animation. Last but not least, tell Keyguard to start exiting immediately if animations for exiting are disabled, like when going to phone/camera on lockscreen. Before, we always had a delay of 1 second because we waited for the timeout. Bug: 1599196 Bug: 18272544 Change-Id: I596b2489f814b934abd256e16079d3d3f326e209 --- .../keyguard/KeyguardViewMediator.java | 11 ++-- .../com/android/server/am/ActivityStack.java | 3 - .../server/am/ActivityStackSupervisor.java | 14 +++- .../com/android/server/wm/WindowAnimator.java | 65 +++++++++++++------ .../server/wm/WindowManagerService.java | 12 ++-- .../com/android/server/wm/WindowState.java | 10 ++- .../server/wm/WindowStateAnimator.java | 30 ++++++--- 7 files changed, 102 insertions(+), 43 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 172aaf67b8733..7ca8fc173a624 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -426,7 +426,9 @@ public class KeyguardViewMediator extends SystemUI { } public void keyguardDone(boolean authenticated) { - KeyguardViewMediator.this.keyguardDone(authenticated, true); + if (!mKeyguardDonePending) { + KeyguardViewMediator.this.keyguardDone(authenticated, true); + } } public void keyguardDoneDrawing() { @@ -1049,9 +1051,6 @@ public class KeyguardViewMediator extends SystemUI { public void keyguardDone(boolean authenticated, boolean wakeup) { if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")"); EventLog.writeEvent(70000, 2); - synchronized (this) { - mKeyguardDonePending = false; - } Message msg = mHandler.obtainMessage(KEYGUARD_DONE, authenticated ? 1 : 0, wakeup ? 1 : 0); mHandler.sendMessage(msg); } @@ -1122,6 +1121,9 @@ public class KeyguardViewMediator extends SystemUI { */ private void handleKeyguardDone(boolean authenticated, boolean wakeup) { if (DEBUG) Log.d(TAG, "handleKeyguardDone"); + synchronized (this) { + mKeyguardDonePending = false; + } if (authenticated) { mUpdateMonitor.clearFailedUnlockAttempts(); @@ -1297,6 +1299,7 @@ public class KeyguardViewMediator extends SystemUI { } private void handleOnActivityDrawn() { + if (DEBUG) Log.d(TAG, "handleOnActivityDrawn: mKeyguardDonePending=" + mKeyguardDonePending); if (mKeyguardDonePending) { mStatusBarKeyguardViewManager.onActivityDrawn(); } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 0dae028fbb2ba..3a1fafe2bbc3e 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1538,9 +1538,6 @@ final class ActivityStack { ActivityOptions.abort(options); if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Top activity resumed " + next); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); - - // Make sure to notify Keyguard as well if it is waiting for an activity to be drawn. - mStackSupervisor.notifyActivityDrawnForKeyguard(); return false; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 099151fb20cae..120002e419d86 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -656,7 +656,6 @@ public final class ActivityStackSupervisor implements DisplayListener { void reportActivityVisibleLocked(ActivityRecord r) { sendWaitingVisibleReportLocked(r); - notifyActivityDrawnForKeyguard(); } void sendWaitingVisibleReportLocked(ActivityRecord r) { @@ -1832,6 +1831,7 @@ public final class ActivityStackSupervisor implements DisplayListener { final ActivityStack lastStack = getLastStack(); ActivityRecord curTop = lastStack == null? null : lastStack.topRunningNonDelayedActivityLocked(notTop); + boolean movedToFront = false; if (curTop != null && (curTop.task != intentActivity.task || curTop.task != lastStack.topTask())) { r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); @@ -1851,6 +1851,7 @@ public final class ActivityStackSupervisor implements DisplayListener { intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE); } options = null; + movedToFront = true; } } // If the caller has requested that the target task be @@ -1865,6 +1866,12 @@ public final class ActivityStackSupervisor implements DisplayListener { // sure we have correctly resumed the top activity. if (doResume) { resumeTopActivitiesLocked(targetStack, null, options); + + // Make sure to notify Keyguard as well if we are not running an app + // transition later. + if (!movedToFront) { + notifyActivityDrawnForKeyguard(); + } } else { ActivityOptions.abort(options); } @@ -1956,6 +1963,11 @@ public final class ActivityStackSupervisor implements DisplayListener { // sure we have correctly resumed the top activity. if (doResume) { targetStack.resumeTopActivityLocked(null, options); + if (!movedToFront) { + // Make sure to notify Keyguard as well if we are not running an app + // transition later. + notifyActivityDrawnForKeyguard(); + } } else { ActivityOptions.abort(options); } diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 82e4bb15b7f09..8af85781c5691 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -21,6 +21,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static com.android.server.wm.WindowManagerService.DEBUG_KEYGUARD; import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION; import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE; @@ -241,6 +242,7 @@ public class WindowAnimator { winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f); winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS); winAnimator.mAnimationIsEntrance = false; + winAnimator.mAnimationStartTime = -1; } } else { if (DEBUG_KEYGUARD) Slog.d(TAG, @@ -263,6 +265,7 @@ public class WindowAnimator { null : winShowWhenLocked.mAppToken; boolean wallpaperInUnForceHiding = false; + boolean startingInUnForceHiding = false; ArrayList unForceHiding = null; WindowState wallpaper = null; for (int i = windows.size() - 1; i >= 0; i--) { @@ -344,8 +347,13 @@ public class WindowAnimator { if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Now policy hidden: " + win); } else { - if (!win.showLw(false, false)) { - // Was already showing. + boolean applyExistingExitAnimation = mPostKeyguardExitAnimation != null + && !winAnimator.mKeyguardGoingAwayAnimation + && win.hasDrawnLw(); + + // If the window is already showing and we don't need to apply an existing + // Keyguard exit animation, skip. + if (!win.showLw(false, false) && !applyExistingExitAnimation) { continue; } final boolean visibleNow = win.isVisibleNow(); @@ -364,11 +372,19 @@ public class WindowAnimator { if ((flags & FLAG_SHOW_WALLPAPER) != 0) { wallpaperInUnForceHiding = true; } - } else if (mPostKeyguardExitAnimation != null) { + if (win.mAttrs.type == TYPE_APPLICATION_STARTING) { + startingInUnForceHiding = true; + } + } else if (applyExistingExitAnimation) { // We're already in the middle of an animation. Use the existing // animation to bring in this window. - winAnimator.setAnimation(mPostKeyguardExitAnimation); - winAnimator.keyguardGoingAwayAnimation = true; + if (DEBUG_KEYGUARD) Slog.v(TAG, + "Applying existing Keyguard exit animation to new window: win=" + + win); + Animation a = mPolicy.createForceHideEnterAnimation( + false, mKeyguardGoingAwayToNotificationShade); + winAnimator.setAnimation(a, mPostKeyguardExitAnimation.getStartTime()); + winAnimator.mKeyguardGoingAwayAnimation = true; } final WindowState currentFocus = mService.mCurrentFocus; if (currentFocus == null || currentFocus.mLayer < win.mLayer) { @@ -421,25 +437,34 @@ public class WindowAnimator { } // end forall windows // If we have windows that are being show due to them no longer - // being force-hidden, apply the appropriate animation to them. + // being force-hidden, apply the appropriate animation to them if animations are not + // disabled. if (unForceHiding != null) { - // This only happens the first time that we detect the keyguard is animating out. - if (mKeyguardGoingAwayDisableWindowAnimations) { - if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: skipping anim for windows"); - } else { - if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: created anim for windows=" - + unForceHiding); - mPostKeyguardExitAnimation = mPolicy.createForceHideEnterAnimation( - wallpaperInUnForceHiding, mKeyguardGoingAwayToNotificationShade); - } - if (mPostKeyguardExitAnimation != null) { + if (!mKeyguardGoingAwayDisableWindowAnimations) { + boolean first = true; for (int i=unForceHiding.size()-1; i>=0; i--) { final WindowStateAnimator winAnimator = unForceHiding.get(i); - winAnimator.setAnimation(mPostKeyguardExitAnimation); - winAnimator.keyguardGoingAwayAnimation = true; + Animation a = mPolicy.createForceHideEnterAnimation( + wallpaperInUnForceHiding && !startingInUnForceHiding, + mKeyguardGoingAwayToNotificationShade); + if (a != null) { + if (DEBUG_KEYGUARD) Slog.v(TAG, + "Starting keyguard exit animation on window " + winAnimator.mWin); + winAnimator.setAnimation(a); + winAnimator.mKeyguardGoingAwayAnimation = true; + if (first) { + mPostKeyguardExitAnimation = a; + mPostKeyguardExitAnimation.setStartTime(mCurrentTime); + first = false; + } + } } + } else if (mKeyguardGoingAway) { + mPolicy.startKeyguardExitAnimation(mCurrentTime, 0 /* duration */); + mKeyguardGoingAway = false; } + // Wallpaper is going away in un-force-hide motion, animate it as well. if (!wallpaperInUnForceHiding && wallpaper != null && !mKeyguardGoingAwayDisableWindowAnimations) { @@ -459,8 +484,10 @@ public class WindowAnimator { mPostKeyguardExitAnimation.getStartOffset(), mPostKeyguardExitAnimation.getDuration()); mKeyguardGoingAway = false; - } else if (mPostKeyguardExitAnimation.hasEnded()) { + } else if (mCurrentTime - mPostKeyguardExitAnimation.getStartTime() + > mPostKeyguardExitAnimation.getDuration()) { // Done with the animation, reset. + if (DEBUG_KEYGUARD) Slog.v(TAG, "Done with Keyguard exit animations."); mPostKeyguardExitAnimation = null; } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 6cb1e4adc96cc..1e492a596f54e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1759,7 +1759,7 @@ public class WindowManagerService extends IWindowManager.Stub // wallpaper during the animation so it doesn't flicker out. final boolean hasWallpaper = (w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 || (w.mAppToken != null - && w.mWinAnimator.keyguardGoingAwayAnimation); + && w.mWinAnimator.mKeyguardGoingAwayAnimation); if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) { if (DEBUG_WALLPAPER) Slog.v(TAG, @@ -2541,8 +2541,8 @@ public class WindowManagerService extends IWindowManager.Stub } mInputMonitor.updateInputWindowsLw(false /*force*/); - if (true || localLOGV) Slog.v(TAG, "addWindow: New client " + client.asBinder() - + ": window=" + win + " Callers=" + Debug.getCallers(5)); + if (true || localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG, "addWindow: New client " + + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5)); if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) { reportNewConfig = true; @@ -5411,7 +5411,7 @@ public class WindowManagerService extends IWindowManager.Stub public void notifyActivityDrawnForKeyguard() { if (DEBUG_KEYGUARD) Slog.d(TAG, "notifyActivityDrawnForKeyguard: waiting=" - + mKeyguardWaitingForActivityDrawn); + + mKeyguardWaitingForActivityDrawn + " Callers=" + Debug.getCallers(5)); synchronized (mWindowMap) { if (mKeyguardWaitingForActivityDrawn) { mPolicy.notifyActivityDrawnForKeyguardLw(); @@ -9322,6 +9322,7 @@ public class WindowManagerService extends IWindowManager.Stub } updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true /*updateInputWindows*/); mFocusMayChange = false; + notifyActivityDrawnForKeyguard(); } return changes; @@ -9809,7 +9810,8 @@ public class WindowManagerService extends IWindowManager.Stub atoken.numInterestingWindows = atoken.numDrawnWindows = 0; atoken.startingDisplayed = false; } - if ((w.isOnScreen() || winAnimator.mAttrType == TYPE_BASE_APPLICATION) + if ((w.isOnScreenIgnoringKeyguard() + || winAnimator.mAttrType == TYPE_BASE_APPLICATION) && !w.mExiting && !w.mDestroying) { if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) { Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw() diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index f9efc809162da..021a6e4dc3733 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -935,7 +935,15 @@ final class WindowState implements WindowManagerPolicy.WindowState { * being visible. */ boolean isOnScreen() { - if (!mHasSurface || !mPolicyVisibility || mDestroying) { + return mPolicyVisibility && isOnScreenIgnoringKeyguard(); + } + + /** + * Like isOnScreen(), but ignores any force hiding of the window due + * to the keyguard. + */ + boolean isOnScreenIgnoringKeyguard() { + if (!mHasSurface || mDestroying) { return false; } final AppWindowToken atoken = mAppToken; diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 819ca509b92ac..e9290652151d0 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -97,6 +97,7 @@ class WindowStateAnimator { boolean mWasAnimating; // Were we animating going into the most recent animation step? int mAnimLayer; int mLastLayer; + long mAnimationStartTime; SurfaceControl mSurfaceControl; SurfaceControl mPendingDestroySurface; @@ -147,7 +148,7 @@ class WindowStateAnimator { * window is first added or shown, cleared when the callback has been made. */ boolean mEnteringAnimation; - boolean keyguardGoingAwayAnimation; + boolean mKeyguardGoingAwayAnimation; /** This is set when there is no Surface */ static final int NO_SURFACE = 0; @@ -210,7 +211,7 @@ class WindowStateAnimator { mIsWallpaper = win.mIsWallpaper; } - public void setAnimation(Animation anim) { + public void setAnimation(Animation anim, long startTime) { if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim); mAnimating = false; mLocalAnimating = false; @@ -221,6 +222,11 @@ class WindowStateAnimator { mTransformation.clear(); mTransformation.setAlpha(mLastHidden ? 0 : 1); mHasLocalTransformation = true; + mAnimationStartTime = startTime; + } + + public void setAnimation(Animation anim) { + setAnimation(anim, -1); } public void clearAnimation() { @@ -229,7 +235,7 @@ class WindowStateAnimator { mLocalAnimating = false; mAnimation.cancel(); mAnimation = null; - keyguardGoingAwayAnimation = false; + mKeyguardGoingAwayAnimation = false; } } @@ -299,7 +305,9 @@ class WindowStateAnimator { final DisplayInfo displayInfo = displayContent.getDisplayInfo(); mAnimDw = displayInfo.appWidth; mAnimDh = displayInfo.appHeight; - mAnimation.setStartTime(currentTime); + mAnimation.setStartTime(mAnimationStartTime != -1 + ? mAnimationStartTime + : currentTime); mLocalAnimating = true; mAnimating = true; } @@ -351,7 +359,7 @@ class WindowStateAnimator { + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false)); mAnimating = false; - keyguardGoingAwayAnimation = false; + mKeyguardGoingAwayAnimation = false; mLocalAnimating = false; if (mAnimation != null) { mAnimation.cancel(); @@ -500,9 +508,6 @@ class WindowStateAnimator { Slog.v(TAG, "Draw state now committed in " + mWin); } mDrawState = COMMIT_DRAW_PENDING; - if (startingWindow) { - mService.notifyActivityDrawnForKeyguard(); - } return true; } return false; @@ -1786,9 +1791,14 @@ class WindowStateAnimator { * @return true if an animation has been loaded. */ boolean applyAnimationLocked(int transit, boolean isEntrance) { - if (mLocalAnimating && mAnimationIsEntrance == isEntrance) { + if ((mLocalAnimating && mAnimationIsEntrance == isEntrance) + || mKeyguardGoingAwayAnimation) { // If we are trying to apply an animation, but already running - // an animation of the same type, then just leave that one alone. + // an animation of the same type, or when we are playing the Keyguard dismissing + // animation, then just leave that one alone. + + // TODO: if mKeyguardGoingAwayAnimation and this is a exiting starting window, modify + // existing animation to fade it out as well. return true; }