fix: BLE reconnect를 fresh scan→connect 방식으로 변경
기존: connectGatt(autoConnect=true) — Android에서 매우 불안정, 수분 걸림 변경: BLE 스캔으로 기기를 다시 찾은 후 connectGatt(autoConnect=false)로 빠르게 연결 재연결 흐름: 1. watchdog 15초 타임아웃 → forceDisconnectAndReconnect() 2. scheduleAutoReconnect() → 3s/5s/10s 백오프 3. attemptAutoReconnect(): - BLE 스캔 시작 (기기 이름 or MAC 주소 매칭) - 발견 시 즉시 connectGatt(autoConnect=false) → 빠른 연결 - 8초 스캔 타임아웃 → 다음 attempt - 최대 5회 시도 후 실패 처리 4. 모든 단계 BleDebugLogger에 기록 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -418,8 +418,11 @@ class BleManager private constructor(private val context: Context) {
|
||||
handler.postDelayed(timer, delay)
|
||||
}
|
||||
|
||||
private var reconnectScanCallback: ScanCallback? = null
|
||||
|
||||
private fun attemptAutoReconnect() {
|
||||
val address = lastConnectedAddress ?: return
|
||||
val targetAddress = lastConnectedAddress ?: return
|
||||
val targetName = debugLogger.deviceName
|
||||
if (bluetoothAdapter?.isEnabled != true) {
|
||||
onReconnectionFailed?.invoke()
|
||||
isReconnecting.value = false
|
||||
@@ -427,15 +430,69 @@ class BleManager private constructor(private val context: Context) {
|
||||
}
|
||||
|
||||
reconnectAttempt++
|
||||
logd { "Attempting auto-reconnect #$reconnectAttempt to $address" }
|
||||
logd { "Auto-reconnect #$reconnectAttempt: scanning for $targetName ($targetAddress)" }
|
||||
debugLogger.info("RECONNECT_SCAN #$reconnectAttempt scanning for $targetName")
|
||||
|
||||
bluetoothGatt?.let { gatt ->
|
||||
try { gatt.close() } catch (_: Exception) {}
|
||||
bluetoothGatt = null
|
||||
}
|
||||
|
||||
val device = bluetoothAdapter.getRemoteDevice(address)
|
||||
bluetoothGatt = device.connectGatt(context, true, gattCallback, BluetoothDevice.TRANSPORT_LE)
|
||||
// Fresh scan to find the device again
|
||||
val scanner = bluetoothAdapter.bluetoothLeScanner
|
||||
if (scanner == null) {
|
||||
scheduleAutoReconnect()
|
||||
return
|
||||
}
|
||||
|
||||
// Stop any previous reconnect scan
|
||||
reconnectScanCallback?.let {
|
||||
try { scanner.stopScan(it) } catch (_: Exception) {}
|
||||
}
|
||||
|
||||
val callback = object : ScanCallback() {
|
||||
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
||||
val name = try { result.device.name ?: "" } catch (_: Exception) { "" }
|
||||
val address = result.device.address
|
||||
|
||||
if (address == targetAddress || (targetName.isNotEmpty() && name == targetName)) {
|
||||
logd { "Reconnect scan found: $name ($address)" }
|
||||
debugLogger.info("RECONNECT_FOUND $name ($address) RSSI=${result.rssi}")
|
||||
|
||||
try { scanner.stopScan(this) } catch (_: Exception) {}
|
||||
reconnectScanCallback = null
|
||||
|
||||
// Connect directly (autoConnect=false for fast connection)
|
||||
bluetoothGatt = result.device.connectGatt(
|
||||
context, false, gattCallback, BluetoothDevice.TRANSPORT_LE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
reconnectScanCallback = callback
|
||||
|
||||
try {
|
||||
scanner.startScan(callback)
|
||||
} catch (e: Exception) {
|
||||
debugLogger.error("RECONNECT_SCAN_FAIL ${e.message}")
|
||||
scheduleAutoReconnect()
|
||||
return
|
||||
}
|
||||
|
||||
// Stop scan after 8 seconds → retry next attempt
|
||||
handler.postDelayed({
|
||||
try { scanner.stopScan(callback) } catch (_: Exception) {}
|
||||
reconnectScanCallback = null
|
||||
|
||||
if (!isConnected.value && reconnectAttempt < maxReconnectAttempts) {
|
||||
debugLogger.warn("RECONNECT_SCAN_TIMEOUT #$reconnectAttempt — device not found")
|
||||
scheduleAutoReconnect()
|
||||
} else if (!isConnected.value) {
|
||||
debugLogger.reconnectFailed()
|
||||
isReconnecting.value = false
|
||||
onReconnectionFailed?.invoke()
|
||||
}
|
||||
}, 8000)
|
||||
}
|
||||
|
||||
private fun cancelReconnectTimer() {
|
||||
|
||||
Reference in New Issue
Block a user