Add phone-side test UI for voice loop testing without Android Auto
ClippyAuto CI / build (push) Failing after 5s
ClippyAuto CI / build (push) Failing after 5s
SetupActivity now has Connect + Talk buttons, status display, and log output. Allows testing the full STT → Matrix → Clippy → TTS pipeline from the phone.
This commit is contained in:
@@ -1,30 +1,150 @@
|
|||||||
package farm.hobbs.clippyauto.ui
|
package farm.hobbs.clippyauto.ui
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.ScrollView
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import farm.hobbs.clippyauto.R
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import farm.hobbs.clippyauto.VoiceLoop
|
||||||
|
import farm.hobbs.clippyauto.matrix.MatrixRestClient
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Phone-side activity for initial setup and session monitoring.
|
* Phone-side activity for setup and standalone voice testing.
|
||||||
*
|
* The real UI is in Android Auto, but this lets you test the voice
|
||||||
* v1 MVP:
|
* pipeline without needing a car or DHU.
|
||||||
* - Login to Matrix homeserver (first run)
|
|
||||||
* - Show "session active" indicator during Android Auto use
|
|
||||||
* - Display debrief summary notification after session ends
|
|
||||||
*
|
|
||||||
* v2:
|
|
||||||
* - Full conversation transcript review
|
|
||||||
* - Settings (silence thresholds, TTS voice, etc.)
|
|
||||||
*/
|
*/
|
||||||
class SetupActivity : AppCompatActivity() {
|
class SetupActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val HOMESERVER = "https://mess.hobbs.farm"
|
||||||
|
private const val ROOM_ID = "!KSovCtghshGUfVDbQg:hobbs.farm"
|
||||||
|
private const val CLIPPY_USER = "@clippy:hobbs.farm"
|
||||||
|
private const val MATRIX_USER = "clippyauto"
|
||||||
|
private const val MATRIX_PASS = "ClippyAuto2026!"
|
||||||
|
private const val MIC_PERMISSION_CODE = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
|
||||||
|
private var voiceLoop: VoiceLoop? = null
|
||||||
|
private lateinit var statusText: TextView
|
||||||
|
private lateinit var logText: TextView
|
||||||
|
private lateinit var talkButton: Button
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
// TODO: Build setup UI
|
|
||||||
// - Matrix homeserver URL (pre-filled: mess.hobbs.farm)
|
val layout = LinearLayout(this).apply {
|
||||||
// - Username / password fields
|
orientation = LinearLayout.VERTICAL
|
||||||
// - Login button
|
setPadding(48, 48, 48, 48)
|
||||||
// - Status: connected / disconnected
|
}
|
||||||
// - "Session active" indicator
|
|
||||||
|
// Title
|
||||||
|
layout.addView(TextView(this).apply {
|
||||||
|
text = "📎 ClippyAuto"
|
||||||
|
textSize = 28f
|
||||||
|
setPadding(0, 0, 0, 16)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Status
|
||||||
|
statusText = TextView(this).apply {
|
||||||
|
text = "Tap Connect to start"
|
||||||
|
textSize = 18f
|
||||||
|
setPadding(0, 0, 0, 24)
|
||||||
|
}
|
||||||
|
layout.addView(statusText)
|
||||||
|
|
||||||
|
// Connect button
|
||||||
|
val connectButton = Button(this).apply {
|
||||||
|
text = "🔌 Connect to Matrix"
|
||||||
|
setOnClickListener { connectToMatrix() }
|
||||||
|
}
|
||||||
|
layout.addView(connectButton)
|
||||||
|
|
||||||
|
// Talk button
|
||||||
|
talkButton = Button(this).apply {
|
||||||
|
text = "🎙️ Talk to Clippy"
|
||||||
|
isEnabled = false
|
||||||
|
setOnClickListener { voiceLoop?.onTalkPressed() }
|
||||||
|
}
|
||||||
|
layout.addView(talkButton)
|
||||||
|
|
||||||
|
// Log output
|
||||||
|
logText = TextView(this).apply {
|
||||||
|
text = "Log:\n"
|
||||||
|
textSize = 12f
|
||||||
|
setPadding(0, 24, 0, 0)
|
||||||
|
}
|
||||||
|
val scroll = ScrollView(this).apply {
|
||||||
|
addView(logText)
|
||||||
|
}
|
||||||
|
layout.addView(scroll)
|
||||||
|
|
||||||
|
setContentView(layout)
|
||||||
|
|
||||||
|
// Request mic permission
|
||||||
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
ActivityCompat.requestPermissions(
|
||||||
|
this, arrayOf(Manifest.permission.RECORD_AUDIO), MIC_PERMISSION_CODE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun connectToMatrix() {
|
||||||
|
statusText.text = "Connecting to Matrix..."
|
||||||
|
log("Connecting to $HOMESERVER...")
|
||||||
|
|
||||||
|
val matrixClient = MatrixRestClient(HOMESERVER)
|
||||||
|
|
||||||
|
voiceLoop = VoiceLoop(
|
||||||
|
context = this,
|
||||||
|
matrixClient = matrixClient,
|
||||||
|
roomId = ROOM_ID,
|
||||||
|
clippyUserId = CLIPPY_USER,
|
||||||
|
onStateChange = { state, status ->
|
||||||
|
runOnUiThread {
|
||||||
|
statusText.text = status
|
||||||
|
log("State: $state → $status")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
val loggedIn = withContext(Dispatchers.IO) {
|
||||||
|
matrixClient.login(MATRIX_USER, MATRIX_PASS)
|
||||||
|
}
|
||||||
|
if (loggedIn) {
|
||||||
|
log("✅ Logged in as @clippyauto:hobbs.farm")
|
||||||
|
voiceLoop?.initialize()
|
||||||
|
voiceLoop?.startSession()
|
||||||
|
talkButton.isEnabled = true
|
||||||
|
statusText.text = "Connected! Tap Talk to Clippy"
|
||||||
|
} else {
|
||||||
|
log("❌ Login failed")
|
||||||
|
statusText.text = "⚠️ Matrix login failed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun log(msg: String) {
|
||||||
|
runOnUiThread {
|
||||||
|
logText.append("$msg\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
voiceLoop?.endSession()
|
||||||
|
voiceLoop?.destroy()
|
||||||
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user