Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 485411cb authored by Daniel Akinola's avatar Daniel Akinola
Browse files

Add CUJs for sysui e2e shade perf tests

Adding CUJs for sysui e2e scenarios related to connected display shade.

Bug: 362719719
Bug: 378688537
Test: EXEMPT refactor only
Flag: com.android.systemui.shade_window_goes_around
Change-Id: I3d04b0a09ba60d1e998709a6eaaf9484cf2d2611
parent b56f987a
Loading
Loading
Loading
Loading
+14 −3
Original line number Original line Diff line number Diff line
@@ -416,8 +416,16 @@ public class Cuj {
     */
     */
    public static final int CUJ_WEAR_NOTIFICATION_TRAY_OPEN = 137;
    public static final int CUJ_WEAR_NOTIFICATION_TRAY_OPEN = 137;


    /**
     * Tracking when notification shade window gets moved between displays
     *
     * <p>Tracking starts when the notification shade starts to move to a new display, and ends
     * when the notification shade is fully expanded in the new display.
     */
    public static final int CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE = 138;

    // When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
    // When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
    @VisibleForTesting static final int LAST_CUJ = CUJ_WEAR_NOTIFICATION_TRAY_OPEN;
    @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE;


    /** @hide */
    /** @hide */
    @IntDef({
    @IntDef({
@@ -546,8 +554,8 @@ public class Cuj {
            CUJ_WEAR_CAROUSEL_FLING_JANK,
            CUJ_WEAR_CAROUSEL_FLING_JANK,
            CUJ_WEAR_CAROUSEL_SWIPE_JANK,
            CUJ_WEAR_CAROUSEL_SWIPE_JANK,
            CUJ_WEAR_QSS_TRAY_OPEN,
            CUJ_WEAR_QSS_TRAY_OPEN,
            CUJ_WEAR_NOTIFICATION_TRAY_OPEN
            CUJ_WEAR_NOTIFICATION_TRAY_OPEN,

            CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface CujType {}
    public @interface CujType {}
@@ -687,6 +695,7 @@ public class Cuj {
        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WEAR_CAROUSEL_SWIPE_JANK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WEAR_CAROUSEL_SWIPE_JANK;
        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WEAR_CAROUSEL_SWIPE_JANK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WEAR_CAROUSEL_SWIPE_JANK;
        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WEAR_QSS_TRAY_OPEN] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WEAR_QSS_TRAY_OPEN;
        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WEAR_QSS_TRAY_OPEN] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WEAR_QSS_TRAY_OPEN;
        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WEAR_NOTIFICATION_TRAY_OPEN] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WEAR_NOTIFICATION_TRAY_OPEN;
        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WEAR_NOTIFICATION_TRAY_OPEN] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WEAR_NOTIFICATION_TRAY_OPEN;
        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE;
    }
    }


    private Cuj() {
    private Cuj() {
@@ -957,6 +966,8 @@ public class Cuj {
                return "WEAR_QSS_TRAY_OPEN";
                return "WEAR_QSS_TRAY_OPEN";
            case CUJ_WEAR_NOTIFICATION_TRAY_OPEN:
            case CUJ_WEAR_NOTIFICATION_TRAY_OPEN:
                return "WEAR_NOTIFICATION_TRAY_OPEN";
                return "WEAR_NOTIFICATION_TRAY_OPEN";
            case CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE:
                return "DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE";
        }
        }
        return "UNKNOWN";
        return "UNKNOWN";
    }
    }
+80 −4
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import com.android.internal.logging.latencyTracker
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.common.ui.view.fakeChoreographerUtils
import com.android.systemui.common.ui.view.fakeChoreographerUtils
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
import com.android.systemui.testKosmos
@@ -30,6 +31,7 @@ import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.runTest
import org.junit.runner.RunWith
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mockito.never
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verify
@@ -38,14 +40,16 @@ import org.mockito.kotlin.any
@SmallTest
@SmallTest
@RunWith(AndroidJUnit4::class)
@RunWith(AndroidJUnit4::class)
@android.platform.test.annotations.EnabledOnRavenwood
@android.platform.test.annotations.EnabledOnRavenwood
class ShadeDisplayChangeLatencyTrackerTest : SysuiTestCase() {
class ShadeDisplayChangePerformanceTrackerTest : SysuiTestCase() {
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val configurationRepository = kosmos.fakeConfigurationRepository
    private val configurationRepository = kosmos.fakeConfigurationRepository
    private val latencyTracker = kosmos.latencyTracker
    private val latencyTracker = kosmos.latencyTracker
    private val jankMonitor = kosmos.interactionJankMonitor
    private val testScope = kosmos.testScope
    private val testScope = kosmos.testScope
    private val choreographerUtils = kosmos.fakeChoreographerUtils
    private val choreographerUtils = kosmos.fakeChoreographerUtils
    private val shadeTestUtil = kosmos.shadeTestUtil


    private val underTest = kosmos.shadeDisplayChangeLatencyTracker
    private val underTest = kosmos.shadeDisplayChangePerformanceTracker


    @Test
    @Test
    fun onShadeDisplayChanging_afterMovedToDisplayAndDoFrameCompleted_atomReported() =
    fun onShadeDisplayChanging_afterMovedToDisplayAndDoFrameCompleted_atomReported() =
@@ -61,6 +65,28 @@ class ShadeDisplayChangeLatencyTrackerTest : SysuiTestCase() {
            verify(latencyTracker).onActionEnd(any())
            verify(latencyTracker).onActionEnd(any())
        }
        }


    @Test
    fun onShadeDisplayChanging_jankCujBegins() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)

            verify(jankMonitor).begin(any(), anyInt())
        }

    @Test
    fun onShadeDisplayChanging_afterShadeExpansion_jankCujEnd() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)

            verify(jankMonitor).begin(any(), anyInt())

            sendOnMovedToDisplay(1)
            choreographerUtils.completeDoFrame()
            shadeTestUtil.setShadeExpansion(1f)

            verify(jankMonitor).end(anyInt())
        }

    @Test
    @Test
    fun onChange_doFrameTimesOut_previousCancelled() =
    fun onChange_doFrameTimesOut_previousCancelled() =
        testScope.runTest {
        testScope.runTest {
@@ -87,10 +113,25 @@ class ShadeDisplayChangeLatencyTrackerTest : SysuiTestCase() {
            advanceTimeBy(100.seconds)
            advanceTimeBy(100.seconds)


            verify(latencyTracker).onActionCancel(any())
            verify(latencyTracker).onActionCancel(any())
            verify(jankMonitor).cancel(anyInt())
        }
        }


    @Test
    @Test
    fun onChange_whilePreviousWasInProgress_previousCancelledAndNewStarted() =
    fun onChange_onShadeExpandedTimesOut_cancelled() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)

            verify(jankMonitor).begin(any(), anyInt())

            sendOnMovedToDisplay(1)
            choreographerUtils.completeDoFrame()
            advanceTimeBy(100.seconds)

            verify(jankMonitor).cancel(anyInt())
        }

    @Test
    fun onChange_whilePreviousWasInProgress_previousLatencyRecordCancelledAndNewStarted() =
        testScope.runTest {
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)
            underTest.onShadeDisplayChanging(1)


@@ -103,7 +144,20 @@ class ShadeDisplayChangeLatencyTrackerTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    fun onChange_multiple_multipleReported() =
    fun onChange_whilePreviousWasInProgress_previousJankRecordCancelledAndNewStarted() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)

            verify(jankMonitor).begin(any(), anyInt())

            underTest.onShadeDisplayChanging(2)

            verify(jankMonitor).cancel(anyInt())
            verify(jankMonitor, times(2)).begin(any(), anyInt())
        }

    @Test
    fun onChange_multiple_multipleLatencyRecordReported() =
        testScope.runTest {
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)
            underTest.onShadeDisplayChanging(1)
            verify(latencyTracker).onActionStart(any())
            verify(latencyTracker).onActionStart(any())
@@ -122,6 +176,28 @@ class ShadeDisplayChangeLatencyTrackerTest : SysuiTestCase() {
            verify(latencyTracker, times(2)).onActionEnd(any())
            verify(latencyTracker, times(2)).onActionEnd(any())
        }
        }


    @Test
    fun onChange_multiple_multipleJankRecordReported() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)
            verify(jankMonitor).begin(any(), anyInt())

            sendOnMovedToDisplay(1)
            choreographerUtils.completeDoFrame()
            shadeTestUtil.setShadeExpansion(1f)

            verify(jankMonitor).end(anyInt())

            underTest.onShadeDisplayChanging(0)

            sendOnMovedToDisplay(0)
            choreographerUtils.completeDoFrame()
            shadeTestUtil.setShadeExpansion(1f)

            verify(jankMonitor, times(2)).begin(any(), anyInt())
            verify(jankMonitor, times(2)).end(anyInt())
        }

    private fun sendOnMovedToDisplay(displayId: Int) {
    private fun sendOnMovedToDisplay(displayId: Int) {
        configurationRepository.onMovedToDisplay(displayId)
        configurationRepository.onMovedToDisplay(displayId)
    }
    }
+3 −3
Original line number Original line Diff line number Diff line
@@ -58,7 +58,7 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
    private val positionRepository = kosmos.fakeShadeDisplaysRepository
    private val positionRepository = kosmos.fakeShadeDisplaysRepository
    private val shadeContext = kosmos.mockedWindowContext
    private val shadeContext = kosmos.mockedWindowContext
    private val resources = kosmos.mockResources
    private val resources = kosmos.mockResources
    private val latencyTracker = kosmos.mockedShadeDisplayChangeLatencyTracker
    private val performanceTracker = kosmos.mockedShadeDisplayChangePerformanceTracker
    private val configuration = mock<Configuration>()
    private val configuration = mock<Configuration>()
    private val display = mock<Display>()
    private val display = mock<Display>()
    private val activeNotificationRepository = kosmos.activeNotificationListRepository
    private val activeNotificationRepository = kosmos.activeNotificationListRepository
@@ -104,14 +104,14 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    fun start_shadeInWrongPosition_logsStartToLatencyTracker() =
    fun start_shadeInWrongPosition_logsStartToPerformanceTracker() =
        testScope.runTest {
        testScope.runTest {
            whenever(display.displayId).thenReturn(0)
            whenever(display.displayId).thenReturn(0)
            positionRepository.setPendingDisplayId(1)
            positionRepository.setPendingDisplayId(1)


            underTest.start()
            underTest.start()


            verify(latencyTracker).onShadeDisplayChanging(eq(1))
            verify(performanceTracker).onShadeDisplayChanging(eq(1))
        }
        }


    @Test
    @Test
+22 −9
Original line number Original line Diff line number Diff line
@@ -16,9 +16,12 @@
package com.android.systemui.shade
package com.android.systemui.shade


import android.util.Log
import android.util.Log
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.util.LatencyTracker
import com.android.internal.util.LatencyTracker
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
import com.android.systemui.shade.domain.interactor.ShadeDisplaysWaitInteractor
import com.android.systemui.shade.domain.interactor.ShadeDisplaysWaitInteractor
import java.util.concurrent.CancellationException
import java.util.concurrent.CancellationException
@@ -30,21 +33,23 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout
import kotlinx.coroutines.withTimeout


/**
/**
 * Tracks the time it takes to move the shade from one display to another.
 * Records the performance of moving the shade from one display to another - tracking both the
 * - The start event is when [ShadeDisplaysRepository] propagates the new display ID.
 * latency and jank involved in the process.
 * - The end event is one frame after the shade configuration controller receives a new
 * - Recording starts when [ShadeDisplaysRepository] propagates the new display ID.
 *   configuration change.
 * - Latency tracking ends one frame after the shade configuration controller receives a new
 *
 *   configuration change. (Note: even if the configuration of the new display is the same,
 * Note that even in the unlikely case the configuration of the new display is the same,
 *   onConfigurationChange is called anyway as it is triggered by
 * onConfigurationChange is called anyway as is is triggered by
 *   [NotificationShadeWindowView.onMovedToDisplay].
 *   [NotificationShadeWindowView.onMovedToDisplay].
 * - Jank tracking ends after the shade window is fully expanded.
 */
 */
@SysUISingleton
@SysUISingleton
class ShadeDisplayChangeLatencyTracker
class ShadeDisplayChangePerformanceTracker
@Inject
@Inject
constructor(
constructor(
    private val latencyTracker: LatencyTracker,
    private val latencyTracker: LatencyTracker,
    private val shadeRootView: WindowRootView,
    @Background private val bgScope: CoroutineScope,
    @Background private val bgScope: CoroutineScope,
    private val jankMonitor: InteractionJankMonitor,
    private val waitInteractor: ShadeDisplaysWaitInteractor,
    private val waitInteractor: ShadeDisplaysWaitInteractor,
) {
) {


@@ -69,10 +74,13 @@ constructor(


    private suspend fun onShadeDisplayChangingAsync(displayId: Int) {
    private suspend fun onShadeDisplayChangingAsync(displayId: Int) {
        try {
        try {
            jankMonitor.begin(shadeRootView, CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE)
            latencyTracker.onActionStart(SHADE_MOVE_ACTION)
            latencyTracker.onActionStart(SHADE_MOVE_ACTION)
            waitForOnMovedToDisplayDispatchedToView(displayId)
            waitForOnMovedToDisplayDispatchedToView(displayId)
            waitUntilNextDoFrameDone(displayId)
            waitUntilNextDoFrameDone(displayId)
            latencyTracker.onActionEnd(SHADE_MOVE_ACTION)
            latencyTracker.onActionEnd(SHADE_MOVE_ACTION)
            waitForShadeExpanded()
            jankMonitor.end(CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE)
        } catch (e: Exception) {
        } catch (e: Exception) {
            val reason =
            val reason =
                when (e) {
                when (e) {
@@ -84,6 +92,7 @@ constructor(
                }
                }
            Log.e(TAG, reason, e)
            Log.e(TAG, reason, e)
            latencyTracker.onActionCancel(SHADE_MOVE_ACTION)
            latencyTracker.onActionCancel(SHADE_MOVE_ACTION)
            jankMonitor.cancel(CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE)
        }
        }
    }
    }


@@ -97,6 +106,10 @@ constructor(
        withTimeout(TIMEOUT) { waitInteractor.waitForNextDoFrameDone(newDisplayId, TAG) }
        withTimeout(TIMEOUT) { waitInteractor.waitForNextDoFrameDone(newDisplayId, TAG) }
    }
    }


    private suspend fun waitForShadeExpanded() {
        withTimeout(TIMEOUT) { waitInteractor.waitForShadeExpanded(TAG) }
    }

    private companion object {
    private companion object {
        const val TAG = "ShadeDisplayLatency"
        const val TAG = "ShadeDisplayLatency"
        val TIMEOUT = 3.seconds
        val TIMEOUT = 3.seconds
+3 −3
Original line number Original line Diff line number Diff line
@@ -29,7 +29,7 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.core.LogLevel
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.shade.ShadeDisplayChangeLatencyTracker
import com.android.systemui.shade.ShadeDisplayChangePerformanceTracker
import com.android.systemui.shade.ShadeDisplayLog
import com.android.systemui.shade.ShadeDisplayLog
import com.android.systemui.shade.ShadeTraceLogger.logMoveShadeWindowTo
import com.android.systemui.shade.ShadeTraceLogger.logMoveShadeWindowTo
import com.android.systemui.shade.ShadeTraceLogger.t
import com.android.systemui.shade.ShadeTraceLogger.t
@@ -72,7 +72,7 @@ constructor(
    @ShadeDisplayAware private val shadeContext: WindowContext,
    @ShadeDisplayAware private val shadeContext: WindowContext,
    @Background private val bgScope: CoroutineScope,
    @Background private val bgScope: CoroutineScope,
    @Main private val mainThreadContext: CoroutineContext,
    @Main private val mainThreadContext: CoroutineContext,
    private val shadeDisplayChangeLatencyTracker: ShadeDisplayChangeLatencyTracker,
    private val shadeDisplayChangePerformanceTracker: ShadeDisplayChangePerformanceTracker,
    private val shadeExpandedInteractor: ShadeExpandedStateInteractor,
    private val shadeExpandedInteractor: ShadeExpandedStateInteractor,
    private val shadeExpansionIntent: ShadeExpansionIntent,
    private val shadeExpansionIntent: ShadeExpansionIntent,
    private val activeNotificationsInteractor: ActiveNotificationsInteractor,
    private val activeNotificationsInteractor: ActiveNotificationsInteractor,
@@ -142,7 +142,7 @@ constructor(
            withContext(mainThreadContext) {
            withContext(mainThreadContext) {
                traceReparenting {
                traceReparenting {
                    collapseAndExpandShadeIfNeeded(destinationId) {
                    collapseAndExpandShadeIfNeeded(destinationId) {
                        shadeDisplayChangeLatencyTracker.onShadeDisplayChanging(destinationId)
                        shadeDisplayChangePerformanceTracker.onShadeDisplayChanging(destinationId)
                        reparentToDisplayId(id = destinationId)
                        reparentToDisplayId(id = destinationId)
                    }
                    }
                    checkContextDisplayMatchesExpected(destinationId)
                    checkContextDisplayMatchesExpected(destinationId)
Loading