From 76edaa25a4255892a6cfbb2033b3368aca10c658 Mon Sep 17 00:00:00 2001 From: virtus Date: Fri, 10 Apr 2026 18:56:36 +0700 Subject: [PATCH] feat: Implement native Android MediaSession and foreground service for TTS playback - Add `ReaderTtsMediaService` to handle background playback, media controls, and notifications on Android - Integrate `MediaSessionCompat` to support external media controls and lock screen integration - Add `ReaderTtsMediaBridge` for synchronized state communication between Kotlin and Flutter - Update `TtsNotifier` to use the native Android service when available, with a fallback for other platforms - Implement sentence-level highlighting and tapping to start reading from a specific location - Update Android manifest with necessary permissions for foreground services and notifications - Adjust TTS speech rate constants and improve playback health monitoring and recovery logic --- android/app/build.gradle.kts | 5 + android/app/google-services.json | 53 +- android/app/src/main/AndroidManifest.xml | 7 + .../com/example/reader_app/MainActivity.kt | 131 +++ .../reader_app/tts/ReaderTtsMediaBridge.kt | 44 + .../reader_app/tts/ReaderTtsMediaService.kt | 924 ++++++++++++++++++ .../reader/presentation/reader_screen.dart | 126 ++- .../presentation/tts_player_widget.dart | 2 +- lib/features/reader/tts/tts_service.dart | 628 +++++++++--- 9 files changed, 1706 insertions(+), 214 deletions(-) create mode 100644 android/app/src/main/kotlin/com/example/reader_app/tts/ReaderTtsMediaBridge.kt create mode 100644 android/app/src/main/kotlin/com/example/reader_app/tts/ReaderTtsMediaService.kt diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 38bb3c7..eadf608 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -4,6 +4,7 @@ import java.util.Properties plugins { id("com.android.application") id("kotlin-android") + id("kotlin-parcelize") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id("dev.flutter.flutter-gradle-plugin") id("com.google.gms.google-services") @@ -66,6 +67,10 @@ android { } } +dependencies { + implementation("androidx.media:media:1.7.0") +} + flutter { source = "../.." } diff --git a/android/app/google-services.json b/android/app/google-services.json index bcfb5fd..92d0075 100644 --- a/android/app/google-services.json +++ b/android/app/google-services.json @@ -5,43 +5,6 @@ "storage_bucket": "reader-1658c.firebasestorage.app" }, "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:308259929553:android:9142ae16d9ddd8a91c34f0", - "android_client_info": { - "package_name": "com.example.reader_app" - } - }, - "oauth_client": [ - { - "client_id": "308259929553-7cdc4g8fe7os799trig7hk7ugkuansov.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "com.example.reader_app", - "certificate_hash": "f7e9f7ec9bafd1de69934b2c9b52ee491d73bad7" - } - }, - { - "client_id": "308259929553-9oame596io3s4lcj9cdb5db6v3i6f6rk.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyBibgTrvBWtJBL4PGeIyahBwRlYKcjQ47k" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "308259929553-9oame596io3s4lcj9cdb5db6v3i6f6rk.apps.googleusercontent.com", - "client_type": 3 - } - ] - } - } - }, { "client_info": { "mobilesdk_app_id": "1:308259929553:android:14f7828b9b9ca9d31c34f0", @@ -50,6 +13,22 @@ } }, "oauth_client": [ + { + "client_id": "308259929553-fd8teopc4chi2jjd8kr5vn9inn35ar6j.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "dev.fevirtus.reader", + "certificate_hash": "fa21a3e6a319b71b2dd0ef9573b22046dba5d55c" + } + }, + { + "client_id": "308259929553-kdfvnu11cq6k9a2l1b3gtrmfmtsggduk.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "dev.fevirtus.reader", + "certificate_hash": "f7e9f7ec9bafd1de69934b2c9b52ee491d73bad7" + } + }, { "client_id": "308259929553-9oame596io3s4lcj9cdb5db6v3i6f6rk.apps.googleusercontent.com", "client_type": 3 diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index baf8bc1..d93e766 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ + + + +