Rokid/app/src/main/java/com/yuanxuan/rokid/device/DeviceServiceManager.kt

284 lines
9.6 KiB
Kotlin

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>(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
}
}