diff --git a/android/src/main/kotlin/com/gdelataillade/alarm/alarm/AlarmPlugin.kt b/android/src/main/kotlin/com/gdelataillade/alarm/alarm/AlarmPlugin.kt index 3d3c4eca..16d6748e 100644 --- a/android/src/main/kotlin/com/gdelataillade/alarm/alarm/AlarmPlugin.kt +++ b/android/src/main/kotlin/com/gdelataillade/alarm/alarm/AlarmPlugin.kt @@ -11,27 +11,39 @@ import android.content.Context import android.content.Intent import androidx.annotation.NonNull import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.plugin.common.EventChannel import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result -import io.flutter.plugin.common.BinaryMessenger import io.flutter.Log class AlarmPlugin: FlutterPlugin, MethodCallHandler { private lateinit var context: Context - private lateinit var channel : MethodChannel + private lateinit var methodChannel : MethodChannel + private lateinit var eventChannel: EventChannel companion object { @JvmStatic - lateinit var binaryMessenger: BinaryMessenger + var eventSink: EventChannel.EventSink? = null } override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { context = flutterPluginBinding.applicationContext - channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.gdelataillade.alarm/alarm") - channel.setMethodCallHandler(this) - binaryMessenger = flutterPluginBinding.binaryMessenger + + methodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.gdelataillade.alarm/alarm") + methodChannel.setMethodCallHandler(this) + + eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "com.gdelataillade.alarm/events") + eventChannel.setStreamHandler(object : EventChannel.StreamHandler { + override fun onListen(arguments: Any?, events: EventChannel.EventSink) { + eventSink = events + } + + override fun onCancel(arguments: Any?) { + eventSink = null + } + }) } override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { @@ -156,6 +168,7 @@ class AlarmPlugin: FlutterPlugin, MethodCallHandler { } override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { - channel.setMethodCallHandler(null) + methodChannel.setMethodCallHandler(null) + eventChannel.setStreamHandler(null) } } \ No newline at end of file diff --git a/android/src/main/kotlin/com/gdelataillade/alarm/alarm/AlarmService.kt b/android/src/main/kotlin/com/gdelataillade/alarm/alarm/AlarmService.kt index e6c89e52..64c3e022 100644 --- a/android/src/main/kotlin/com/gdelataillade/alarm/alarm/AlarmService.kt +++ b/android/src/main/kotlin/com/gdelataillade/alarm/alarm/AlarmService.kt @@ -14,12 +14,10 @@ import android.os.IBinder import android.os.PowerManager import android.os.Build import io.flutter.Log -import io.flutter.plugin.common.MethodChannel import io.flutter.embedding.engine.dart.DartExecutor import io.flutter.embedding.engine.FlutterEngine class AlarmService : Service() { - private var channel: MethodChannel? = null private var audioService: AudioService? = null private var vibrationService: VibrationService? = null private var volumeService: VolumeService? = null @@ -33,15 +31,6 @@ class AlarmService : Service() { override fun onCreate() { super.onCreate() - try { - val messenger = AlarmPlugin.binaryMessenger - if (messenger != null) { - channel = MethodChannel(messenger, "com.gdelataillade.alarm/alarm") - } - } catch (e: Exception) { - Log.e("AlarmService", "Error while creating method channel: $e") - } - audioService = AudioService(this) vibrationService = VibrationService(this) volumeService = VolumeService(this) @@ -93,15 +82,7 @@ class AlarmService : Service() { Log.e("AlarmService", "Error in starting foreground service", e) } - try { - if (channel != null) { - channel?.invokeMethod("alarmRinging", mapOf("id" to id)) - } else { - Log.e("AlarmService", "Method channel is null") - } - } catch (e: Exception) { - Log.e("AlarmService", "Error while invoking alarmRinging channel: $e") - } + AlarmPlugin.eventSink?.success(mapOf("id" to id)) if (volume >= 0.0 && volume <= 1.0) { volumeService?.setVolume(volume, showSystemUI) diff --git a/android/src/main/kotlin/com/gdelataillade/alarm/services/AudioService.kt b/android/src/main/kotlin/com/gdelataillade/alarm/services/AudioService.kt index 481adc1b..f23d1b3b 100644 --- a/android/src/main/kotlin/com/gdelataillade/alarm/services/AudioService.kt +++ b/android/src/main/kotlin/com/gdelataillade/alarm/services/AudioService.kt @@ -82,6 +82,7 @@ class AudioService(private val context: Context) { if (isPlaying) { stop() } + reset() release() } mediaPlayers.remove(id) @@ -121,6 +122,7 @@ class AudioService(private val context: Context) { if (mediaPlayer.isPlaying) { mediaPlayer.stop() } + mediaPlayer.reset() mediaPlayer.release() } mediaPlayers.clear() diff --git a/lib/alarm.dart b/lib/alarm.dart index 759a6a9b..32168d21 100644 --- a/lib/alarm.dart +++ b/lib/alarm.dart @@ -35,10 +35,9 @@ class Alarm { if (showDebugLogs) print('[Alarm] $message'); }; - await Future.wait([ - if (android) AndroidAlarm.init(), - AlarmStorage.init(), - ]); + if (android) AndroidAlarm.init(); + await AlarmStorage.init(); + await checkAlarm(); } diff --git a/lib/src/android_alarm.dart b/lib/src/android_alarm.dart index 0efccc3a..eb7130d1 100644 --- a/lib/src/android_alarm.dart +++ b/lib/src/android_alarm.dart @@ -7,29 +7,35 @@ import 'package:flutter/services.dart'; /// Uses method channel to interact with the native platform. class AndroidAlarm { - /// Method channel for the alarm. + /// Method channel for the alarm operations. static const platform = MethodChannel('com.gdelataillade.alarm/alarm'); + /// Event channel for the alarm events. + static const eventChannel = EventChannel('com.gdelataillade.alarm/events'); + /// Whether there are other alarms set. static bool get hasOtherAlarms => AlarmStorage.getSavedAlarms().length > 1; - /// Initializes the method channel. - static Future init() async { - platform.setMethodCallHandler(handleMethodCall); - } + /// Starts listening to the alarm events. + static void init() => listenToAlarmEvents(); - /// Handles the method call from the native platform. - static Future handleMethodCall(MethodCall call) async { - try { - if (call.method == 'alarmRinging') { - final arguments = call.arguments as Map; - final id = arguments['id'] as int; - final settings = Alarm.getAlarm(id); - if (settings != null) Alarm.ringStream.add(settings); - } - } catch (e) { - alarmPrint('Handle method call "${call.method}" error: $e'); - } + /// Listens to the alarm events. + static void listenToAlarmEvents() { + eventChannel.receiveBroadcastStream().listen( + (dynamic event) { + try { + final eventMap = Map.from(event as Map); + final id = eventMap['id'] as int; + final settings = Alarm.getAlarm(id); + if (settings != null) Alarm.ringStream.add(settings); + } catch (e) { + alarmPrint('Error receiving alarm events: $e'); + } + }, + onError: (dynamic error, StackTrace stackTrace) { + alarmPrint('Error listening to alarm events: $error, $stackTrace'); + }, + ); } /// Schedules a native alarm with given [settings] with its notification.