Skip to content

Commit 0343554

Browse files
nikosnikos
authored andcommitted
android: end call on stem press during a call
Once setupStemActions() marks the mute press as customized during a call, the firmware stops handling the end-call press natively and forwards every press to the app. handleCallStemPress only intercepted the mute press, so end-call presses fell through to the user's normal stem action (play/pause, next track, etc.) and never ended the call. Identify the end-call press as the opposite of the mute press from CALL_MANAGEMENT_CONFIG and route it through rejectCall(), which already handles both telephony (TelecomManager.endCall) and VoIP (HEADSETHOOK fallback for Teams/Zoom/Meet).
1 parent ac5079b commit 0343554

1 file changed

Lines changed: 19 additions & 12 deletions

File tree

android/app/src/main/java/me/kavishdevar/librepods/services/AirPodsService.kt

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,26 +1280,33 @@ class AirPodsService : Service(), SharedPreferences.OnSharedPreferenceChangeList
12801280

12811281
/**
12821282
* Handles a stem press during an active call. Returns true if the press was
1283-
* the configured mute press type and was handled here; false otherwise (the
1284-
* caller should fall through to normal stem-action handling).
1283+
* either the configured mute press or the configured end-call press; false
1284+
* otherwise (the caller should fall through to normal stem-action handling).
12851285
*
1286-
* The end-call press type is intentionally NOT handled here so the OS / AirPods
1287-
* native HFP behavior can end the call (which works for both telephony and VoIP).
1286+
* Once we mark any press as customized in setupStemActions() during a call,
1287+
* the firmware stops handling end-call natively and forwards every press to
1288+
* us, so we have to end the call ourselves.
12881289
*/
12891290
private fun handleCallStemPress(pressType: StemPressType): Boolean {
12901291
// CALL_MANAGEMENT_CONFIG byte[1]: 0x02 = mute on double press (flipped), 0x03 = mute on single press (default)
12911292
val callConfig = aacpManager.getControlCommandStatus(
12921293
AACPManager.Companion.ControlCommandIdentifiers.CALL_MANAGEMENT_CONFIG
12931294
)?.value
12941295
val muteIsDoublePress = callConfig?.getOrNull(1) == 0x02.toByte()
1295-
val isMutePress = (pressType == StemPressType.SINGLE_PRESS && !muteIsDoublePress) ||
1296-
(pressType == StemPressType.DOUBLE_PRESS && muteIsDoublePress)
1297-
Log.d(TAG, "Call stem press: $pressType, muteIsDoublePress=$muteIsDoublePress, isMutePress=$isMutePress")
1298-
if (isMutePress) {
1299-
toggleMicMute()
1300-
return true
1301-
}
1302-
return false
1296+
val mutePressType = if (muteIsDoublePress) StemPressType.DOUBLE_PRESS else StemPressType.SINGLE_PRESS
1297+
val endCallPressType = if (muteIsDoublePress) StemPressType.SINGLE_PRESS else StemPressType.DOUBLE_PRESS
1298+
Log.d(TAG, "Call stem press: $pressType, mutePressType=$mutePressType, endCallPressType=$endCallPressType")
1299+
return when (pressType) {
1300+
mutePressType -> {
1301+
toggleMicMute()
1302+
true
1303+
}
1304+
endCallPressType -> {
1305+
rejectCall()
1306+
true
1307+
}
1308+
else -> false
1309+
}
13031310
}
13041311

13051312
private fun toggleMicMute() {

0 commit comments

Comments
 (0)