Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new notification features #3724

Merged
merged 21 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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" />
maniac103 marked this conversation as resolved.
Show resolved Hide resolved

<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