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

Commit 137cb7b5 authored by dshivangi's avatar dshivangi
Browse files

Fix latency tracking for fold to screenoff case

Currently when the device goes to sleep on fold, the latency tracking
implementation waits for forever for the screen to turn ON.
The ideal behavior should be to not wait at all and knowing in
advance/instantaneously that the screen will not turn ON on fold.
This CL implemets a logic where we wait for 10 seconds for either
screen-turned-on or device-is-asleep event.

Test: atest DisplaySwitchLatencyTrackerTest
Bug: 286539409
Flag: ACONFIG fold_lock_setting_enabled TRUNKFOOD
Change-Id: I231276f1d87e91d45c29be807f3cb998c4bbcb5d
parent 4c1bdc28
Loading
Loading
Loading
Loading
+37 −11
Original line number Diff line number Diff line
@@ -29,25 +29,31 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.ScreenPowerState
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.shared.system.SysUiStatsLog
import com.android.systemui.unfold.DisplaySwitchLatencyTracker.DisplaySwitchLatencyEvent
import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg
import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor
import com.android.systemui.util.Compile
import com.android.systemui.util.Utils.isDeviceFoldable
import com.android.systemui.util.animation.data.repository.AnimationStatusRepository
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.race
import com.android.systemui.util.time.SystemClock
import com.android.systemui.util.time.measureTimeMillis
import java.time.Duration
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout

/**
 * [DisplaySwitchLatencyTracker] tracks latency and related fields for display switch of a foldable
@@ -70,6 +76,8 @@ constructor(
) : CoreStartable {

    private val backgroundDispatcher = singleThreadBgExecutor.asCoroutineDispatcher()
    private val isAodEnabled: Boolean
        get() = keyguardInteractor.isAodAvailable.value

    @OptIn(ExperimentalCoroutinesApi::class)
    override fun start() {
@@ -98,10 +106,16 @@ constructor(

                        val displaySwitchTimeMs =
                            measureTimeMillis(systemClock) {
                                try {
                                    withTimeout(SCREEN_EVENT_TIMEOUT) {
                                        traceAsync(TAG, "displaySwitch") {
                                            waitForDisplaySwitch(toFoldableDeviceState)
                                        }
                                    }
                                } catch (e: TimeoutCancellationException) {
                                    Log.e(TAG, "Wait for display switch timed out")
                                }
                            }

                        displaySwitchLatencyEvent =
                            displaySwitchLatencyEvent.withAfterFields(
@@ -129,19 +143,19 @@ constructor(
        val isTransitionEnabled =
            unfoldTransitionInteractor.isAvailable &&
                animationStatusRepository.areAnimationsEnabled().first()
        if (shouldWaitForScreenOn(toFoldableDeviceState, isTransitionEnabled)) {
            waitForScreenTurnedOn()
        } else {
        if (shouldWaitForTransitionStart(toFoldableDeviceState, isTransitionEnabled)) {
            traceAsync(TAG, "waitForTransitionStart()") {
                unfoldTransitionInteractor.waitForTransitionStart()
            }
        } else {
            race({ waitForScreenTurnedOn() }, { waitForGoToSleepWithScreenOff() })
        }
    }

    private fun shouldWaitForScreenOn(
    private fun shouldWaitForTransitionStart(
        toFoldableDeviceState: Int,
        isTransitionEnabled: Boolean
    ): Boolean = (toFoldableDeviceState == FOLDABLE_DEVICE_STATE_CLOSED || !isTransitionEnabled)
    ): Boolean = (toFoldableDeviceState != FOLDABLE_DEVICE_STATE_CLOSED && isTransitionEnabled)

    private suspend fun waitForScreenTurnedOn() {
        traceAsync(TAG, "waitForScreenTurnedOn()") {
@@ -149,19 +163,30 @@ constructor(
        }
    }

    private suspend fun waitForGoToSleepWithScreenOff() {
        traceAsync(TAG, "waitForGoToSleepWithScreenOff()") {
            powerInteractor.detailedWakefulness
                .filter { it.internalWakefulnessState == WakefulnessState.ASLEEP && !isAodEnabled }
                .first()
        }
    }

    private fun getCurrentState(): Int =
        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 {
    private fun isStateAod(): Boolean = (isAsleepDueToFold() && isAodEnabled)

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

    private fun isAsleepDueToFold(): Boolean {
        val lastWakefulnessEvent = powerInteractor.detailedWakefulness.value
        val isAodEnabled = keyguardInteractor.isAodAvailable.value

        return (lastWakefulnessEvent.isAsleep() &&
            (lastWakefulnessEvent.lastSleepReason == WakeSleepReason.FOLD) &&
            isAodEnabled)
            (lastWakefulnessEvent.lastSleepReason == WakeSleepReason.FOLD))
    }

    private inline fun log(msg: () -> String) {
@@ -232,6 +257,7 @@ constructor(
        private const val VALUE_UNKNOWN = -1
        private const val TAG = "DisplaySwitchLatency"
        private val DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE)
        private val SCREEN_EVENT_TIMEOUT = Duration.ofMillis(15000).toMillis()

        private const val FOLDABLE_DEVICE_STATE_UNKNOWN =
            SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__FROM_FOLDABLE_DEVICE_STATE__STATE_UNKNOWN
+34 −0
Original line number Diff line number Diff line
@@ -321,4 +321,38 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() {
            verify(displaySwitchLatencyLogger, never()).log(any())
        }
    }

    @Test
    fun foldToScreenOff_capturesToStateAsScreenOff() {
        testScope.runTest {
            areAnimationEnabled.emit(true)
            deviceState.emit(DeviceState.UNFOLDED)
            isAodAvailable.emit(false)

            displaySwitchLatencyTracker.start()
            deviceState.emit(DeviceState.HALF_FOLDED)
            systemClock.advanceTime(50)
            runCurrent()
            deviceState.emit(DeviceState.FOLDED)
            lastWakefulnessEvent.emit(
                WakefulnessModel(
                    internalWakefulnessState = WakefulnessState.ASLEEP,
                    lastSleepReason = WakeSleepReason.FOLD
                )
            )
            screenPowerState.emit(ScreenPowerState.SCREEN_OFF)
            runCurrent()

            verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor))
            val loggedEvent = loggerArgumentCaptor.value
            val expectedLoggedEvent =
                DisplaySwitchLatencyEvent(
                    latencyMs = 0,
                    fromFoldableDeviceState = FOLDABLE_DEVICE_STATE_HALF_OPEN,
                    toFoldableDeviceState = FOLDABLE_DEVICE_STATE_CLOSED,
                    toState = SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__SCREEN_OFF
                )
            assertThat(loggedEvent).isEqualTo(expectedLoggedEvent)
        }
    }
}