From a474935e3ca84a9344bcdab5d9bed917707ff404 Mon Sep 17 00:00:00 2001 From: jjangddu Date: Thu, 23 Apr 2026 15:13:11 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20GATT=20=EC=97=90=EB=9F=AC=EB=A1=9C=20?= =?UTF-8?q?=EB=81=8A=EA=B8=B8=20=EB=95=8C=EB=8F=84=20=EC=9E=90=EB=8F=99=20?= =?UTF-8?q?reconnect=20=EC=8B=9C=EC=9E=91=20(=ED=95=B5=EC=8B=AC=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 근본 원인: Android BLE가 disconnect 시 STATUS_DISCONNECTED가 아닌 GATT 에러(status≠0)로 콜백을 보냄. 기존 에러 경로에서는 reconnectAttempt>0일 때만 재연결 → 첫 끊김 시 재연결 안 됨. 수정: - wasConnected 체크: 이전에 연결됨 + 사용자 disconnect 아님 → 자동 reconnect - GATT_ERROR 로그 + DISCONNECTED(gatt_error) 로그 기록 - stopBatteryPolling/stopWatchdog 호출 추가 - watchdog: connected=false 감지 시 무한 루프 대신 break Co-Authored-By: Claude Opus 4.6 (1M context) --- .../medilightv2android/ble/BleManager.kt | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) 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 1717bf4..dd45b33 100644 --- a/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt +++ b/app/src/main/java/com/example/medilightv2android/ble/BleManager.kt @@ -376,9 +376,14 @@ class BleManager private constructor(private val context: Context) { } val silenceMs = System.currentTimeMillis() - lastRxTimestamp - debugLogger.info("WATCHDOG_CHECK silence=${silenceMs}ms connected=${isConnected.value}") + val connected = isConnected.value + debugLogger.info("WATCHDOG_CHECK silence=${silenceMs}ms connected=$connected") - if (!isConnected.value) continue + // connected=false면 정상 경로에서 이미 처리됨 → watchdog 종료 + if (!connected) { + debugLogger.info("WATCHDOG_STOP — already disconnected (handled by GATT callback)") + break + } if (silenceMs > watchdogTimeoutMs) { // 직접 로그 기록 (handler 블로킹 무관) @@ -551,7 +556,12 @@ class BleManager private constructor(private val context: Context) { connectionTimer = null if (status != BluetoothGatt.GATT_SUCCESS && newState != BluetoothProfile.STATE_CONNECTED) { - loge { "GATT connection failed with status: $status" } + val wasConnected = isConnected.value + loge { "GATT error: status=$status newState=$newState wasConnected=$wasConnected" } + debugLogger.error("GATT_ERROR status=$status newState=$newState wasConnected=$wasConnected") + + stopBatteryPolling() + stopWatchdog() bluetoothGatt = null txCharacteristic = null rxCharacteristic = null @@ -563,7 +573,11 @@ class BleManager private constructor(private val context: Context) { gatt.close() - if (reconnectAttempt > 0 && lastConnectedAddress != null) { + if (wasConnected && lastConnectedAddress != null && !isUserDisconnect) { + debugLogger.disconnected("gatt_error", status) + onUnexpectedDisconnect?.invoke() + scheduleAutoReconnect() + } else if (reconnectAttempt > 0 && lastConnectedAddress != null) { scheduleAutoReconnect() } else { isReconnecting.value = false