package com.stand.standapp.utils import android.app.ZysjSystemManager import android.content.Context import android.os.Handler import android.os.Looper import com.stand.standapp.MainActivity import com.stand.standapp.TempCallActivity import timber.log.Timber /** * 硬件 GPIO 监听管理类 (用于物理 PTT 按键) */ object GpioManager { private var mZysjSystemManager: ZysjSystemManager? = null @Volatile private var mIsRunning = false private var mThread: Thread? = null private var lastGpioValue = 1 // 默认松开状态 (1) fun init(context: Context) { if (mZysjSystemManager != null) return try { mZysjSystemManager = context.applicationContext.getSystemService("zysj") as? ZysjSystemManager Timber.tag("GPIO").i("ZysjSystemManager initialized: ${mZysjSystemManager != null}") } catch (e: Exception) { Timber.tag("GPIO").e(e, "Failed to get ZysjSystemManager") } } fun startListening() { if (mIsRunning) return mIsRunning = true mThread = Thread { Timber.tag("GPIO").i("Start GPIO listening thread") while (mIsRunning) { try { // 硬件轮询频率优化:150ms 既能保证响应速度,又能降低 CPU 消耗 Thread.sleep(150) val manager = mZysjSystemManager ?: continue // 获取 GPIO 1 的值 (0 按下, 1 松开) val currentValue = manager.get_zysj_gpio_value(1) if (currentValue != lastGpioValue) { Timber.tag("GPIO").d("GPIO 1 Value changed: $lastGpioValue -> $currentValue") handleGpioChange(currentValue) lastGpioValue = currentValue } } catch (e: InterruptedException) { Timber.tag("GPIO").i("GPIO thread interrupted, exiting gracefully") break } catch (e: Exception) { Timber.tag("GPIO").e(e, "Error in GPIO loop") } } }.apply { start() } } fun stopListening() { mIsRunning = false mThread?.interrupt() mThread = null mZysjSystemManager = null isSpeaking = false lastGpioValue = 1 Timber.tag("GPIO").i("GPIO listening stopped and state reset") } private var isSpeaking = false private var lastSpeakTime = 0L private val MIN_SPEAK_DURATION = 200L private fun handleGpioChange(value: Int) { // 切换到主线程处理逻辑,确保线程安全且方便使用 Handler Handler(Looper.getMainLooper()).post { if (value == 0) { // 硬件按下 PTT if (!isSpeaking) { isSpeaking = true lastSpeakTime = System.currentTimeMillis() com.example.kingway.ptt.SendAtUtil.speakPlay() Timber.tag("GPIO").d("PTT Speak Play (Hardware)") // 统一使用 updatePttTalkStatus 更新 UI MainActivity.executeJs("updatePttTalkStatus(true)") // 同步 TempCallActivity TempCallActivity.instance?.onGpioPressed() Timber.tag("GPIO").d("Notified TempCallActivity: onGpioPressed") } else { Timber.tag("GPIO").w("GPIO pressed but isSpeaking already true — ignoring") } } else { // 硬件松开 PTT Timber.tag("GPIO").d("GPIO released, isSpeaking=%s", isSpeaking) if (isSpeaking) { val now = System.currentTimeMillis() val duration = now - lastSpeakTime if (duration < MIN_SPEAK_DURATION) { val delay = MIN_SPEAK_DURATION - duration Timber.tag("GPIO").d("Hardware speak duration too short ($duration ms), delaying release by $delay ms") Handler(Looper.getMainLooper()).postDelayed({ realRelease() }, delay) } else { realRelease() } } } } } private fun realRelease() { if (isSpeaking) { isSpeaking = false com.example.kingway.ptt.SendAtUtil.speakRelease() Timber.tag("GPIO").d("PTT Speak Release (Hardware)") // 统一使用 updatePttTalkStatus 更新 UI MainActivity.executeJs("updatePttTalkStatus(false)") // 同步 TempCallActivity TempCallActivity.instance?.onGpioReleased() Timber.tag("GPIO").d("Notified TempCallActivity: onGpioReleased") } else { Timber.tag("GPIO").w("GPIO realRelease skipped: already released") } } }