feat: Add connection type indicators to SignalBadge

Move BLE key and AAP connection icons into the SignalBadge pill.

Add BleKeyState enum on PodDevice to expose IRK/ENC state cleanly.

Key icon: outlined for IRK-only, solid for IRK+ENC.

Bluetooth icon shown when AAP transport is active.
This commit is contained in:
darken
2026-03-31 19:17:09 +02:00
committed by Matthias Urhahn
parent f65c6e4a29
commit 70e5b99e1d
7 changed files with 230 additions and 46 deletions
@@ -11,6 +11,7 @@ import eu.darken.capod.pods.core.apple.ble.devices.DualApplePods
import eu.darken.capod.pods.core.apple.aap.AapPodState
import eu.darken.capod.pods.core.apple.aap.protocol.AapSetting
import eu.darken.capod.pods.core.apple.ble.devices.ApplePods
import eu.darken.capod.pods.core.apple.ble.protocol.ProximityPayload
import io.kotest.matchers.nulls.shouldBeNull
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
@@ -355,4 +356,54 @@ class PodDeviceTest : BaseTest() {
val device = deviceWithBleQuality(0.50f, aap = null)
device.computeAapBoost(now) shouldBe 0f
}
// --- bleKeyState tests ---
@Test
fun `bleKeyState - null BLE returns NONE`() {
val device = PodDevice(ble = null, aap = null)
device.bleKeyState shouldBe BleKeyState.NONE
}
@Test
fun `bleKeyState - non-Apple BLE returns NONE`() {
val device = PodDevice(ble = mockk(relaxed = true) { every { model } returns PodModel.UNKNOWN }, aap = null)
device.bleKeyState shouldBe BleKeyState.NONE
}
@Test
fun `bleKeyState - Apple BLE without IRK match returns NONE`() {
val ble = mockk<DualApplePods>(relaxed = true) {
every { model } returns PodModel.AIRPODS_PRO3
every { meta } returns ApplePods.AppleMeta(isIRKMatch = false)
every { payload } returns ProximityPayload(public = ProximityPayload.Public(UByteArray(9)), private = null)
}
val device = PodDevice(ble = ble, aap = null)
device.bleKeyState shouldBe BleKeyState.NONE
}
@Test
fun `bleKeyState - IRK match without private payload returns IRK_ONLY`() {
val ble = mockk<DualApplePods>(relaxed = true) {
every { model } returns PodModel.AIRPODS_PRO3
every { meta } returns ApplePods.AppleMeta(isIRKMatch = true)
every { payload } returns ProximityPayload(public = ProximityPayload.Public(UByteArray(9)), private = null)
}
val device = PodDevice(ble = ble, aap = null)
device.bleKeyState shouldBe BleKeyState.IRK_ONLY
}
@Test
fun `bleKeyState - IRK match with private payload returns IRK_AND_ENCRYPTED`() {
val ble = mockk<DualApplePods>(relaxed = true) {
every { model } returns PodModel.AIRPODS_PRO3
every { meta } returns ApplePods.AppleMeta(isIRKMatch = true)
every { payload } returns ProximityPayload(
public = ProximityPayload.Public(UByteArray(9)),
private = ProximityPayload.Private(UByteArray(8)),
)
}
val device = PodDevice(ble = ble, aap = null)
device.bleKeyState shouldBe BleKeyState.IRK_AND_ENCRYPTED
}
}