mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-14 18:26:11 -04:00
fix(monitor): Use AAP message time for Last Seen while connected
This commit is contained in:
@@ -64,7 +64,8 @@ data class PodDevice(
|
||||
val hasDualMicrophone: Boolean get() = ble is HasDualMicrophone
|
||||
|
||||
// Signal / timing
|
||||
val seenLastAt: Instant? get() = ble?.seenLastAt ?: cached?.lastSeenAt
|
||||
val seenLastAt: Instant?
|
||||
get() = listOfNotNull(ble?.seenLastAt, aap?.lastMessageAt, cached?.lastSeenAt).maxOrNull()
|
||||
val seenFirstAt: Instant? get() = ble?.seenFirstAt
|
||||
val signalQuality: Float
|
||||
get() {
|
||||
|
||||
@@ -108,6 +108,21 @@ class PodDeviceCacheTest : BaseTest() {
|
||||
device.seenLastAt shouldBe fiveMinAgo
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `seenLastAt prefers live AAP message over stale cache`() {
|
||||
// Reproduces the reported bug: while AAP is connected, iOS throttles BLE advertising.
|
||||
// After BlePodMonitor evicts the BLE snapshot, the merged device had ble=null and the
|
||||
// getter fell through to the stale cache, showing "hours ago" even though AAP traffic
|
||||
// was still flowing. Live AAP messages must win over any cached timestamp.
|
||||
val freshAapMessage = Instant.parse("2026-03-31T11:59:55Z") // 5s ago, newer than cache
|
||||
val aap = AapPodState(
|
||||
connectionState = AapPodState.ConnectionState.READY,
|
||||
lastMessageAt = freshAapMessage,
|
||||
)
|
||||
val device = PodDevice(profileId = "test-profile", ble = null, aap = aap, cached = cachedState)
|
||||
device.seenLastAt shouldBe freshAapMessage
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `profileId falls back to cache`() {
|
||||
val device = PodDevice(profileId = "test-profile", ble = null, aap = null, cached = cachedState)
|
||||
|
||||
@@ -143,6 +143,33 @@ class PodDeviceTest : BaseTest() {
|
||||
device.rssi shouldBe 0
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `seenLastAt uses AAP lastMessageAt when BLE is null`() {
|
||||
val aapMessageAt = Instant.parse("2026-04-01T12:00:00Z")
|
||||
val aap = AapPodState(
|
||||
connectionState = AapPodState.ConnectionState.READY,
|
||||
lastMessageAt = aapMessageAt,
|
||||
)
|
||||
val device = PodDevice(profileId = null, ble = null, aap = aap)
|
||||
device.seenLastAt shouldBe aapMessageAt
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `seenLastAt picks max of BLE and AAP timestamps`() {
|
||||
val bleSeenAt = Instant.parse("2026-04-01T12:00:00Z")
|
||||
val aapMessageAt = bleSeenAt.plusSeconds(25) // AAP is more recent
|
||||
val ble = mockk<DualApplePods>(relaxed = true) {
|
||||
every { model } returns PodModel.AIRPODS_PRO3
|
||||
every { seenLastAt } returns bleSeenAt
|
||||
}
|
||||
val aap = AapPodState(
|
||||
connectionState = AapPodState.ConnectionState.READY,
|
||||
lastMessageAt = aapMessageAt,
|
||||
)
|
||||
val device = PodDevice(profileId = null, ble = ble, aap = aap)
|
||||
device.seenLastAt shouldBe aapMessageAt
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `charging properties delegate to BLE interfaces`() {
|
||||
val mock = mockk<DualApplePods>(relaxed = true) {
|
||||
|
||||
Reference in New Issue
Block a user