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

Commit 0b8413e9 authored by Helen Cheuk's avatar Helen Cheuk Committed by Android (Google) Code Review
Browse files

Merge "[Contextual Edu] Update data on education triggered" into main

parents 006496c2 a19b0f2b
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -85,7 +85,9 @@ class ContextualEducationRepositoryTest : SysuiTestCase() {
                GestureEduModel(
                    signalCount = 2,
                    educationShownCount = 1,
                    lastShortcutTriggeredTime = kosmos.fakeEduClock.instant()
                    lastShortcutTriggeredTime = kosmos.fakeEduClock.instant(),
                    lastEducationTime = kosmos.fakeEduClock.instant(),
                    usageSessionStartTime = kosmos.fakeEduClock.instant(),
                )
            underTest.updateGestureEduModel(BACK) { newModel }
            val model by collectLastValue(underTest.readGestureEduModelFlow(BACK))
+49 −3
Original line number Diff line number Diff line
@@ -22,9 +22,15 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.contextualeducation.GestureType
import com.android.systemui.contextualeducation.GestureType.BACK
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.education.data.model.GestureEduModel
import com.android.systemui.education.data.repository.contextualEducationRepository
import com.android.systemui.education.data.repository.fakeEduClock
import com.android.systemui.education.shared.model.EducationUiType
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -37,6 +43,7 @@ class KeyboardTouchpadEduInteractorTest : SysuiTestCase() {
    private val testScope = kosmos.testScope
    private val contextualEduInteractor = kosmos.contextualEducationInteractor
    private val underTest: KeyboardTouchpadEduInteractor = kosmos.keyboardTouchpadEduInteractor
    private val eduClock = kosmos.fakeEduClock

    @Before
    fun setup() {
@@ -46,11 +53,31 @@ class KeyboardTouchpadEduInteractorTest : SysuiTestCase() {
    @Test
    fun newEducationInfoOnMaxSignalCountReached() =
        testScope.runTest {
            tryTriggeringEducation(BACK)
            triggerMaxEducationSignals(BACK)
            val model by collectLastValue(underTest.educationTriggered)
            assertThat(model?.gestureType).isEqualTo(BACK)
        }

    @Test
    fun newEducationToastOn1stEducation() =
        testScope.runTest {
            val model by collectLastValue(underTest.educationTriggered)
            triggerMaxEducationSignals(BACK)
            assertThat(model?.educationUiType).isEqualTo(EducationUiType.Toast)
        }

    @Test
    @kotlinx.coroutines.ExperimentalCoroutinesApi
    fun newEducationNotificationOn2ndEducation() =
        testScope.runTest {
            val model by collectLastValue(underTest.educationTriggered)
            triggerMaxEducationSignals(BACK)
            // runCurrent() to trigger 1st education
            runCurrent()
            triggerMaxEducationSignals(BACK)
            assertThat(model?.educationUiType).isEqualTo(EducationUiType.Notification)
        }

    @Test
    fun noEducationInfoBeforeMaxSignalCountReached() =
        testScope.runTest {
@@ -64,11 +91,30 @@ class KeyboardTouchpadEduInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val model by collectLastValue(underTest.educationTriggered)
            contextualEduInteractor.updateShortcutTriggerTime(BACK)
            tryTriggeringEducation(BACK)
            triggerMaxEducationSignals(BACK)
            assertThat(model).isNull()
        }

    private suspend fun tryTriggeringEducation(gestureType: GestureType) {
    @Test
    fun startNewUsageSessionWhen2ndSignalReceivedAfterSessionDeadline() =
        testScope.runTest {
            val model by
                collectLastValue(kosmos.contextualEducationRepository.readGestureEduModelFlow(BACK))
            contextualEduInteractor.incrementSignalCount(BACK)
            eduClock.offset(KeyboardTouchpadEduInteractor.usageSessionDuration.plus(1.seconds))
            val secondSignalReceivedTime = eduClock.instant()
            contextualEduInteractor.incrementSignalCount(BACK)

            assertThat(model)
                .isEqualTo(
                    GestureEduModel(
                        signalCount = 1,
                        usageSessionStartTime = secondSignalReceivedTime
                    )
                )
        }

    private suspend fun triggerMaxEducationSignals(gestureType: GestureType) {
        // Increment max number of signal to try triggering education
        for (i in 1..KeyboardTouchpadEduInteractor.MAX_SIGNAL_COUNT) {
            contextualEduInteractor.incrementSignalCount(gestureType)
+2 −0
Original line number Diff line number Diff line
@@ -26,4 +26,6 @@ data class GestureEduModel(
    val signalCount: Int = 0,
    val educationShownCount: Int = 0,
    val lastShortcutTriggeredTime: Instant? = null,
    val usageSessionStartTime: Instant? = null,
    val lastEducationTime: Instant? = null,
)
+28 −2
Original line number Diff line number Diff line
@@ -73,6 +73,8 @@ constructor(
        const val SIGNAL_COUNT_SUFFIX = "_SIGNAL_COUNT"
        const val NUMBER_OF_EDU_SHOWN_SUFFIX = "_NUMBER_OF_EDU_SHOWN"
        const val LAST_SHORTCUT_TRIGGERED_TIME_SUFFIX = "_LAST_SHORTCUT_TRIGGERED_TIME"
        const val USAGE_SESSION_START_TIME_SUFFIX = "_USAGE_SESSION_START_TIME"
        const val LAST_EDUCATION_TIME_SUFFIX = "_LAST_EDUCATION_TIME"

        const val DATASTORE_DIR = "education/USER%s_ContextualEducation"
    }
@@ -113,6 +115,14 @@ constructor(
                preferences[getLastShortcutTriggeredTimeKey(gestureType)]?.let {
                    Instant.ofEpochSecond(it)
                },
            usageSessionStartTime =
                preferences[getUsageSessionStartTimeKey(gestureType)]?.let {
                    Instant.ofEpochSecond(it)
                },
            lastEducationTime =
                preferences[getLastEducationTimeKey(gestureType)]?.let {
                    Instant.ofEpochSecond(it)
                },
        )
    }

@@ -125,11 +135,21 @@ constructor(
            val updatedModel = transform(currentModel)
            preferences[getSignalCountKey(gestureType)] = updatedModel.signalCount
            preferences[getEducationShownCountKey(gestureType)] = updatedModel.educationShownCount
            updateTimeByInstant(
            setInstant(
                preferences,
                updatedModel.lastShortcutTriggeredTime,
                getLastShortcutTriggeredTimeKey(gestureType)
            )
            setInstant(
                preferences,
                updatedModel.usageSessionStartTime,
                getUsageSessionStartTimeKey(gestureType)
            )
            setInstant(
                preferences,
                updatedModel.lastEducationTime,
                getLastEducationTimeKey(gestureType)
            )
        }
    }

@@ -142,7 +162,13 @@ constructor(
    private fun getLastShortcutTriggeredTimeKey(gestureType: GestureType): Preferences.Key<Long> =
        longPreferencesKey(gestureType.name + LAST_SHORTCUT_TRIGGERED_TIME_SUFFIX)

    private fun updateTimeByInstant(
    private fun getUsageSessionStartTimeKey(gestureType: GestureType): Preferences.Key<Long> =
        longPreferencesKey(gestureType.name + USAGE_SESSION_START_TIME_SUFFIX)

    private fun getLastEducationTimeKey(gestureType: GestureType): Preferences.Key<Long> =
        longPreferencesKey(gestureType.name + LAST_EDUCATION_TIME_SUFFIX)

    private fun setInstant(
        preferences: MutablePreferences,
        instant: Instant?,
        key: Preferences.Key<Long>
+25 −1
Original line number Diff line number Diff line
@@ -68,7 +68,13 @@ constructor(
    }

    suspend fun incrementSignalCount(gestureType: GestureType) {
        repository.updateGestureEduModel(gestureType) { it.copy(signalCount = it.signalCount + 1) }
        repository.updateGestureEduModel(gestureType) {
            it.copy(
                signalCount = it.signalCount + 1,
                usageSessionStartTime =
                    if (it.signalCount == 0) clock.instant() else it.usageSessionStartTime
            )
        }
    }

    suspend fun updateShortcutTriggerTime(gestureType: GestureType) {
@@ -76,4 +82,22 @@ constructor(
            it.copy(lastShortcutTriggeredTime = clock.instant())
        }
    }

    suspend fun updateOnEduTriggered(gestureType: GestureType) {
        repository.updateGestureEduModel(gestureType) {
            it.copy(
                // Reset signal counter and usageSessionStartTime after edu triggered
                signalCount = 0,
                lastEducationTime = clock.instant(),
                educationShownCount = it.educationShownCount + 1,
                usageSessionStartTime = null
            )
        }
    }

    suspend fun startNewUsageSession(gestureType: GestureType) {
        repository.updateGestureEduModel(gestureType) {
            it.copy(usageSessionStartTime = clock.instant(), signalCount = 1)
        }
    }
}
Loading