From 2490a8ee9f1efe401b0e532f3749bf151580cc6f Mon Sep 17 00:00:00 2001 From: "Alexander \"PapaTutuWawa" Date: Sun, 30 Jul 2023 20:40:59 +0200 Subject: [PATCH] fix: Add payload to all intents --- example/lib/main.dart | 3 + .../me/polynom/moxplatform_android/Api.java | 64 +++++++++++++++++-- .../MoxplatformAndroidPlugin.java | 13 +++- .../NotificationReceiver.kt | 26 +++++--- .../moxplatform_android/Notifications.kt | 37 +++++++++-- .../lib/src/notifications_android.dart | 8 ++- .../lib/src/api.g.dart | 34 +++++++++- .../lib/src/notifications.dart | 5 +- .../lib/src/notifications_stub.dart | 4 +- pigeons/api.dart | 9 ++- 10 files changed, 171 insertions(+), 32 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index bc6ea6d..aabae91 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -44,11 +44,13 @@ class MyAppState extends State { await MoxplatformPlugin.notifications.createNotificationChannel( "Test notification channel", + "Test1", channelId, false, ); await MoxplatformPlugin.notifications.createNotificationChannel( "Test notification channel for warnings", + "Test2", otherChannelId, false, ); @@ -191,6 +193,7 @@ class MyHomePage extends StatelessWidget { messages: messages, channelId: channelId, jid: 'testjid', + isGroupchat: true, extra: { 'jid': 'testjid', 'avatarPath': 'lol', diff --git a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Api.java b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Api.java index 30f3bac..1a18664 100644 --- a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Api.java +++ b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Api.java @@ -387,6 +387,20 @@ public class Api { this.messages = setterArg; } + /** Flag indicating whether this notification is from a groupchat or not. */ + private @NonNull Boolean isGroupchat; + + public @NonNull Boolean getIsGroupchat() { + return isGroupchat; + } + + public void setIsGroupchat(@NonNull Boolean setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"isGroupchat\" is null."); + } + this.isGroupchat = setterArg; + } + /** Additional data to include. */ private @Nullable Map extra; @@ -438,6 +452,13 @@ public class Api { return this; } + private @Nullable Boolean isGroupchat; + + public @NonNull Builder setIsGroupchat(@NonNull Boolean setterArg) { + this.isGroupchat = setterArg; + return this; + } + private @Nullable Map extra; public @NonNull Builder setExtra(@Nullable Map setterArg) { @@ -452,6 +473,7 @@ public class Api { pigeonReturn.setChannelId(channelId); pigeonReturn.setJid(jid); pigeonReturn.setMessages(messages); + pigeonReturn.setIsGroupchat(isGroupchat); pigeonReturn.setExtra(extra); return pigeonReturn; } @@ -459,12 +481,13 @@ public class Api { @NonNull ArrayList toList() { - ArrayList toListResult = new ArrayList(6); + ArrayList toListResult = new ArrayList(7); toListResult.add(title); toListResult.add(id); toListResult.add(channelId); toListResult.add(jid); toListResult.add(messages); + toListResult.add(isGroupchat); toListResult.add(extra); return toListResult; } @@ -481,7 +504,9 @@ public class Api { pigeonResult.setJid((String) jid); Object messages = list.get(4); pigeonResult.setMessages((List) messages); - Object extra = list.get(5); + Object isGroupchat = list.get(5); + pigeonResult.setIsGroupchat((Boolean) isGroupchat); + Object extra = list.get(6); pigeonResult.setExtra((Map) extra); return pigeonResult; } @@ -914,12 +939,14 @@ public class Api { /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface MoxplatformApi { - void createNotificationChannel(@NonNull String title, @NonNull String id, @NonNull Boolean urgent); + void createNotificationChannel(@NonNull String title, @NonNull String description, @NonNull String id, @NonNull Boolean urgent); void showMessagingNotification(@NonNull MessagingNotification notification); void showNotification(@NonNull RegularNotification notification); + void dismissNotification(@NonNull Long id); + void setNotificationSelfAvatar(@NonNull String path); void setNotificationI18n(@NonNull NotificationI18nData data); @@ -948,10 +975,11 @@ public class Api { ArrayList wrapped = new ArrayList(); ArrayList args = (ArrayList) message; String titleArg = (String) args.get(0); - String idArg = (String) args.get(1); - Boolean urgentArg = (Boolean) args.get(2); + String descriptionArg = (String) args.get(1); + String idArg = (String) args.get(2); + Boolean urgentArg = (Boolean) args.get(3); try { - api.createNotificationChannel(titleArg, idArg, urgentArg); + api.createNotificationChannel(titleArg, descriptionArg, idArg, urgentArg); wrapped.add(0, null); } catch (Throwable exception) { @@ -1002,6 +1030,30 @@ public class Api { api.showNotification(notificationArg); wrapped.add(0, null); } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.dismissNotification", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + Number idArg = (Number) args.get(0); + try { + api.dismissNotification((idArg == null) ? null : idArg.longValue()); + wrapped.add(0, null); + } catch (Throwable exception) { ArrayList wrappedError = wrapError(exception); wrapped = wrappedError; diff --git a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/MoxplatformAndroidPlugin.java b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/MoxplatformAndroidPlugin.java index ac2f555..03833ed 100644 --- a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/MoxplatformAndroidPlugin.java +++ b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/MoxplatformAndroidPlugin.java @@ -2,8 +2,8 @@ package me.polynom.moxplatform_android; import static androidx.core.content.ContextCompat.getSystemService; import static me.polynom.moxplatform_android.ConstantsKt.SHARED_PREFERENCES_KEY; -import static me.polynom.moxplatform_android.RecordSentMessageKt.recordSentMessage; import static me.polynom.moxplatform_android.CryptoKt.*; +import static me.polynom.moxplatform_android.RecordSentMessageKt.*; import me.polynom.moxplatform_android.Api.*; @@ -18,6 +18,7 @@ import android.content.SharedPreferences; import android.util.Log; import androidx.annotation.NonNull; +import androidx.core.app.NotificationManagerCompat; import androidx.core.content.ContextCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -39,7 +40,7 @@ import io.flutter.plugin.common.JSONMethodCodec; import kotlin.Unit; import kotlin.jvm.functions.Function1; -public class MoxplatformAndroidPlugin extends BroadcastReceiver implements FlutterPlugin, MethodCallHandler, EventChannel.StreamHandler, ServiceAware, MoxplatformApi { + public class MoxplatformAndroidPlugin extends BroadcastReceiver implements FlutterPlugin, MethodCallHandler, EventChannel.StreamHandler, ServiceAware, MoxplatformApi { public static final String entrypointKey = "entrypoint_handle"; public static final String extraDataKey = "extra_data"; private static final String autoStartAtBootKey = "auto_start_at_boot"; @@ -258,10 +259,11 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt } @Override - public void createNotificationChannel(@NonNull String title, @NonNull String id, @NonNull Boolean urgent) { + public void createNotificationChannel(@NonNull String title, @NonNull String description, @NonNull String id, @NonNull Boolean urgent) { final NotificationChannel channel = new NotificationChannel(id, title, urgent ? NotificationManager.IMPORTANCE_HIGH : NotificationManager.IMPORTANCE_DEFAULT); channel.enableVibration(true); channel.enableLights(true); + channel.setDescription(description); final NotificationManager manager = getSystemService(context, NotificationManager.class); manager.createNotificationChannel(channel); } @@ -276,6 +278,11 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt NotificationsKt.showNotification(context, notification); } + @Override + public void dismissNotification(@NonNull Long id) { + NotificationManagerCompat.from(context).cancel(id.intValue()); + } + @Override public void setNotificationSelfAvatar(@NonNull String path) { NotificationDataManager.INSTANCE.setAvatarPath(path); diff --git a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/NotificationReceiver.kt b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/NotificationReceiver.kt index 3ddeb9f..f608e16 100644 --- a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/NotificationReceiver.kt +++ b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/NotificationReceiver.kt @@ -42,16 +42,30 @@ class NotificationReceiver : BroadcastReceiver() { .find { it.id == id }?.notification } + private fun extractPayloadMapFromIntent(intent: Intent): Map { + val extras = mutableMapOf() + intent.extras?.keySet()!!.forEach { + Log.d(TAG, "Checking $it -> ${intent.extras!!.get(it)}") + if (it.startsWith("payload_")) { + Log.d(TAG, "Adding $it") + extras[it.substring(8)] = intent.extras!!.getString(it) + } + } + + return extras + } + private fun handleMarkAsRead(context: Context, intent: Intent) { - NotificationManagerCompat.from(context).cancel(intent.getLongExtra(MARK_AS_READ_ID_KEY, -1).toInt()) MoxplatformAndroidPlugin.notificationSink?.success( NotificationEvent().apply { jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!! type = Api.NotificationEventType.MARK_AS_READ payload = null + extra = extractPayloadMapFromIntent(intent) }.toList() ) + NotificationManagerCompat.from(context).cancel(intent.getLongExtra(MARK_AS_READ_ID_KEY, -1).toInt()) dismissNotification(context, intent); } @@ -63,6 +77,7 @@ class NotificationReceiver : BroadcastReceiver() { jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!! type = Api.NotificationEventType.REPLY payload = replyPayload.toString() + extra = extractPayloadMapFromIntent(intent) }.toList() ) @@ -148,19 +163,12 @@ class NotificationReceiver : BroadcastReceiver() { } private fun handleTap(context: Context, intent: Intent) { - val extras = mutableMapOf() - intent.extras?.keySet()!!.forEach { - if (it.startsWith("payload_")) { - extras[it.substring(8)] = intent.extras!!.getString(it) - } - } - MoxplatformAndroidPlugin.notificationSink?.success( NotificationEvent().apply { jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!! type = Api.NotificationEventType.OPEN payload = null - extra = extras + extra = extractPayloadMapFromIntent(intent) }.toList() ) diff --git a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Notifications.kt b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Notifications.kt index eafa1b9..083575f 100644 --- a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Notifications.kt +++ b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Notifications.kt @@ -14,6 +14,7 @@ import androidx.core.app.RemoteInput import androidx.core.content.FileProvider import androidx.core.graphics.drawable.IconCompat import java.io.File +import java.lang.Exception /* * Holds "persistent" data for notifications, like i18n strings. While not useful now, this is @@ -78,6 +79,10 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif action = REPLY_ACTION putExtra(NOTIFICATION_EXTRA_JID_KEY, notification.jid) putExtra(NOTIFICATION_EXTRA_ID_KEY, notification.id) + + notification.extra?.forEach { + putExtra("payload_${it.key}", it.value) + } } val replyPendingIntent = PendingIntent.getBroadcast( context.applicationContext, @@ -99,6 +104,10 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif action = MARK_AS_READ_ACTION putExtra(NOTIFICATION_EXTRA_JID_KEY, notification.jid) putExtra(NOTIFICATION_EXTRA_ID_KEY, notification.id) + + notification.extra?.forEach { + putExtra("payload_${it.key}", it.value) + } } val markAsReadPendingIntent = PendingIntent.getBroadcast( context.applicationContext, @@ -144,7 +153,14 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif } }.build() val style = NotificationCompat.MessagingStyle(selfPerson); - for (message in notification.messages) { + style.isGroupConversation = notification.isGroupchat + if (notification.isGroupchat) { + style.conversationTitle = notification.title + } + + for (i in notification.messages.indices) { + val message = notification.messages[i] + // Build the sender val sender = Person.Builder().apply { setName(message.sender) @@ -152,11 +168,15 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif // Set the avatar, if available if (message.avatarPath != null) { - setIcon( - IconCompat.createWithAdaptiveBitmap( - BitmapFactory.decodeFile(message.avatarPath), - ), - ) + try { + setIcon( + IconCompat.createWithAdaptiveBitmap( + BitmapFactory.decodeFile(message.avatarPath), + ), + ) + } catch (ex: Throwable) { + Log.w(TAG, "Failed to open avatar at ${message.avatarPath}") + } } }.build() @@ -204,6 +224,11 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif addAction(replyAction) addAction(markAsReadAction) + // Groupchat title + if (notification.isGroupchat) { + setContentTitle(notification.title) + } + setAllowSystemGeneratedContextualActions(true) setCategory(Notification.CATEGORY_MESSAGE) diff --git a/packages/moxplatform_android/lib/src/notifications_android.dart b/packages/moxplatform_android/lib/src/notifications_android.dart index 9f3494d..acd0610 100644 --- a/packages/moxplatform_android/lib/src/notifications_android.dart +++ b/packages/moxplatform_android/lib/src/notifications_android.dart @@ -11,10 +11,11 @@ class AndroidNotificationsImplementation extends NotificationsImplementation { @override Future createNotificationChannel( String title, + String description, String id, bool urgent, ) async { - return _api.createNotificationChannel(title, id, urgent); + return _api.createNotificationChannel(title, description, id, urgent); } @override @@ -29,6 +30,11 @@ class AndroidNotificationsImplementation extends NotificationsImplementation { return _api.showNotification(notification); } + @override + Future dismissNotification(int id) async { + return _api.dismissNotification(id); + } + @override Future setNotificationSelfAvatar(String path) async { return _api.setNotificationSelfAvatar(path); diff --git a/packages/moxplatform_platform_interface/lib/src/api.g.dart b/packages/moxplatform_platform_interface/lib/src/api.g.dart index fd4b2d0..67246d7 100644 --- a/packages/moxplatform_platform_interface/lib/src/api.g.dart +++ b/packages/moxplatform_platform_interface/lib/src/api.g.dart @@ -106,6 +106,7 @@ class MessagingNotification { required this.channelId, required this.jid, required this.messages, + required this.isGroupchat, this.extra, }); @@ -124,6 +125,9 @@ class MessagingNotification { /// Messages to show. List messages; + /// Flag indicating whether this notification is from a groupchat or not. + bool isGroupchat; + /// Additional data to include. Map? extra; @@ -134,6 +138,7 @@ class MessagingNotification { channelId, jid, messages, + isGroupchat, extra, ]; } @@ -146,7 +151,8 @@ class MessagingNotification { channelId: result[2]! as String, jid: result[3]! as String, messages: (result[4] as List?)!.cast(), - extra: (result[5] as Map?)?.cast(), + isGroupchat: result[5]! as bool, + extra: (result[6] as Map?)?.cast(), ); } } @@ -331,12 +337,12 @@ class MoxplatformApi { static const MessageCodec codec = _MoxplatformApiCodec(); - Future createNotificationChannel(String arg_title, String arg_id, bool arg_urgent) async { + Future createNotificationChannel(String arg_title, String arg_description, String arg_id, bool arg_urgent) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.createNotificationChannel', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_title, arg_id, arg_urgent]) as List?; + await channel.send([arg_title, arg_description, arg_id, arg_urgent]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -397,6 +403,28 @@ class MoxplatformApi { } } + Future dismissNotification(int arg_id) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.dismissNotification', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_id]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + Future setNotificationSelfAvatar(String arg_path) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.setNotificationSelfAvatar', codec, diff --git a/packages/moxplatform_platform_interface/lib/src/notifications.dart b/packages/moxplatform_platform_interface/lib/src/notifications.dart index 2c69bf5..3918bed 100644 --- a/packages/moxplatform_platform_interface/lib/src/notifications.dart +++ b/packages/moxplatform_platform_interface/lib/src/notifications.dart @@ -4,7 +4,7 @@ import 'package:moxplatform_platform_interface/src/api.g.dart'; abstract class NotificationsImplementation { /// Creates a notification channel with the name [title] and id [id]. If [urgent] is true, then /// it configures the channel as carrying urgent information. - Future createNotificationChannel(String title, String id, bool urgent); + Future createNotificationChannel(String title, String description, String id, bool urgent); /// Shows a notification [notification] in the messaging style with everyting it needs. Future showMessagingNotification(MessagingNotification notification); @@ -12,6 +12,9 @@ abstract class NotificationsImplementation { /// Shows a regular notification [notification]. Future showNotification(RegularNotification notification); + /// Dismisses the notification with id [id]. + Future dismissNotification(int id); + /// Sets the path to the self-avatar for in-notification replies. Future setNotificationSelfAvatar(String path); diff --git a/packages/moxplatform_platform_interface/lib/src/notifications_stub.dart b/packages/moxplatform_platform_interface/lib/src/notifications_stub.dart index d847a1e..0fe38d4 100644 --- a/packages/moxplatform_platform_interface/lib/src/notifications_stub.dart +++ b/packages/moxplatform_platform_interface/lib/src/notifications_stub.dart @@ -4,7 +4,7 @@ import 'package:moxplatform_platform_interface/src/notifications.dart'; class StubNotificationsImplementation extends NotificationsImplementation { @override - Future createNotificationChannel(String title, String id, bool urgent) async {} + Future createNotificationChannel(String title, String description, String id, bool urgent) async {} @override Future showMessagingNotification(MessagingNotification notification) async {} @@ -12,6 +12,8 @@ class StubNotificationsImplementation extends NotificationsImplementation { @override Future showNotification(RegularNotification notification) async {} + @override + Future dismissNotification(int id) async {} @override Future setNotificationSelfAvatar(String path) async {} diff --git a/pigeons/api.dart b/pigeons/api.dart index 33ae13b..f68f400 100644 --- a/pigeons/api.dart +++ b/pigeons/api.dart @@ -54,7 +54,7 @@ class NotificationMessage { } class MessagingNotification { - const MessagingNotification(this.title, this.id, this.jid, this.messages, this.channelId, this.extra); + const MessagingNotification(this.title, this.id, this.jid, this.messages, this.channelId, this.isGroupchat, this.extra); /// The title of the conversation. final String title; @@ -71,6 +71,9 @@ class MessagingNotification { /// Messages to show. final List messages; + /// Flag indicating whether this notification is from a groupchat or not. + final bool isGroupchat; + /// Additional data to include. final Map? extra; } @@ -111,6 +114,7 @@ class NotificationEvent { this.jid, this.type, this.payload, + this.extra, ); /// The JID the notification was for. @@ -143,9 +147,10 @@ class NotificationI18nData { @HostApi() abstract class MoxplatformApi { - void createNotificationChannel(String title, String id, bool urgent); + void createNotificationChannel(String title, String description, String id, bool urgent); void showMessagingNotification(MessagingNotification notification); void showNotification(RegularNotification notification); + void dismissNotification(int id); void setNotificationSelfAvatar(String path); void setNotificationI18n(NotificationI18nData data); String getPersistentDataPath();