diff --git a/android/src/main/kotlin/com/pravera/flutter_foreground_task/models/NotificationOptions.kt b/android/src/main/kotlin/com/pravera/flutter_foreground_task/models/NotificationOptions.kt index 81ccba2..2cc7be8 100644 --- a/android/src/main/kotlin/com/pravera/flutter_foreground_task/models/NotificationOptions.kt +++ b/android/src/main/kotlin/com/pravera/flutter_foreground_task/models/NotificationOptions.kt @@ -156,6 +156,36 @@ data class NotificationOptions( } } + fun notificationContent(context: Context, map: Map<*, *>?) { + val prefs = context.getSharedPreferences( + PrefsKey.NOTIFICATION_OPTIONS_PREFS, Context.MODE_PRIVATE) + + val id = map?.get(PrefsKey.NOTIFICATION_ID) as? Int ?: 1000 + val contentTitle = map?.get(PrefsKey.NOTIFICATION_CONTENT_TITLE) as? String ?: "" + val contentText = map?.get(PrefsKey.NOTIFICATION_CONTENT_TEXT) as? String ?: "" + + val iconData = map?.get(PrefsKey.ICON_DATA) as? Map<*, *> + var iconDataJson: String? = null + if (iconData != null) { + iconDataJson = JSONObject(iconData).toString() + } + + val buttons = map?.get(PrefsKey.BUTTONS) as? List<*> + var buttonsJson: String? = null + if (buttons != null) { + buttonsJson = JSONArray(buttons).toString() + } + + with(prefs.edit()) { + putInt(PrefsKey.NOTIFICATION_ID, id) + putString(PrefsKey.NOTIFICATION_CONTENT_TITLE, contentTitle) + putString(PrefsKey.NOTIFICATION_CONTENT_TEXT, contentText) + putString(PrefsKey.ICON_DATA, iconDataJson) + putString(PrefsKey.BUTTONS, buttonsJson) + commit() + } + } + fun clearData(context: Context) { val prefs = context.getSharedPreferences( PrefsKey.NOTIFICATION_OPTIONS_PREFS, Context.MODE_PRIVATE) diff --git a/android/src/main/kotlin/com/pravera/flutter_foreground_task/service/ForegroundService.kt b/android/src/main/kotlin/com/pravera/flutter_foreground_task/service/ForegroundService.kt index 0c953e8..40dfaad 100644 --- a/android/src/main/kotlin/com/pravera/flutter_foreground_task/service/ForegroundService.kt +++ b/android/src/main/kotlin/com/pravera/flutter_foreground_task/service/ForegroundService.kt @@ -155,6 +155,7 @@ class ForegroundService : Service(), MethodChannel.MethodCallHandler { override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { when (call.method) { "initialize" -> startForegroundTask() + "notification" -> notifyService(call) else -> result.notImplemented() } } @@ -280,6 +281,45 @@ class ForegroundService : Service(), MethodChannel.MethodCallHandler { isRunningService = false } + private fun notifyService(call: MethodCall) { + val argsMap = call.arguments as? Map<*, *> + NotificationOptions.notificationContent(applicationContext, argsMap) + notificationOptions = NotificationOptions.getData(applicationContext) + + // channel info + val pm = applicationContext.packageManager + val channelId = notificationOptions.channelId + + // notification icon + val iconData = notificationOptions.iconData + val iconBackgroundColor: Int? + val iconResId: Int + if (iconData != null) { + iconBackgroundColor = iconData.backgroundColorRgb?.let(::getRgbColor) + iconResId = getIconResIdFromIconData(iconData) + } else { + iconBackgroundColor = null + iconResId = getIconResIdFromAppInfo(pm) + } + + // Modify notification + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val nm = getSystemService(NotificationManager::class.java) + val builder = Notification.Builder(this, channelId) + builder.setSmallIcon(iconResId) + if (iconBackgroundColor != null) { + builder.setColor(iconBackgroundColor) + } + builder.setContentTitle(notificationOptions.contentTitle) + builder.setContentText(notificationOptions.contentText) + val actions = buildButtonActions().toTypedArray() + builder.setActions(*actions) + nm.notify(notificationOptions.id, builder.build()) + } + + isRunningService = true + } + @SuppressLint("WakelockTimeout") private fun acquireLockMode() { if (foregroundTaskOptions.allowWakeLock && (wakeLock == null || wakeLock?.isHeld == false)) { diff --git a/example/android/build.gradle b/example/android/build.gradle index 83ae220..3cdaac9 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -26,6 +26,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/lib/flutter_foreground_task.dart b/lib/flutter_foreground_task.dart index 4b9101c..320b7b3 100644 --- a/lib/flutter_foreground_task.dart +++ b/lib/flutter_foreground_task.dart @@ -8,6 +8,8 @@ import 'package:flutter_foreground_task/exception/foreground_task_exception.dart import 'package:flutter_foreground_task/models/foreground_task_options.dart'; import 'package:flutter_foreground_task/models/ios_notification_options.dart'; import 'package:flutter_foreground_task/models/android_notification_options.dart'; +import 'package:flutter_foreground_task/models/notification_button.dart'; +import 'package:flutter_foreground_task/models/notification_icon_data.dart'; import 'package:flutter_foreground_task/models/notification_permission.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'flutter_foreground_task_platform_interface.dart'; @@ -55,6 +57,7 @@ class FlutterForegroundTask { static late IOSNotificationOptions _iosNotificationOptions; static late ForegroundTaskOptions _foregroundTaskOptions; static bool _initialized = false; + static late MethodChannel backgroundChannel; /// Initialize the [FlutterForegroundTask]. static void init({ @@ -111,6 +114,27 @@ class FlutterForegroundTask { static Future stopService() => FlutterForegroundTaskPlatform.instance.stopService(); + /// Notifies the foreground service. + static Future notification({ + required int notificationId, + String? notificationTitle, + String? notificationText, + NotificationIconData? iconData, + List? buttons, + }) async { + final options = { + 'notificationId': notificationId, + 'notificationContentTitle': notificationTitle, + 'notificationContentText': notificationText, + 'iconData': iconData?.toJson(), + 'buttons': buttons?.map((e) => e.toJson()).toList(), + }; + + // Notifies the foreground task. + await backgroundChannel.invokeMethod('notification', options); + return true; + } + /// Returns whether the foreground service is running. static Future get isRunningService => FlutterForegroundTaskPlatform.instance.isRunningService; @@ -248,8 +272,8 @@ class FlutterForegroundTask { /// It must always be called from a top-level function, otherwise foreground task will not work. static void setTaskHandler(TaskHandler handler) { // Create a method channel to communicate with the platform. - const backgroundChannel = - MethodChannel('flutter_foreground_task/background'); + backgroundChannel = + const MethodChannel('flutter_foreground_task/background'); // Binding the framework to the flutter engine. WidgetsFlutterBinding.ensureInitialized();