package pw.binom.viewmate.phone import android.Manifest import android.content.pm.PackageManager import android.graphics.Color import android.os.Bundle import android.view.Gravity import android.view.WindowManager import android.widget.FrameLayout import android.widget.TextView import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.core.content.ContextCompat import pw.binom.viewmate.phone.stt.SttDebug import pw.binom.viewmate.phone.agent.LlmDebug import pw.binom.viewmate.phone.ui.ViewMateApp import java.io.File class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestBtPermissions() window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) setContent { ViewMateApp() } if (intent?.getBooleanExtra("stt_debug", false) == true) { runSttDebug() } if (intent?.getBooleanExtra("llm_debug", false) == true) { runLlmDebug() } } /** * Runtime-запрос Bluetooth-пермишенов (TASK-transport.md п.5): только при * вкл. SPP ([PhoneConfig.USE_BLUETOOTH]). На 31+ — BLUETOOTH_CONNECT/SCAN, * на ≤30 — BLUETOOTH/BLUETOOTH_ADMIN. Если уже выданы — молча пропускаем. */ private fun requestBtPermissions() { if (!PhoneConfig.USE_BLUETOOTH) return val needed = BtServerTransport.runtimePermissions() val missing = needed.filter { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED } if (missing.isNotEmpty()) { requestPermissions(missing.toTypedArray(), 1009) log("bt", "запрошены Bluetooth-пермишены (SPP): ${missing.joinToString()}") } } /** Smoke Koog-клиента: один вызов llm.binom.pw, ответ в лог [llm]. */ private fun runLlmDebug() { showOverlay("[llm] вызываю llm.binom.pw...") Thread { LlmDebug.run(BuildConfig.LLM_API_KEY, BuildConfig.LLM_MODEL) runOnUiThread { showOverlay("[llm] готово — смотри лог") } }.start() } /** Отладочный прогон распознавания: берёт первый wav из filesDir/samples. */ private fun runSttDebug() { val samplesDir = File(filesDir, "samples") val wav = samplesDir.listFiles() ?.filter { it.isFile && it.extension.equals("wav", true) } ?.firstOrNull() if (wav == null) { val msg = "[stt] нет wav-файлов в ${samplesDir.absolutePath}" log("stt", msg) showOverlay(msg) return } showOverlay("[stt] распознаю ${wav.name}...") Thread { val text = SttDebug.run(this, wav.absolutePath) runOnUiThread { showOverlay(text ?: "[stt] не удалось распознать") } }.start() } /** TextView поверх экрана — чтобы видеть результат на эмуляторе. */ private fun showOverlay(text: String) { val tv = TextView(this).apply { this.text = text setTextColor(Color.WHITE) setBackgroundColor(Color.argb(200, 0, 0, 0)) textSize = 16f setPadding(24, 24, 24, 24) } addContentView( tv, FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.TOP, ), ) } }