Fix jank in CUJ_NOTIFICATION_HEADS_UP_APPEAR

Use Choreographer to delay animation and mitigate jank in
J<NOTIFICATION_HEADS_UP_APPEAR>

Test: 1) setprop persist.debug.animator.trace_fraction true &&
      device_config put interaction_jank_monitor enabled true.
      2) Capture perfetto trace while posting test HUN. 3) Inspect the
      trace; verify that sysui's frames during the
      J<NOTIFICATION_HEADS_UP_APPEAR> CUJ are not in high latency state
Bug: 262705829
Change-Id: I34df2978310a27859725ede28dd556c35d4bd785
This commit is contained in:
Peter Kalauskas
2022-12-19 16:59:26 -08:00
parent 3e92172c8b
commit 64982b5314

View File

@@ -24,6 +24,7 @@ import android.graphics.Canvas;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.view.Choreographer;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
@@ -492,12 +493,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
if (animationListener != null) {
mAppearAnimator.addListener(animationListener);
}
if (delay > 0) {
// we need to apply the initial state already to avoid drawn frames in the wrong state
updateAppearAnimationAlpha();
updateAppearRect();
mAppearAnimator.setStartDelay(delay);
}
// we need to apply the initial state already to avoid drawn frames in the wrong state
updateAppearAnimationAlpha();
updateAppearRect();
mAppearAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mWasCancelled;
@@ -528,7 +526,20 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mWasCancelled = true;
}
});
mAppearAnimator.start();
// Cache the original animator so we can check if the animation should be started in the
// Choreographer callback. It's possible that the original animator (mAppearAnimator) is
// replaced with a new value before the callback is called.
ValueAnimator cachedAnimator = mAppearAnimator;
// Even when delay=0, starting the animation on the next frame is necessary to avoid jank.
// Not doing so will increase the chances our Animator will be forced to skip a value of
// the animation's progression, causing stutter.
Choreographer.getInstance().postFrameCallbackDelayed(
frameTimeNanos -> {
if (mAppearAnimator == cachedAnimator) {
mAppearAnimator.start();
}
}, delay);
}
private int getCujType(boolean isAppearing) {