Loading packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +4 −4 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ import com.android.systemui.dreams.AssistantAttentionMonitor import com.android.systemui.dreams.DreamMonitor import com.android.systemui.dreams.homecontrols.HomeControlsDreamStartable import com.android.systemui.globalactions.GlobalActionsComponent import com.android.systemui.inputdevice.oobe.KeyboardTouchpadOobeTutorialCoreStartable import com.android.systemui.inputdevice.tutorial.KeyboardTouchpadTutorialCoreStartable import com.android.systemui.keyboard.KeyboardUI import com.android.systemui.keyboard.PhysicalKeyboardCoreStartable import com.android.systemui.keyguard.KeyguardViewConfigurator Loading Loading @@ -258,9 +258,9 @@ abstract class SystemUICoreStartableModule { @Binds @IntoMap @ClassKey(KeyboardTouchpadOobeTutorialCoreStartable::class) abstract fun bindOobeSchedulerCoreStartable( listener: KeyboardTouchpadOobeTutorialCoreStartable @ClassKey(KeyboardTouchpadTutorialCoreStartable::class) abstract fun bindKeyboardTouchpadTutorialCoreStartable( listener: KeyboardTouchpadTutorialCoreStartable ): CoreStartable @Binds Loading packages/SystemUI/src/com/android/systemui/inputdevice/oobe/KeyboardTouchpadOobeTutorialCoreStartable.kt→packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartable.kt +7 −6 Original line number Diff line number Diff line Loading @@ -14,23 +14,24 @@ * limitations under the License. */ package com.android.systemui.inputdevice.oobe package com.android.systemui.inputdevice.tutorial import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.inputdevice.oobe.domain.interactor.OobeSchedulerInteractor import com.android.systemui.inputdevice.tutorial.domain.interactor.TutorialSchedulerInteractor import com.android.systemui.shared.Flags.newTouchpadGesturesTutorial import dagger.Lazy import javax.inject.Inject /** A [CoreStartable] to launch a scheduler for keyboard and touchpad OOBE education */ /** A [CoreStartable] to launch a scheduler for keyboard and touchpad education */ @SysUISingleton class KeyboardTouchpadOobeTutorialCoreStartable class KeyboardTouchpadTutorialCoreStartable @Inject constructor(private val oobeSchedulerInteractor: Lazy<OobeSchedulerInteractor>) : CoreStartable { constructor(private val tutorialSchedulerInteractor: Lazy<TutorialSchedulerInteractor>) : CoreStartable { override fun start() { if (newTouchpadGesturesTutorial()) { oobeSchedulerInteractor.get().start() tutorialSchedulerInteractor.get().start() } } } packages/SystemUI/src/com/android/systemui/inputdevice/oobe/data/model/OobeSchedulerInfo.kt→packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/model/TutorialSchedulerInfo.kt +4 −4 Original line number Diff line number Diff line Loading @@ -14,14 +14,14 @@ * limitations under the License. */ package com.android.systemui.inputdevice.oobe.data.model package com.android.systemui.inputdevice.tutorial.data.model data class OobeSchedulerInfo( data class TutorialSchedulerInfo( val keyboard: DeviceSchedulerInfo = DeviceSchedulerInfo(), val touchpad: DeviceSchedulerInfo = DeviceSchedulerInfo() ) data class DeviceSchedulerInfo(var isLaunched: Boolean = false, var connectionTime: Long? = null) { data class DeviceSchedulerInfo(var isLaunched: Boolean = false, var connectTime: Long? = null) { val wasEverConnected: Boolean get() = connectionTime != null get() = connectTime != null } packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/repository/TutorialSchedulerRepository.kt 0 → 100644 +83 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.inputdevice.tutorial.data.repository import android.content.Context 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 import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.inputdevice.tutorial.data.model.DeviceSchedulerInfo import com.android.systemui.inputdevice.tutorial.data.model.TutorialSchedulerInfo import javax.inject.Inject import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map @SysUISingleton class TutorialSchedulerRepository @Inject constructor(@Application private val applicationContext: Context) { private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = DATASTORE_NAME) suspend fun loadData(): TutorialSchedulerInfo { 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 updateLaunch(device: DeviceType) { applicationContext.dataStore.edit { pref -> pref[getLaunchedKey(device)] = true } } private fun getSchedulerInfo(pref: Preferences): TutorialSchedulerInfo { return TutorialSchedulerInfo( keyboard = getDeviceSchedulerInfo(pref, DeviceType.KEYBOARD), touchpad = getDeviceSchedulerInfo(pref, DeviceType.TOUCHPAD) ) } private fun getDeviceSchedulerInfo(pref: Preferences, device: DeviceType): DeviceSchedulerInfo { val isLaunched = pref[getLaunchedKey(device)] ?: false val connectionTime = pref[getConnectKey(device)] ?: null return DeviceSchedulerInfo(isLaunched, connectionTime) } private fun getLaunchedKey(device: DeviceType) = booleanPreferencesKey(device.name + IS_LAUNCHED_SUFFIX) private fun getConnectKey(device: DeviceType) = longPreferencesKey(device.name + CONNECT_TIME_SUFFIX) companion object { const val DATASTORE_NAME = "TutorialScheduler" const val IS_LAUNCHED_SUFFIX = "_IS_LAUNCHED" const val CONNECT_TIME_SUFFIX = "_CONNECTED_TIME" } } enum class DeviceType { KEYBOARD, TOUCHPAD } packages/SystemUI/src/com/android/systemui/inputdevice/oobe/domain/interactor/OobeSchedulerInteractor.kt→packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt +37 −21 Original line number Diff line number Diff line Loading @@ -14,14 +14,15 @@ * limitations under the License. */ package com.android.systemui.inputdevice.oobe.domain.interactor package com.android.systemui.inputdevice.tutorial.domain.interactor import android.content.Context import android.content.Intent import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.inputdevice.oobe.data.model.DeviceSchedulerInfo import com.android.systemui.inputdevice.oobe.data.model.OobeSchedulerInfo import com.android.systemui.inputdevice.tutorial.data.model.DeviceSchedulerInfo import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType 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 Loading @@ -35,49 +36,65 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch /** * When the first time a keyboard or touchpad id connected, wait for [LAUNCH_DELAY], then launch the * When the first time a keyboard or touchpad is connected, wait for [LAUNCH_DELAY], then launch the * tutorial as soon as there's a connected device */ @SysUISingleton class OobeSchedulerInteractor class TutorialSchedulerInteractor @Inject constructor( @Application private val context: Context, @Application private val applicationScope: CoroutineScope, private val keyboardRepository: KeyboardRepository, private val touchpadRepository: TouchpadRepository private val touchpadRepository: TouchpadRepository, private val tutorialSchedulerRepository: TutorialSchedulerRepository ) { private val info = OobeSchedulerInfo() fun start() { applicationScope.launch { val info = tutorialSchedulerRepository.loadData() if (!info.keyboard.isLaunched) { applicationScope.launch { schedule(keyboardRepository.isAnyKeyboardConnected, info.keyboard) schedule( keyboardRepository.isAnyKeyboardConnected, info.keyboard, DeviceType.KEYBOARD ) } } if (!info.touchpad.isLaunched) { applicationScope.launch { schedule(touchpadRepository.isAnyTouchpadConnected, info.touchpad) schedule( touchpadRepository.isAnyTouchpadConnected, info.touchpad, DeviceType.TOUCHPAD ) } } } } private suspend fun schedule(isAnyDeviceConnected: Flow<Boolean>, info: DeviceSchedulerInfo) { private suspend fun schedule( isAnyDeviceConnected: Flow<Boolean>, info: DeviceSchedulerInfo, deviceType: DeviceType ) { if (!info.wasEverConnected) { waitForDeviceConnection(isAnyDeviceConnected) info.connectionTime = Instant.now().toEpochMilli() info.connectTime = Instant.now().toEpochMilli() tutorialSchedulerRepository.updateConnectTime(deviceType, info.connectTime!!) } delay(remainingTimeMillis(info.connectionTime!!)) delay(remainingTimeMillis(info.connectTime!!)) waitForDeviceConnection(isAnyDeviceConnected) info.isLaunched = true launchOobe() tutorialSchedulerRepository.updateLaunch(deviceType) launchTutorial() } private suspend fun waitForDeviceConnection(isAnyDeviceConnected: Flow<Boolean>): Boolean { return isAnyDeviceConnected.filter { it }.first() } private fun launchOobe() { private fun launchTutorial() { val intent = Intent(TUTORIAL_ACTION) intent.addCategory(Intent.CATEGORY_DEFAULT) intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) Loading @@ -90,7 +107,6 @@ constructor( } companion object { const val TAG = "OobeSchedulerInteractor" const val TUTORIAL_ACTION = "com.android.systemui.action.TOUCHPAD_TUTORIAL" private val LAUNCH_DELAY = Duration.ofHours(72).toMillis() } Loading Loading
packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +4 −4 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ import com.android.systemui.dreams.AssistantAttentionMonitor import com.android.systemui.dreams.DreamMonitor import com.android.systemui.dreams.homecontrols.HomeControlsDreamStartable import com.android.systemui.globalactions.GlobalActionsComponent import com.android.systemui.inputdevice.oobe.KeyboardTouchpadOobeTutorialCoreStartable import com.android.systemui.inputdevice.tutorial.KeyboardTouchpadTutorialCoreStartable import com.android.systemui.keyboard.KeyboardUI import com.android.systemui.keyboard.PhysicalKeyboardCoreStartable import com.android.systemui.keyguard.KeyguardViewConfigurator Loading Loading @@ -258,9 +258,9 @@ abstract class SystemUICoreStartableModule { @Binds @IntoMap @ClassKey(KeyboardTouchpadOobeTutorialCoreStartable::class) abstract fun bindOobeSchedulerCoreStartable( listener: KeyboardTouchpadOobeTutorialCoreStartable @ClassKey(KeyboardTouchpadTutorialCoreStartable::class) abstract fun bindKeyboardTouchpadTutorialCoreStartable( listener: KeyboardTouchpadTutorialCoreStartable ): CoreStartable @Binds Loading
packages/SystemUI/src/com/android/systemui/inputdevice/oobe/KeyboardTouchpadOobeTutorialCoreStartable.kt→packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/KeyboardTouchpadTutorialCoreStartable.kt +7 −6 Original line number Diff line number Diff line Loading @@ -14,23 +14,24 @@ * limitations under the License. */ package com.android.systemui.inputdevice.oobe package com.android.systemui.inputdevice.tutorial import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.inputdevice.oobe.domain.interactor.OobeSchedulerInteractor import com.android.systemui.inputdevice.tutorial.domain.interactor.TutorialSchedulerInteractor import com.android.systemui.shared.Flags.newTouchpadGesturesTutorial import dagger.Lazy import javax.inject.Inject /** A [CoreStartable] to launch a scheduler for keyboard and touchpad OOBE education */ /** A [CoreStartable] to launch a scheduler for keyboard and touchpad education */ @SysUISingleton class KeyboardTouchpadOobeTutorialCoreStartable class KeyboardTouchpadTutorialCoreStartable @Inject constructor(private val oobeSchedulerInteractor: Lazy<OobeSchedulerInteractor>) : CoreStartable { constructor(private val tutorialSchedulerInteractor: Lazy<TutorialSchedulerInteractor>) : CoreStartable { override fun start() { if (newTouchpadGesturesTutorial()) { oobeSchedulerInteractor.get().start() tutorialSchedulerInteractor.get().start() } } }
packages/SystemUI/src/com/android/systemui/inputdevice/oobe/data/model/OobeSchedulerInfo.kt→packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/model/TutorialSchedulerInfo.kt +4 −4 Original line number Diff line number Diff line Loading @@ -14,14 +14,14 @@ * limitations under the License. */ package com.android.systemui.inputdevice.oobe.data.model package com.android.systemui.inputdevice.tutorial.data.model data class OobeSchedulerInfo( data class TutorialSchedulerInfo( val keyboard: DeviceSchedulerInfo = DeviceSchedulerInfo(), val touchpad: DeviceSchedulerInfo = DeviceSchedulerInfo() ) data class DeviceSchedulerInfo(var isLaunched: Boolean = false, var connectionTime: Long? = null) { data class DeviceSchedulerInfo(var isLaunched: Boolean = false, var connectTime: Long? = null) { val wasEverConnected: Boolean get() = connectionTime != null get() = connectTime != null }
packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/data/repository/TutorialSchedulerRepository.kt 0 → 100644 +83 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.inputdevice.tutorial.data.repository import android.content.Context 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 import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.inputdevice.tutorial.data.model.DeviceSchedulerInfo import com.android.systemui.inputdevice.tutorial.data.model.TutorialSchedulerInfo import javax.inject.Inject import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map @SysUISingleton class TutorialSchedulerRepository @Inject constructor(@Application private val applicationContext: Context) { private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = DATASTORE_NAME) suspend fun loadData(): TutorialSchedulerInfo { 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 updateLaunch(device: DeviceType) { applicationContext.dataStore.edit { pref -> pref[getLaunchedKey(device)] = true } } private fun getSchedulerInfo(pref: Preferences): TutorialSchedulerInfo { return TutorialSchedulerInfo( keyboard = getDeviceSchedulerInfo(pref, DeviceType.KEYBOARD), touchpad = getDeviceSchedulerInfo(pref, DeviceType.TOUCHPAD) ) } private fun getDeviceSchedulerInfo(pref: Preferences, device: DeviceType): DeviceSchedulerInfo { val isLaunched = pref[getLaunchedKey(device)] ?: false val connectionTime = pref[getConnectKey(device)] ?: null return DeviceSchedulerInfo(isLaunched, connectionTime) } private fun getLaunchedKey(device: DeviceType) = booleanPreferencesKey(device.name + IS_LAUNCHED_SUFFIX) private fun getConnectKey(device: DeviceType) = longPreferencesKey(device.name + CONNECT_TIME_SUFFIX) companion object { const val DATASTORE_NAME = "TutorialScheduler" const val IS_LAUNCHED_SUFFIX = "_IS_LAUNCHED" const val CONNECT_TIME_SUFFIX = "_CONNECTED_TIME" } } enum class DeviceType { KEYBOARD, TOUCHPAD }
packages/SystemUI/src/com/android/systemui/inputdevice/oobe/domain/interactor/OobeSchedulerInteractor.kt→packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt +37 −21 Original line number Diff line number Diff line Loading @@ -14,14 +14,15 @@ * limitations under the License. */ package com.android.systemui.inputdevice.oobe.domain.interactor package com.android.systemui.inputdevice.tutorial.domain.interactor import android.content.Context import android.content.Intent import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.inputdevice.oobe.data.model.DeviceSchedulerInfo import com.android.systemui.inputdevice.oobe.data.model.OobeSchedulerInfo import com.android.systemui.inputdevice.tutorial.data.model.DeviceSchedulerInfo import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType 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 Loading @@ -35,49 +36,65 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch /** * When the first time a keyboard or touchpad id connected, wait for [LAUNCH_DELAY], then launch the * When the first time a keyboard or touchpad is connected, wait for [LAUNCH_DELAY], then launch the * tutorial as soon as there's a connected device */ @SysUISingleton class OobeSchedulerInteractor class TutorialSchedulerInteractor @Inject constructor( @Application private val context: Context, @Application private val applicationScope: CoroutineScope, private val keyboardRepository: KeyboardRepository, private val touchpadRepository: TouchpadRepository private val touchpadRepository: TouchpadRepository, private val tutorialSchedulerRepository: TutorialSchedulerRepository ) { private val info = OobeSchedulerInfo() fun start() { applicationScope.launch { val info = tutorialSchedulerRepository.loadData() if (!info.keyboard.isLaunched) { applicationScope.launch { schedule(keyboardRepository.isAnyKeyboardConnected, info.keyboard) schedule( keyboardRepository.isAnyKeyboardConnected, info.keyboard, DeviceType.KEYBOARD ) } } if (!info.touchpad.isLaunched) { applicationScope.launch { schedule(touchpadRepository.isAnyTouchpadConnected, info.touchpad) schedule( touchpadRepository.isAnyTouchpadConnected, info.touchpad, DeviceType.TOUCHPAD ) } } } } private suspend fun schedule(isAnyDeviceConnected: Flow<Boolean>, info: DeviceSchedulerInfo) { private suspend fun schedule( isAnyDeviceConnected: Flow<Boolean>, info: DeviceSchedulerInfo, deviceType: DeviceType ) { if (!info.wasEverConnected) { waitForDeviceConnection(isAnyDeviceConnected) info.connectionTime = Instant.now().toEpochMilli() info.connectTime = Instant.now().toEpochMilli() tutorialSchedulerRepository.updateConnectTime(deviceType, info.connectTime!!) } delay(remainingTimeMillis(info.connectionTime!!)) delay(remainingTimeMillis(info.connectTime!!)) waitForDeviceConnection(isAnyDeviceConnected) info.isLaunched = true launchOobe() tutorialSchedulerRepository.updateLaunch(deviceType) launchTutorial() } private suspend fun waitForDeviceConnection(isAnyDeviceConnected: Flow<Boolean>): Boolean { return isAnyDeviceConnected.filter { it }.first() } private fun launchOobe() { private fun launchTutorial() { val intent = Intent(TUTORIAL_ACTION) intent.addCategory(Intent.CATEGORY_DEFAULT) intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) Loading @@ -90,7 +107,6 @@ constructor( } companion object { const val TAG = "OobeSchedulerInteractor" const val TUTORIAL_ACTION = "com.android.systemui.action.TOUCHPAD_TUTORIAL" private val LAUNCH_DELAY = Duration.ofHours(72).toMillis() } Loading