From 33c4e94d07883c764205e9f5ceaeeeb2a403e503 Mon Sep 17 00:00:00 2001 From: jjangddu Date: Mon, 3 Aug 2026 15:28:23 +0900 Subject: [PATCH] =?UTF-8?q?feat(firmware):=20=EC=9D=B4=EB=AF=B8=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0=EB=90=9C=20=EA=B8=B0=EA=B8=B0=20=EC=9E=88?= =?UTF-8?q?=EC=9C=BC=EB=A9=B4=20=EC=8A=A4=EC=BA=94=20=EC=83=9D=EB=9E=B5=20?= =?UTF-8?q?=C2=B7=20=EB=B0=94=EB=A1=9C=20=EC=9E=AC=EC=97=B0=EA=B2=B0=20(cl?= =?UTF-8?q?oud-mvp=2019a1c12=20=EC=9D=B4=EC=8B=9D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 이전 fix (47317b3) 는 진입 시 disconnect 만 했지만 사용자가 여전히 Scan → Connect 를 수동으로 눌러야 했음. UX 낭비. 이제: 1. 진입 → 이미 연결된 기기 체크 (BleManager.isConnected) 2. BluetoothDevice + name 캡처 3. 메인 앱 disconnect (프로브 광고 재개) 4. 1.5s 대기 (BLE stack 정리) 5. DfuManager.connectDirectly(device, name) — 스캔 생략 6. 사용자는 CONNECTED 상태에서 "Start DFU" 만 누르면 됨 BleManager.kt (demo-final path): currentBluetoothDevice getter 추가 DfuManager.kt: connectDirectly(device, name) FirmwareUpdateView.kt: LaunchedEffect 개편 — 조건 분기 · delay · auto-connect 연결 없이 진입하면 기존 스캔 flow 유지. Co-Authored-By: Claude Opus 4.7 --- .../com/medithings/vesiscan/ble/BleManager.kt | 7 ++++++ .../vesiscan/firmware/DfuManager.kt | 10 ++++++++ .../firmware/ui/FirmwareUpdateView.kt | 24 ++++++++++++++----- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/medithings/vesiscan/ble/BleManager.kt b/app/src/main/java/com/medithings/vesiscan/ble/BleManager.kt index acb84f6..f101331 100644 --- a/app/src/main/java/com/medithings/vesiscan/ble/BleManager.kt +++ b/app/src/main/java/com/medithings/vesiscan/ble/BleManager.kt @@ -114,6 +114,13 @@ class BleManager private constructor(private val context: Context) { val batteryLevel = mutableStateOf(0) val bluetoothEnabled = mutableStateOf(bluetoothAdapter?.isEnabled == true) val isServiceReady = mutableStateOf(false) + + /** 현재 GATT 연결된 BluetoothDevice · 없으면 null. Firmware DFU 진입 시 + * 스캔 생략하고 바로 이 기기로 재연결하는 경로에서 사용. */ + val currentBluetoothDevice: android.bluetooth.BluetoothDevice? + @android.annotation.SuppressLint("MissingPermission") + get() = bluetoothGatt?.device + val isBonded: Boolean @android.annotation.SuppressLint("MissingPermission") get() = bluetoothGatt?.device?.bondState == android.bluetooth.BluetoothDevice.BOND_BONDED diff --git a/app/src/main/java/com/medithings/vesiscan/firmware/DfuManager.kt b/app/src/main/java/com/medithings/vesiscan/firmware/DfuManager.kt index cae7a0e..bf15100 100644 --- a/app/src/main/java/com/medithings/vesiscan/firmware/DfuManager.kt +++ b/app/src/main/java/com/medithings/vesiscan/firmware/DfuManager.kt @@ -195,6 +195,16 @@ class DfuManager(context: Context) { ).also { it.connect(device.device) } } + /** + * 스캔 생략 · 이미 알고 있는 기기에 바로 연결 (2026-08-03). + * 메인 앱이 이미 프로브에 연결됐던 상태에서 FirmwareUpdate 진입할 때 사용. + */ + fun connectDirectly(device: BluetoothDevice, name: String) { + val scanned = ScannedDevice(device = device, name = name, rssi = 0, inDfuMode = false) + log("skip scan — using previously connected device: $name") + connect(scanned) + } + fun disconnect() { closeNus() if (phase.value == DfuPhase.CONNECTED || phase.value == DfuPhase.CONNECTING) { diff --git a/app/src/main/java/com/medithings/vesiscan/firmware/ui/FirmwareUpdateView.kt b/app/src/main/java/com/medithings/vesiscan/firmware/ui/FirmwareUpdateView.kt index d4d8730..185bfca 100644 --- a/app/src/main/java/com/medithings/vesiscan/firmware/ui/FirmwareUpdateView.kt +++ b/app/src/main/java/com/medithings/vesiscan/firmware/ui/FirmwareUpdateView.kt @@ -91,13 +91,25 @@ fun FirmwareUpdateScreen(onBack: () -> Unit, modifier: Modifier = Modifier) { ) { result -> granted = result.values.all { it } } LaunchedEffect(Unit) { - // 진입 시 메인 앱 BLE 연결 해제 — 프로브가 연결 중이면 광고 중단되어 - // DfuManager 스캔에서 안 보이는 문제 해결 (2026-08-03). - runCatching { - com.medithings.vesiscan.ble.BleManager.getInstance(context).disconnect() - } manager.loadFirmware() - if (!granted) launcher.launch(perms) + if (!granted) { + launcher.launch(perms) + return@LaunchedEffect + } + + // 이미 메인 앱이 연결된 기기가 있으면 스캔 생략 · 자동 재연결로 UX 단축 (2026-08-03). + val bleManager = com.medithings.vesiscan.ble.BleManager.getInstance(context) + val preConnectedDevice = if (bleManager.isConnected.value) bleManager.currentBluetoothDevice else null + val preConnectedName = bleManager.connectedDeviceName.value + + // 메인 앱 BLE 연결 해제 — 프로브가 연결 중이면 광고 중단되어 스캔 안 보임. + runCatching { bleManager.disconnect() } + + // 이미 알던 기기가 있으면 스캔 없이 바로 재연결 시도. + if (preConnectedDevice != null && preConnectedName.isNotEmpty()) { + kotlinx.coroutines.delay(1500) // BLE stack 정리 · 재광고 대기 + manager.connectDirectly(preConnectedDevice, preConnectedName) + } } DisposableEffect(Unit) { onDispose { manager.shutdown() } }