Skip to content

feat(android): Auto-disable CA volume ducking when only one AirPod is worn (#616)#675

Open
QuantumBreakz wants to merge 1 commit into
librepods-org:mainfrom
QuantumBreakz:feat/616-ca-both-pods-only
Open

feat(android): Auto-disable CA volume ducking when only one AirPod is worn (#616)#675
QuantumBreakz wants to merge 1 commit into
librepods-org:mainfrom
QuantumBreakz:feat/616-ca-both-pods-only

Conversation

@QuantumBreakz

Copy link
Copy Markdown

Summary

Closes #616

Implements the app-side suppression approach suggested by @tabjy and accepted by @kavishdevar.

When the new "Only when both AirPods are worn" toggle is ON, the Conversational Awareness volume-ducking event (startSpeaking()) is silently ignored if fewer than two buds are currently in-ear. The stopSpeaking() (volume restore) path is never gated, so volume can never get stuck low.


Changes

AirPodsService.kt

  • Added conversationalAwarenessBothPodsOnly: Boolean = false to ServiceConfig
  • Seeded conversational_awareness_both_pods_only in first-run SharedPreferences defaults (false)
  • Loaded the pref in initializeConfig()
  • Added live-change case in onSharedPreferenceChanged()
  • The gate in onConversationAwarenessReceived():
    val budsInEar = earDetectionNotification.status.count { it == 0x00.toByte() }
    val blockedForSinglePod = config.conversationalAwarenessBothPodsOnly && budsInEar < 2
    if (status == 1 || status == 2) {
        if (!blockedForSinglePod) MediaController.startSpeaking()
    } else if (status == 6 || 8 || 9) {
        MediaController.stopSpeaking() // never gated
    }

AppSettingsViewModel.kt

  • Added conversationalAwarenessBothPodsOnlyEnabled: Boolean = false to AppSettingsUiState
  • Loaded the pref in loadSettings()
  • Added setConversationalAwarenessBothPodsOnlyEnabled(enabled: Boolean) setter

AppSettingsScreen.kt

  • Added a third StyledToggle inside the existing Conversational Awareness StyledList, between "Pause Music" and "Relative volume"

strings.xml

<string name="conversational_awareness_both_pods_only">Only when both AirPods are worn</string>
<string name="conversational_awareness_both_pods_only_description">Only lowers the volume when you speak if both AirPods are in your ears.</string>

Behaviour

Toggle One AirPod Both AirPods
OFF (default) Volume ducks ✅ Volume ducks ✅
ON Volume does not duck ✅ Volume ducks ✅

The stopSpeaking() path always runs regardless of toggle state — volume is always restored.


Testing

Build verified: ./gradlew assembleFossDebugBUILD SUCCESSFUL (51 tasks, 0 errors).

Manual test steps:

  1. Enable the toggle in Settings → Conversational Awareness
  2. Play music, insert one AirPod, speak → volume should not duck
  3. Insert both AirPods, speak → volume should duck
  4. Disable the toggle → always ducks (original behaviour restored)

Notes

  • Default is false in all five required places — zero behaviour change for existing users
  • Uses app-side suppression (no firmware commands) as recommended by the reporter
  • Reads ear state from the existing earDetectionNotification.status array (0x00 = in-ear)

- Add conversationalAwarenessBothPodsOnly field to ServiceConfig (default false)
- Seed 'conversational_awareness_both_pods_only' pref on first run (default false)
- Load pref in initializeConfig() and handle live changes in onSharedPreferenceChanged()
- Add conversationalAwarenessBothPodsOnlyEnabled to AppSettingsUiState
- Add setConversationalAwarenessBothPodsOnlyEnabled() setter to AppSettingsViewModel
- Add StyledToggle in AppSettingsScreen inside the Conversational Awareness list
- Add string resources: conversational_awareness_both_pods_only + _description

Default is off — no behavior change for existing users.

Fixes librepods-org#616
@QuantumBreakz

Copy link
Copy Markdown
Author

Hey @kavishdevar 👋

This PR implements the feature requested in #616 by @tabjy using the app-side suppression approach you approved.

Since this is submitted from a fork, I can't set reviewers or assignees programmatically. Could you please:

  • Assign yourself (or another maintainer) as reviewer
  • Assign @tabjy as the original reporter/assignee if appropriate

Build is verified: ./gradlew assembleFossDebugBUILD SUCCESSFUL (51 tasks, 0 errors, 0 new warnings).

Happy to make any changes based on your review! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Automatically disable conversational awareness when only one single AirPod is inserted

2 participants