fix(aap): Report speaking=true for Conversational Awareness resume (status 5)

This commit is contained in:
darken
2026-06-18 12:07:19 +02:00
committed by Matthias Urhahn
parent 5c5cc6f28e
commit f0c9d318ff
3 changed files with 11 additions and 5 deletions
@@ -103,9 +103,10 @@ sealed class AapSetting {
* Push-only from device — reports speaking detection state (command 0x4B).
*
* [rawValue] is the status byte: the last byte of the 4-byte `02 00 01 XX` form (or the single
* byte of the legacy form), preserved so consumers can classify it. [speaking] is `true` only
* for the speaking-onset statuses (`1`, `2`); every other value (`0`, `3`, `4`, `5`, `0x0B`, …)
* is `false`. START/RESUME/HOLD/STOP classification for the reaction lives in [ConversationAwarenessEvent].
* byte of the legacy form), preserved so consumers can classify it. [speaking] is `true` while
* the wearer is talkingonset (`1`, `2`) or resumed after a pause (`5`); every other value
* (`0`, `3`, `4`, `0x0B`, …) is `false`. START/RESUME/HOLD/STOP classification for the reaction
* lives in [ConversationAwarenessEvent].
*/
data class ConversationalAwarenessState(
val speaking: Boolean,
@@ -197,8 +197,11 @@ class DefaultAapDeviceProfile(
p[3].toInt() and 0xFF
else -> return null
}
// speaking = the "started/active speaking" statuses (1,2); see ConversationAwarenessEvent.
val speaking = status in ConversationAwarenessEvent.SPEAKING_STATUSES
// speaking = the wearer is currently speaking: onset (1,2) or resumed after a pause (5).
// See ConversationAwarenessEvent. (Consumers read rawValue for full classification; this
// bool just exposes "is talking now", so a resume must count as speaking too.)
val speaking = status in ConversationAwarenessEvent.SPEAKING_STATUSES ||
status in ConversationAwarenessEvent.RESUME_STATUSES
return AapSetting.ConversationalAwarenessState::class to
AapSetting.ConversationalAwarenessState(speaking, rawValue = status)
}
@@ -412,6 +412,8 @@ class DefaultAapDeviceProfileTest : BaseAapSessionTest() {
@Nested
inner class ConversationAwarenessStateTests {
@Test fun `speaking start`() { decodeSetting<AapSetting.ConversationalAwarenessState>(aapMessage("04 00 04 00 4B 00 01")).speaking shouldBe true }
@Test fun `speaking resume`() { decodeSetting<AapSetting.ConversationalAwarenessState>(aapMessage("04 00 04 00 4B 00 05")).speaking shouldBe true }
@Test fun `speaking pause`() { decodeSetting<AapSetting.ConversationalAwarenessState>(aapMessage("04 00 04 00 4B 00 03")).speaking shouldBe false }
@Test fun `speaking stop`() { decodeSetting<AapSetting.ConversationalAwarenessState>(aapMessage("04 00 04 00 4B 00 04")).speaking shouldBe false }
@Test fun `empty payload returns null`() { profile.decodeSetting(aapMessage("04 00 04 00 4B 00")).shouldBeNull() }
}