From f8d77da969edc2f191d349f7d9a30d02edcbd388 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Tue, 11 Nov 2014 16:59:12 +0100 Subject: [PATCH] Improve lockscreen launch animations - Add a timeout so if WindowManager "forgets" to tell that the activity has drawn, we still unlock after 3 seconds, so the user is not completely stuck. - Use the screen height instead of the window height for the translation animation. - Don't run the animation if the attached window is not null. The animation from the attached window will influence the transformation as well, so there is no need to run an additional animation in this case (apps with SurfaceView's had broken unlock transitions because of this). - If the starting window needs to go away while the unlock transition is running, modify the existing animation such that it fades out in the same transition. Bug: 15991916 Change-Id: Ia5dfa31e1bc0d5745fe228e1daf08e268733b6f1 --- core/res/res/anim/app_starting_exit.xml | 11 ++++-- .../res/res/anim/lock_screen_behind_enter.xml | 2 +- .../lock_screen_behind_enter_wallpaper.xml | 2 +- .../keyguard/KeyguardViewMediator.java | 23 ++++++++--- .../com/android/server/wm/WindowAnimator.java | 6 ++- .../server/wm/WindowStateAnimator.java | 38 +++++++++++++++++-- 6 files changed, 65 insertions(+), 17 deletions(-) diff --git a/core/res/res/anim/app_starting_exit.xml b/core/res/res/anim/app_starting_exit.xml index 60e4109837d4f..aaf7f156883bf 100644 --- a/core/res/res/anim/app_starting_exit.xml +++ b/core/res/res/anim/app_starting_exit.xml @@ -18,8 +18,11 @@ */ --> - - - + diff --git a/core/res/res/anim/lock_screen_behind_enter.xml b/core/res/res/anim/lock_screen_behind_enter.xml index e8afada382859..6f3c4d4200f9c 100644 --- a/core/res/res/anim/lock_screen_behind_enter.xml +++ b/core/res/res/anim/lock_screen_behind_enter.xml @@ -21,7 +21,7 @@ android:shareInterpolator="false" android:startOffset="100"> - diff --git a/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml b/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml index ce974dc8099dc..660b66258fed2 100644 --- a/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml +++ b/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml @@ -23,7 +23,7 @@ android:interpolator="@interpolator/decelerate_quint" android:duration="400"/> - diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 7ca8fc173a624..20e418cb44cee 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -113,6 +113,8 @@ import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; */ public class KeyguardViewMediator extends SystemUI { private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000; + private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000; + final static boolean DEBUG = false; private final static boolean DBG_WAKE = false; @@ -136,6 +138,7 @@ public class KeyguardViewMediator extends SystemUI { private static final int DISMISS = 17; private static final int START_KEYGUARD_EXIT_ANIM = 18; private static final int ON_ACTIVITY_DRAWN = 19; + private static final int KEYGUARD_DONE_PENDING_TIMEOUT = 20; /** * The default amount of time we stay awake (used for all key input) @@ -294,7 +297,7 @@ public class KeyguardViewMediator extends SystemUI { // ActivityManagerService) will not reconstruct the keyguard if it is already showing. synchronized (KeyguardViewMediator.this) { mSwitchingUser = true; - mKeyguardDonePending = false; + resetKeyguardDonePendingLocked(); resetStateLocked(); adjustStatusBarLocked(); // When we switch users we want to bring the new user to the biometric unlock even @@ -450,6 +453,8 @@ public class KeyguardViewMediator extends SystemUI { mKeyguardDonePending = true; mHideAnimationRun = true; mStatusBarKeyguardViewManager.startPreHideAnimation(null /* finishRunnable */); + mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_PENDING_TIMEOUT, + KEYGUARD_DONE_PENDING_TIMEOUT_MS); } @Override @@ -584,7 +589,7 @@ public class KeyguardViewMediator extends SystemUI { mScreenOn = false; if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")"); - mKeyguardDonePending = false; + resetKeyguardDonePendingLocked(); mHideAnimationRun = false; // Lock immediately based on setting if secure (user has a pin/pattern/password). @@ -1108,6 +1113,9 @@ public class KeyguardViewMediator extends SystemUI { StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj; handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration); break; + case KEYGUARD_DONE_PENDING_TIMEOUT: + Log.w(TAG, "Timeout while waiting for activity drawn!"); + // Fall through. case ON_ACTIVITY_DRAWN: handleOnActivityDrawn(); break; @@ -1122,7 +1130,7 @@ public class KeyguardViewMediator extends SystemUI { private void handleKeyguardDone(boolean authenticated, boolean wakeup) { if (DEBUG) Log.d(TAG, "handleKeyguardDone"); synchronized (this) { - mKeyguardDonePending = false; + resetKeyguardDonePendingLocked(); } if (authenticated) { @@ -1242,7 +1250,7 @@ public class KeyguardViewMediator extends SystemUI { mStatusBarKeyguardViewManager.show(options); mHiding = false; mShowing = true; - mKeyguardDonePending = false; + resetKeyguardDonePendingLocked(); mHideAnimationRun = false; updateActivityLockScreenState(); adjustStatusBarLocked(); @@ -1321,7 +1329,7 @@ public class KeyguardViewMediator extends SystemUI { mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration); mShowing = false; - mKeyguardDonePending = false; + resetKeyguardDonePendingLocked(); mHideAnimationRun = false; updateActivityLockScreenState(); adjustStatusBarLocked(); @@ -1417,6 +1425,11 @@ public class KeyguardViewMediator extends SystemUI { && mSearchManager.getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null; } + private void resetKeyguardDonePendingLocked() { + mKeyguardDonePending = false; + mHandler.removeMessages(KEYGUARD_DONE_PENDING_TIMEOUT); + } + public void onBootCompleted() { mUpdateMonitor.dispatchBootCompleted(); synchronized (this) { diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 8af85781c5691..a90cc9572c687 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -349,7 +349,8 @@ public class WindowAnimator { } else { boolean applyExistingExitAnimation = mPostKeyguardExitAnimation != null && !winAnimator.mKeyguardGoingAwayAnimation - && win.hasDrawnLw(); + && win.hasDrawnLw() + && win.mAttachedWindow == null; // If the window is already showing and we don't need to apply an existing // Keyguard exit animation, skip. @@ -364,7 +365,8 @@ public class WindowAnimator { } if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Now policy shown: " + win); - if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0) { + if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0 + && win.mAttachedWindow == null) { if (unForceHiding == null) { unForceHiding = new ArrayList<>(); } diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index e9290652151d0..87d420f0d9195 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -53,10 +53,13 @@ import android.view.View; import android.view.WindowManager; import android.view.WindowManagerPolicy; import android.view.WindowManager.LayoutParams; +import android.view.animation.AlphaAnimation; import android.view.animation.Animation; +import android.view.animation.AnimationSet; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; +import com.android.internal.R; import com.android.server.wm.WindowManagerService.H; import java.io.PrintWriter; @@ -98,6 +101,7 @@ class WindowStateAnimator { int mAnimLayer; int mLastLayer; long mAnimationStartTime; + long mLastAnimationTime; SurfaceControl mSurfaceControl; SurfaceControl mPendingDestroySurface; @@ -312,6 +316,7 @@ class WindowStateAnimator { mAnimating = true; } if ((mAnimation != null) && mLocalAnimating) { + mLastAnimationTime = currentTime; if (stepAnimation(currentTime)) { return true; } @@ -1794,11 +1799,14 @@ class WindowStateAnimator { if ((mLocalAnimating && mAnimationIsEntrance == isEntrance) || mKeyguardGoingAwayAnimation) { // If we are trying to apply an animation, but already running - // an animation of the same type, or when we are playing the Keyguard dismissing - // animation, then just leave that one alone. + // an animation of the same type, 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. + // If we are in a keyguard exit animation, and the window should animate away, modify + // keyguard exit animation such that it also fades out. + if (mAnimation != null && mKeyguardGoingAwayAnimation + && transit == WindowManagerPolicy.TRANSIT_PREVIEW_DONE) { + applyFadeoutDuringKeyguardExitAnimation(); + } return true; } @@ -1856,6 +1864,28 @@ class WindowStateAnimator { return mAnimation != null; } + private void applyFadeoutDuringKeyguardExitAnimation() { + long startTime = mAnimation.getStartTime(); + long duration = mAnimation.getDuration(); + long elapsed = mLastAnimationTime - startTime; + long fadeDuration = duration - elapsed; + if (fadeDuration <= 0) { + // Never mind, this would be no visible animation, so abort the animation change. + return; + } + AnimationSet newAnimation = new AnimationSet(false /* shareInterpolator */); + newAnimation.setDuration(duration); + newAnimation.setStartTime(startTime); + newAnimation.addAnimation(mAnimation); + Animation fadeOut = AnimationUtils.loadAnimation( + mContext, com.android.internal.R.anim.app_starting_exit); + fadeOut.setDuration(fadeDuration); + fadeOut.setStartOffset(elapsed); + newAnimation.addAnimation(fadeOut); + newAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mAnimDw, mAnimDh); + mAnimation = newAnimation; + } + public void dump(PrintWriter pw, String prefix, boolean dumpAll) { if (mAnimating || mLocalAnimating || mAnimationIsEntrance || mAnimation != null) {