From 3a5399162d37385f4b4f31713b9a0672ead97144 Mon Sep 17 00:00:00 2001 From: Philipp Heckel Date: Tue, 4 Jan 2022 23:45:24 +0100 Subject: [PATCH] Add "click" handling --- .../io.heckel.ntfy.data.Database/5.json | 12 +++-- .../main/java/io/heckel/ntfy/data/Database.kt | 10 ++++- .../java/io/heckel/ntfy/msg/ApiService.kt | 3 ++ .../io/heckel/ntfy/msg/NotificationService.kt | 44 ++++++++++++------- .../heckel/ntfy/firebase/FirebaseService.kt | 2 + 5 files changed, 52 insertions(+), 19 deletions(-) diff --git a/app/schemas/io.heckel.ntfy.data.Database/5.json b/app/schemas/io.heckel.ntfy.data.Database/5.json index dd398a4..228cf1f 100644 --- a/app/schemas/io.heckel.ntfy.data.Database/5.json +++ b/app/schemas/io.heckel.ntfy.data.Database/5.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 5, - "identityHash": "306578182c2ad0f9803956beda094d28", + "identityHash": "f662a6c15e0b9e510350918228bfa0ea", "entities": [ { "tableName": "Subscription", @@ -80,7 +80,7 @@ }, { "tableName": "Notification", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `deleted` INTEGER NOT NULL, PRIMARY KEY(`id`, `subscriptionId`))", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `deleted` INTEGER NOT NULL, PRIMARY KEY(`id`, `subscriptionId`))", "fields": [ { "fieldPath": "id", @@ -131,6 +131,12 @@ "affinity": "TEXT", "notNull": true }, + { + "fieldPath": "click", + "columnName": "click", + "affinity": "TEXT", + "notNull": true + }, { "fieldPath": "deleted", "columnName": "deleted", @@ -152,7 +158,7 @@ "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '306578182c2ad0f9803956beda094d28')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f662a6c15e0b9e510350918228bfa0ea')" ] } } \ No newline at end of file diff --git a/app/src/main/java/io/heckel/ntfy/data/Database.kt b/app/src/main/java/io/heckel/ntfy/data/Database.kt index 578663f..d188809 100644 --- a/app/src/main/java/io/heckel/ntfy/data/Database.kt +++ b/app/src/main/java/io/heckel/ntfy/data/Database.kt @@ -51,10 +51,11 @@ data class Notification( @ColumnInfo(name = "notificationId") val notificationId: Int, // Android notification popup ID @ColumnInfo(name = "priority", defaultValue = "3") val priority: Int, // 1=min, 3=default, 5=max @ColumnInfo(name = "tags") val tags: String, + @ColumnInfo(name = "click") val click: String, // URL/intent to open on notification click @ColumnInfo(name = "deleted") val deleted: Boolean, ) -@androidx.room.Database(entities = [Subscription::class, Notification::class], version = 5) +@androidx.room.Database(entities = [Subscription::class, Notification::class], version = 6) abstract class Database : RoomDatabase() { abstract fun subscriptionDao(): SubscriptionDao abstract fun notificationDao(): NotificationDao @@ -71,6 +72,7 @@ abstract class Database : RoomDatabase() { .addMigrations(MIGRATION_2_3) .addMigrations(MIGRATION_3_4) .addMigrations(MIGRATION_4_5) + .addMigrations(MIGRATION_5_6) .fallbackToDestructiveMigration() .build() this.instance = instance @@ -115,6 +117,12 @@ abstract class Database : RoomDatabase() { db.execSQL("CREATE UNIQUE INDEX index_Subscription_upConnectorToken ON Subscription (upConnectorToken)") } } + + private val MIGRATION_5_6 = object : Migration(5, 6) { + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL("ALTER TABLE Notification ADD COLUMN click TEXT NOT NULL DEFAULT('')") + } + } } } diff --git a/app/src/main/java/io/heckel/ntfy/msg/ApiService.kt b/app/src/main/java/io/heckel/ntfy/msg/ApiService.kt index afcb3d8..fcfbee1 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/ApiService.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/ApiService.kt @@ -120,6 +120,7 @@ class ApiService { message = message.message, priority = toPriority(message.priority), tags = joinTags(message.tags), + click = message.click ?: "", notificationId = Random.nextInt(), deleted = false ) @@ -149,6 +150,7 @@ class ApiService { message = message.message, priority = toPriority(message.priority), tags = joinTags(message.tags), + click = message.click ?: "", notificationId = 0, deleted = false ) @@ -164,6 +166,7 @@ class ApiService { val topic: String, val priority: Int?, val tags: List?, + val click: String?, val title: String?, val message: String ) diff --git a/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt b/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt index a514768..4624b04 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt @@ -7,9 +7,9 @@ import android.app.TaskStackBuilder import android.content.Context import android.content.Intent import android.media.RingtoneManager +import android.net.Uri import android.os.Build import android.util.Log -import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import io.heckel.ntfy.R @@ -24,37 +24,38 @@ class NotificationService(val context: Context) { fun send(subscription: Subscription, notification: Notification) { Log.d(TAG, "Displaying notification $notification") - // Create an Intent for the activity you want to start - val intent = Intent(context, DetailActivity::class.java) - intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id) - intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl) - intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic) - intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, subscription.instant) - intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil) - val pendingIntent: PendingIntent? = TaskStackBuilder.create(context).run { - addNextIntentWithParentStack(intent) // Add the intent, which inflates the back stack - getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT) // Get the PendingIntent containing the entire back stack - } - val title = formatTitle(subscription, notification) val message = formatMessage(notification) val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val channelId = toChannelId(notification.priority) - val notificationBuilder = NotificationCompat.Builder(context, channelId) + var notificationBuilder = NotificationCompat.Builder(context, channelId) .setSmallIcon(R.drawable.ic_notification) .setColor(ContextCompat.getColor(context, R.color.primaryColor)) .setContentTitle(title) .setContentText(message) .setStyle(NotificationCompat.BigTextStyle().bigText(message)) .setSound(defaultSoundUri) - .setContentIntent(pendingIntent) // Click target for notification .setAutoCancel(true) // Cancel when notification is clicked + notificationBuilder = setContentIntent(notificationBuilder, subscription, notification) val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager maybeCreateNotificationChannel(notificationManager, notification.priority) notificationManager.notify(notification.notificationId, notificationBuilder.build()) } + private fun setContentIntent(builder: NotificationCompat.Builder, subscription: Subscription, notification: Notification): NotificationCompat.Builder? { + if (notification.click == "") { + return builder.setContentIntent(detailActivityIntent(subscription)) + } + return try { + val uri = Uri.parse(notification.click) + val viewIntent = PendingIntent.getActivity(context, 0, Intent(Intent.ACTION_VIEW, uri), 0) + builder.setContentIntent(viewIntent) + } catch (e: Exception) { + builder.setContentIntent(detailActivityIntent(subscription)) + } + } + fun cancel(notification: Notification) { if (notification.notificationId != 0) { Log.d(TAG, "Cancelling notification ${notification.id}: ${notification.message}") @@ -68,6 +69,19 @@ class NotificationService(val context: Context) { (1..5).forEach { priority -> maybeCreateNotificationChannel(notificationManager, priority) } } + private fun detailActivityIntent(subscription: Subscription): PendingIntent? { + val intent = Intent(context, DetailActivity::class.java) + intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_ID, subscription.id) + intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_BASE_URL, subscription.baseUrl) + intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_TOPIC, subscription.topic) + intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_INSTANT, subscription.instant) + intent.putExtra(MainActivity.EXTRA_SUBSCRIPTION_MUTED_UNTIL, subscription.mutedUntil) + return TaskStackBuilder.create(context).run { + addNextIntentWithParentStack(intent) // Add the intent, which inflates the back stack + getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT) // Get the PendingIntent containing the entire back stack + } + } + private fun maybeCreateNotificationChannel(notificationManager: NotificationManager, priority: Int) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Note: To change a notification channel, you must delete the old one and create a new one! diff --git a/app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt b/app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt index 6f59637..77e42af 100644 --- a/app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt +++ b/app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt @@ -56,6 +56,7 @@ class FirebaseService : FirebaseMessagingService() { val message = data["message"] val priority = data["priority"]?.toIntOrNull() val tags = data["tags"] + val click = data["click"] val truncated = (data["truncated"] ?: "") == "1" if (id == null || topic == null || message == null || timestamp == null) { Log.d(TAG, "Discarding unexpected message: from=${remoteMessage.from}, fcmprio=${remoteMessage.priority}, fcmprio_orig=${remoteMessage.originalPriority}, data=${data}") @@ -83,6 +84,7 @@ class FirebaseService : FirebaseMessagingService() { notificationId = Random.nextInt(), priority = toPriority(priority), tags = tags ?: "", + click = click ?: "", deleted = false ) if (repository.addNotification(notification)) {