feat(android): add privacy-aware TTS foundation#1494
Conversation
Resolve and classify installed TTS engines, persist per-engine trust acknowledgements, and arbitrate audio focus with voice-note playback. Fixes #1479
|
Warning Review limit reached
Next review available in: 25 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughAdds TTS engine discovery and selection, trust warnings with per-engine acknowledgement, shared audio-focus handoff between voice and TTS playback, persisted preferences, settings UI, localization, and extensive Robolectric coverage. ChangesTTS foundation
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related issues
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Ready to review this PR? Stage has broken it down into 5 individual chapters for you: Chapters generated by Stage for commit d1bb943 on Jul 16, 2026 7:09pm UTC. |
Preview APK for PR #1494Home-screen label: 1494 White Noise with the blueprint launcher icon — installs side-by-side with the production and staging apps. Install directly — one tap, no GitHub sign-in (public, content-addressed Every push to this PR rebuilds and updates this comment. |
Adversarial review — changes requestedReviewed exact head Blocking
Suggestions
Verification
No out-of-scope follow-up issues filed; these findings are in #1479's engine-resolution/lifecycle scope. |
Address adversarial review findings for #1479.
|
Addressed all three blocking adversarial findings and the three follow-up suggestions in signed commit
Verification: both compile variants, 4,434 unit tests, both Roborazzi variants, ktlint, Android lint, diff/locale/security sweeps, and an independent pre-commit review all pass. |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/main/java/dev/ipf/whitenoise/android/audio/AudioFocusOwner.kt`:
- Around line 54-61: Update acquire() around previousOwnerSurrender so a thrown
surrender callback does not leave the newly acquired owner and focus active
while propagating failure. Catch the callback failure and roll back the newly
acquired focus/ownership before returning or rethrowing, or enforce that
completeCallback() is non-throwing; preserve normal completion when surrender
succeeds.
In
`@app/src/main/java/dev/ipf/whitenoise/android/ui/settings/TextToSpeechScreen.kt`:
- Around line 122-127: Update the requiresTtsTrustWarning call in the engine
selection flow to pass the candidate engine’s static trust via engine.trust
instead of appState.runtimeTrustForTtsSelectionWarning(...). Preserve the
existing package name and warning preference arguments.
In `@app/src/main/res/values-de/strings.xml`:
- Around line 1076-1083: Standardize the German TTS terminology on
“Sprachausgabe” across the strings in this block: replace the “Engine” wording
in tts_settings_subtitle, tts_settings_explainer_usable, and
tts_settings_engine_local, and replace “Sprachmodul” in
tts_settings_engine_title. Preserve each string’s existing meaning while
ensuring the selected component is described consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 738c6202-0322-4b3e-8739-eb194d65ac86
📒 Files selected for processing (32)
app/src/main/AndroidManifest.xmlapp/src/main/java/dev/ipf/whitenoise/android/audio/AudioFocusOwner.ktapp/src/main/java/dev/ipf/whitenoise/android/audio/VoicePlaybackController.ktapp/src/main/java/dev/ipf/whitenoise/android/audio/tts/TtsEngineCatalog.ktapp/src/main/java/dev/ipf/whitenoise/android/audio/tts/TtsEngineResolver.ktapp/src/main/java/dev/ipf/whitenoise/android/audio/tts/TtsEngineSelection.ktapp/src/main/java/dev/ipf/whitenoise/android/audio/tts/TtsResolutionDispatch.ktapp/src/main/java/dev/ipf/whitenoise/android/audio/tts/TtsTrustWarning.ktapp/src/main/java/dev/ipf/whitenoise/android/state/AppState.ktapp/src/main/java/dev/ipf/whitenoise/android/state/TtsEnginePreferences.ktapp/src/main/java/dev/ipf/whitenoise/android/state/TtsWarningPreferences.ktapp/src/main/java/dev/ipf/whitenoise/android/ui/navigation/AppDestinations.ktapp/src/main/java/dev/ipf/whitenoise/android/ui/settings/SettingsScreen.ktapp/src/main/java/dev/ipf/whitenoise/android/ui/settings/TextToSpeechScreen.ktapp/src/main/res/values-b+zh+Hant/strings.xmlapp/src/main/res/values-de/strings.xmlapp/src/main/res/values-es/strings.xmlapp/src/main/res/values-fr/strings.xmlapp/src/main/res/values-it/strings.xmlapp/src/main/res/values-pt/strings.xmlapp/src/main/res/values-ru/strings.xmlapp/src/main/res/values-tr/strings.xmlapp/src/main/res/values-zh/strings.xmlapp/src/main/res/values/strings.xmlapp/src/test/java/dev/ipf/whitenoise/android/audio/AudioFocusOwnerHandoffTest.ktapp/src/test/java/dev/ipf/whitenoise/android/audio/VoicePlaybackControllerFocusTest.ktapp/src/test/java/dev/ipf/whitenoise/android/audio/tts/TtsEngineResolverTest.ktapp/src/test/java/dev/ipf/whitenoise/android/audio/tts/TtsEngineSelectionTest.ktapp/src/test/java/dev/ipf/whitenoise/android/audio/tts/TtsTrustWarningTest.ktapp/src/test/java/dev/ipf/whitenoise/android/state/TtsEnginePreferencesTest.ktapp/src/test/java/dev/ipf/whitenoise/android/state/TtsStartupDiscoveryCoverageTest.ktapp/src/test/java/dev/ipf/whitenoise/android/state/TtsWarningPreferencesTest.kt
Fixes #1479
Summary
Verification
./gradlew :app:compileDevZapstoreDebugKotlin :app:compileDevPlayDebugKotlin --no-daemon --stacktrace./gradlew :app:testDevZapstoreDebugUnitTest :app:testDevPlayDebugUnitTest --no-daemon --stacktrace./gradlew :app:verifyRoborazziDevZapstoreDebug :app:verifyRoborazziDevPlayDebug --no-daemon --stacktrace./gradlew :app:ktlintCheck --no-daemon --stacktrace./gradlew :app:lintDevZapstoreDebug :app:lintDevPlayDebug --no-daemon --stacktraceorigin/master; all commands passedSensitive paths
Privacy-sensitive plaintext-routing and trust-decision paths:
app/src/main/java/dev/ipf/whitenoise/android/audio/tts/TtsEngineResolver.ktapp/src/main/java/dev/ipf/whitenoise/android/audio/tts/TtsTrustWarning.ktapp/src/main/java/dev/ipf/whitenoise/android/state/TtsWarningPreferences.ktNo crypto, MLS, CGKA, key-handling, authentication, or protocol-state code changed.
Follow-up scope
The actual Speak action and final message-action UI remain in #1480 and #1481 as planned.
Summary by CodeRabbit
New Features
Bug Fixes