package com.yuanxuan.rokid.device import android.app.Application import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.BatteryManager import com.rokid.dcg.sprite.service.IInstructListener import com.rokid.dcg.sprite.service.IInstructService import com.rokid.dcg.sprite.service.ISpriteMediaService import com.rokid.dcg.sprite.service.ISystemFuncService import com.rokid.dcg.sprite.service.ITTSService import com.rokid.dcg.sprite.service.ServiceManager import com.rokid.dcg.sprite.syskey.SysKeyAction import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import timber.log.Timber import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException class DeviceServiceManager(val context: Application) { companion object { /** * 语音指令等待超时 */ private const val INSTRUCT_WAITE_TIME = 15000L } private var instructService: IInstructService? = null private var ttsService: ITTSService? = null private var systemFuncService: ISystemFuncService? = null private var spriteMediaService: ISpriteMediaService? = null private val _instructState = MutableStateFlow(InstructState.None) val instructState = _instructState.asStateFlow() /** * 系统电量 */ private val _batteryPercentage = MutableStateFlow(-1) val batteryPercentage = _batteryPercentage.asStateFlow() lateinit var sn: String private set val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception -> Timber.e(exception, "全局捕获协程异常:${exception.message}") } private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main + coroutineExceptionHandler) private var wakeTimeoutJob: Job? = null init { val filter = IntentFilter().apply { addAction(SysKeyAction.SPRITE_BUTTON_DOWN) addAction(SysKeyAction.SPRITE_BUTTON_UP) addAction(SysKeyAction.SPRITE_BUTTON_CLICK) addAction(SysKeyAction.SPRITE_BUTTON_LONG_PRESS) addAction(SysKeyAction.SPRITE_BUTTON_VERY_VERY_LONG_PRESS) addAction(SysKeyAction.TOUCH_BAR_LONG_PRESS) addAction(Intent.ACTION_BATTERY_CHANGED) // 监听电量 } context.registerReceiver(SysKeyReceiver(), filter) scope.launch { instructState.collect { Timber.d("语音指令状态 $it") when (it) { InstructState.None -> instructService?.unregisterListener(instructListener) InstructState.WaitingInstructState -> { instructService?.registerListener(instructListener) startWakeTimeoutCountdown() } } } } } val instructListener = object : IInstructListener.Stub() { override fun onInstructReceived(p0: Int) { Timber.d("接受到语音指令$p0") if (p0 != IInstructService.INSTRUCT_QUIT) { startWakeTimeoutCountdown() } when (p0) { IInstructService.INSTRUCT_WAKEUP -> { } IInstructService.INSTRUCT_VOLUME_UP -> { systemFuncServiceTodo { service -> setVolumeSpecified(service.volumeSpecified + 1) } } IInstructService.INSTRUCT_VOLUME_DOWN -> { systemFuncServiceTodo { service -> setVolumeSpecified(service.volumeSpecified - 1) } } IInstructService.INSTRUCT_LIGHT_UP -> { systemFuncServiceTodo { service -> setBrightnessSpecified(service.brightnessSpecified + 1) } } IInstructService.INSTRUCT_LIGHT_DOWN -> { systemFuncServiceTodo { service -> setBrightnessSpecified(service.brightnessSpecified - 1) } } IInstructService.INSTRUCT_TAKE_PHOTO -> { } IInstructService.INSTRUCT_START_AUDIO_RECORD -> { } IInstructService.INSTRUCT_STOP_AUDIO_RECORD -> { } IInstructService.INSTRUCT_START_VIDEO_RECORD -> { } IInstructService.INSTRUCT_STOP_VIDEO_RECORD -> { } IInstructService.INSTRUCT_QUIT -> { _instructState.update { InstructState.None } } } } } /** * [INSTRUCT_WAITE_TIME] 一段时间无新指令 退出等待状态 */ private fun startWakeTimeoutCountdown() { wakeTimeoutJob?.cancel() wakeTimeoutJob = scope.launch { delay(INSTRUCT_WAITE_TIME) _instructState.update { InstructState.None } } } fun playTTS(msg: String) { ttsServiceTodo { ttsService?.playTtsMsg(msg) } } suspend fun getSn() = suspendCancellableCoroutine { continuation -> ServiceManager.getSystemFuncService(context) { service -> if (service == null) { continuation.resumeWithException(Throwable("没有拿到SN 要重启APP")) return@getSystemFuncService } systemFuncService = service sn = service.sn continuation.resume(sn) } } private inline fun ttsServiceTodo(crossinline todo: (ITTSService) -> Unit) { if (ttsService == null) { ServiceManager.getTTSService(context) { service -> if (service == null) { Timber.d("设备初始化TTS服务失败") return@getTTSService } ttsService = service todo.invoke(service) } } else { todo.invoke(ttsService!!) } } private inline fun systemFuncServiceTodo(crossinline todo: (ISystemFuncService) -> Unit) { if (systemFuncService == null) { ServiceManager.getSystemFuncService(context) { service -> if (service == null) { Timber.d("设备初始化系统功能服务失败") return@getSystemFuncService } systemFuncService = service todo.invoke(service) } } else { todo.invoke(systemFuncService!!) } } private inline fun instructServiceTodo(crossinline todo: (IInstructService) -> Unit) { if (instructService == null) { ServiceManager.getInstructService(context) { service -> if (service == null) { Timber.d("设备初始化语音指令服务失败") return@getInstructService } instructService = service todo.invoke(service) } } else { todo.invoke(instructService!!) } } private fun setVolumeSpecified(volume: Int) { systemFuncService?.volumeSpecified = volume.coerceIn(0, 15) } private fun setBrightnessSpecified(brightness: Int) { systemFuncService?.brightnessSpecified = brightness.coerceIn(0, 15) } inner class SysKeyReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val action = intent?.action ?: return when (action) { Intent.ACTION_BATTERY_CHANGED -> { val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1) if (level == -1 || scale == -1) return val batteryPercentage = (level / scale.toFloat() * 100).toInt() _batteryPercentage.update { batteryPercentage } } SysKeyAction.SPRITE_BUTTON_DOWN -> { Timber.d("按下拍照键 SPRITE_BUTTON_DOWN") } SysKeyAction.SPRITE_BUTTON_UP -> { Timber.d("抬起拍照键 SPRITE_BUTTON_UP") } SysKeyAction.SPRITE_BUTTON_CLICK -> { Timber.d("点击拍照键 SPRITE_BUTTON_CLICK") } SysKeyAction.SPRITE_BUTTON_LONG_PRESS -> { Timber.d("长按拍照键 SPRITE_BUTTON_LONG_PRESS") } SysKeyAction.SPRITE_BUTTON_VERY_VERY_LONG_PRESS -> { Timber.d("超级长的长按拍照键 SPRITE_BUTTON_VERY_VERY_LONG_PRESS") } SysKeyAction.TOUCH_BAR_LONG_PRESS -> { Timber.d("长按触摸板 TOUCH_BAR_LONG_PRESS") instructServiceTodo { _instructState.update { InstructState.WaitingInstructState } } } } } } sealed interface InstructState { data object None : InstructState data object WaitingInstructState : InstructState } }