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

Commit a9109e93 authored by Michał Brzeziński's avatar Michał Brzeziński Committed by Android (Google) Code Review
Browse files

Merge "Not measuring latency when fold event results in screen off" into main

parents 97858b29 ea30bf35
Loading
Loading
Loading
Loading
+47 −35
Original line number Diff line number Diff line
@@ -31,17 +31,13 @@ import com.android.systemui.deviceStateManager
import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.FOLDED
import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.HALF_FOLDED
import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.UNFOLDED
import com.android.systemui.display.data.repository.fakeDeviceStateRepository
import com.android.systemui.foldedDeviceStateList
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setScreenPowerState
import com.android.systemui.power.domain.interactor.PowerInteractorFactory
import com.android.systemui.power.shared.model.ScreenPowerState.SCREEN_OFF
import com.android.systemui.power.shared.model.ScreenPowerState.SCREEN_ON
import com.android.systemui.shared.system.SysUiStatsLog
import com.android.systemui.testKosmos
import com.android.systemui.unfold.DisplaySwitchLatencyTracker.Companion.FOLDABLE_DEVICE_STATE_CLOSED
@@ -82,7 +78,6 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
    private val testScope: TestScope = kosmos.testScope

    private val resources = mock<Resources>()
    private val deviceStateRepository = kosmos.fakeDeviceStateRepository
    private val powerInteractor = PowerInteractorFactory.create().powerInteractor
    private val keyguardInteractor = mock<KeyguardInteractor>()
    private val displaySwitchLatencyLogger = mock<DisplaySwitchLatencyLogger>()
@@ -106,7 +101,6 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
        whenever(keyguardInteractor.isAodAvailable).thenReturn(isAodAvailable)
        whenever(screenTimeoutPolicyRepository.screenTimeoutActive).thenReturn(screenTimeoutActive)
        powerInteractor.setAwakeForTest()
        powerInteractor.setScreenPowerState(SCREEN_ON)

        setDisplaySwitchState(Idle(newDeviceState = FOLDED))

@@ -166,7 +160,6 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
            setDisplaySwitchState(Idle(HALF_FOLDED))

            setDisplaySwitchState(Switching(HALF_FOLDED))
            powerInteractor.setScreenPowerState(SCREEN_ON)
            systemClock.advanceTime(200)
            setDisplaySwitchState(Idle(FOLDED))

@@ -185,22 +178,13 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
        testScope.runTest {
            isAodAvailable.emit(true)
            setDisplaySwitchState(Idle(HALF_FOLDED))
            setDisplaySwitchState(Switching(HALF_FOLDED))

            setDisplaySwitchState(Switching(HALF_FOLDED))
            powerInteractor.setAsleepForTest(sleepReason = GO_TO_SLEEP_REASON_DEVICE_FOLD)
            powerInteractor.setScreenPowerState(SCREEN_OFF)

            systemClock.advanceTime(200)
            setDisplaySwitchState(Idle(FOLDED))

            val expectedLoggedEvent =
                successfulEvent(
                    latencyMs = 200,
                    fromFoldableDeviceState = FOLDABLE_DEVICE_STATE_HALF_OPEN,
                    toFoldableDeviceState = FOLDABLE_DEVICE_STATE_CLOSED,
                    toState = SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__AOD,
                )
            assertThat(capturedLogEvent()).isEqualTo(expectedLoggedEvent)
            assertThat(capturedLogEvent().toState)
                .isEqualTo(SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__AOD)
        }
    }

@@ -211,20 +195,54 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
            isAodAvailable.emit(false)

            setDisplaySwitchState(Switching(HALF_FOLDED))

            powerInteractor.setAsleepForTest(sleepReason = GO_TO_SLEEP_REASON_DEVICE_FOLD)
            powerInteractor.setScreenPowerState(SCREEN_OFF)
            setDisplaySwitchState(Idle(FOLDED))

            assertThat(capturedLogEvent().toState)
                .isEqualTo(SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__SCREEN_OFF)
        }
    }

    @Test
    fun foldingWhileScreenIsAlreadyOff_capturesToStateAsScreenOff() {
        testScope.runTest {
            setDisplaySwitchState(Idle(HALF_FOLDED))
            powerInteractor.setAsleepForTest()

            setDisplaySwitchState(Switching(HALF_FOLDED))
            setDisplaySwitchState(Idle(FOLDED))

            val expectedLoggedEvent =
                successfulEvent(
                    latencyMs = 0,
                    fromFoldableDeviceState = FOLDABLE_DEVICE_STATE_HALF_OPEN,
                    toFoldableDeviceState = FOLDABLE_DEVICE_STATE_CLOSED,
                    toState = SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__SCREEN_OFF,
                )
            assertThat(capturedLogEvent()).isEqualTo(expectedLoggedEvent)
            assertThat(capturedLogEvent().toState)
                .isEqualTo(SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__SCREEN_OFF)
        }
    }

    @Test
    fun foldingWhileScreenIsAlreadyOff_capturesFromStateAsScreenOff() {
        testScope.runTest {
            setDisplaySwitchState(Idle(HALF_FOLDED))
            powerInteractor.setAsleepForTest()

            setDisplaySwitchState(Switching(HALF_FOLDED))
            setDisplaySwitchState(Idle(FOLDED))

            assertThat(capturedLogEvent().fromState)
                .isEqualTo(SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__FROM_STATE__SCREEN_OFF)
        }
    }

    @Test
    fun foldingWhileAod_capturesFromStateAsAod() {
        testScope.runTest {
            setDisplaySwitchState(Idle(HALF_FOLDED))
            powerInteractor.setAsleepForTest()
            isAodAvailable.value = true

            setDisplaySwitchState(Switching(HALF_FOLDED))
            setDisplaySwitchState(Idle(FOLDED))

            assertThat(capturedLogEvent().fromState)
                .isEqualTo(SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__FROM_STATE__AOD)
        }
    }

@@ -237,7 +255,6 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
            setDisplaySwitchState(Switching(HALF_FOLDED))

            powerInteractor.setAsleepForTest(sleepReason = GO_TO_SLEEP_REASON_DEVICE_FOLD)
            powerInteractor.setScreenPowerState(SCREEN_OFF)

            setDisplaySwitchState(Idle(FOLDED))

@@ -303,7 +320,6 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
            setDisplaySwitchState(Idle(HALF_FOLDED))

            setDisplaySwitchState(Switching(FOLDED))
            powerInteractor.setScreenPowerState(SCREEN_ON)
            setDisplaySwitchState(Idle(FOLDED))

            verify(latencyTracker).onActionEnd(ACTION_SWITCH_DISPLAY_FOLD)
@@ -349,7 +365,6 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
            setDisplaySwitchState(Switching(HALF_FOLDED))

            setDisplaySwitchState(Corrupted(HALF_FOLDED))
            powerInteractor.setScreenPowerState(SCREEN_ON)
            setDisplaySwitchState(Idle(UNFOLDED))

            verify(latencyTracker).onActionCancel(ACTION_SWITCH_DISPLAY_FOLD)
@@ -363,7 +378,6 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
            setDisplaySwitchState(Switching(HALF_FOLDED))
            setDisplaySwitchState(Corrupted(HALF_FOLDED))
            setDisplaySwitchState(Idle(FOLDED))
            powerInteractor.setScreenPowerState(SCREEN_ON)

            setDisplaySwitchState(Switching(HALF_FOLDED))
            setDisplaySwitchState(Idle(UNFOLDED))
@@ -381,7 +395,6 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
            setDisplaySwitchState(Idle(UNFOLDED))

            setDisplaySwitchState(Switching(FOLDED))
            powerInteractor.setScreenPowerState(SCREEN_ON)
            setDisplaySwitchState(Idle(FOLDED))

            verify(latencyTracker, times(2)).onActionStart(ACTION_SWITCH_DISPLAY_FOLD)
@@ -420,7 +433,6 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
    fun displaySwitchTimedOut_foldTrackingCancelled() {
        testScope.runTest {
            setDisplaySwitchState(Switching(HALF_FOLDED))
            powerInteractor.setScreenPowerState(SCREEN_ON)

            setDisplaySwitchState(Idle(FOLDED, timedOut = true))

+24 −13
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.shared.system.SysUiStatsLog
import com.android.systemui.unfold.DisplaySwitchLatencyTracker.DisplaySwitchLatencyEvent
import com.android.systemui.unfold.DisplaySwitchLatencyTracker.TrackingResult.CORRUPTED
@@ -103,7 +102,7 @@ constructor(
                    } else {
                        latencyTracker.onActionEnd(ACTION_SWITCH_DISPLAY_UNFOLD)

                        if (getCurrentState()
                        if (getToState()
                            != SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__SCREEN_OFF
                        ) {
                            latencyTracker.onActionEnd(ACTION_SWITCH_DISPLAY_FOLD)
@@ -150,8 +149,13 @@ constructor(
                else -> SUCCESS
            }
        val event = switchingUpdate.event ?: return
        val displaySwitchTimeMs = updatesChain.finalUpdate.elapsedTime - switchingUpdate.elapsedTime
        val toState = getCurrentState()
        val toState = getToState()
        val displaySwitchTimeMs =
            if (isStateScreenOff()) {
                LATENCY_UNDEFINED // we don't care about latency in this case
            } else {
                updatesChain.finalUpdate.elapsedTime - switchingUpdate.elapsedTime
            }
        log {
            "trackingResult=$trackingResult, " +
                "fromFoldableDeviceState=${startingIdleState.switchState.newDeviceState}" +
@@ -232,23 +236,29 @@ constructor(
            TIMED_OUT -> SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TRACKING_RESULT__TIMED_OUT
        }

    private fun getCurrentState(): Int =
    private fun getToState(): Int =
        // not checking asleep/screen off reason means we misrepresent toState for case when user
        // folds and quickly puts device to sleep with power button. But still it seems better
        // than not putting SCREEN_OFF as reason when device is just asleep and user folds.
        when {
            isStateAod() -> SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__AOD
            isStateScreenOff() -> SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__SCREEN_OFF
            else -> SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__UNKNOWN
        }

    private fun isStateAod(): Boolean = (isAsleepDueToFold() && isAodEnabled)
    private fun getFromState(): Int =
        when {
            isStateAod() -> SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__FROM_STATE__AOD
            isStateScreenOff() ->
                SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__FROM_STATE__SCREEN_OFF
            else -> SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__FROM_STATE__UNKNOWN
        }

    private fun isStateScreenOff(): Boolean = (isAsleepDueToFold() && !isAodEnabled)
    private fun isStateAod() = isAsleep() && isAodEnabled

    private fun isAsleepDueToFold(): Boolean {
        val lastWakefulnessEvent = powerInteractor.detailedWakefulness.value
    private fun isStateScreenOff() = isAsleep() && !isAodEnabled

        return (lastWakefulnessEvent.isAsleep() &&
            (lastWakefulnessEvent.lastSleepReason == WakeSleepReason.FOLD))
    }
    private fun isAsleep() = powerInteractor.detailedWakefulness.value.isAsleep()

    private inline fun log(msg: () -> String) {
        if (DEBUG) Log.d(TAG, msg())
@@ -262,7 +272,7 @@ constructor(
            } else {
                HAS_SCREEN_WAKELOCKS
            }
        return copy(screenWakelockStatus = screenWakelockStatus)
        return copy(screenWakelockStatus = screenWakelockStatus, fromState = getFromState())
    }

    /**
@@ -310,6 +320,7 @@ constructor(

    companion object {
        private const val VALUE_UNKNOWN = -1
        private const val LATENCY_UNDEFINED = -1
        private const val TAG = "DisplaySwitchLatency"
        private val DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE)

+10 −6
Original line number Diff line number Diff line
@@ -72,20 +72,24 @@ sealed interface DisplaySwitchState {

    /**
     * Displays are in a stable state aka not in the process of switching. If we couldn't track
     * display switch properly because end event never arrived within [SCREEN_EVENT_TIMEOUT],
     * [timedOut] is set to true.
     * display switch properly because end event never arrived within
     * [FoldableDisplaySwitchTrackingInteractor.SCREEN_EVENT_TIMEOUT], [timedOut] is set to true.
     */
    data class Idle(override val newDeviceState: DeviceState, val timedOut: Boolean = false) :
        DisplaySwitchState

    /** Displays are currently switching. This state can only come directly after [Idle] state. */
    /**
     * Displays are currently switching. This state can only come directly after [Idle] state.
     * Switching might not be visible to the user, that is, folding device with screen off still
     * emits Switching event as we're swapping default displays.
     */
    data class Switching(override val newDeviceState: DeviceState) : DisplaySwitchState

    /**
     * Switching displays happened multiple times before [Idle] state could settle. This state will
     * hold until no new display switch related events are sent within [COOL_DOWN_DURATION] window.
     * This event can only happen directly after [Switching] state and is always directly followed
     * by [Idle] state.
     * hold until no new display switch related events are sent within
     * [FoldableDisplaySwitchTrackingInteractor.COOL_DOWN_DURATION] window. This event can only
     * happen directly after [Switching] state and is always directly followed by [Idle] state.
     */
    data class Corrupted(override val newDeviceState: DeviceState) : DisplaySwitchState