From 506248655dea3340ac8070e5b7a5a61ac5395a4e Mon Sep 17 00:00:00 2001 From: jjangddu Date: Thu, 23 Apr 2026 12:22:07 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20BLE=20=EB=A1=9C=EA=B7=B8=20Downloads=20?= =?UTF-8?q?=ED=8F=B4=EB=8D=94=EC=97=90=20=EC=A0=80=EC=9E=A5=20(=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=ED=83=90=EC=83=89=EA=B8=B0=20=EC=A0=91=EA=B7=BC=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - exportToDownloads(): Downloads/VesiScan_BLE_날짜.log 로 저장 - 실패 시 fallback으로 내부 저장소에 저장 - Toast로 저장 경로 안내 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../services/BleDebugLogger.kt | 55 ++++++++++++------- .../views/monitoring/PiezoMonitoringView.kt | 11 +++- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/example/medilightv2android/services/BleDebugLogger.kt b/app/src/main/java/com/example/medilightv2android/services/BleDebugLogger.kt index b9d4eae..0942beb 100644 --- a/app/src/main/java/com/example/medilightv2android/services/BleDebugLogger.kt +++ b/app/src/main/java/com/example/medilightv2android/services/BleDebugLogger.kt @@ -207,32 +207,47 @@ class BleDebugLogger private constructor(private val context: Context) { // ── File Export ── + private fun writeLogContent(writer: java.io.BufferedWriter) { + writer.write("=== VesiScan BLE Debug Log ===\n") + writer.write("Device: $deviceName\n") + writer.write("Session: ${dateFmt.format(Date(sessionStart))}\n") + writer.write("Duration: ${sessionDurationSec()}s\n") + writer.write("TX: $txCount RX: $rxCount Errors: $errorCount Timeouts: $packetTimeouts\n") + + if (rssiHistory.isNotEmpty()) { + writer.write("RSSI: avg=${rssiHistory.map { it.second }.average().toInt()} ") + writer.write("min=${rssiHistory.minOf { it.second }} max=${rssiHistory.maxOf { it.second }}\n") + } + + writer.write("=".repeat(60) + "\n\n") + + for (entry in entries) { + writer.write(entry.toLogLine() + "\n") + } + } + fun exportToFile(): File { val fileName = "ble_debug_${dateFmt.format(Date())}.log" val file = File(logDir, fileName) - - file.bufferedWriter().use { writer -> - writer.write("=== VesiScan BLE Debug Log ===\n") - writer.write("Device: $deviceName\n") - writer.write("Session: ${dateFmt.format(Date(sessionStart))}\n") - writer.write("Duration: ${sessionDurationSec()}s\n") - writer.write("TX: $txCount RX: $rxCount Errors: $errorCount Timeouts: $packetTimeouts\n") - - if (rssiHistory.isNotEmpty()) { - writer.write("RSSI: avg=${rssiHistory.map { it.second }.average().toInt()} ") - writer.write("min=${rssiHistory.minOf { it.second }} max=${rssiHistory.maxOf { it.second }}\n") - } - - writer.write("=".repeat(60) + "\n\n") - - for (entry in entries) { - writer.write(entry.toLogLine() + "\n") - } - } - + file.bufferedWriter().use { writeLogContent(it) } return file } + /** Downloads 폴더에 저장 (파일 탐색기에서 바로 접근 가능) */ + fun exportToDownloads(): File? { + return try { + val downloadsDir = android.os.Environment.getExternalStoragePublicDirectory( + android.os.Environment.DIRECTORY_DOWNLOADS + ) + val fileName = "VesiScan_BLE_${dateFmt.format(Date())}.log" + val file = File(downloadsDir, fileName) + file.bufferedWriter().use { writeLogContent(it) } + file + } catch (e: Exception) { + null + } + } + fun exportToJsonFile(): File { val fileName = "ble_debug_${dateFmt.format(Date())}.jsonl" val file = File(logDir, fileName) diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt index 38edc70..d4ac6a3 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt +++ b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt @@ -1115,11 +1115,16 @@ private fun BleDebugPanel(bleManager: BleManager) { Icon(Icons.Default.ContentCopy, "Copy", tint = Color.Gray, modifier = Modifier.size(16.dp)) } - // Export file button + // Export to Downloads IconButton( onClick = { - val file = logger.exportToFile() - android.widget.Toast.makeText(context, "Saved: ${file.name}", android.widget.Toast.LENGTH_SHORT).show() + val file = logger.exportToDownloads() + if (file != null) { + android.widget.Toast.makeText(context, "Downloads/${file.name} 저장 완료", android.widget.Toast.LENGTH_LONG).show() + } else { + logger.exportToFile() + android.widget.Toast.makeText(context, "내부 저장소에 저장됨", android.widget.Toast.LENGTH_SHORT).show() + } }, modifier = Modifier.size(32.dp) ) {