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