Loading core/java/com/android/internal/jank/Cuj.java +14 −2 Original line number Diff line number Diff line Loading @@ -147,8 +147,16 @@ public class Cuj { */ public static final int CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW = 104; /** * Track fade-in animation when in SystemUI process fold * * <p>Tracking starts after the screen turns on and finish when the animation is over {@link * com.android.systemui.unfold.FoldLightRevealOverlayAnimation#playFoldLightRevealOverlayAnimation} for the span */ public static final int CUJ_FOLD_ANIM = 105; // When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE. @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW; @VisibleForTesting static final int LAST_CUJ = CUJ_FOLD_ANIM; /** @hide */ @IntDef({ Loading Loading @@ -244,7 +252,8 @@ public class Cuj { CUJ_LAUNCHER_WIDGET_BOTTOM_SHEET_CLOSE_BACK, CUJ_LAUNCHER_PRIVATE_SPACE_LOCK, CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK, CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, CUJ_FOLD_ANIM }) @Retention(RetentionPolicy.SOURCE) public @interface CujType {} Loading Loading @@ -351,6 +360,7 @@ public class Cuj { CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_PRIVATE_SPACE_LOCK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_PRIVATE_SPACE_LOCK; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_PRIVATE_SPACE_UNLOCK; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_MAXIMIZE_WINDOW; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_FOLD_ANIM] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__FOLD_ANIM; } private Cuj() { Loading Loading @@ -555,6 +565,8 @@ public class Cuj { return "LAUNCHER_PRIVATE_SPACE_UNLOCK"; case CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW: return "DESKTOP_MODE_MAXIMIZE_WINDOW"; case CUJ_FOLD_ANIM: return "FOLD_ANIM"; } return "UNKNOWN"; } Loading packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt +21 −7 Original line number Diff line number Diff line Loading @@ -22,9 +22,12 @@ import android.animation.ValueAnimator import android.annotation.BinderThread import android.os.SystemProperties import android.util.Log import android.view.View import android.view.animation.DecelerateInterpolator import com.android.app.tracing.TraceUtils.traceAsync import com.android.internal.foldables.FoldLockSettingAvailabilityProvider import com.android.internal.jank.Cuj.CUJ_FOLD_ANIM import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.display.data.repository.DeviceStateRepository import com.android.systemui.power.domain.interactor.PowerInteractor Loading Loading @@ -65,7 +68,8 @@ constructor( @Background private val applicationScope: CoroutineScope, private val animationStatusRepository: AnimationStatusRepository, private val controllerFactory: FullscreenLightRevealAnimationController.Factory, private val foldLockSettingAvailabilityProvider: FoldLockSettingAvailabilityProvider private val foldLockSettingAvailabilityProvider: FoldLockSettingAvailabilityProvider, private val interactionJankMonitor: InteractionJankMonitor ) : FullscreenLightRevealAnimation { private val revealProgressValueAnimator: ValueAnimator = Loading Loading @@ -149,7 +153,8 @@ constructor( private suspend fun waitForGoToSleep() = traceAsync(TAG, "waitForGoToSleep()") { powerInteractor.isAsleep.filter { it }.first() } private suspend fun playFoldLightRevealOverlayAnimation() { private suspend fun playFoldLightRevealOverlayAnimation() = trackCuj(CUJ_FOLD_ANIM, controller.scrimView) { revealProgressValueAnimator.duration = ANIMATION_DURATION revealProgressValueAnimator.interpolator = DecelerateInterpolator() revealProgressValueAnimator.addUpdateListener { animation -> Loading @@ -158,6 +163,15 @@ constructor( revealProgressValueAnimator.startAndAwaitCompletion() } private suspend fun trackCuj(cuj: Int, view: View?, block: suspend () -> Unit) { view?.let { interactionJankMonitor.begin(it, cuj) } try { block() } finally { if (view != null) interactionJankMonitor.end(cuj) } } private suspend fun ValueAnimator.startAndAwaitCompletion(): Unit = suspendCancellableCoroutine { continuation -> val listener = Loading packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt +4 −1 Original line number Diff line number Diff line Loading @@ -81,7 +81,10 @@ constructor( private var currentRotation: Int = context.display.rotation private var root: SurfaceControlViewHost? = null private var scrimView: LightRevealScrim? = null /** The scrim view that is used to reveal the screen. */ var scrimView: LightRevealScrim? = null private set private val rotationWatcher = RotationWatcher() private val internalDisplayInfos: List<DisplayInfo> = Loading packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt +64 −20 Original line number Diff line number Diff line Loading @@ -22,7 +22,10 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.foldables.FoldLockSettingAvailabilityProvider import com.android.internal.jank.Cuj.CUJ_FOLD_ANIM import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.SysuiTestCase import com.android.systemui.animation.AnimatorTestRule import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState import com.android.systemui.display.data.repository.fakeDeviceStateRepository import com.android.systemui.kosmos.Kosmos Loading @@ -32,27 +35,34 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setScreenPowerState import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.power.shared.model.ScreenPowerState import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.util.animation.data.repository.fakeAnimationStatusRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.atLeast import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import org.mockito.kotlin.any import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.whenever @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) @RunWith(AndroidTestingRunner::class) @OptIn(ExperimentalCoroutinesApi::class) class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { @get:Rule val animatorTestRule = AnimatorTestRule(this) private val kosmos = Kosmos() private val testScope: TestScope = kosmos.testScope private val fakeDeviceStateRepository = kosmos.fakeDeviceStateRepository Loading @@ -63,6 +73,8 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { private val mockFoldLockSettingAvailabilityProvider = mock<FoldLockSettingAvailabilityProvider>() private val onOverlayReady = mock<Runnable>() private val mockJankMonitor = mock<InteractionJankMonitor>() private val mockScrimView = mock<LightRevealScrim>() private lateinit var foldLightRevealAnimation: FoldLightRevealOverlayAnimation @Before Loading @@ -71,6 +83,8 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { whenever(mockFoldLockSettingAvailabilityProvider.isFoldLockBehaviorAvailable) .thenReturn(true) fakeAnimationStatusRepository.onAnimationStatusChanged(true) whenever(mockFullScreenController.scrimView).thenReturn(mockScrimView) whenever(mockJankMonitor.begin(any(), eq(CUJ_FOLD_ANIM))).thenReturn(true) foldLightRevealAnimation = FoldLightRevealOverlayAnimation( Loading @@ -80,7 +94,8 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.backgroundScope, fakeAnimationStatusRepository, mockControllerFactory, mockFoldLockSettingAvailabilityProvider mockFoldLockSettingAvailabilityProvider, mockJankMonitor ) foldLightRevealAnimation.init() } Loading @@ -99,9 +114,9 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.runTest { foldDeviceToScreenOff() emitLastWakefulnessEventStartingToSleep() advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) turnScreenOn() advanceTimeBy(ANIMATION_DURATION) advanceTime(ANIMATION_DURATION) verifyFoldAnimationDidNotPlay() } Loading @@ -111,8 +126,8 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.runTest { foldDeviceToScreenOff() emitLastWakefulnessEventStartingToSleep() advanceTimeBy(SHORT_DELAY_MS) advanceTimeBy(ANIMATION_DURATION) advanceTime(SHORT_DELAY_MS) advanceTime(ANIMATION_DURATION) verifyFoldAnimationDidNotPlay() } Loading @@ -122,10 +137,10 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.runTest { foldDeviceToScreenOff() foldLightRevealAnimation.onScreenTurningOn {} advanceTimeBy(WAIT_FOR_ANIMATION_TIMEOUT_MS) advanceTime(WAIT_FOR_ANIMATION_TIMEOUT_MS) powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON) advanceTimeBy(SHORT_DELAY_MS) advanceTimeBy(ANIMATION_DURATION) advanceTime(SHORT_DELAY_MS) advanceTime(ANIMATION_DURATION) verifyFoldAnimationDidNotPlay() } Loading @@ -135,10 +150,12 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.runTest { foldDeviceToScreenOff() foldLightRevealAnimation.onScreenTurningOn {} advanceTimeBy(SHORT_DELAY_MS) advanceTimeBy(ANIMATION_DURATION) advanceTime(SHORT_DELAY_MS) clearInvocations(mockFullScreenController) // Unfold the device fakeDeviceStateRepository.emit(DeviceState.HALF_FOLDED) advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON) verifyOverlayWasRemoved() Loading @@ -149,11 +166,37 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.runTest { foldDeviceToScreenOff() turnScreenOn() advanceTimeBy(ANIMATION_DURATION) clearInvocations(mockFullScreenController) advanceTime(ANIMATION_DURATION) verifyOverlayWasRemoved() } @Test fun foldToScreenOn_jankCujIsStarted() = testScope.runTest { foldDeviceToScreenOff() turnScreenOn() // Cuj has started but not ended verify(mockJankMonitor, times(1)).begin(any(), eq(CUJ_FOLD_ANIM)) verify(mockJankMonitor, never()).end(eq(CUJ_FOLD_ANIM)) } @Test fun foldToScreenOn_animationFinished_jankCujIsFinished() = testScope.runTest { foldDeviceToScreenOff() turnScreenOn() advanceTime(ANIMATION_DURATION) verify(mockJankMonitor, times(1)).end(eq(CUJ_FOLD_ANIM)) } private fun TestScope.advanceTime(timeMs: Long) { animatorTestRule.advanceTimeBy(timeMs) advanceTimeBy(timeMs) } @Test fun unfold_immediatelyRunRunnable() = testScope.runTest { Loading @@ -165,18 +208,18 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { private suspend fun TestScope.foldDeviceToScreenOff() { fakeDeviceStateRepository.emit(DeviceState.HALF_FOLDED) powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON) advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) fakeDeviceStateRepository.emit(DeviceState.FOLDED) advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_OFF) advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) } private fun TestScope.turnScreenOn() { foldLightRevealAnimation.onScreenTurningOn {} advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON) advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) } private fun emitLastWakefulnessEventStartingToSleep() = Loading @@ -195,6 +238,7 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { const val WAIT_FOR_ANIMATION_TIMEOUT_MS = 2000L val ANIMATION_DURATION: Long get() = SystemProperties.getLong("persist.fold_animation_duration", 200L) const val SHORT_DELAY_MS = 50L } } Loading
core/java/com/android/internal/jank/Cuj.java +14 −2 Original line number Diff line number Diff line Loading @@ -147,8 +147,16 @@ public class Cuj { */ public static final int CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW = 104; /** * Track fade-in animation when in SystemUI process fold * * <p>Tracking starts after the screen turns on and finish when the animation is over {@link * com.android.systemui.unfold.FoldLightRevealOverlayAnimation#playFoldLightRevealOverlayAnimation} for the span */ public static final int CUJ_FOLD_ANIM = 105; // When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE. @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW; @VisibleForTesting static final int LAST_CUJ = CUJ_FOLD_ANIM; /** @hide */ @IntDef({ Loading Loading @@ -244,7 +252,8 @@ public class Cuj { CUJ_LAUNCHER_WIDGET_BOTTOM_SHEET_CLOSE_BACK, CUJ_LAUNCHER_PRIVATE_SPACE_LOCK, CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK, CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, CUJ_FOLD_ANIM }) @Retention(RetentionPolicy.SOURCE) public @interface CujType {} Loading Loading @@ -351,6 +360,7 @@ public class Cuj { CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_PRIVATE_SPACE_LOCK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_PRIVATE_SPACE_LOCK; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_PRIVATE_SPACE_UNLOCK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_PRIVATE_SPACE_UNLOCK; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_MAXIMIZE_WINDOW; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_FOLD_ANIM] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__FOLD_ANIM; } private Cuj() { Loading Loading @@ -555,6 +565,8 @@ public class Cuj { return "LAUNCHER_PRIVATE_SPACE_UNLOCK"; case CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW: return "DESKTOP_MODE_MAXIMIZE_WINDOW"; case CUJ_FOLD_ANIM: return "FOLD_ANIM"; } return "UNKNOWN"; } Loading
packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt +21 −7 Original line number Diff line number Diff line Loading @@ -22,9 +22,12 @@ import android.animation.ValueAnimator import android.annotation.BinderThread import android.os.SystemProperties import android.util.Log import android.view.View import android.view.animation.DecelerateInterpolator import com.android.app.tracing.TraceUtils.traceAsync import com.android.internal.foldables.FoldLockSettingAvailabilityProvider import com.android.internal.jank.Cuj.CUJ_FOLD_ANIM import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.display.data.repository.DeviceStateRepository import com.android.systemui.power.domain.interactor.PowerInteractor Loading Loading @@ -65,7 +68,8 @@ constructor( @Background private val applicationScope: CoroutineScope, private val animationStatusRepository: AnimationStatusRepository, private val controllerFactory: FullscreenLightRevealAnimationController.Factory, private val foldLockSettingAvailabilityProvider: FoldLockSettingAvailabilityProvider private val foldLockSettingAvailabilityProvider: FoldLockSettingAvailabilityProvider, private val interactionJankMonitor: InteractionJankMonitor ) : FullscreenLightRevealAnimation { private val revealProgressValueAnimator: ValueAnimator = Loading Loading @@ -149,7 +153,8 @@ constructor( private suspend fun waitForGoToSleep() = traceAsync(TAG, "waitForGoToSleep()") { powerInteractor.isAsleep.filter { it }.first() } private suspend fun playFoldLightRevealOverlayAnimation() { private suspend fun playFoldLightRevealOverlayAnimation() = trackCuj(CUJ_FOLD_ANIM, controller.scrimView) { revealProgressValueAnimator.duration = ANIMATION_DURATION revealProgressValueAnimator.interpolator = DecelerateInterpolator() revealProgressValueAnimator.addUpdateListener { animation -> Loading @@ -158,6 +163,15 @@ constructor( revealProgressValueAnimator.startAndAwaitCompletion() } private suspend fun trackCuj(cuj: Int, view: View?, block: suspend () -> Unit) { view?.let { interactionJankMonitor.begin(it, cuj) } try { block() } finally { if (view != null) interactionJankMonitor.end(cuj) } } private suspend fun ValueAnimator.startAndAwaitCompletion(): Unit = suspendCancellableCoroutine { continuation -> val listener = Loading
packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt +4 −1 Original line number Diff line number Diff line Loading @@ -81,7 +81,10 @@ constructor( private var currentRotation: Int = context.display.rotation private var root: SurfaceControlViewHost? = null private var scrimView: LightRevealScrim? = null /** The scrim view that is used to reveal the screen. */ var scrimView: LightRevealScrim? = null private set private val rotationWatcher = RotationWatcher() private val internalDisplayInfos: List<DisplayInfo> = Loading
packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt +64 −20 Original line number Diff line number Diff line Loading @@ -22,7 +22,10 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.foldables.FoldLockSettingAvailabilityProvider import com.android.internal.jank.Cuj.CUJ_FOLD_ANIM import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.SysuiTestCase import com.android.systemui.animation.AnimatorTestRule import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState import com.android.systemui.display.data.repository.fakeDeviceStateRepository import com.android.systemui.kosmos.Kosmos Loading @@ -32,27 +35,34 @@ import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.se import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setScreenPowerState import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.power.shared.model.ScreenPowerState import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.util.animation.data.repository.fakeAnimationStatusRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.atLeast import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import org.mockito.kotlin.any import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.whenever @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) @RunWith(AndroidTestingRunner::class) @OptIn(ExperimentalCoroutinesApi::class) class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { @get:Rule val animatorTestRule = AnimatorTestRule(this) private val kosmos = Kosmos() private val testScope: TestScope = kosmos.testScope private val fakeDeviceStateRepository = kosmos.fakeDeviceStateRepository Loading @@ -63,6 +73,8 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { private val mockFoldLockSettingAvailabilityProvider = mock<FoldLockSettingAvailabilityProvider>() private val onOverlayReady = mock<Runnable>() private val mockJankMonitor = mock<InteractionJankMonitor>() private val mockScrimView = mock<LightRevealScrim>() private lateinit var foldLightRevealAnimation: FoldLightRevealOverlayAnimation @Before Loading @@ -71,6 +83,8 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { whenever(mockFoldLockSettingAvailabilityProvider.isFoldLockBehaviorAvailable) .thenReturn(true) fakeAnimationStatusRepository.onAnimationStatusChanged(true) whenever(mockFullScreenController.scrimView).thenReturn(mockScrimView) whenever(mockJankMonitor.begin(any(), eq(CUJ_FOLD_ANIM))).thenReturn(true) foldLightRevealAnimation = FoldLightRevealOverlayAnimation( Loading @@ -80,7 +94,8 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.backgroundScope, fakeAnimationStatusRepository, mockControllerFactory, mockFoldLockSettingAvailabilityProvider mockFoldLockSettingAvailabilityProvider, mockJankMonitor ) foldLightRevealAnimation.init() } Loading @@ -99,9 +114,9 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.runTest { foldDeviceToScreenOff() emitLastWakefulnessEventStartingToSleep() advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) turnScreenOn() advanceTimeBy(ANIMATION_DURATION) advanceTime(ANIMATION_DURATION) verifyFoldAnimationDidNotPlay() } Loading @@ -111,8 +126,8 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.runTest { foldDeviceToScreenOff() emitLastWakefulnessEventStartingToSleep() advanceTimeBy(SHORT_DELAY_MS) advanceTimeBy(ANIMATION_DURATION) advanceTime(SHORT_DELAY_MS) advanceTime(ANIMATION_DURATION) verifyFoldAnimationDidNotPlay() } Loading @@ -122,10 +137,10 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.runTest { foldDeviceToScreenOff() foldLightRevealAnimation.onScreenTurningOn {} advanceTimeBy(WAIT_FOR_ANIMATION_TIMEOUT_MS) advanceTime(WAIT_FOR_ANIMATION_TIMEOUT_MS) powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON) advanceTimeBy(SHORT_DELAY_MS) advanceTimeBy(ANIMATION_DURATION) advanceTime(SHORT_DELAY_MS) advanceTime(ANIMATION_DURATION) verifyFoldAnimationDidNotPlay() } Loading @@ -135,10 +150,12 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.runTest { foldDeviceToScreenOff() foldLightRevealAnimation.onScreenTurningOn {} advanceTimeBy(SHORT_DELAY_MS) advanceTimeBy(ANIMATION_DURATION) advanceTime(SHORT_DELAY_MS) clearInvocations(mockFullScreenController) // Unfold the device fakeDeviceStateRepository.emit(DeviceState.HALF_FOLDED) advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON) verifyOverlayWasRemoved() Loading @@ -149,11 +166,37 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { testScope.runTest { foldDeviceToScreenOff() turnScreenOn() advanceTimeBy(ANIMATION_DURATION) clearInvocations(mockFullScreenController) advanceTime(ANIMATION_DURATION) verifyOverlayWasRemoved() } @Test fun foldToScreenOn_jankCujIsStarted() = testScope.runTest { foldDeviceToScreenOff() turnScreenOn() // Cuj has started but not ended verify(mockJankMonitor, times(1)).begin(any(), eq(CUJ_FOLD_ANIM)) verify(mockJankMonitor, never()).end(eq(CUJ_FOLD_ANIM)) } @Test fun foldToScreenOn_animationFinished_jankCujIsFinished() = testScope.runTest { foldDeviceToScreenOff() turnScreenOn() advanceTime(ANIMATION_DURATION) verify(mockJankMonitor, times(1)).end(eq(CUJ_FOLD_ANIM)) } private fun TestScope.advanceTime(timeMs: Long) { animatorTestRule.advanceTimeBy(timeMs) advanceTimeBy(timeMs) } @Test fun unfold_immediatelyRunRunnable() = testScope.runTest { Loading @@ -165,18 +208,18 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { private suspend fun TestScope.foldDeviceToScreenOff() { fakeDeviceStateRepository.emit(DeviceState.HALF_FOLDED) powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON) advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) fakeDeviceStateRepository.emit(DeviceState.FOLDED) advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_OFF) advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) } private fun TestScope.turnScreenOn() { foldLightRevealAnimation.onScreenTurningOn {} advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) powerInteractor.setScreenPowerState(ScreenPowerState.SCREEN_ON) advanceTimeBy(SHORT_DELAY_MS) advanceTime(SHORT_DELAY_MS) } private fun emitLastWakefulnessEventStartingToSleep() = Loading @@ -195,6 +238,7 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() { const val WAIT_FOR_ANIMATION_TIMEOUT_MS = 2000L val ANIMATION_DURATION: Long get() = SystemProperties.getLong("persist.fold_animation_duration", 200L) const val SHORT_DELAY_MS = 50L } }