From c0305ec89d3c2af28dc71bb4d77076db82a18f7a Mon Sep 17 00:00:00 2001 From: Jordan Hotmann Date: Wed, 15 Apr 2026 14:49:26 -0600 Subject: [PATCH 1/2] feat: add file attachment support to SEND_MESSAGE broadcast intent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds file_uri (content:// URI string) and filename (optional override) extras to the io.heckel.ntfy.SEND_MESSAGE broadcast intent. Validates that file_uri uses the content:// scheme, derives filename from the URI via fileStat() if not overridden, and pipes the file as the raw HTTP body via ContentUriRequestBody — matching the ShareActivity pattern. Co-Authored-By: Claude Sonnet 4.6 --- .../io/heckel/ntfy/msg/BroadcastService.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt b/app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt index 821b2f2ea..eab59f021 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt @@ -2,6 +2,7 @@ package io.heckel.ntfy.msg import android.content.Context import android.content.Intent +import android.net.Uri import io.heckel.ntfy.R import io.heckel.ntfy.db.Action import io.heckel.ntfy.db.Notification @@ -83,10 +84,24 @@ class BroadcastService(private val ctx: Context) { else -> 0 } val delay = getStringExtra(intent,"delay") ?: "" + val fileUriString = getStringExtra(intent, "file_uri") + val filenameOverride = getStringExtra(intent, "filename") ?: "" GlobalScope.launch(Dispatchers.IO) { val repository = Repository.getInstance(ctx) val user = repository.getUser(baseUrl) // May be null try { + val (body, filename) = if (fileUriString != null) { + val uri = Uri.parse(fileUriString) + if (uri.scheme != "content") { + Log.w(TAG, "file_uri must use the content:// scheme, got ${uri.scheme}://. Aborting.") + return@launch + } + val stat = fileStat(ctx, uri) + val body = ContentUriRequestBody(ctx.contentResolver, uri, stat.size) + Pair(body, filenameOverride.ifEmpty { stat.filename }) + } else { + Pair(null, "") // filename ignored when no file_uri + } Log.d(TAG, "Publishing message $intent") api.publish( baseUrl = baseUrl, @@ -96,7 +111,9 @@ class BroadcastService(private val ctx: Context) { title = title, priority = priority, tags = splitTags(tags), - delay = delay + delay = delay, + body = body, + filename = filename, ) } catch (e: Exception) { Log.w(TAG, "Unable to publish message: ${e.message}", e) From 933147a43dbd92ebf462fb23421e6a5a0fd0bc6e Mon Sep 17 00:00:00 2001 From: Jordan Hotmann Date: Wed, 15 Apr 2026 14:51:58 -0600 Subject: [PATCH 2/2] fix: improve file_uri error log clarity and add comment Co-Authored-By: Claude Sonnet 4.6 --- app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt b/app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt index eab59f021..a21acae3f 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/BroadcastService.kt @@ -93,9 +93,10 @@ class BroadcastService(private val ctx: Context) { val (body, filename) = if (fileUriString != null) { val uri = Uri.parse(fileUriString) if (uri.scheme != "content") { - Log.w(TAG, "file_uri must use the content:// scheme, got ${uri.scheme}://. Aborting.") + Log.w(TAG, "file_uri must use the content:// scheme, got '${uri.scheme}'. Aborting.") return@launch } + // fileStat() throws on invalid/missing URI; caught below val stat = fileStat(ctx, uri) val body = ContentUriRequestBody(ctx.contentResolver, uri, stat.size) Pair(body, filenameOverride.ifEmpty { stat.filename })