-
-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor -> Android native alarm service (#105)
* Create android native alarm service * Add multiple alarms management * Add stop method & previous volume & fadeDuration * Increment plugin version to 2.2.0 * Implement alarm isRinging method * Add minor fixes * Remove native notification * Split alarm services * Add onRing callback * Fix NotificationOnKillService * Optimize alarm services instances * Make alarm foreground service * Add full screen intent notification * Add minor adjustments * Handle immediate alarms * Update android installation steps * Remove stopOnNotificationOpen * Update changelog & readme + add minor improvements * Update pubspec * Update version to 3.0.0-dev.1
- Loading branch information
1 parent
a8ef6aa
commit 5e01be2
Showing
26 changed files
with
742 additions
and
686 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 118 additions & 32 deletions
150
android/src/main/kotlin/com/gdelataillade/alarm/alarm/AlarmPlugin.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,138 @@ | ||
package com.gdelataillade.alarm.alarm | ||
|
||
import com.gdelataillade.alarm.services.NotificationOnKillService | ||
|
||
import android.os.Build | ||
import android.os.Handler | ||
import android.os.Looper | ||
import android.app.AlarmManager | ||
import android.app.PendingIntent | ||
import android.content.Context | ||
import android.content.Intent | ||
import androidx.annotation.NonNull | ||
import io.flutter.Log | ||
import io.flutter.embedding.engine.plugins.FlutterPlugin | ||
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 | ||
|
||
/// Communication between Flutter Alarm service and native Android. | ||
class AlarmPlugin: FlutterPlugin, MethodCallHandler { | ||
private lateinit var context: Context | ||
private lateinit var channel : MethodChannel | ||
private lateinit var context: Context | ||
private lateinit var channel : MethodChannel | ||
|
||
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { | ||
context = flutterPluginBinding.applicationContext | ||
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.gdelataillade.alarm/notifOnAppKill") | ||
channel.setMethodCallHandler(this) | ||
} | ||
companion object { | ||
@JvmStatic | ||
lateinit var binaryMessenger: BinaryMessenger | ||
} | ||
|
||
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { | ||
when (call.method) { | ||
"setNotificationOnKillService" -> { | ||
val title = call.argument<String>("title") | ||
val description = call.argument<String>("description") | ||
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { | ||
context = flutterPluginBinding.applicationContext | ||
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.gdelataillade.alarm/alarm") | ||
channel.setMethodCallHandler(this) | ||
binaryMessenger = flutterPluginBinding.binaryMessenger | ||
} | ||
|
||
val serviceIntent = Intent(context, NotificationOnKillService::class.java) | ||
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { | ||
when (call.method) { | ||
"setAlarm" -> { | ||
val id = call.argument<Int>("id")!! | ||
val delayInSeconds = call.argument<Int>("delayInSeconds")!! | ||
|
||
serviceIntent.putExtra("title", title) | ||
serviceIntent.putExtra("description", description) | ||
val alarmIntent = createAlarmIntent(context, call, id) | ||
|
||
context.startService(serviceIntent) | ||
result.success(true) | ||
} | ||
"stopNotificationOnKillService" -> { | ||
val serviceIntent = Intent(context, NotificationOnKillService::class.java) | ||
context.stopService(serviceIntent) | ||
result.success(true) | ||
} | ||
else -> { | ||
result.notImplemented() | ||
if (delayInSeconds <= 5) { | ||
handleImmediateAlarm(context, alarmIntent, delayInSeconds) | ||
} else { | ||
handleDelayedAlarm(context, alarmIntent, delayInSeconds, id) | ||
} | ||
|
||
result.success(true) | ||
} | ||
"stopAlarm" -> { | ||
val id = call.argument<Int>("id") | ||
|
||
// Intent to stop the alarm | ||
val stopIntent = Intent(context, AlarmService::class.java) | ||
stopIntent.action = "STOP_ALARM" | ||
stopIntent.putExtra("id", id) | ||
context.startService(stopIntent) | ||
|
||
// Intent to cancel the future alarm if it's set | ||
val alarmIntent = Intent(context, AlarmReceiver::class.java) | ||
val pendingIntent = PendingIntent.getBroadcast(context, id!!, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT) | ||
|
||
// Cancel the future alarm using AlarmManager | ||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager | ||
alarmManager.cancel(pendingIntent) | ||
|
||
result.success(true) | ||
} | ||
"isRinging" -> { | ||
val id = call.argument<Int>("id") | ||
val ringingAlarmIds = AlarmService.ringingAlarmIds | ||
val isRinging = ringingAlarmIds.contains(id) | ||
result.success(isRinging) | ||
} | ||
"setNotificationOnKillService" -> { | ||
val title = call.argument<String>("title") | ||
val description = call.argument<String>("description") | ||
val body = call.argument<String>("body") | ||
|
||
val serviceIntent = Intent(context, NotificationOnKillService::class.java) | ||
serviceIntent.putExtra("title", title) | ||
serviceIntent.putExtra("description", description) | ||
|
||
context.startService(serviceIntent) | ||
|
||
result.success(true) | ||
} | ||
"stopNotificationOnKillService" -> { | ||
val serviceIntent = Intent(context, NotificationOnKillService::class.java) | ||
context.stopService(serviceIntent) | ||
result.success(true) | ||
} | ||
else -> { | ||
result.notImplemented() | ||
} | ||
} | ||
} | ||
} | ||
|
||
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { | ||
channel.setMethodCallHandler(null) | ||
} | ||
} | ||
fun createAlarmIntent(context: Context, call: MethodCall, id: Int?): Intent { | ||
val alarmIntent = Intent(context, AlarmReceiver::class.java) | ||
setIntentExtras(alarmIntent, call, id) | ||
return alarmIntent | ||
} | ||
|
||
fun setIntentExtras(intent: Intent, call: MethodCall, id: Int?) { | ||
intent.putExtra("id", id) | ||
intent.putExtra("assetAudioPath", call.argument<String>("assetAudioPath")) | ||
intent.putExtra("loopAudio", call.argument<Boolean>("loopAudio")) | ||
intent.putExtra("vibrate", call.argument<Boolean>("vibrate")) | ||
intent.putExtra("volume", call.argument<Boolean>("volume")) | ||
intent.putExtra("fadeDuration", call.argument<Double>("fadeDuration")) | ||
intent.putExtra("notificationTitle", call.argument<String>("notificationTitle")) | ||
intent.putExtra("notificationBody", call.argument<String>("notificationBody")) | ||
intent.putExtra("fullScreenIntent", call.argument<Boolean>("fullScreenIntent")) | ||
} | ||
|
||
fun handleImmediateAlarm(context: Context, intent: Intent, delayInSeconds: Int) { | ||
val handler = Handler(Looper.getMainLooper()) | ||
handler.postDelayed({ | ||
context.sendBroadcast(intent) | ||
}, delayInSeconds * 1000L) | ||
} | ||
|
||
fun handleDelayedAlarm(context: Context, intent: Intent, delayInSeconds: Int, id: Int) { | ||
val triggerTime = System.currentTimeMillis() + delayInSeconds * 1000 | ||
val pendingIntent = PendingIntent.getBroadcast(context, id, intent, PendingIntent.FLAG_UPDATE_CURRENT) | ||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager | ||
|
||
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent) | ||
} | ||
|
||
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { | ||
channel.setMethodCallHandler(null) | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
android/src/main/kotlin/com/gdelataillade/alarm/alarm/AlarmReceiver.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.gdelataillade.alarm.alarm | ||
|
||
import android.content.BroadcastReceiver | ||
import android.content.Context | ||
import android.content.Intent | ||
import io.flutter.Log | ||
|
||
class AlarmReceiver : BroadcastReceiver() { | ||
override fun onReceive(context: Context, intent: Intent) { | ||
val serviceIntent = Intent(context, AlarmService::class.java) | ||
serviceIntent.putExtras(intent) | ||
|
||
context.startService(serviceIntent) | ||
} | ||
} |
Oops, something went wrong.