From e9b6aef07c1cdd2b82723a7e80ea31d0b6601fe8 Mon Sep 17 00:00:00 2001 From: g150446 Date: Sun, 28 Dec 2025 10:29:59 +0900 Subject: [PATCH 1/2] Fix crash when connecting to watches in recovery firmware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recovery firmware returns an empty byte array for the BLE connectivity characteristic, causing ArrayIndexOutOfBoundsException when trying to parse connection status. Added bounds checking to handle empty arrays safely, allowing users to connect and update watches in recovery mode. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- .../bt/ble/pebble/ConnectivityWatcher.kt | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/connection/bt/ble/pebble/ConnectivityWatcher.kt b/libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/connection/bt/ble/pebble/ConnectivityWatcher.kt index f194c9daf..8c06fdd8b 100644 --- a/libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/connection/bt/ble/pebble/ConnectivityWatcher.kt +++ b/libpebble3/src/commonMain/kotlin/io/rebble/libpebblecommon/connection/bt/ble/pebble/ConnectivityWatcher.kt @@ -88,14 +88,29 @@ class ConnectivityStatus(characteristicValue: ByteArray) { val pairingErrorCode: PairingErrorCode init { - val flags = characteristicValue[0] - connected = flags and 0b1 > 0 - paired = flags and 0b10 > 0 - encrypted = flags and 0b100 > 0 - hasBondedGateway = flags and 0b1000 > 0 - supportsPinningWithoutSlaveSecurity = flags and 0b10000 > 0 - hasRemoteAttemptedToUseStalePairing = flags and 0b100000 > 0 - pairingErrorCode = PairingErrorCode.getByValue(characteristicValue[3]) + // Handle empty array (can happen with recovery firmware) + if (characteristicValue.isEmpty()) { + connected = false + paired = false + encrypted = false + hasBondedGateway = false + supportsPinningWithoutSlaveSecurity = false + hasRemoteAttemptedToUseStalePairing = false + pairingErrorCode = PairingErrorCode.NO_ERROR + } else { + val flags = characteristicValue[0] + connected = flags and 0b1 > 0 + paired = flags and 0b10 > 0 + encrypted = flags and 0b100 > 0 + hasBondedGateway = flags and 0b1000 > 0 + supportsPinningWithoutSlaveSecurity = flags and 0b10000 > 0 + hasRemoteAttemptedToUseStalePairing = flags and 0b100000 > 0 + pairingErrorCode = if (characteristicValue.size > 3) { + PairingErrorCode.getByValue(characteristicValue[3]) + } else { + PairingErrorCode.NO_ERROR + } + } } override fun toString(): String = From 60d6e35e1f12b0dae1cb2bf26e09fea6d0ac7051 Mon Sep 17 00:00:00 2001 From: g150446 Date: Sun, 28 Dec 2025 14:09:13 +0900 Subject: [PATCH 2/2] Fix firmware sideload error messages not showing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When firmware sideload failed with a safety check error (e.g., board mismatch), the UI would stay on "Idle" instead of showing the error message. Now properly displays error messages from the Idle state's lastFailure field. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- .../coredevices/pebble/ui/DebugFirmwareSideload.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pebble/src/commonMain/kotlin/coredevices/pebble/ui/DebugFirmwareSideload.kt b/pebble/src/commonMain/kotlin/coredevices/pebble/ui/DebugFirmwareSideload.kt index 32cde1e69..30a2d34f6 100644 --- a/pebble/src/commonMain/kotlin/coredevices/pebble/ui/DebugFirmwareSideload.kt +++ b/pebble/src/commonMain/kotlin/coredevices/pebble/ui/DebugFirmwareSideload.kt @@ -84,7 +84,15 @@ private sealed class UiFirmwareUpdateStatus { "Couldn't start: ${status.error.message()}" ) - is FirmwareUpdater.FirmwareUpdateStatus.NotInProgress.Idle -> Idle + is FirmwareUpdater.FirmwareUpdateStatus.NotInProgress.Idle -> { + // Check if there was a failure + val failure = status.lastFailure + if (failure != null) { + Error(failure, failure.message ?: "Unknown error") + } else { + Idle + } + } } } }