Store launch time when tutorial is launched
Required for contextual education
Bug: 359560702
Flag: com.android.systemui.shared.new_touchpad_gestures_tutorial
Test: TutorialSchedulerInteractorTest.kt (follow up CLs)
Change-Id: Ibd277e8f9d4de20ebf923608369bd618bfec183c
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/model/TutorialSchedulerInfo.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/model/TutorialSchedulerInfo.kt
index 9f46846..1dbe83a 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/model/TutorialSchedulerInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/model/TutorialSchedulerInfo.kt
@@ -16,7 +16,23 @@
package com.android.systemui.inputdevice.tutorial.data.model
-data class DeviceSchedulerInfo(var isLaunched: Boolean = false, var connectTime: Long? = null) {
+import java.time.Instant
+
+data class DeviceSchedulerInfo(
+ var launchTime: Instant? = null,
+ var firstConnectionTime: Instant? = null
+) {
+ constructor(
+ launchTimeSec: Long?,
+ firstConnectionTimeSec: Long?
+ ) : this(
+ launchTimeSec?.let { Instant.ofEpochSecond(it) },
+ firstConnectionTimeSec?.let { Instant.ofEpochSecond(it) }
+ )
+
val wasEverConnected: Boolean
- get() = connectTime != null
+ get() = firstConnectionTime != null
+
+ val isLaunched: Boolean
+ get() = launchTime != null
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/repository/TutorialSchedulerRepository.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/repository/TutorialSchedulerRepository.kt
index 36b9ac7..d8d4bd6 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/repository/TutorialSchedulerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/repository/TutorialSchedulerRepository.kt
@@ -20,7 +20,6 @@
import androidx.annotation.VisibleForTesting
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
-import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
@@ -28,6 +27,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.inputdevice.tutorial.data.model.DeviceSchedulerInfo
+import java.time.Instant
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.first
@@ -43,28 +43,31 @@
constructor(
@Application applicationContext: Context,
@Background backgroundScope: CoroutineScope
- ) : this(applicationContext, backgroundScope, dataStoreName = "TutorialScheduler")
+ ) : this(applicationContext, backgroundScope, dataStoreName = DATASTORE_NAME)
private val Context.dataStore: DataStore<Preferences> by
preferencesDataStore(name = dataStoreName, scope = backgroundScope)
suspend fun isLaunched(deviceType: DeviceType): Boolean = loadData()[deviceType]!!.isLaunched
+ suspend fun launchTime(deviceType: DeviceType): Instant? = loadData()[deviceType]!!.launchTime
+
suspend fun wasEverConnected(deviceType: DeviceType): Boolean =
loadData()[deviceType]!!.wasEverConnected
- suspend fun connectTime(deviceType: DeviceType): Long = loadData()[deviceType]!!.connectTime!!
+ suspend fun firstConnectionTime(deviceType: DeviceType): Instant? =
+ loadData()[deviceType]!!.firstConnectionTime
private suspend fun loadData(): Map<DeviceType, DeviceSchedulerInfo> {
return applicationContext.dataStore.data.map { pref -> getSchedulerInfo(pref) }.first()
}
- suspend fun updateConnectTime(device: DeviceType, time: Long) {
- applicationContext.dataStore.edit { pref -> pref[getConnectKey(device)] = time }
+ suspend fun updateFirstConnectionTime(device: DeviceType, time: Instant) {
+ applicationContext.dataStore.edit { pref -> pref[getConnectKey(device)] = time.epochSecond }
}
- suspend fun updateLaunch(device: DeviceType) {
- applicationContext.dataStore.edit { pref -> pref[getLaunchedKey(device)] = true }
+ suspend fun updateLaunchTime(device: DeviceType, time: Instant) {
+ applicationContext.dataStore.edit { pref -> pref[getLaunchKey(device)] = time.epochSecond }
}
private fun getSchedulerInfo(pref: Preferences): Map<DeviceType, DeviceSchedulerInfo> {
@@ -75,13 +78,13 @@
}
private fun getDeviceSchedulerInfo(pref: Preferences, device: DeviceType): DeviceSchedulerInfo {
- val isLaunched = pref[getLaunchedKey(device)] ?: false
- val connectionTime = pref[getConnectKey(device)] ?: null
- return DeviceSchedulerInfo(isLaunched, connectionTime)
+ val launchTime = pref[getLaunchKey(device)]
+ val connectionTime = pref[getConnectKey(device)]
+ return DeviceSchedulerInfo(launchTime, connectionTime)
}
- private fun getLaunchedKey(device: DeviceType) =
- booleanPreferencesKey(device.name + IS_LAUNCHED_SUFFIX)
+ private fun getLaunchKey(device: DeviceType) =
+ longPreferencesKey(device.name + LAUNCH_TIME_SUFFIX)
private fun getConnectKey(device: DeviceType) =
longPreferencesKey(device.name + CONNECT_TIME_SUFFIX)
@@ -92,8 +95,9 @@
}
companion object {
- const val IS_LAUNCHED_SUFFIX = "_IS_LAUNCHED"
- const val CONNECT_TIME_SUFFIX = "_CONNECTED_TIME"
+ const val DATASTORE_NAME = "TutorialScheduler"
+ const val LAUNCH_TIME_SUFFIX = "_LAUNCH_TIME"
+ const val CONNECT_TIME_SUFFIX = "_CONNECT_TIME"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
index b3b8f21..a8d7dad 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt
@@ -26,9 +26,11 @@
import com.android.systemui.inputdevice.tutorial.data.repository.TutorialSchedulerRepository
import com.android.systemui.keyboard.data.repository.KeyboardRepository
import com.android.systemui.touchpad.data.repository.TouchpadRepository
+import java.time.Duration
import java.time.Instant
import javax.inject.Inject
import kotlin.time.Duration.Companion.hours
+import kotlin.time.toKotlinDuration
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.filter
@@ -84,9 +86,9 @@
private suspend fun schedule(deviceType: DeviceType) {
if (!repo.wasEverConnected(deviceType)) {
waitForDeviceConnection(deviceType)
- repo.updateConnectTime(deviceType, Instant.now().toEpochMilli())
+ repo.updateFirstConnectionTime(deviceType, Instant.now())
}
- delay(remainingTimeMillis(start = repo.connectTime(deviceType)))
+ delay(remainingTime(start = repo.firstConnectionTime(deviceType)!!))
waitForDeviceConnection(deviceType)
}
@@ -95,9 +97,9 @@
private suspend fun launchTutorial(tutorialType: TutorialType) {
if (tutorialType == TutorialType.KEYBOARD || tutorialType == TutorialType.BOTH)
- repo.updateLaunch(KEYBOARD)
+ repo.updateLaunchTime(KEYBOARD, Instant.now())
if (tutorialType == TutorialType.TOUCHPAD || tutorialType == TutorialType.BOTH)
- repo.updateLaunch(TOUCHPAD)
+ repo.updateLaunchTime(TOUCHPAD, Instant.now())
// TODO: launch tutorial
Log.d(TAG, "Launch tutorial for $tutorialType")
}
@@ -113,19 +115,21 @@
return if (deviceType == KEYBOARD) TutorialType.KEYBOARD else TutorialType.TOUCHPAD
}
- private fun remainingTimeMillis(start: Long): Long {
- val elapsed = Instant.now().toEpochMilli() - start
- return LAUNCH_DELAY - elapsed
+ private fun remainingTime(start: Instant): kotlin.time.Duration {
+ val elapsed = Duration.between(start, Instant.now())
+ return LAUNCH_DELAY.minus(elapsed).toKotlinDuration()
}
companion object {
const val TAG = "TutorialSchedulerInteractor"
- private val DEFAULT_LAUNCH_DELAY = 72.hours.inWholeMilliseconds
- private val LAUNCH_DELAY: Long
+ private val DEFAULT_LAUNCH_DELAY_SEC = 72.hours.inWholeSeconds
+ private val LAUNCH_DELAY: Duration
get() =
- SystemProperties.getLong(
- "persist.peripheral_tutorial_delay_ms",
- DEFAULT_LAUNCH_DELAY
+ Duration.ofSeconds(
+ SystemProperties.getLong(
+ "persist.peripheral_tutorial_delay_sec",
+ DEFAULT_LAUNCH_DELAY_SEC
+ )
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
index 7583399..1d96c4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/inputdevice/data/repository/TutorialSchedulerRepositoryTest.kt
@@ -68,20 +68,23 @@
@Test
fun connectKeyboard() =
testScope.runTest {
- val now = Instant.now().toEpochMilli()
- underTest.updateConnectTime(KEYBOARD, now)
+ val now = Instant.now()
+ underTest.updateFirstConnectionTime(KEYBOARD, now)
assertThat(underTest.wasEverConnected(KEYBOARD)).isTrue()
- assertThat(underTest.connectTime(KEYBOARD)).isEqualTo(now)
+ assertThat(underTest.firstConnectionTime(KEYBOARD)!!.epochSecond)
+ .isEqualTo(now.epochSecond)
assertThat(underTest.wasEverConnected(TOUCHPAD)).isFalse()
}
@Test
fun launchKeyboard() =
testScope.runTest {
- underTest.updateLaunch(KEYBOARD)
+ val now = Instant.now()
+ underTest.updateLaunchTime(KEYBOARD, now)
assertThat(underTest.isLaunched(KEYBOARD)).isTrue()
+ assertThat(underTest.launchTime(KEYBOARD)!!.epochSecond).isEqualTo(now.epochSecond)
assertThat(underTest.isLaunched(TOUCHPAD)).isFalse()
}
}