Skip to content

Conversation

@d-init-d
Copy link

@d-init-d d-init-d commented Feb 7, 2026

Summary

This PR adds an Android TextToSpeech (TTS) bridge to the launcher, exposing the system TTS framework to Lua via a new android.tts namespace. This enables KOReader-side plugins to implement “Read Aloud” using the user’s configured system TTS engine (Google/Samsung/…).

API exposed to Lua

assets/android.lua now provides:

  • android.tts.init() -> boolean (requests initialization; initialization completes asynchronously)
  • android.tts.speak(text, queueMode) -> boolean (returns false if the engine is not ready yet)
  • android.tts.stop() -> boolean
  • android.tts.isSpeaking() -> boolean
  • android.tts.setSpeechRate(ratePercent) -> boolean (e.g. 50..200)
  • android.tts.setPitch(pitchPercent) -> boolean (e.g. 50..200)
  • android.tts.openSettings() -> void
  • android.tts.installData() -> void
  • android.tts.say(text, queueMode) convenience wrapper

Constants:

  • android.tts.QUEUE_FLUSH = 0
  • android.tts.QUEUE_ADD = 1

Implementation Details

  • app/src/main/java/org/koreader/launcher/LuaInterface.kt
    • Adds tts* methods to the Lua/JNI interface.
  • app/src/main/java/org/koreader/launcher/MainActivity.kt
    • Implements the tts* methods.
    • Stores a TextToSpeech instance and a readiness flag (ttsInitialized).
    • Executes TTS calls on the UI thread via runOnUiThread (except for isSpeaking, which is best-effort).
    • Cleans up on onDestroy() via ttsShutdownInternal().
  • assets/android.lua
    • Adds the android.tts namespace and ensures JNI varargs type-safety by casting ints with ffi.new("int32_t", ...).

Testing

  • Codacy: PASS.
  • Note: GitHub Actions build workflow for this PR is awaiting maintainer approval because it comes from a fork.
  • Manual verification steps:
    1. Build and install KOReader for Android.
    2. From Lua (or a plugin), call android.tts.init() and retry android.tts.say("hello") until it returns true.
    3. Verify android.tts.stop() and android.tts.isSpeaking().
    4. Verify android.tts.openSettings() and android.tts.installData().

Limitations

  • No ForegroundService/notification controls (kept out of scope for this MVP bridge).
  • Requires an installed system TTS engine and voice data for the desired language.

This change is Reviewable

@d-init-d
Copy link
Author

CI note: this PR is from a fork, so the GitHub Actions build workflow is currently awaiting maintainer approval (shows as action_required).

  • Previous compile issue (ACTION_TTS_SETTINGS unresolved reference) has been fixed.
  • Codacy check is green.

Could a maintainer please click “Approve and run” for the workflow run so the build checks can execute? Thanks!

@Frenzie
Copy link
Member

Frenzie commented Feb 10, 2026

Are all of these methods API level 4?

@pazos
Copy link
Member

pazos commented Feb 10, 2026

Could you move the kotlin implementation from MainActivity to its own class?. TTSEngine or something like that works :)

@d-init-d
Copy link
Author

Yes, I've verified the API compatibility:

  • TextToSpeech class and basic methods are API 4+.
  • The speak(String, int, HashMap) overload is deprecated in API 21, but it remains available and functional on newer devices. Since our minSdkVersion is 18, using this overload ensures support for older devices (API 18-20) without requiring runtime version checks.
  • setSpeechRate, setPitch, isSpeaking are API 1+.
  • shutdown, stop are API 4+.
  • ACTION_INSTALL_TTS_DATA is API 4+.
    So the implementation is safe for minSdkVersion 18.

@d-init-d
Copy link
Author

Done! I've refactored the TTS logic into a dedicated TTSEngine class as requested in cf6f860. MainActivity now delegates TTS operations to TTSEngine.

@d-init-d
Copy link
Author

d-init-d commented Feb 11, 2026

Follow-up pushed in 9715be6 and 3df263d to address Codacy findings from the refactor (unused import + consecutive blank lines). Waiting for Codacy to re-run on latest commit.

@d-init-d
Copy link
Author

Correction: follow-up pushed in 9715be6 and 3df263d to address Codacy findings from the refactor (unused import + consecutive blank lines). Waiting for Codacy to re-run on latest commit.

@d-init-d
Copy link
Author

Pushed another follow-up in 92150ff to reduce Codacy complexity by simplifying TTSEngine control flow while keeping behavior the same. Waiting for Codacy result on latest commit.

@d-init-d
Copy link
Author

All requested follow-ups are now addressed:

  • API-level compatibility clarified
  • TTS implementation extracted out of MainActivity into TTSEngine
  • Codacy findings fixed

Latest commit is a95a2fa and Codacy is now green. Ready for re-review.

@Frenzie
Copy link
Member

Frenzie commented Feb 11, 2026

Pushed another follow-up in 92150ff to reduce Codacy complexity by simplifying TTSEngine control flow while keeping behavior the same. Waiting for Codacy result on latest commit.

I note it got rid of the lock. Is that all okay and thread-safe?

On average I wouldn't pay too much attention to automated "complexity" checks btw; it's often significantly more complex when refactored into dozens of tiny functions you have to chase down (but in this case it looks much clearer :-).

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.

3 participants