Skip to content

Commit

Permalink
Implement new notification features (openhab#3724)
Browse files Browse the repository at this point in the history
Closes openhab#3193

Signed-off-by: mueller-ma <[email protected]>
Co-authored-by: Danny Baumann <[email protected]>
  • Loading branch information
mueller-ma and maniac103 authored Jul 11, 2024
1 parent c71ea33 commit bdb34a0
Show file tree
Hide file tree
Showing 12 changed files with 520 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ object NotificationPoller {

val lastSeenMessageId = prefs.getString(PrefKeys.FOSS_LAST_SEEN_MESSAGE, null)
prefs.edit {
val newestSeenId = messages.firstOrNull()?.id ?: lastSeenMessageId
val newestSeenId = messages.firstOrNull()?.id?.persistedId ?: lastSeenMessageId
putString(PrefKeys.FOSS_LAST_SEEN_MESSAGE, newestSeenId)
}
if (lastSeenMessageId == null) {
Expand All @@ -61,7 +61,7 @@ object NotificationPoller {
return
}

val lastSeenIndex = messages.map { msg -> msg.id }.indexOf(lastSeenMessageId)
val lastSeenIndex = messages.map { msg -> msg.id.persistedId }.indexOf(lastSeenMessageId)
val newMessages = if (lastSeenIndex >= 0) messages.subList(0, lastSeenIndex) else messages
val notifHelper = NotificationHelper(context)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
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.toCloudNotificationAction
import org.openhab.habdroid.model.toOH2IconResource
import org.openhab.habdroid.util.map
import org.openhab.habdroid.util.toJsonArrayOrNull

class FcmMessageListenerService : FirebaseMessagingService() {
private lateinit var notifHelper: NotificationHelper
Expand All @@ -42,23 +47,33 @@ class FcmMessageListenerService : FirebaseMessagingService() {

when (messageType) {
"notification" -> {
val actions = data["actions"]
?.toJsonArrayOrNull()
?.map { it.toCloudNotificationAction() }
?.filterNotNull()
val cloudNotification = CloudNotification(
data["persistedId"].orEmpty(),
data["message"].orEmpty(),
id = CloudNotificationId(data["persistedId"].orEmpty(), data["reference-id"]),
title = data["title"].orEmpty(),
message = data["message"].orEmpty(),
// Older versions of openhab-cloud didn't send the notification generation
// timestamp, so use the (undocumented) google.sent_time as a time reference
// in that case. If that also isn't present, don't show time at all.
data["timestamp"]?.toLong() ?: message.sentTime,
data["icon"].toOH2IconResource(),
data["severity"]
createdTimestamp = data["timestamp"]?.toLong() ?: message.sentTime,
icon = data["icon"].toOH2IconResource(),
tag = data["tag"],
actions = actions,
onClickAction = data["on-click"]?.let { CloudNotificationAction("", it) },
mediaAttachmentUrl = data["media-attachment-url"]
)

runBlocking {
notifHelper.showNotification(cloudNotification)
}
}
"hideNotification" -> {
notifHelper.cancelNotification(data["persistedId"].orEmpty().hashCode())
data["tag"]?.let { tag -> notifHelper.cancelNotificationsByTag(tag) }
val id = CloudNotificationId(data["persistedId"].orEmpty(), data["reference-id"])
notifHelper.cancelNotificationById(id)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion mobile/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@
android:name=".background.CopyToClipboardReceiver"
android:exported="false" />
<receiver
android:name=".core.NotificationDismissedReceiver"
android:name=".core.NotificationHandlingReceiver"
android:exported="false" />

<activity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import org.openhab.habdroid.background.tiles.AbstractTileService
import org.openhab.habdroid.background.tiles.TileData
import org.openhab.habdroid.core.CloudMessagingHelper
import org.openhab.habdroid.core.OpenHabApplication
import org.openhab.habdroid.model.CloudNotificationAction
import org.openhab.habdroid.model.NfcTag
import org.openhab.habdroid.ui.TaskerItemPickerActivity
import org.openhab.habdroid.ui.homescreenwidget.ItemUpdateWidget
Expand Down Expand Up @@ -279,6 +280,7 @@ class BackgroundTasksManager : BroadcastReceiver() {
const val WORKER_TAG_PREFIX_TASKER = "tasker-"
const val WORKER_TAG_PREFIX_WIDGET = "widget-"
const val WORKER_TAG_PREFIX_TILE = "tile-"
const val WORKER_TAG_PREFIX_NOTIFICATION = "notification-"
const val WORKER_TAG_PREFIX_TILE_ID = "tile_id-"
const val WORKER_TAG_VOICE_COMMAND = "voiceCommand"

Expand Down Expand Up @@ -428,6 +430,20 @@ class BackgroundTasksManager : BroadcastReceiver() {
)
}

fun enqueueNotificationAction(context: Context, action: CloudNotificationAction.Action.ItemCommandAction) {
enqueueItemUpload(
context,
WORKER_TAG_PREFIX_NOTIFICATION + action.itemName,
action.itemName,
null,
ItemUpdateWorker.ValueWithInfo(action.command),
isImportant = true,
showToast = true,
asCommand = true,
forceUpdate = true
)
}

fun buildVoiceRecognitionIntent(context: Context, fromBackground: Boolean): Intent {
val callbackIntent = Intent(context, BackgroundTasksManager::class.java).apply {
action = ACTION_VOICE_RESULT
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/

package org.openhab.habdroid.core

import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.core.content.IntentCompat
import androidx.core.net.toUri
import org.openhab.habdroid.BuildConfig
import org.openhab.habdroid.background.BackgroundTasksManager
import org.openhab.habdroid.model.CloudNotificationAction
import org.openhab.habdroid.model.CloudNotificationId
import org.openhab.habdroid.ui.MainActivity
import org.openhab.habdroid.util.PendingIntent_Immutable
import org.openhab.habdroid.util.openInBrowser

class NotificationHandlingReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d(TAG, "onReceive(): $intent")
when (intent.action) {
ACTION_DISMISSED -> {
val notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, 0)
Log.d(TAG, "Dismissed notification $notificationId")
NotificationHelper(context).handleNotificationDismissed(notificationId)
}
ACTION_NOTIF_ACTION -> {
val cna = IntentCompat.getParcelableExtra(
intent,
EXTRA_NOTIFICATION_ACTION,
CloudNotificationAction::class.java
) ?: return
val notificationId = IntentCompat.getParcelableExtra(
intent,
EXTRA_NOTIFICATION_ID,
CloudNotificationId::class.java
) ?: return
Log.d(TAG, "Received action from $notificationId: $cna")

when (val action = cna.action) {
is CloudNotificationAction.Action.ItemCommandAction ->
BackgroundTasksManager.enqueueNotificationAction(context, action)
is CloudNotificationAction.Action.UrlAction ->
action.url.toUri().openInBrowser(context)
is CloudNotificationAction.Action.NoAction -> {
// no-op
}
else -> {
throw IllegalArgumentException("Got unexpected action: $action")
}
}
NotificationHelper(context).cancelNotificationById(notificationId)
}
}
}

companion object {
private val TAG = NotificationHandlingReceiver::class.java.simpleName

const val ACTION_DISMISSED = "${BuildConfig.APPLICATION_ID}.action.NOTIFICATION_DISMISSED"
const val ACTION_NOTIF_ACTION = "${BuildConfig.APPLICATION_ID}.action.NOTIFICATION_ACTION"

const val EXTRA_NOTIFICATION_ID = "notification_id"
const val EXTRA_NOTIFICATION_ACTION = "notification_action"

fun createDismissedPendingIntent(context: Context, notificationId: Int): PendingIntent {
val intent = Intent(context, NotificationHandlingReceiver::class.java).apply {
action = ACTION_DISMISSED
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
}
return PendingIntent.getBroadcast(
context,
notificationId,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent_Immutable
)
}

fun createActionPendingIntent(
context: Context,
notificationId: CloudNotificationId,
cna: CloudNotificationAction
): PendingIntent = when (val cnaAction = cna.action) {
is CloudNotificationAction.Action.UiCommandAction -> {
val intent = Intent(context, MainActivity::class.java).apply {
action = Intent.ACTION_VIEW
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP or
Intent.FLAG_ACTIVITY_NEW_TASK
putExtra(MainActivity.EXTRA_UI_COMMAND, cnaAction.command)
putExtra(MainActivity.EXTRA_CLOUD_NOTIFICATION_ID, notificationId)
}
PendingIntent.getActivity(
context,
notificationId.notificationId + cna.hashCode(),
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent_Immutable
)
}
else -> {
val intent = Intent(context, NotificationHandlingReceiver::class.java).apply {
action = ACTION_NOTIF_ACTION
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
putExtra(EXTRA_NOTIFICATION_ACTION, cna)
}
PendingIntent.getBroadcast(
context,
notificationId.notificationId + cna.hashCode(),
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent_Immutable
)
}
}
}
}
Loading

0 comments on commit bdb34a0

Please sign in to comment.