I'm trying to write an Audio Player App with fine grained control over Headset media buttons. On some devices it works as expected, on others (mostly more modern ones with Android > 12) the headset button has a strange delay of 1000ms when the button is held / pressed down for longer times.
The pattern `ACTION_DOWN / ACTION_UP / ACTION_DOWN+hold` produces the following event log on an Android 13 device (Pixel 4a, GrapheneOS):
This shows that holding the headset button down for a while produces a delay of 1000ms followed by a `ACTION_DOWN` with a `repeatCount=2` skipping the `repeatCount=1` event
The problem with this is, that I developed a headset button pattern-recognition algorithm to react to these specific planned tap codes (similar to iOS / iPod Nano 7 headset button handling):
The algorithm is very simple and based on accurate timing, where the desired action is executed after
`650ms`
of receiving no further button events, which is (in my opinion) the perfect timing to execute action fast with enough flexibility. I still like to keep this value configurable, because other people might have slightly different preferences on timing.
However, a low timer like this is no longer possible with a delay of `1000ms`, because the delayed action is getting executed too early (after 650ms before receiving the ACTION_DOWN event after 1000ms).
So the `TAP+hold` patterns are getting messed up due to this delay problem.
I can think of possible solutions
The pattern `ACTION_DOWN / ACTION_UP / ACTION_DOWN+hold` produces the following event log on an Android 13 device (Pixel 4a, GrapheneOS):
event log:
2025-06-20 07:06:21.635 12076-12076 === keyCode=KEYCODE_HEADSETHOOK, action=ACTION_DOWN, repeatCount=0
2025-06-20 07:06:21.637 12076-12076 === keyCode=KEYCODE_HEADSETHOOK, action=ACTION_UP, repeatCount=0
# > 1000ms event delay on hold key????
2025-06-20 07:06:22.642 12076-12076 === keyCode=KEYCODE_HEADSETHOOK, action=ACTION_DOWN, repeatCount=2
2025-06-20 07:06:22.698 12076-12076 === keyCode=KEYCODE_HEADSETHOOK, action=ACTION_DOWN, repeatCount=3
2025-06-20 07:06:22.748 12076-12076 === keyCode=KEYCODE_HEADSETHOOK, action=ACTION_DOWN, repeatCount=4
2025-06-20 07:06:22.800 12076-12076 === keyCode=KEYCODE_HEADSETHOOK, action=ACTION_DOWN, repeatCount=5
This shows that holding the headset button down for a while produces a delay of 1000ms followed by a `ACTION_DOWN` with a `repeatCount=2` skipping the `repeatCount=1` event
The problem with this is, that I developed a headset button pattern-recognition algorithm to react to these specific planned tap codes (similar to iOS / iPod Nano 7 headset button handling):
- `TAP` - play/pause
- `TAP-TAP` - next (chapter or track)
- `TAP-TAP-TAP` - prev (chapter or track)
- `TAP+hold` - go back 30 seconds
- broken: `TAP-TAP+hold` - fast-forward
- broken: `TAP-TAP-TAP+hold` - rewind
The algorithm is very simple and based on accurate timing, where the desired action is executed after
`650ms`
of receiving no further button events, which is (in my opinion) the perfect timing to execute action fast with enough flexibility. I still like to keep this value configurable, because other people might have slightly different preferences on timing.
However, a low timer like this is no longer possible with a delay of `1000ms`, because the delayed action is getting executed too early (after 650ms before receiving the ACTION_DOWN event after 1000ms).
So the `TAP+hold` patterns are getting messed up due to this delay problem.
I can think of possible solutions
- Workaround the 1000ms delay and get every event with no delay in onMediaButtonEvent (the RIGHT way - is this possible?)
- Raising the 650ms schedule timer to 1100ms which leads to slower response times
- A totally custom `MediaButtonReceiver` handling everything myself (is that even possible)?
- "Merge" events (a.k.a detect bogus patterns - e.g. double tap, perform action "next", remember last state, then detect long press and undo "next" and perform rewind from last state)
- onMediaButtonEvent handling
- MediaButton-Tap-Pattern-Algorithm (relevant part)
Last edited: