diff options
3 files changed, 55 insertions, 23 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java index a678edc0eb06..ac0a3fd8dbc4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java @@ -28,6 +28,7 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.stack.AnimationProperties; +import com.android.systemui.statusbar.phone.AnimatorHandle; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -47,6 +48,7 @@ public class KeyguardVisibilityHelper { private final ScreenOffAnimationController mScreenOffAnimationController; private boolean mAnimateYPos; private boolean mKeyguardViewVisibilityAnimating; + private AnimatorHandle mKeyguardAnimatorHandle; private boolean mLastOccludedState = false; private final AnimationProperties mAnimationProperties = new AnimationProperties(); private final LogBuffer mLogBuffer; @@ -83,6 +85,10 @@ public class KeyguardVisibilityHelper { boolean keyguardFadingAway, boolean goingToFullShade, int oldStatusBarState) { + if (mKeyguardAnimatorHandle != null) { + mKeyguardAnimatorHandle.cancel(); + mKeyguardAnimatorHandle = null; + } mView.animate().cancel(); boolean isOccluded = mKeyguardStateController.isOccluded(); mKeyguardViewVisibilityAnimating = false; @@ -116,7 +122,7 @@ public class KeyguardVisibilityHelper { .setDuration(320) .setInterpolator(Interpolators.ALPHA_IN) .withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable); - log("keyguardFadingAway transition w/ Y Aniamtion"); + log("keyguardFadingAway transition w/ Y Animation"); } else if (statusBarState == KEYGUARD) { if (keyguardFadingAway) { mKeyguardViewVisibilityAnimating = true; @@ -148,7 +154,7 @@ public class KeyguardVisibilityHelper { // Ask the screen off animation controller to animate the keyguard visibility for us // since it may need to be cancelled due to keyguard lifecycle events. - mScreenOffAnimationController.animateInKeyguard( + mKeyguardAnimatorHandle = mScreenOffAnimationController.animateInKeyguard( mView, mAnimateKeyguardStatusViewVisibleEndRunnable); } else { log("Direct set Visibility to VISIBLE"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt index c8174669cc65..b3031515ae9d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt @@ -85,16 +85,17 @@ class ScreenOffAnimationController @Inject constructor( /** * Called when keyguard is about to be displayed and allows to perform custom animation + * + * @return A handle that can be used for cancelling the animation, if necessary */ - fun animateInKeyguard(keyguardView: View, after: Runnable) = - animations.firstOrNull { + fun animateInKeyguard(keyguardView: View, after: Runnable): AnimatorHandle? { + animations.forEach { if (it.shouldAnimateInKeyguard()) { - it.animateInKeyguard(keyguardView, after) - true - } else { - false + return@animateInKeyguard it.animateInKeyguard(keyguardView, after) } } + return null + } /** * If returns true it will disable propagating touches to apps and keyguard @@ -211,7 +212,10 @@ interface ScreenOffAnimation { fun onAlwaysOnChanged(alwaysOn: Boolean) {} fun shouldAnimateInKeyguard(): Boolean = false - fun animateInKeyguard(keyguardView: View, after: Runnable) = after.run() + fun animateInKeyguard(keyguardView: View, after: Runnable): AnimatorHandle? { + after.run() + return null + } fun shouldDelayKeyguardShow(): Boolean = false fun isKeyguardShowDelayed(): Boolean = false @@ -224,3 +228,7 @@ interface ScreenOffAnimation { fun shouldAnimateDozingChange(): Boolean = true fun shouldAnimateClockChange(): Boolean = true } + +interface AnimatorHandle { + fun cancel() +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt index 118bfc55dd4c..deb041454da4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt @@ -160,7 +160,7 @@ class UnlockedScreenOffAnimationController @Inject constructor( * Animates in the provided keyguard view, ending in the same position that it will be in on * AOD. */ - override fun animateInKeyguard(keyguardView: View, after: Runnable) { + override fun animateInKeyguard(keyguardView: View, after: Runnable): AnimatorHandle { shouldAnimateInKeyguard = false keyguardView.alpha = 0f keyguardView.visibility = View.VISIBLE @@ -175,11 +175,36 @@ class UnlockedScreenOffAnimationController @Inject constructor( // We animate the Y properly separately using the PropertyAnimator, as the panel // view also needs to update the end position. PropertyAnimator.cancelAnimation(keyguardView, AnimatableProperty.Y) - PropertyAnimator.setProperty<View>(keyguardView, AnimatableProperty.Y, currentY, - AnimationProperties().setDuration(duration.toLong()), - true /* animate */) - keyguardView.animate() + // Start the animation on the next frame using Choreographer APIs. animateInKeyguard() is + // called while the system is busy processing lots of requests, so delaying the animation a + // frame will mitigate jank. In the event the animation is cancelled before the next frame + // is called, this callback will be removed + val keyguardAnimator = keyguardView.animate() + val nextFrameCallback = TraceUtils.namedRunnable("startAnimateInKeyguard") { + PropertyAnimator.setProperty(keyguardView, AnimatableProperty.Y, currentY, + AnimationProperties().setDuration(duration.toLong()), + true /* animate */) + keyguardAnimator.start() + } + DejankUtils.postAfterTraversal(nextFrameCallback) + val animatorHandle = object : AnimatorHandle { + private var hasCancelled = false + override fun cancel() { + if (!hasCancelled) { + DejankUtils.removeCallbacks(nextFrameCallback) + // If we're cancelled, reset state flags/listeners. The end action above + // will not be called, which is what we want since that will finish the + // screen off animation and show the lockscreen, which we don't want if we + // were cancelled. + aodUiAnimationPlaying = false + decidedToAnimateGoingToSleep = null + keyguardView.animate().setListener(null) + hasCancelled = true + } + } + } + keyguardAnimator .setDuration(duration.toLong()) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .alpha(1f) @@ -205,14 +230,7 @@ class UnlockedScreenOffAnimationController @Inject constructor( } .setListener(object : AnimatorListenerAdapter() { override fun onAnimationCancel(animation: Animator?) { - // If we're cancelled, reset state flags/listeners. The end action above - // will not be called, which is what we want since that will finish the - // screen off animation and show the lockscreen, which we don't want if we - // were cancelled. - aodUiAnimationPlaying = false - decidedToAnimateGoingToSleep = null - keyguardView.animate().setListener(null) - + animatorHandle.cancel() interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD) } @@ -222,7 +240,7 @@ class UnlockedScreenOffAnimationController @Inject constructor( CUJ_SCREEN_OFF_SHOW_AOD) } }) - .start() + return animatorHandle } override fun onStartedWakingUp() { |