Skip to content

Commit

Permalink
fix notification actions (open on phone, replies, etc.)
Browse files Browse the repository at this point in the history
  • Loading branch information
crc-32 committed Feb 8, 2025
1 parent 3d1bd07 commit 63fe642
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ import io.rebble.cobble.shared.datastore.createDataStore
import io.rebble.cobble.shared.domain.calendar.AndroidCalendarActionExecutor
import io.rebble.cobble.shared.domain.calendar.PlatformCalendarActionExecutor
import io.rebble.cobble.shared.domain.common.PebbleDevice
import io.rebble.cobble.shared.domain.notifications.AndroidNotificationActionExecutor
import io.rebble.cobble.shared.domain.notifications.CallNotificationProcessor
import io.rebble.cobble.shared.domain.notifications.NotificationProcessor
import io.rebble.cobble.shared.domain.notifications.PlatformNotificationActionExecutor
import io.rebble.cobble.shared.domain.notifications.*
import io.rebble.cobble.shared.domain.voice.DictationService
import io.rebble.cobble.shared.domain.voice.NullDictationService
import io.rebble.cobble.shared.domain.voice.speechrecognizer.SpeechRecognizerDictationService
Expand Down Expand Up @@ -63,7 +60,8 @@ val androidModule = module {
AppMessageHandler(pebbleDevice),
VoiceSessionHandler(pebbleDevice),
AudioStreamHandler(pebbleDevice),
AppLogHandler(pebbleDevice)
AppLogHandler(pebbleDevice),
NotificationActionHandler(pebbleDevice)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ class AndroidNotificationActionExecutor(): PlatformNotificationActionExecutor, K

override suspend fun handleMetaNotificationAction(action: MetaNotificationAction, itemId: Uuid, attributes: List<TimelineItem.Attribute>): TimelineService.ActionResponse {
val sbn = activeNotifsState.value[itemId]
?: return TimelineService.ActionResponse(success = false)
?: run {
Logging.w("Notification not found for action, could be notif before we started tracking them")
return TimelineService.ActionResponse(success = false)
}
return when (action) {
MetaNotificationAction.Dismiss -> actionIntent(sbn.notification.deleteIntent)
.map {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.rebble.cobble.shared.di

import io.rebble.cobble.shared.domain.calendar.CalendarSync
import io.rebble.cobble.shared.domain.calendar.PhoneCalendarSyncer
import io.rebble.cobble.shared.domain.notifications.NotificationActionHandler
import io.rebble.cobble.shared.domain.timeline.TimelineActionManager
import io.rebble.cobble.shared.domain.timeline.WatchTimelineSyncer
import io.rebble.cobble.shared.errors.GlobalExceptionHandler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,6 @@ open class PebbleDevice(

val appMessageTransactionSequence = AppMessageTransactionSequence().iterator()

// Required for the system handler
val systemService: SystemService by inject {parametersOf(protocolHandler)}

init {
// This will init all the handlers by reading the lazy value causing them to be injected
negotiationScope.launch {
val initNHandlers = negotiationHandlers.joinToString { it::class.simpleName ?: "Unknown" }
Logging.i("Initialised negotiation handlers: $initNHandlers")
ConnectionStateManager.connectionState.first { it is ConnectionState.Connected && it.watch.address == address }
val connectionScope = connectionScope.filterNotNull().first()
connectionScope.launch {
val initHandlers = handlers.joinToString { it::class.simpleName ?: "Unknown" }
Logging.i("Initialised handlers: $initHandlers")
}
}
}

override fun toString(): String = "< PebbleDevice address=$address >"

//TODO: Move to per-protocol handler services, so we can have multiple PebbleDevices, this is the first of many
Expand All @@ -81,10 +64,25 @@ open class PebbleDevice(
val appFetchService: AppFetchService by inject {parametersOf(protocolHandler)}
val voiceService: VoiceService by inject {parametersOf(protocolHandler)}
val audioStreamService: AudioStreamService by inject {parametersOf(protocolHandler)}
val systemService: SystemService by inject {parametersOf(protocolHandler)}

val putBytesController: PutBytesController by inject {parametersOf(this)}
val timelineActionManager: TimelineActionManager by inject {parametersOf(this)}

init {
// This will init all the handlers by reading the lazy value causing them to be injected
negotiationScope.launch {
val initNHandlers = negotiationHandlers.joinToString { it::class.simpleName ?: "Unknown" }
Logging.i("Initialised negotiation handlers: $initNHandlers")
ConnectionStateManager.connectionState.first { it is ConnectionState.Connected && it.watch.address == address }
val connectionScope = connectionScope.filterNotNull().first()
connectionScope.launch {
val initHandlers = handlers.joinToString { it::class.simpleName ?: "Unknown" }
Logging.i("Initialised handlers: $initHandlers")
}
}
}

override fun close() {
negotiationScope.cancel("PebbleDevice closed")
connectionScope.value?.cancel("PebbleDevice closed")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,56 +1,57 @@
package io.rebble.cobble.shared.domain.notifications

import io.rebble.cobble.shared.Logging
import io.rebble.cobble.shared.domain.common.PebbleDevice
import io.rebble.cobble.shared.domain.timeline.TimelineActionManager
import io.rebble.cobble.shared.handlers.CobbleHandler
import io.rebble.libpebblecommon.services.blobdb.TimelineService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

class NotificationActionHandler(scope: CoroutineScope): KoinComponent, CobbleHandler {
class NotificationActionHandler(private val pebbleDevice: PebbleDevice): KoinComponent, CobbleHandler {
companion object {
const val NOTIFICATION_UUID_PREFIX = "cafecafe"
}
private val timelineActionManager: TimelineActionManager by inject()
private val notificationActionExecutor: PlatformNotificationActionExecutor by inject()

private val timelineActionManager = pebbleDevice.timelineActionManager
private val notificationActionFlow = timelineActionManager.actionFlow.filter {
val (action, _) = it
action.itemID.get().toString().startsWith(NOTIFICATION_UUID_PREFIX)
}

init {
notificationActionFlow.onEach {
val (action, deferred) = it
val itemId = action.itemID.get()
val response = try {
if (action.actionID.get().toInt() < MetaNotificationAction.metaActionLength) {
notificationActionExecutor.handleMetaNotificationAction(
MetaNotificationAction.entries[action.actionID.get().toInt()],
itemId,
action.attributes.list
)
} else {
notificationActionExecutor.handlePlatformAction(
action.actionID.get().toInt(),
itemId,
action.attributes.list
pebbleDevice.negotiationScope.launch {
notificationActionFlow.onEach {
val (action, deferred) = it
val itemId = action.itemID.get()
Logging.v("Handling notification action for item $itemId")
val response = try {
if (action.actionID.get().toInt() < MetaNotificationAction.metaActionLength) {
notificationActionExecutor.handleMetaNotificationAction(
MetaNotificationAction.entries[action.actionID.get().toInt()],
itemId,
action.attributes.list
)
} else {
notificationActionExecutor.handlePlatformAction(
action.actionID.get().toInt(),
itemId,
action.attributes.list
)
}
} catch (e: NoSuchElementException) {
Logging.e("Error while handling notification action", e)
TimelineService.ActionResponse(
success = false
)
}
} catch (e: NoSuchElementException) {
Logging.e("Error while handling notification action", e)
TimelineService.ActionResponse(
success = false
)
}
deferred.complete(response)
}.catch {
Logging.e("Error while handling notification action", it)
}.launchIn(scope)
deferred.complete(response)
}.catch {
Logging.e("Error while handling notification action", it)
}.launchIn(pebbleDevice.connectionScope.filterNotNull().first())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.benasher44.uuid.Uuid
import io.rebble.cobble.shared.Logging
import io.rebble.cobble.shared.database.dao.TimelinePinDao
import io.rebble.cobble.shared.domain.common.PebbleDevice
import io.rebble.cobble.shared.domain.notifications.NotificationActionHandler
import io.rebble.libpebblecommon.packets.blobdb.TimelineAction
import io.rebble.libpebblecommon.services.blobdb.TimelineService
import kotlinx.coroutines.CompletableDeferred
Expand Down Expand Up @@ -36,7 +37,9 @@ class TimelineActionManager(private val pebbleDevice: PebbleDevice): KoinCompone
val (action, _) = it
val itemId = action.itemID.get()
val item = timelineDao.get(itemId) ?: run {
Logging.w("Received action for non-existent item $itemId")
if (!itemId.toString().startsWith(NotificationActionHandler.NOTIFICATION_UUID_PREFIX)) {
Logging.w("Received action for non-existent item $itemId")
}
return@filter false
}
item.parentId == appId
Expand Down

0 comments on commit 63fe642

Please sign in to comment.