1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.inputdevice.tutorial.data.repository
18 
19 import android.content.Context
20 import androidx.datastore.core.DataStore
21 import androidx.datastore.preferences.core.Preferences
22 import androidx.datastore.preferences.core.edit
23 import androidx.datastore.preferences.core.longPreferencesKey
24 import androidx.datastore.preferences.preferencesDataStore
25 import com.android.systemui.dagger.SysUISingleton
26 import com.android.systemui.dagger.qualifiers.Application
27 import com.android.systemui.dagger.qualifiers.Background
28 import com.android.systemui.inputdevice.tutorial.data.model.DeviceSchedulerInfo
29 import java.time.Instant
30 import javax.inject.Inject
31 import kotlinx.coroutines.CoroutineScope
32 import kotlinx.coroutines.flow.first
33 import kotlinx.coroutines.flow.map
34 
35 @SysUISingleton
36 class TutorialSchedulerRepository(
37     private val applicationContext: Context,
38     backgroundScope: CoroutineScope,
39     dataStoreName: String,
40 ) {
41     @Inject
42     constructor(
43         @Application applicationContext: Context,
44         @Background backgroundScope: CoroutineScope,
45     ) : this(applicationContext, backgroundScope, dataStoreName = DATASTORE_NAME)
46 
47     private val Context.dataStore: DataStore<Preferences> by
48         preferencesDataStore(name = dataStoreName, scope = backgroundScope)
49 
50     suspend fun isLaunched(deviceType: DeviceType): Boolean = loadData()[deviceType]!!.isLaunched
51 
52     suspend fun launchTime(deviceType: DeviceType): Instant? = loadData()[deviceType]!!.launchTime
53 
54     suspend fun wasEverConnected(deviceType: DeviceType): Boolean =
55         loadData()[deviceType]!!.wasEverConnected
56 
57     suspend fun firstConnectionTime(deviceType: DeviceType): Instant? =
58         loadData()[deviceType]!!.firstConnectionTime
59 
60     private suspend fun loadData(): Map<DeviceType, DeviceSchedulerInfo> {
61         return applicationContext.dataStore.data.map { pref -> getSchedulerInfo(pref) }.first()
62     }
63 
64     suspend fun updateFirstConnectionTime(device: DeviceType, time: Instant) {
65         applicationContext.dataStore.edit { pref -> pref[getConnectKey(device)] = time.epochSecond }
66     }
67 
68     suspend fun updateLaunchTime(device: DeviceType, time: Instant) {
69         applicationContext.dataStore.edit { pref -> pref[getLaunchKey(device)] = time.epochSecond }
70     }
71 
72     private fun getSchedulerInfo(pref: Preferences): Map<DeviceType, DeviceSchedulerInfo> {
73         return mapOf(
74             DeviceType.KEYBOARD to getDeviceSchedulerInfo(pref, DeviceType.KEYBOARD),
75             DeviceType.TOUCHPAD to getDeviceSchedulerInfo(pref, DeviceType.TOUCHPAD),
76         )
77     }
78 
79     private fun getDeviceSchedulerInfo(pref: Preferences, device: DeviceType): DeviceSchedulerInfo {
80         val launchTime = pref[getLaunchKey(device)]
81         val connectionTime = pref[getConnectKey(device)]
82         return DeviceSchedulerInfo(launchTime, connectionTime)
83     }
84 
85     private fun getLaunchKey(device: DeviceType) =
86         longPreferencesKey(device.name + LAUNCH_TIME_SUFFIX)
87 
88     private fun getConnectKey(device: DeviceType) =
89         longPreferencesKey(device.name + CONNECT_TIME_SUFFIX)
90 
91     suspend fun clear() {
92         applicationContext.dataStore.edit { it.clear() }
93     }
94 
95     companion object {
96         const val DATASTORE_NAME = "TutorialScheduler"
97         const val LAUNCH_TIME_SUFFIX = "_LAUNCH_TIME"
98         const val CONNECT_TIME_SUFFIX = "_CONNECT_TIME"
99     }
100 }
101 
102 enum class DeviceType {
103     KEYBOARD,
104     TOUCHPAD,
105 }
106