Loading core/java/com/android/internal/jank/InteractionJankMonitor.java +22 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,8 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_UNLOCK_ANIMATION; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON; Loading Loading @@ -177,6 +179,8 @@ public class InteractionJankMonitor { public static final int CUJ_USER_SWITCH = 37; public static final int CUJ_SPLASHSCREEN_AVD = 38; public static final int CUJ_SPLASHSCREEN_EXIT_ANIM = 39; public static final int CUJ_SCREEN_OFF = 40; public static final int CUJ_SCREEN_OFF_SHOW_AOD = 41; private static final int NO_STATSD_LOGGING = -1; Loading Loading @@ -225,6 +229,8 @@ public class InteractionJankMonitor { UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD, }; private static volatile InteractionJankMonitor sInstance; Loading Loading @@ -285,6 +291,8 @@ public class InteractionJankMonitor { CUJ_USER_SWITCH, CUJ_SPLASHSCREEN_AVD, CUJ_SPLASHSCREEN_EXIT_ANIM, CUJ_SCREEN_OFF, CUJ_SCREEN_OFF_SHOW_AOD, }) @Retention(RetentionPolicy.SOURCE) public @interface CujType { Loading Loading @@ -422,6 +430,16 @@ public class InteractionJankMonitor { } } /** * @param cujType cuj type * @return true if the cuj is under instrumenting, false otherwise. */ public boolean isInstrumenting(@CujType int cujType) { synchronized (mLock) { return mRunningTrackers.contains(cujType); } } /** * Begins a trace session. * Loading Loading @@ -690,6 +708,10 @@ public class InteractionJankMonitor { return "SPLASHSCREEN_AVD"; case CUJ_SPLASHSCREEN_EXIT_ANIM: return "SPLASHSCREEN_EXIT_ANIM"; case CUJ_SCREEN_OFF: return "SCREEN_OFF"; case CUJ_SCREEN_OFF_SHOW_AOD: return "SCREEN_OFF_SHOW_AOD"; } return "UNKNOWN"; } Loading packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt +12 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,8 @@ class LinearLightRevealEffect(private val isVertical: Boolean) : LightRevealEffe override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) { val interpolatedAmount = INTERPOLATOR.getInterpolation(amount) scrim.interpolatedRevealAmount = interpolatedAmount scrim.startColorAlpha = getPercentPastThreshold(1 - interpolatedAmount, threshold = 1 - START_COLOR_REVEAL_PERCENTAGE) Loading Loading @@ -152,6 +154,7 @@ class CircleReveal( // non-interpolated amount val fadeAmount = getPercentPastThreshold(amount, 0.5f) val radius = startRadius + ((endRadius - startRadius) * amount) scrim.interpolatedRevealAmount = amount scrim.revealGradientEndColorAlpha = 1f - fadeAmount scrim.setRevealGradientBounds( centerX - radius /* left */, Loading Loading @@ -182,6 +185,7 @@ class PowerButtonReveal( with(scrim) { revealGradientEndColorAlpha = 1f - fadeAmount interpolatedRevealAmount = interpolatedAmount setRevealGradientBounds( width * (1f + OFF_SCREEN_START_AMOUNT) - width * WIDTH_INCREASE_MULTIPLIER * interpolatedAmount, Loading Loading @@ -284,6 +288,14 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, } } var interpolatedRevealAmount: Float = 1f val isScrimAlmostOccludes: Boolean get() { // if the interpolatedRevealAmount less than 0.1, over 90% of the screen is black. return interpolatedRevealAmount < 0.1f } private fun updateScrimOpaque() { isScrimOpaque = revealAmount == 0.0f && alpha == 1.0f && visibility == VISIBLE } Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +28 −3 Original line number Diff line number Diff line Loading @@ -9,6 +9,9 @@ import android.os.Handler import android.provider.Settings import android.view.Surface import android.view.View import com.android.internal.jank.InteractionJankMonitor import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD import com.android.systemui.animation.Interpolators import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.KeyguardViewMediator Loading Loading @@ -50,7 +53,8 @@ class UnlockedScreenOffAnimationController @Inject constructor( private val keyguardViewMediatorLazy: dagger.Lazy<KeyguardViewMediator>, private val keyguardStateController: KeyguardStateController, private val dozeParameters: dagger.Lazy<DozeParameters>, private val globalSettings: GlobalSettings private val globalSettings: GlobalSettings, private val interactionJankMonitor: InteractionJankMonitor ) : WakefulnessLifecycle.Observer, ScreenOffAnimation { private val handler = Handler() Loading Loading @@ -78,17 +82,28 @@ class UnlockedScreenOffAnimationController @Inject constructor( sendUnlockedScreenOffProgressUpdate( 1f - (it.animatedFraction as Float), 1f - (it.animatedValue as Float)) if (lightRevealScrim.isScrimAlmostOccludes && interactionJankMonitor.isInstrumenting(CUJ_SCREEN_OFF)) { // ends the instrument when the scrim almost occludes the screen. // because the following janky frames might not be perceptible. interactionJankMonitor.end(CUJ_SCREEN_OFF) } } addListener(object : AnimatorListenerAdapter() { override fun onAnimationCancel(animation: Animator?) { lightRevealScrim.revealAmount = 1f lightRevealAnimationPlaying = false sendUnlockedScreenOffProgressUpdate(0f, 0f) interactionJankMonitor.cancel(CUJ_SCREEN_OFF) } override fun onAnimationEnd(animation: Animator?) { lightRevealAnimationPlaying = false } override fun onAnimationStart(animation: Animator?) { interactionJankMonitor.begin(statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF) } }) } Loading Loading @@ -163,6 +178,16 @@ class UnlockedScreenOffAnimationController @Inject constructor( decidedToAnimateGoingToSleep = null // We need to unset the listener. These are persistent for future animators keyguardView.animate().setListener(null) interactionJankMonitor.end(CUJ_SCREEN_OFF_SHOW_AOD) } override fun onAnimationCancel(animation: Animator?) { interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD) } override fun onAnimationStart(animation: Animator?) { interactionJankMonitor.begin( statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF_SHOW_AOD) } }) .start() Loading Loading @@ -244,10 +269,10 @@ class UnlockedScreenOffAnimationController @Inject constructor( // already expanded and showing notifications/QS, the animation looks really messy. For now, // disable it if the notification panel is not fully collapsed. if ((!this::statusBar.isInitialized || !statusBar.notificationPanelViewController.isFullyCollapsed) !statusBar.notificationPanelViewController.isFullyCollapsed) && // Status bar might be expanded because we have started // playing the animation already && !isAnimationPlaying() !isAnimationPlaying() ) { return false } Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt +5 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.View import androidx.test.filters.SmallTest import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.KeyguardViewMediator import com.android.systemui.keyguard.WakefulnessLifecycle Loading Loading @@ -59,6 +60,8 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { private lateinit var wakefulnessLifecycle: WakefulnessLifecycle @Mock private lateinit var statusBarStateController: StatusBarStateControllerImpl @Mock private lateinit var interactionJankMonitor: InteractionJankMonitor @Before fun setUp() { Loading @@ -71,7 +74,8 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { dagger.Lazy<KeyguardViewMediator> { keyguardViewMediator }, keyguardStateController, dagger.Lazy<DozeParameters> { dozeParameters }, globalSettings globalSettings, interactionJankMonitor ) controller.initialize(statusbar, lightRevealScrim) } Loading Loading
core/java/com/android/internal/jank/InteractionJankMonitor.java +22 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,8 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_UNLOCK_ANIMATION; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON; Loading Loading @@ -177,6 +179,8 @@ public class InteractionJankMonitor { public static final int CUJ_USER_SWITCH = 37; public static final int CUJ_SPLASHSCREEN_AVD = 38; public static final int CUJ_SPLASHSCREEN_EXIT_ANIM = 39; public static final int CUJ_SCREEN_OFF = 40; public static final int CUJ_SCREEN_OFF_SHOW_AOD = 41; private static final int NO_STATSD_LOGGING = -1; Loading Loading @@ -225,6 +229,8 @@ public class InteractionJankMonitor { UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SCREEN_OFF_SHOW_AOD, }; private static volatile InteractionJankMonitor sInstance; Loading Loading @@ -285,6 +291,8 @@ public class InteractionJankMonitor { CUJ_USER_SWITCH, CUJ_SPLASHSCREEN_AVD, CUJ_SPLASHSCREEN_EXIT_ANIM, CUJ_SCREEN_OFF, CUJ_SCREEN_OFF_SHOW_AOD, }) @Retention(RetentionPolicy.SOURCE) public @interface CujType { Loading Loading @@ -422,6 +430,16 @@ public class InteractionJankMonitor { } } /** * @param cujType cuj type * @return true if the cuj is under instrumenting, false otherwise. */ public boolean isInstrumenting(@CujType int cujType) { synchronized (mLock) { return mRunningTrackers.contains(cujType); } } /** * Begins a trace session. * Loading Loading @@ -690,6 +708,10 @@ public class InteractionJankMonitor { return "SPLASHSCREEN_AVD"; case CUJ_SPLASHSCREEN_EXIT_ANIM: return "SPLASHSCREEN_EXIT_ANIM"; case CUJ_SCREEN_OFF: return "SCREEN_OFF"; case CUJ_SCREEN_OFF_SHOW_AOD: return "SCREEN_OFF_SHOW_AOD"; } return "UNKNOWN"; } Loading
packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt +12 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,8 @@ class LinearLightRevealEffect(private val isVertical: Boolean) : LightRevealEffe override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) { val interpolatedAmount = INTERPOLATOR.getInterpolation(amount) scrim.interpolatedRevealAmount = interpolatedAmount scrim.startColorAlpha = getPercentPastThreshold(1 - interpolatedAmount, threshold = 1 - START_COLOR_REVEAL_PERCENTAGE) Loading Loading @@ -152,6 +154,7 @@ class CircleReveal( // non-interpolated amount val fadeAmount = getPercentPastThreshold(amount, 0.5f) val radius = startRadius + ((endRadius - startRadius) * amount) scrim.interpolatedRevealAmount = amount scrim.revealGradientEndColorAlpha = 1f - fadeAmount scrim.setRevealGradientBounds( centerX - radius /* left */, Loading Loading @@ -182,6 +185,7 @@ class PowerButtonReveal( with(scrim) { revealGradientEndColorAlpha = 1f - fadeAmount interpolatedRevealAmount = interpolatedAmount setRevealGradientBounds( width * (1f + OFF_SCREEN_START_AMOUNT) - width * WIDTH_INCREASE_MULTIPLIER * interpolatedAmount, Loading Loading @@ -284,6 +288,14 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, } } var interpolatedRevealAmount: Float = 1f val isScrimAlmostOccludes: Boolean get() { // if the interpolatedRevealAmount less than 0.1, over 90% of the screen is black. return interpolatedRevealAmount < 0.1f } private fun updateScrimOpaque() { isScrimOpaque = revealAmount == 0.0f && alpha == 1.0f && visibility == VISIBLE } Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +28 −3 Original line number Diff line number Diff line Loading @@ -9,6 +9,9 @@ import android.os.Handler import android.provider.Settings import android.view.Surface import android.view.View import com.android.internal.jank.InteractionJankMonitor import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD import com.android.systemui.animation.Interpolators import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.KeyguardViewMediator Loading Loading @@ -50,7 +53,8 @@ class UnlockedScreenOffAnimationController @Inject constructor( private val keyguardViewMediatorLazy: dagger.Lazy<KeyguardViewMediator>, private val keyguardStateController: KeyguardStateController, private val dozeParameters: dagger.Lazy<DozeParameters>, private val globalSettings: GlobalSettings private val globalSettings: GlobalSettings, private val interactionJankMonitor: InteractionJankMonitor ) : WakefulnessLifecycle.Observer, ScreenOffAnimation { private val handler = Handler() Loading Loading @@ -78,17 +82,28 @@ class UnlockedScreenOffAnimationController @Inject constructor( sendUnlockedScreenOffProgressUpdate( 1f - (it.animatedFraction as Float), 1f - (it.animatedValue as Float)) if (lightRevealScrim.isScrimAlmostOccludes && interactionJankMonitor.isInstrumenting(CUJ_SCREEN_OFF)) { // ends the instrument when the scrim almost occludes the screen. // because the following janky frames might not be perceptible. interactionJankMonitor.end(CUJ_SCREEN_OFF) } } addListener(object : AnimatorListenerAdapter() { override fun onAnimationCancel(animation: Animator?) { lightRevealScrim.revealAmount = 1f lightRevealAnimationPlaying = false sendUnlockedScreenOffProgressUpdate(0f, 0f) interactionJankMonitor.cancel(CUJ_SCREEN_OFF) } override fun onAnimationEnd(animation: Animator?) { lightRevealAnimationPlaying = false } override fun onAnimationStart(animation: Animator?) { interactionJankMonitor.begin(statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF) } }) } Loading Loading @@ -163,6 +178,16 @@ class UnlockedScreenOffAnimationController @Inject constructor( decidedToAnimateGoingToSleep = null // We need to unset the listener. These are persistent for future animators keyguardView.animate().setListener(null) interactionJankMonitor.end(CUJ_SCREEN_OFF_SHOW_AOD) } override fun onAnimationCancel(animation: Animator?) { interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD) } override fun onAnimationStart(animation: Animator?) { interactionJankMonitor.begin( statusBar.notificationShadeWindowView, CUJ_SCREEN_OFF_SHOW_AOD) } }) .start() Loading Loading @@ -244,10 +269,10 @@ class UnlockedScreenOffAnimationController @Inject constructor( // already expanded and showing notifications/QS, the animation looks really messy. For now, // disable it if the notification panel is not fully collapsed. if ((!this::statusBar.isInitialized || !statusBar.notificationPanelViewController.isFullyCollapsed) !statusBar.notificationPanelViewController.isFullyCollapsed) && // Status bar might be expanded because we have started // playing the animation already && !isAnimationPlaying() !isAnimationPlaying() ) { return false } Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt +5 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.View import androidx.test.filters.SmallTest import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.KeyguardViewMediator import com.android.systemui.keyguard.WakefulnessLifecycle Loading Loading @@ -59,6 +60,8 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { private lateinit var wakefulnessLifecycle: WakefulnessLifecycle @Mock private lateinit var statusBarStateController: StatusBarStateControllerImpl @Mock private lateinit var interactionJankMonitor: InteractionJankMonitor @Before fun setUp() { Loading @@ -71,7 +74,8 @@ class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() { dagger.Lazy<KeyguardViewMediator> { keyguardViewMediator }, keyguardStateController, dagger.Lazy<DozeParameters> { dozeParameters }, globalSettings globalSettings, interactionJankMonitor ) controller.initialize(statusbar, lightRevealScrim) } Loading