diff --git a/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt b/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt index d96607b..f9a4f0e 100644 --- a/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt +++ b/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt @@ -352,31 +352,39 @@ class BleManager private constructor(private val context: Context) { batteryTimer = null } - // ── Watchdog (zombie connection detection) ── + // ── Watchdog (zombie connection detection, runs on separate thread) ── + + private var watchdogJob: Thread? = null + @Volatile private var watchdogRunning = false private fun startWatchdog() { stopWatchdog() lastRxTimestamp = System.currentTimeMillis() - val check = object : Runnable { - override fun run() { - if (!isConnected.value) return + watchdogRunning = true + + watchdogJob = Thread({ + while (watchdogRunning) { + try { Thread.sleep(5000) } catch (_: InterruptedException) { break } + if (!watchdogRunning) break + if (!isConnected.value) continue + val silenceMs = System.currentTimeMillis() - lastRxTimestamp if (silenceMs > watchdogTimeoutMs) { - logw { "Watchdog: no RX for ${silenceMs}ms — forcing disconnect + reconnect" } - debugLogger.error("WATCHDOG_TIMEOUT silence=${silenceMs}ms — forcing reconnect") - forceDisconnectAndReconnect() - return + handler.post { + logw { "Watchdog: no RX for ${silenceMs}ms — forcing disconnect + reconnect" } + debugLogger.error("WATCHDOG_TIMEOUT silence=${silenceMs}ms — forcing reconnect") + forceDisconnectAndReconnect() + } + break } - handler.postDelayed(this, 5000) } - } - watchdogTimer = check - handler.postDelayed(check, 5000) + }, "BLE-Watchdog").also { it.isDaemon = true; it.start() } } private fun stopWatchdog() { - watchdogTimer?.let { handler.removeCallbacks(it) } - watchdogTimer = null + watchdogRunning = false + watchdogJob?.interrupt() + watchdogJob = null } private fun forceDisconnectAndReconnect() {