summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/jank/Cuj.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt84
4 files changed, 103 insertions, 30 deletions
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 23bd64dd1068..a52d33ab7c42 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -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({
@@ -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 {}
@@ -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() {
@@ -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";
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt
index aea739dcb6cc..9faa84ea9120 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt
@@ -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
@@ -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 =
@@ -149,13 +153,23 @@ constructor(
private suspend fun waitForGoToSleep() =
traceAsync(TAG, "waitForGoToSleep()") { powerInteractor.isAsleep.filter { it }.first() }
- private suspend fun playFoldLightRevealOverlayAnimation() {
- revealProgressValueAnimator.duration = ANIMATION_DURATION
- revealProgressValueAnimator.interpolator = DecelerateInterpolator()
- revealProgressValueAnimator.addUpdateListener { animation ->
- controller.updateRevealAmount(animation.animatedFraction)
+ private suspend fun playFoldLightRevealOverlayAnimation() =
+ trackCuj(CUJ_FOLD_ANIM, controller.scrimView) {
+ revealProgressValueAnimator.duration = ANIMATION_DURATION
+ revealProgressValueAnimator.interpolator = DecelerateInterpolator()
+ revealProgressValueAnimator.addUpdateListener { animation ->
+ controller.updateRevealAmount(animation.animatedFraction)
+ }
+ 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)
}
- revealProgressValueAnimator.startAndAwaitCompletion()
}
private suspend fun ValueAnimator.startAndAwaitCompletion(): Unit =
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
index 135edfcb6a42..f368cac53dbb 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
@@ -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> =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
index dddc71216da1..a56507af6575 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
@@ -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
@@ -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
@@ -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
@@ -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(
@@ -80,7 +94,8 @@ class FoldLightRevealOverlayAnimationTest : SysuiTestCase() {
testScope.backgroundScope,
fakeAnimationStatusRepository,
mockControllerFactory,
- mockFoldLockSettingAvailabilityProvider
+ mockFoldLockSettingAvailabilityProvider,
+ mockJankMonitor
)
foldLightRevealAnimation.init()
}
@@ -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()
}
@@ -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()
}
@@ -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()
}
@@ -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()
@@ -149,12 +166,38 @@ 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 {
foldLightRevealAnimation.onScreenTurningOn(onOverlayReady)
@@ -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() =
@@ -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
}
}