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

Commit a2c7d989 authored by Darrell Shi's avatar Darrell Shi
Browse files

Log ui events for transitions between hub and dream

Test: atest DreamOverlayServiceTest
Test: atest CommunalLoggerStartableTest
Test: verified manually on device
Fix: 327448990
Flag: com.android.systemui.communal_hub
Change-Id: Ic7b121d81dfcc96670c06c1bcbb8b4d8ee21f628
parent 6db50103
Loading
Loading
Loading
Loading
+159 −11
Original line number Original line Diff line number Diff line
@@ -22,10 +22,13 @@ import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneKey
import com.android.internal.logging.UiEventLogger
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.android.systemui.testKosmos
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -53,18 +56,21 @@ class CommunalLoggerStartableTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val testScope = kosmos.testScope


    private lateinit var communalInteractor: CommunalInteractor
    private lateinit var communalSceneInteractor: CommunalSceneInteractor
    private lateinit var keyguardRepository: FakeKeyguardRepository
    private lateinit var underTest: CommunalLoggerStartable
    private lateinit var underTest: CommunalLoggerStartable


    @Before
    @Before
    fun setUp() {
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        MockitoAnnotations.initMocks(this)
        communalInteractor = kosmos.communalInteractor
        communalSceneInteractor = kosmos.communalSceneInteractor
        keyguardRepository = kosmos.fakeKeyguardRepository


        underTest =
        underTest =
            CommunalLoggerStartable(
            CommunalLoggerStartable(
                testScope.backgroundScope,
                testScope.backgroundScope,
                communalInteractor,
                communalSceneInteractor,
                kosmos.keyguardInteractor,
                uiEventLogger,
                uiEventLogger,
            )
            )
        underTest.start()
        underTest.start()
@@ -73,10 +79,13 @@ class CommunalLoggerStartableTest : SysuiTestCase() {
    @Test
    @Test
    fun transitionStateLogging_enterCommunalHub() =
    fun transitionStateLogging_enterCommunalHub() =
        testScope.runTest {
        testScope.runTest {
            // Not dreaming
            keyguardRepository.setDreamingWithOverlay(false)

            // Transition state is default (non-communal)
            // Transition state is default (non-communal)
            val transitionState =
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Default))
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Default))
            communalInteractor.setTransitionState(transitionState)
            communalSceneInteractor.setTransitionState(transitionState)
            runCurrent()
            runCurrent()


            // Verify nothing is logged from the default state
            // Verify nothing is logged from the default state
@@ -99,12 +108,15 @@ class CommunalLoggerStartableTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    fun transitionStateLogging_enterCommunalHub_canceled() =
    fun transitionStateLogging_cancelEnteringCommunalHub() =
        testScope.runTest {
        testScope.runTest {
            // Not dreaming
            keyguardRepository.setDreamingWithOverlay(false)

            // Transition state is default (non-communal)
            // Transition state is default (non-communal)
            val transitionState =
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Default))
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Default))
            communalInteractor.setTransitionState(transitionState)
            communalSceneInteractor.setTransitionState(transitionState)
            runCurrent()
            runCurrent()


            // Verify nothing is logged from the default state
            // Verify nothing is logged from the default state
@@ -132,10 +144,13 @@ class CommunalLoggerStartableTest : SysuiTestCase() {
    @Test
    @Test
    fun transitionStateLogging_exitCommunalHub() =
    fun transitionStateLogging_exitCommunalHub() =
        testScope.runTest {
        testScope.runTest {
            // Not dreaming
            keyguardRepository.setDreamingWithOverlay(false)

            // Transition state is communal
            // Transition state is communal
            val transitionState =
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Communal))
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Communal))
            communalInteractor.setTransitionState(transitionState)
            communalSceneInteractor.setTransitionState(transitionState)
            runCurrent()
            runCurrent()


            // Verify SHOWN is logged when it's the default state
            // Verify SHOWN is logged when it's the default state
@@ -158,12 +173,15 @@ class CommunalLoggerStartableTest : SysuiTestCase() {
        }
        }


    @Test
    @Test
    fun transitionStateLogging_exitCommunalHub_canceled() =
    fun transitionStateLogging_cancelExitingCommunalHub() =
        testScope.runTest {
        testScope.runTest {
            // Not dreaming
            keyguardRepository.setDreamingWithOverlay(false)

            // Transition state is communal
            // Transition state is communal
            val transitionState =
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Communal))
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Communal))
            communalInteractor.setTransitionState(transitionState)
            communalSceneInteractor.setTransitionState(transitionState)
            runCurrent()
            runCurrent()


            // Clear the initial SHOWN event from the logger
            // Clear the initial SHOWN event from the logger
@@ -188,6 +206,136 @@ class CommunalLoggerStartableTest : SysuiTestCase() {
            verify(uiEventLogger, never()).log(CommunalUiEvent.COMMUNAL_HUB_GONE)
            verify(uiEventLogger, never()).log(CommunalUiEvent.COMMUNAL_HUB_GONE)
        }
        }


    @Test
    fun transitionStateLogging_dreaming_enterCommunalHub() =
        testScope.runTest {
            // Dreaming
            keyguardRepository.setDreamingWithOverlay(true)

            // Transition state is default (non-communal)
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Default))
            communalSceneInteractor.setTransitionState(transitionState)
            runCurrent()

            // Verify nothing is logged from the default state
            verify(uiEventLogger, never()).log(any())

            // Start transition to communal
            transitionState.value = transition(to = CommunalScenes.Communal)
            runCurrent()

            // Verify UiEvent logged
            verify(uiEventLogger).log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_SWIPE_START)

            // Finish transition to communal
            transitionState.value = idle(CommunalScenes.Communal)
            runCurrent()

            // Verify UiEvent logged
            verify(uiEventLogger).log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_SWIPE_FINISH)
            verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SHOWN)
        }

    @Test
    fun transitionStateLogging_dreaming_cancelEnteringCommunalHub() =
        testScope.runTest {
            // Dreaming
            keyguardRepository.setDreamingWithOverlay(true)

            // Transition state is default (non-communal)
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Default))
            communalSceneInteractor.setTransitionState(transitionState)
            runCurrent()

            // Verify nothing is logged from the default state
            verify(uiEventLogger, never()).log(any())

            // Start transition to communal
            transitionState.value = transition(to = CommunalScenes.Communal)
            runCurrent()

            // Verify UiEvent logged
            verify(uiEventLogger).log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_SWIPE_START)

            // Cancel the transition
            transitionState.value = idle(CommunalScenes.Default)
            runCurrent()

            // Verify UiEvent logged
            verify(uiEventLogger).log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_SWIPE_CANCEL)

            // Verify neither SHOWN nor GONE is logged
            verify(uiEventLogger, never()).log(CommunalUiEvent.COMMUNAL_HUB_SHOWN)
            verify(uiEventLogger, never()).log(CommunalUiEvent.COMMUNAL_HUB_GONE)
        }

    @Test
    fun transitionStateLogging_dreaming_exitCommunalHub() =
        testScope.runTest {
            // Dreaming
            keyguardRepository.setDreamingWithOverlay(true)

            // Transition state is communal
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Communal))
            communalSceneInteractor.setTransitionState(transitionState)
            runCurrent()

            // Verify SHOWN is logged when it's the default state
            verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SHOWN)

            // Start transition from communal
            transitionState.value = transition(from = CommunalScenes.Communal)
            runCurrent()

            // Verify UiEvent logged
            verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_TO_DREAM_SWIPE_START)

            // Finish transition to communal
            transitionState.value = idle(CommunalScenes.Default)
            runCurrent()

            // Verify UiEvent logged
            verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_TO_DREAM_SWIPE_FINISH)
            verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_GONE)
        }

    @Test
    fun transitionStateLogging_dreaming_cancelExitingCommunalHub() =
        testScope.runTest {
            // Dreaming
            keyguardRepository.setDreamingWithOverlay(true)

            // Transition state is communal
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(idle(CommunalScenes.Communal))
            communalSceneInteractor.setTransitionState(transitionState)
            runCurrent()

            // Clear the initial SHOWN event from the logger
            clearInvocations(uiEventLogger)

            // Start transition from communal
            transitionState.value = transition(from = CommunalScenes.Communal)
            runCurrent()

            // Verify UiEvent logged
            verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_TO_DREAM_SWIPE_START)

            // Cancel the transition
            transitionState.value = idle(CommunalScenes.Communal)
            runCurrent()

            // Verify UiEvent logged
            verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_TO_DREAM_SWIPE_CANCEL)

            // Verify neither SHOWN nor GONE is logged
            verify(uiEventLogger, never()).log(CommunalUiEvent.COMMUNAL_HUB_SHOWN)
            verify(uiEventLogger, never()).log(CommunalUiEvent.COMMUNAL_HUB_GONE)
        }

    private fun transition(
    private fun transition(
        from: SceneKey = CommunalScenes.Default,
        from: SceneKey = CommunalScenes.Default,
        to: SceneKey = CommunalScenes.Default,
        to: SceneKey = CommunalScenes.Default,
+2 −0
Original line number Original line Diff line number Diff line
@@ -54,6 +54,7 @@ import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.complication.ComplicationHostViewController
import com.android.systemui.complication.ComplicationHostViewController
import com.android.systemui.complication.ComplicationLayoutEngine
import com.android.systemui.complication.ComplicationLayoutEngine
@@ -660,6 +661,7 @@ class DreamOverlayServiceTest : SysuiTestCase() {
            verify(mDreamOverlayCallback).onRedirectWake(true)
            verify(mDreamOverlayCallback).onRedirectWake(true)
            client.onWakeRequested()
            client.onWakeRequested()
            verify(mCommunalInteractor).changeScene(eq(CommunalScenes.Communal), isNull())
            verify(mCommunalInteractor).changeScene(eq(CommunalScenes.Communal), isNull())
            verify(mUiEventLogger).log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_DREAM_AWAKE_START)
        }
        }


    @Test
    @Test
+38 −11
Original line number Original line Diff line number Diff line
@@ -19,14 +19,16 @@ package com.android.systemui.communal.log
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.internal.logging.UiEventLogger
import com.android.internal.logging.UiEventLogger
import com.android.systemui.CoreStartable
import com.android.systemui.CoreStartable
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalScenes
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.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.filterNotNull
@@ -40,12 +42,13 @@ class CommunalLoggerStartable
@Inject
@Inject
constructor(
constructor(
    @Background private val backgroundScope: CoroutineScope,
    @Background private val backgroundScope: CoroutineScope,
    private val communalInteractor: CommunalInteractor,
    private val communalSceneInteractor: CommunalSceneInteractor,
    private val keyguardInteractor: KeyguardInteractor,
    private val uiEventLogger: UiEventLogger,
    private val uiEventLogger: UiEventLogger,
) : CoreStartable {
) : CoreStartable {


    override fun start() {
    override fun start() {
        communalInteractor.transitionState
        communalSceneInteractor.transitionState
            .map { state ->
            .map { state ->
                when {
                when {
                    state.isOnCommunal() -> CommunalUiEvent.COMMUNAL_HUB_SHOWN
                    state.isOnCommunal() -> CommunalUiEvent.COMMUNAL_HUB_SHOWN
@@ -60,22 +63,46 @@ constructor(
            .onEach { uiEvent -> uiEventLogger.log(uiEvent) }
            .onEach { uiEvent -> uiEventLogger.log(uiEvent) }
            .launchIn(backgroundScope)
            .launchIn(backgroundScope)


        communalInteractor.transitionState
        communalSceneInteractor.transitionState
            .pairwise()
            .pairwise()
            .map { (old, new) ->
            .combine(keyguardInteractor.isDreamingWithOverlay) { (old, new), isDreaming ->
                when {
                when {
                    new.isOnCommunal() && old.isSwipingToCommunal() ->
                    new.isOnCommunal() && old.isSwipingToCommunal() ->
                        if (isDreaming) {
                            CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_SWIPE_FINISH
                        } else {
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_FINISH
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_FINISH
                        }
                    new.isOnCommunal() && old.isSwipingFromCommunal() ->
                    new.isOnCommunal() && old.isSwipingFromCommunal() ->
                        if (isDreaming) {
                            CommunalUiEvent.COMMUNAL_HUB_TO_DREAM_SWIPE_CANCEL
                        } else {
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_CANCEL
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_CANCEL
                        }
                    new.isNotOnCommunal() && old.isSwipingFromCommunal() ->
                    new.isNotOnCommunal() && old.isSwipingFromCommunal() ->
                        if (isDreaming) {
                            CommunalUiEvent.COMMUNAL_HUB_TO_DREAM_SWIPE_FINISH
                        } else {
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_FINISH
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_FINISH
                        }
                    new.isNotOnCommunal() && old.isSwipingToCommunal() ->
                    new.isNotOnCommunal() && old.isSwipingToCommunal() ->
                        if (isDreaming) {
                            CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_SWIPE_CANCEL
                        } else {
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_CANCEL
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_CANCEL
                        }
                    new.isSwipingToCommunal() && old.isNotOnCommunal() ->
                    new.isSwipingToCommunal() && old.isNotOnCommunal() ->
                        if (isDreaming) {
                            CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_SWIPE_START
                        } else {
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_START
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_START
                        }
                    new.isSwipingFromCommunal() && old.isOnCommunal() ->
                    new.isSwipingFromCommunal() && old.isOnCommunal() ->
                        if (isDreaming) {
                            CommunalUiEvent.COMMUNAL_HUB_TO_DREAM_SWIPE_START
                        } else {
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_START
                            CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_START
                        }
                    else -> null
                    else -> null
                }
                }
            }
            }
+14 −8
Original line number Original line Diff line number Diff line
@@ -54,14 +54,20 @@ enum class CommunalUiEvent(private val id: Int) : UiEventEnum {
    COMMUNAL_HUB_SWIPE_UP_TO_BOUNCER(1573),
    COMMUNAL_HUB_SWIPE_UP_TO_BOUNCER(1573),
    @UiEvent(doc = "User performs a swipe down gesture from top to enter shade")
    @UiEvent(doc = "User performs a swipe down gesture from top to enter shade")
    COMMUNAL_HUB_SWIPE_DOWN_TO_SHADE(1574),
    COMMUNAL_HUB_SWIPE_DOWN_TO_SHADE(1574),
    @UiEvent(doc = "User performs a tap gesture on the UMO in Communal Hub")
    @UiEvent(doc = "User starts the swipe gesture to enter the Communal Hub from Dream")
    COMMUNAL_HUB_UMO_TAP(1858),
    DREAM_TO_COMMUNAL_HUB_SWIPE_START(1860),
    @UiEvent(
    @UiEvent(doc = "User finishes the swipe gesture to enter the Communal Hub from Dream")
        doc =
    DREAM_TO_COMMUNAL_HUB_SWIPE_FINISH(1861),
            "A transition from dream to Communal Hub starts. This can be triggered by a tap on " +
    @UiEvent(doc = "User cancels the swipe gesture to enter the Communal Hub from Dream")
                "the dream."
    DREAM_TO_COMMUNAL_HUB_SWIPE_CANCEL(1862),
    )
    @UiEvent(doc = "User starts the swipe gesture to exit the Communal Hub to go to Dream")
    FROM_DREAM_TO_COMMUNAL_HUB_TRANSITION_START(1859);
    COMMUNAL_HUB_TO_DREAM_SWIPE_START(1863),
    @UiEvent(doc = "User finishes the swipe gesture to exit the Communal Hub to go to Dream")
    COMMUNAL_HUB_TO_DREAM_SWIPE_FINISH(1864),
    @UiEvent(doc = "User cancels the swipe gesture to exit the Communal Hub to go to Dream")
    COMMUNAL_HUB_TO_DREAM_SWIPE_CANCEL(1865),
    @UiEvent(doc = "A transition from Dream to Communal Hub starts due to dream awakening")
    DREAM_TO_COMMUNAL_HUB_DREAM_AWAKE_START(1866);


    override fun getId(): Int {
    override fun getId(): Int {
        return id
        return id
+2 −0
Original line number Original line Diff line number Diff line
@@ -56,6 +56,7 @@ import com.android.systemui.ambient.touch.TouchMonitor;
import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent;
import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent;
import com.android.systemui.ambient.touch.scrim.ScrimManager;
import com.android.systemui.ambient.touch.scrim.ScrimManager;
import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.communal.shared.log.CommunalUiEvent;
import com.android.systemui.communal.shared.model.CommunalScenes;
import com.android.systemui.communal.shared.model.CommunalScenes;
import com.android.systemui.complication.Complication;
import com.android.systemui.complication.Complication;
import com.android.systemui.complication.dagger.ComplicationComponent;
import com.android.systemui.complication.dagger.ComplicationComponent;
@@ -407,6 +408,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ


    @Override
    @Override
    public void onWakeRequested() {
    public void onWakeRequested() {
        mUiEventLogger.log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_DREAM_AWAKE_START);
        mCommunalInteractor.changeScene(CommunalScenes.Communal, null);
        mCommunalInteractor.changeScene(CommunalScenes.Communal, null);
    }
    }