Fix jank in CUJ_SCREEN_OFF_SHOW_AOD
Use Choreographer to delay animation and mitigate jank in J<SCREEN_OFF_SHOW_AOD> Test: capture perfetto trace while turning screen off from home screen Bug: 262705829 Change-Id: I6c34668f41ce34d0b7f6bbc0021f149083c38c9b
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user