diff --git a/mobile/src/foss/java/org/openhab/habdroid/core/NotificationPoller.kt b/mobile/src/foss/java/org/openhab/habdroid/core/NotificationPoller.kt index 1a362f8514..c75dc5d556 100644 --- a/mobile/src/foss/java/org/openhab/habdroid/core/NotificationPoller.kt +++ b/mobile/src/foss/java/org/openhab/habdroid/core/NotificationPoller.kt @@ -19,6 +19,7 @@ import androidx.core.content.edit import org.json.JSONArray import org.json.JSONException import org.openhab.habdroid.core.connection.ConnectionFactory +import org.openhab.habdroid.model.CloudNotificationType import org.openhab.habdroid.model.toCloudNotification import org.openhab.habdroid.util.HttpClient import org.openhab.habdroid.util.PrefKeys @@ -65,8 +66,18 @@ object NotificationPoller { val newMessages = if (lastSeenIndex >= 0) messages.subList(0, lastSeenIndex) else messages val notifHelper = NotificationHelper(context) - newMessages.forEach { message -> - notifHelper.showNotification(message) + // Reverse list, so old notifications are processed first and can be hidden by newer notifications. + newMessages.reversed().forEach { message -> + when (message.type) { + CloudNotificationType.NOTIFICATION -> notifHelper.showNotification(message) + CloudNotificationType.HIDE_NOTIFICATION -> { + if (!message.tag.isNullOrEmpty()) { + notifHelper.cancelNotificationsByTag(message.tag) + } else { + notifHelper.cancelNotificationById(message.id) + } + } + } } } } diff --git a/mobile/src/full/java/org/openhab/habdroid/core/FcmMessageListenerService.kt b/mobile/src/full/java/org/openhab/habdroid/core/FcmMessageListenerService.kt index 07a0ed34cf..b093f1d4d0 100644 --- a/mobile/src/full/java/org/openhab/habdroid/core/FcmMessageListenerService.kt +++ b/mobile/src/full/java/org/openhab/habdroid/core/FcmMessageListenerService.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.runBlocking import org.openhab.habdroid.model.CloudNotification import org.openhab.habdroid.model.CloudNotificationAction import org.openhab.habdroid.model.CloudNotificationId +import org.openhab.habdroid.model.CloudNotificationType import org.openhab.habdroid.model.toCloudNotificationAction import org.openhab.habdroid.model.toOH2IconResource import org.openhab.habdroid.util.map @@ -52,6 +53,7 @@ class FcmMessageListenerService : FirebaseMessagingService() { ?.map { it.toCloudNotificationAction() } ?.filterNotNull() val cloudNotification = CloudNotification( + type = CloudNotificationType.NOTIFICATION, id = CloudNotificationId(data["persistedId"].orEmpty(), data["reference-id"]), title = data["title"].orEmpty(), message = data["message"].orEmpty(), diff --git a/mobile/src/main/java/org/openhab/habdroid/model/CloudNotification.kt b/mobile/src/main/java/org/openhab/habdroid/model/CloudNotification.kt index 4956565d8a..6fb2a4f47e 100644 --- a/mobile/src/main/java/org/openhab/habdroid/model/CloudNotification.kt +++ b/mobile/src/main/java/org/openhab/habdroid/model/CloudNotification.kt @@ -44,8 +44,21 @@ data class CloudNotificationId internal constructor( val notificationId get() = (referenceId ?: persistedId).hashCode() } +@Parcelize +enum class CloudNotificationType : Parcelable { + NOTIFICATION, + HIDE_NOTIFICATION +} + +fun String.toCloudNotificationType() = when (this) { + "notification" -> CloudNotificationType.NOTIFICATION + "hideNotification" -> CloudNotificationType.HIDE_NOTIFICATION + else -> null +} + @Parcelize data class CloudNotification internal constructor( + val type: CloudNotificationType, val id: CloudNotificationId, val title: String, val message: String, @@ -117,9 +130,11 @@ fun JSONObject.toCloudNotification(): CloudNotification { val payload = optJSONObject("payload") return CloudNotification( + // Old notifications don't contain "type", so fallback to normal notifications here. + type = payload?.optString("type")?.toCloudNotificationType() ?: CloudNotificationType.NOTIFICATION, id = CloudNotificationId(getString("_id"), payload?.optStringOrNull("reference-id")), title = payload?.optString("title").orEmpty(), - message = payload?.getString("message") ?: getString("message"), + message = payload?.optString("message") ?: optString("message"), createdTimestamp = created, icon = payload?.optStringOrNull("icon").toOH2IconResource() ?: optStringOrNull("icon").toOH2IconResource(), tag = payload?.optStringOrNull("tag") ?: optStringOrNull("severity"), diff --git a/mobile/src/main/java/org/openhab/habdroid/ui/CloudNotificationListFragment.kt b/mobile/src/main/java/org/openhab/habdroid/ui/CloudNotificationListFragment.kt index c2bdd55667..a213ff074b 100644 --- a/mobile/src/main/java/org/openhab/habdroid/ui/CloudNotificationListFragment.kt +++ b/mobile/src/main/java/org/openhab/habdroid/ui/CloudNotificationListFragment.kt @@ -36,6 +36,7 @@ import org.json.JSONArray import org.json.JSONException import org.openhab.habdroid.R import org.openhab.habdroid.core.connection.ConnectionFactory +import org.openhab.habdroid.model.CloudNotificationType import org.openhab.habdroid.model.ServerConfiguration import org.openhab.habdroid.model.toCloudNotification import org.openhab.habdroid.util.HttpClient @@ -152,6 +153,7 @@ class CloudNotificationListFragment : Fragment(), View.OnClickListener, SwipeRef try { val response = conn.httpClient.get(url).asText().response val items = JSONArray(response).map { obj -> obj.toCloudNotification() } + .filter { notification -> notification.type == CloudNotificationType.NOTIFICATION } Log.d(TAG, "Notifications request success, got ${items.size} items") loadOffset += items.size adapter.addLoadedItems(items, items.size == PAGE_SIZE) diff --git a/mobile/src/main/java/org/openhab/habdroid/ui/MainActivity.kt b/mobile/src/main/java/org/openhab/habdroid/ui/MainActivity.kt index 8e638e9c66..638647df9b 100644 --- a/mobile/src/main/java/org/openhab/habdroid/ui/MainActivity.kt +++ b/mobile/src/main/java/org/openhab/habdroid/ui/MainActivity.kt @@ -415,7 +415,8 @@ class MainActivity : AbstractBaseActivity(), ConnectionFactory.UpdateListener { connection != null && SpeechRecognizer.isRecognitionAvailable(this) val debugItems = listOf( R.id.mainmenu_debug_crash, - R.id.mainmenu_debug_clear_mtm + R.id.mainmenu_debug_clear_mtm, + R.id.mainmenu_poll_notifications ) debugItems.forEach { menu.findItem(it).isVisible = BuildConfig.DEBUG @@ -454,6 +455,14 @@ class MainActivity : AbstractBaseActivity(), ConnectionFactory.UpdateListener { } true } + R.id.mainmenu_poll_notifications -> { + if (CloudMessagingHelper.needsPollingForNotifications(this)) { + launch { + CloudMessagingHelper.pollForNotifications(this@MainActivity) + } + } + true + } else -> super.onOptionsItemSelected(item) } } diff --git a/mobile/src/main/res/menu/main_menu.xml b/mobile/src/main/res/menu/main_menu.xml index 03ee41a6ec..0e57d8f1e4 100644 --- a/mobile/src/main/res/menu/main_menu.xml +++ b/mobile/src/main/res/menu/main_menu.xml @@ -10,6 +10,12 @@ android:title="@string/mainmenu_openhab_voice_recognition" app:showAsAction="always" app:iconTint="?android:textColorSecondary" /> +