284 lines
9.6 KiB
Kotlin
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
|
|
}
|
|
|
|
}
|
|
|