feat(android): wire voice recording and transcript into ConnectionService

This commit is contained in:
Sanju Sivalingam
2026-02-20 02:11:41 +05:30
parent 07f608a901
commit 16f581f479
2 changed files with 36 additions and 1 deletions

View File

@@ -62,8 +62,19 @@ class CommandRouter(
currentSteps.value = currentSteps.value + step currentSteps.value = currentSteps.value + step
Log.d(TAG, "Step ${step.step}: ${step.reasoning}") Log.d(TAG, "Step ${step.step}: ${step.reasoning}")
} }
"transcript_partial" -> {
ConnectionService.overlayTranscript.value = msg.text ?: ""
ConnectionService.instance?.overlay?.updateTranscript(msg.text ?: "")
Log.d(TAG, "Transcript partial: ${msg.text}")
}
"transcript_final" -> {
ConnectionService.overlayTranscript.value = msg.text ?: ""
ConnectionService.instance?.overlay?.updateTranscript(msg.text ?: "")
Log.d(TAG, "Transcript final: ${msg.text}")
}
"goal_completed" -> { "goal_completed" -> {
currentGoalStatus.value = if (msg.success == true) GoalStatus.Completed else GoalStatus.Failed currentGoalStatus.value = if (msg.success == true) GoalStatus.Completed else GoalStatus.Failed
ConnectionService.instance?.overlay?.returnToIdle()
Log.i(TAG, "Goal completed: success=${msg.success}, steps=${msg.stepsUsed}") Log.i(TAG, "Goal completed: success=${msg.success}, steps=${msg.stepsUsed}")
} }
"goal_failed" -> { "goal_failed" -> {

View File

@@ -30,6 +30,11 @@ import android.net.Uri
import android.provider.Settings import android.provider.Settings
import com.thisux.droidclaw.model.StopGoalMessage import com.thisux.droidclaw.model.StopGoalMessage
import com.thisux.droidclaw.overlay.AgentOverlay import com.thisux.droidclaw.overlay.AgentOverlay
import com.thisux.droidclaw.model.VoiceStartMessage
import com.thisux.droidclaw.model.VoiceChunkMessage
import com.thisux.droidclaw.model.VoiceStopMessage
import com.thisux.droidclaw.model.OverlayMode
import androidx.compose.runtime.snapshotFlow
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
@@ -47,6 +52,7 @@ class ConnectionService : LifecycleService() {
val currentGoalStatus = MutableStateFlow(GoalStatus.Idle) val currentGoalStatus = MutableStateFlow(GoalStatus.Idle)
val currentGoal = MutableStateFlow("") val currentGoal = MutableStateFlow("")
val errorMessage = MutableStateFlow<String?>(null) val errorMessage = MutableStateFlow<String?>(null)
val overlayTranscript = MutableStateFlow("")
var instance: ConnectionService? = null var instance: ConnectionService? = null
const val ACTION_CONNECT = "com.thisux.droidclaw.CONNECT" const val ACTION_CONNECT = "com.thisux.droidclaw.CONNECT"
@@ -59,13 +65,31 @@ class ConnectionService : LifecycleService() {
private var commandRouter: CommandRouter? = null private var commandRouter: CommandRouter? = null
private var captureManager: ScreenCaptureManager? = null private var captureManager: ScreenCaptureManager? = null
private var wakeLock: PowerManager.WakeLock? = null private var wakeLock: PowerManager.WakeLock? = null
private var overlay: AgentOverlay? = null internal var overlay: AgentOverlay? = null
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
instance = this instance = this
createNotificationChannel() createNotificationChannel()
overlay = AgentOverlay(this) overlay = AgentOverlay(this)
overlay?.onAudioChunk = { base64 ->
webSocket?.sendTyped(VoiceChunkMessage(data = base64))
}
overlay?.onVoiceSend = { _ ->
webSocket?.sendTyped(VoiceStopMessage(action = "send"))
}
overlay?.onVoiceCancel = {
webSocket?.sendTyped(VoiceStopMessage(action = "cancel"))
}
overlay?.let { ov ->
lifecycleScope.launch {
snapshotFlow { ov.mode.value }.collect { mode ->
if (mode == OverlayMode.Listening) {
webSocket?.sendTyped(VoiceStartMessage())
}
}
}
}
} }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {