diff --git a/app/schemas/io.heckel.ntfy.db.Database/11.json b/app/schemas/io.heckel.ntfy.db.Database/11.json index 8d8e064..b54336c 100644 --- a/app/schemas/io.heckel.ntfy.db.Database/11.json +++ b/app/schemas/io.heckel.ntfy.db.Database/11.json @@ -2,11 +2,11 @@ "formatVersion": 1, "database": { "version": 11, - "identityHash": "5a061926458ed65c80431be0a69a2450", + "identityHash": "31f8e6a2032d1d404fad4307abf23e1b", "entities": [ { "tableName": "Subscription", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `baseUrl` TEXT NOT NULL, `topic` TEXT NOT NULL, `instant` INTEGER NOT NULL, `mutedUntil` INTEGER NOT NULL, `minPriority` INTEGER NOT NULL, `autoDelete` INTEGER NOT NULL, `lastNotificationId` TEXT, `icon` TEXT, `upAppId` TEXT, `upConnectorToken` TEXT, `displayName` TEXT, PRIMARY KEY(`id`))", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `baseUrl` TEXT NOT NULL, `topic` TEXT NOT NULL, `instant` INTEGER NOT NULL, `mutedUntil` INTEGER NOT NULL, `minPriority` INTEGER NOT NULL, `autoDelete` INTEGER NOT NULL, `icon` TEXT, `upAppId` TEXT, `upConnectorToken` TEXT, PRIMARY KEY(`id`))", "fields": [ { "fieldPath": "id", @@ -50,12 +50,6 @@ "affinity": "INTEGER", "notNull": true }, - { - "fieldPath": "lastNotificationId", - "columnName": "lastNotificationId", - "affinity": "TEXT", - "notNull": false - }, { "fieldPath": "icon", "columnName": "icon", @@ -73,12 +67,6 @@ "columnName": "upConnectorToken", "affinity": "TEXT", "notNull": false - }, - { - "fieldPath": "displayName", - "columnName": "displayName", - "affinity": "TEXT", - "notNull": false } ], "primaryKey": { @@ -112,7 +100,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, `encoding` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `actions` TEXT, `deleted` INTEGER NOT NULL, `icon_url` TEXT, `icon_type` TEXT, `icon_size` INTEGER, `icon_contentUri` TEXT, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, 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, `encoding` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `actions` TEXT, `deleted` INTEGER NOT NULL, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, PRIMARY KEY(`id`, `subscriptionId`))", "fields": [ { "fieldPath": "id", @@ -187,30 +175,6 @@ "affinity": "INTEGER", "notNull": true }, - { - "fieldPath": "icon.url", - "columnName": "icon_url", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "icon.type", - "columnName": "icon_type", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "icon.size", - "columnName": "icon_size", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "icon.contentUri", - "columnName": "icon_contentUri", - "affinity": "TEXT", - "notNull": false - }, { "fieldPath": "attachment.name", "columnName": "attachment_name", @@ -350,7 +314,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, '5a061926458ed65c80431be0a69a2450')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '31f8e6a2032d1d404fad4307abf23e1b')" ] } } \ No newline at end of file diff --git a/app/schemas/io.heckel.ntfy.db.Database/12.json b/app/schemas/io.heckel.ntfy.db.Database/12.json index 31f125c..e9e36a1 100644 --- a/app/schemas/io.heckel.ntfy.db.Database/12.json +++ b/app/schemas/io.heckel.ntfy.db.Database/12.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 12, - "identityHash": "5a061926458ed65c80431be0a69a2450", + "identityHash": "d230005f4d9824ba9aa34c61003bdcbb", "entities": [ { "tableName": "Subscription", @@ -112,7 +112,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, `encoding` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `actions` TEXT, `deleted` INTEGER NOT NULL, `icon_url` TEXT, `icon_type` TEXT, `icon_size` INTEGER, `icon_contentUri` TEXT, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, 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, `encoding` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `actions` TEXT, `deleted` INTEGER NOT NULL, `icon_url` TEXT, `icon_contentUri` TEXT, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, PRIMARY KEY(`id`, `subscriptionId`))", "fields": [ { "fieldPath": "id", @@ -193,18 +193,6 @@ "affinity": "TEXT", "notNull": false }, - { - "fieldPath": "icon.type", - "columnName": "icon_type", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "icon.size", - "columnName": "icon_size", - "affinity": "INTEGER", - "notNull": false - }, { "fieldPath": "icon.contentUri", "columnName": "icon_contentUri", @@ -350,7 +338,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, '5a061926458ed65c80431be0a69a2450')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd230005f4d9824ba9aa34c61003bdcbb')" ] } } \ No newline at end of file diff --git a/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt b/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt index 49c6464..e0f8f92 100644 --- a/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt +++ b/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt @@ -152,8 +152,6 @@ class Backuper(val context: Context) { val icon = if (n.icon != null) { io.heckel.ntfy.db.Icon( url = n.icon.url, - type = n.icon.type, - size = n.icon.size, contentUri = n.icon.contentUri, ) } else { @@ -281,8 +279,6 @@ class Backuper(val context: Context) { val icon = if (n.icon != null) { Icon( url = n.icon.url, - type = n.icon.type, - size = n.icon.size, contentUri = n.icon.contentUri, ) } else { @@ -403,10 +399,7 @@ data class Attachment( data class Icon( val url: String, // URL (mandatory, see ntfy server) - val type: String?, // MIME type - val size: Long?, // Size in bytes val contentUri: String?, // After it's downloaded, the content:// location - val progress: Int, // Progress during download, -1 if not downloaded ) data class User( diff --git a/app/src/main/java/io/heckel/ntfy/db/Database.kt b/app/src/main/java/io/heckel/ntfy/db/Database.kt index c56fa95..e267a45 100644 --- a/app/src/main/java/io/heckel/ntfy/db/Database.kt +++ b/app/src/main/java/io/heckel/ntfy/db/Database.kt @@ -95,12 +95,10 @@ const val ATTACHMENT_PROGRESS_DONE = 100 @Entity data class Icon( @ColumnInfo(name = "url") val url: String, // URL (mandatory, see ntfy server) - @ColumnInfo(name = "type") val type: String?, // MIME type - @ColumnInfo(name = "size") val size: Long?, // Size in bytes @ColumnInfo(name = "contentUri") val contentUri: String?, // After it's downloaded, the content:// location ) { - constructor(url:String, type: String?, size: Long?) : - this(url, type, size, null) + constructor(url:String) : + this(url, null) } @Entity @@ -282,8 +280,6 @@ abstract class Database : RoomDatabase() { db.execSQL("ALTER TABLE Subscription ADD COLUMN lastNotificationId TEXT") db.execSQL("ALTER TABLE Subscription ADD COLUMN displayName TEXT") db.execSQL("ALTER TABLE Notification ADD COLUMN icon_url TEXT") // Room limitation: Has to be nullable for @Embedded - db.execSQL("ALTER TABLE Notification ADD COLUMN icon_type TEXT") - db.execSQL("ALTER TABLE Notification ADD COLUMN icon_size INT") db.execSQL("ALTER TABLE Notification ADD COLUMN icon_contentUri TEXT") } } diff --git a/app/src/main/java/io/heckel/ntfy/msg/DownloadIconWorker.kt b/app/src/main/java/io/heckel/ntfy/msg/DownloadIconWorker.kt index e4535a5..2521f43 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/DownloadIconWorker.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/DownloadIconWorker.kt @@ -23,7 +23,7 @@ import java.util.concurrent.TimeUnit class DownloadIconWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) { private val client = OkHttpClient.Builder() - .callTimeout(15, TimeUnit.MINUTES) // Total timeout for entire request + .callTimeout(1, TimeUnit.MINUTES) // Total timeout for entire request .connectTimeout(15, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) .writeTimeout(15, TimeUnit.SECONDS) @@ -69,8 +69,7 @@ class DownloadIconWorker(private val context: Context, params: WorkerParameters) if (!response.isSuccessful || response.body == null) { throw Exception("Unexpected response: ${response.code}") } - save(updateIconFromResponse(response)) - if (shouldAbortDownload()) { + if (shouldAbortDownload(response)) { Log.d(TAG, "Aborting download: Content-Length is larger than auto-download setting") return } @@ -85,7 +84,7 @@ class DownloadIconWorker(private val context: Context, params: WorkerParameters) val downloadLimit = if (repository.getAutoDownloadMaxSize() != Repository.AUTO_DOWNLOAD_NEVER && repository.getAutoDownloadMaxSize() != Repository.AUTO_DOWNLOAD_ALWAYS) { repository.getAutoDownloadMaxSize() } else { - null + MAX_ICON_DOWNLOAD_SIZE.toLong() } outFile.use { fileOut -> val fileIn = response.body!!.byteStream() @@ -102,48 +101,14 @@ class DownloadIconWorker(private val context: Context, params: WorkerParameters) } Log.d(TAG, "Icon download: successful response, proceeding with download") save(icon.copy( - size = bytesCopied, contentUri = uri.toString() )) } } catch (e: Exception) { failed(e) - - // Toast in a Worker: https://stackoverflow.com/a/56428145/1440785 - val handler = Handler(Looper.getMainLooper()) - handler.postDelayed({ - Toast - .makeText(context, context.getString(R.string.detail_item_icon_download_failed, e.message), Toast.LENGTH_LONG) - .show() - }, 200) } } - private fun updateIconFromResponse(response: Response): Icon { - val size = if (response.headers["Content-Length"]?.toLongOrNull() != null) { - Log.d(TAG, "We got the long! icon here") - response.headers["Content-Length"]?.toLong() - } else { - icon.size // May be null! - } - val mimeType = if (response.headers["Content-Type"] != null) { - response.headers["Content-Type"] - } else { - val ext = MimeTypeMap.getFileExtensionFromUrl(icon.url) - if (ext != null) { - val typeFromExt = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext) - typeFromExt ?: icon.type // May be null! - } else { - icon.type // May be null! - } - } - Log.d(TAG, "New icon size: $size, type: $mimeType") - return icon.copy( - size = size, - type = mimeType - ) - } - private fun failed(e: Exception) { Log.w(TAG, "Icon download failed", e) maybeDeleteFile() @@ -166,9 +131,9 @@ class DownloadIconWorker(private val context: Context, params: WorkerParameters) repository.updateNotification(notification) } - private fun shouldAbortDownload(): Boolean { + private fun shouldAbortDownload(response: Response): Boolean { val maxAutoDownloadSize = MAX_ICON_DOWNLOAD_SIZE - val size = icon.size ?: return false // Don't abort if size unknown + val size = response.headers["Content-Length"]?.toLongOrNull() ?: return false // Don't abort here if size unknown return size > maxAutoDownloadSize } diff --git a/app/src/main/java/io/heckel/ntfy/msg/NotificationDispatcher.kt b/app/src/main/java/io/heckel/ntfy/msg/NotificationDispatcher.kt index 88593f7..c763b44 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/NotificationDispatcher.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/NotificationDispatcher.kt @@ -60,8 +60,7 @@ class NotificationDispatcher(val context: Context, val repository: Repository) { Log.d(TAG, "Attachment already expired at ${attachment.expires}, not downloading") return false } - val maxAutoDownloadSize = repository.getAutoDownloadMaxSize() - when (maxAutoDownloadSize) { + when (val maxAutoDownloadSize = repository.getAutoDownloadMaxSize()) { Repository.AUTO_DOWNLOAD_ALWAYS -> return true Repository.AUTO_DOWNLOAD_NEVER -> return false else -> { @@ -73,15 +72,7 @@ class NotificationDispatcher(val context: Context, val repository: Repository) { } } private fun shouldDownloadIcon(notification: Notification): Boolean { - if (notification.icon == null) { - return false - } - val icon = notification.icon - val maxIconDownloadSize = DownloadIconWorker.MAX_ICON_DOWNLOAD_SIZE - if (icon.size == null) { - return true // DownloadWorker will bail out if attachment is too large! - } - return icon.size <= maxIconDownloadSize + return notification.icon != null } private fun shouldNotify(subscription: Subscription, notification: Notification, muted: Boolean): Boolean { diff --git a/app/src/main/java/io/heckel/ntfy/msg/NotificationParser.kt b/app/src/main/java/io/heckel/ntfy/msg/NotificationParser.kt index d26f5d0..877a3be 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/NotificationParser.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/NotificationParser.kt @@ -52,9 +52,7 @@ class NotificationParser { } else null val icon: Icon? = if (message.icon != null) { Icon( - url = message.icon, - size = null, - type = null + url = message.icon ) } else null val notification = Notification( 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 eb6dec6..a35ff8d 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt @@ -96,7 +96,7 @@ class NotificationService(val context: Context) { val contentUri = notification.attachment?.contentUri val isSupportedImage = supportedImage(notification.attachment?.type) val subscriptionIcon = if (subscription.icon != null) subscription.icon.readBitmapFromUriOrNull(context) else null - val notificationIcon = if (notification.icon != null && supportedImage(notification.icon.type)) notification.icon.contentUri?.readBitmapFromUriOrNull(context) else null + val notificationIcon = if (notification.icon != null) notification.icon.contentUri?.readBitmapFromUriOrNull(context) else null val largeIcon = notificationIcon ?: subscriptionIcon if (contentUri != null && isSupportedImage) { try {