mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-06-02 06:24:16 +02:00
fix(data): default new-node notifications off for event firmware (#5323)
This commit is contained in:
+19
@@ -31,12 +31,14 @@ import org.meshtastic.core.repository.MeshConfigFlowManager
|
||||
import org.meshtastic.core.repository.MeshConnectionManager
|
||||
import org.meshtastic.core.repository.NodeManager
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.NotificationPrefs
|
||||
import org.meshtastic.core.repository.PlatformAnalytics
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
import org.meshtastic.core.repository.ServiceBroadcasts
|
||||
import org.meshtastic.core.repository.ServiceRepository
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
import org.meshtastic.proto.FileInfo
|
||||
import org.meshtastic.proto.FirmwareEdition
|
||||
import org.meshtastic.proto.HardwareModel
|
||||
import org.meshtastic.proto.NodeInfo
|
||||
import org.meshtastic.core.model.MyNodeInfo as SharedMyNodeInfo
|
||||
@@ -54,6 +56,7 @@ class MeshConfigFlowManagerImpl(
|
||||
private val analytics: PlatformAnalytics,
|
||||
private val commandSender: CommandSender,
|
||||
private val heartbeatSender: DataLayerHeartbeatSender,
|
||||
private val notificationPrefs: NotificationPrefs,
|
||||
@Named("ServiceScope") private val scope: CoroutineScope,
|
||||
) : MeshConfigFlowManager {
|
||||
private val wantConfigDelay = 100L
|
||||
@@ -199,6 +202,8 @@ class MeshConfigFlowManagerImpl(
|
||||
// Transition to Stage 1, discarding any stale data from a prior interrupted handshake.
|
||||
handshakeState = HandshakeState.ReceivingConfig(rawMyNodeInfo = myInfo)
|
||||
nodeManager.setMyNodeNum(myInfo.my_node_num)
|
||||
nodeManager.setFirmwareEdition(myInfo.firmware_edition)
|
||||
applyEventFirmwareNotificationDefaults(myInfo.firmware_edition)
|
||||
|
||||
// Bump the generation so that a pending clear from a prior (interrupted) handshake
|
||||
// will see a stale snapshot and skip its writes, preventing it from wiping config
|
||||
@@ -288,4 +293,18 @@ class MeshConfigFlowManagerImpl(
|
||||
Logger.e(ex) { "Failed to build MyNodeInfo" }
|
||||
null
|
||||
}
|
||||
|
||||
private fun applyEventFirmwareNotificationDefaults(edition: FirmwareEdition) {
|
||||
if (edition != FirmwareEdition.VANILLA) {
|
||||
if (!notificationPrefs.nodeEventsAutoDisabledForEvent.value) {
|
||||
notificationPrefs.setNodeEventsEnabled(false)
|
||||
notificationPrefs.setNodeEventsAutoDisabledForEvent(true)
|
||||
}
|
||||
} else {
|
||||
if (notificationPrefs.nodeEventsAutoDisabledForEvent.value) {
|
||||
notificationPrefs.setNodeEventsEnabled(true)
|
||||
notificationPrefs.setNodeEventsAutoDisabledForEvent(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.getStringSuspend
|
||||
import org.meshtastic.core.resources.new_node_seen
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
import org.meshtastic.proto.FirmwareEdition
|
||||
import org.meshtastic.proto.HardwareModel
|
||||
import org.meshtastic.proto.Paxcount
|
||||
import org.meshtastic.proto.StatusMessage
|
||||
@@ -89,6 +90,12 @@ class NodeManagerImpl(
|
||||
myNodeNum.value = num
|
||||
}
|
||||
|
||||
override val firmwareEdition = MutableStateFlow<FirmwareEdition?>(null)
|
||||
|
||||
override fun setFirmwareEdition(edition: FirmwareEdition?) {
|
||||
firmwareEdition.value = edition
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TIME_MS_TO_S = 1000L
|
||||
}
|
||||
@@ -112,6 +119,7 @@ class NodeManagerImpl(
|
||||
isNodeDbReady.value = false
|
||||
allowNodeDbWrites.value = false
|
||||
myNodeNum.value = null
|
||||
firmwareEdition.value = null
|
||||
}
|
||||
|
||||
override fun getMyNodeInfo(): MyNodeInfo? {
|
||||
|
||||
+54
@@ -23,6 +23,7 @@ import dev.mokkery.every
|
||||
import dev.mokkery.matcher.any
|
||||
import dev.mokkery.mock
|
||||
import dev.mokkery.verify
|
||||
import dev.mokkery.verify.VerifyMode
|
||||
import dev.mokkery.verifySuspend
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -36,6 +37,7 @@ import org.meshtastic.core.repository.HandshakeConstants
|
||||
import org.meshtastic.core.repository.MeshConnectionManager
|
||||
import org.meshtastic.core.repository.NodeManager
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.NotificationPrefs
|
||||
import org.meshtastic.core.repository.PacketHandler
|
||||
import org.meshtastic.core.repository.PlatformAnalytics
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
@@ -43,6 +45,7 @@ import org.meshtastic.core.repository.ServiceBroadcasts
|
||||
import org.meshtastic.core.repository.ServiceRepository
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
import org.meshtastic.proto.FileInfo
|
||||
import org.meshtastic.proto.FirmwareEdition
|
||||
import org.meshtastic.proto.HardwareModel
|
||||
import org.meshtastic.proto.NodeInfo
|
||||
import kotlin.test.BeforeTest
|
||||
@@ -62,6 +65,7 @@ class MeshConfigFlowManagerImplTest {
|
||||
private val analytics = mock<PlatformAnalytics>(MockMode.autofill)
|
||||
private val commandSender = mock<CommandSender>(MockMode.autofill)
|
||||
private val packetHandler = mock<PacketHandler>(MockMode.autofill)
|
||||
private val notificationPrefs = mock<NotificationPrefs>(MockMode.autofill)
|
||||
|
||||
private val testDispatcher = StandardTestDispatcher()
|
||||
private val testScope = TestScope(testDispatcher)
|
||||
@@ -87,6 +91,8 @@ class MeshConfigFlowManagerImplTest {
|
||||
every { packetHandler.sendToRadio(any<org.meshtastic.proto.ToRadio>()) } returns Unit
|
||||
every { nodeManager.nodeDBbyNodeNum } returns emptyMap()
|
||||
every { nodeManager.myNodeNum } returns MutableStateFlow(null)
|
||||
every { notificationPrefs.nodeEventsAutoDisabledForEvent } returns MutableStateFlow(false)
|
||||
every { notificationPrefs.nodeEventsEnabled } returns MutableStateFlow(true)
|
||||
|
||||
manager =
|
||||
MeshConfigFlowManagerImpl(
|
||||
@@ -99,6 +105,7 @@ class MeshConfigFlowManagerImplTest {
|
||||
analytics = analytics,
|
||||
commandSender = commandSender,
|
||||
heartbeatSender = DataLayerHeartbeatSender(packetHandler),
|
||||
notificationPrefs = notificationPrefs,
|
||||
scope = testScope,
|
||||
)
|
||||
}
|
||||
@@ -418,4 +425,51 @@ class MeshConfigFlowManagerImplTest {
|
||||
|
||||
verify { nodeManager.setMyNodeNum(99999) }
|
||||
}
|
||||
|
||||
// ---------- Event firmware notification defaults ----------
|
||||
|
||||
@Test
|
||||
fun `handleMyInfo disables node notifications for event firmware`() = testScope.runTest {
|
||||
every { notificationPrefs.nodeEventsAutoDisabledForEvent } returns MutableStateFlow(false)
|
||||
|
||||
val eventMyInfo = protoMyNodeInfo.copy(firmware_edition = FirmwareEdition.DEFCON)
|
||||
manager.handleMyInfo(eventMyInfo)
|
||||
advanceUntilIdle()
|
||||
|
||||
verify { notificationPrefs.setNodeEventsEnabled(false) }
|
||||
verify { notificationPrefs.setNodeEventsAutoDisabledForEvent(true) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `handleMyInfo does not re-disable if already auto-disabled`() = testScope.runTest {
|
||||
every { notificationPrefs.nodeEventsAutoDisabledForEvent } returns MutableStateFlow(true)
|
||||
|
||||
val eventMyInfo = protoMyNodeInfo.copy(firmware_edition = FirmwareEdition.DEFCON)
|
||||
manager.handleMyInfo(eventMyInfo)
|
||||
advanceUntilIdle()
|
||||
|
||||
verify(mode = VerifyMode.not) { notificationPrefs.setNodeEventsEnabled(any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `handleMyInfo re-enables node notifications when vanilla firmware reconnects`() = testScope.runTest {
|
||||
every { notificationPrefs.nodeEventsAutoDisabledForEvent } returns MutableStateFlow(true)
|
||||
|
||||
manager.handleMyInfo(protoMyNodeInfo)
|
||||
advanceUntilIdle()
|
||||
|
||||
verify { notificationPrefs.setNodeEventsEnabled(true) }
|
||||
verify { notificationPrefs.setNodeEventsAutoDisabledForEvent(false) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `handleMyInfo does not touch prefs for vanilla when not previously auto-disabled`() = testScope.runTest {
|
||||
every { notificationPrefs.nodeEventsAutoDisabledForEvent } returns MutableStateFlow(false)
|
||||
|
||||
manager.handleMyInfo(protoMyNodeInfo)
|
||||
advanceUntilIdle()
|
||||
|
||||
verify(mode = VerifyMode.not) { notificationPrefs.setNodeEventsEnabled(any()) }
|
||||
verify(mode = VerifyMode.not) { notificationPrefs.setNodeEventsAutoDisabledForEvent(any()) }
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -53,6 +53,13 @@ class NotificationPrefsImpl(
|
||||
scope.launch { dataStore.edit { it[KEY_NODE_EVENTS_ENABLED] = enabled } }
|
||||
}
|
||||
|
||||
override val nodeEventsAutoDisabledForEvent: StateFlow<Boolean> =
|
||||
dataStore.data.map { it[KEY_NODE_EVENTS_AUTO_DISABLED] ?: false }.stateIn(scope, SharingStarted.Eagerly, false)
|
||||
|
||||
override fun setNodeEventsAutoDisabledForEvent(disabled: Boolean) {
|
||||
scope.launch { dataStore.edit { it[KEY_NODE_EVENTS_AUTO_DISABLED] = disabled } }
|
||||
}
|
||||
|
||||
override val lowBatteryEnabled: StateFlow<Boolean> =
|
||||
dataStore.data.map { it[KEY_LOW_BATTERY_ENABLED] ?: true }.stateIn(scope, SharingStarted.Eagerly, true)
|
||||
|
||||
@@ -63,6 +70,7 @@ class NotificationPrefsImpl(
|
||||
private companion object {
|
||||
val KEY_MESSAGES_ENABLED = booleanPreferencesKey("notif_messages_enabled")
|
||||
val KEY_NODE_EVENTS_ENABLED = booleanPreferencesKey("notif_node_events_enabled")
|
||||
val KEY_NODE_EVENTS_AUTO_DISABLED = booleanPreferencesKey("notif_node_events_auto_disabled_event")
|
||||
val KEY_LOW_BATTERY_ENABLED = booleanPreferencesKey("notif_low_battery_enabled")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +164,10 @@ interface NotificationPrefs {
|
||||
|
||||
fun setNodeEventsEnabled(enabled: Boolean)
|
||||
|
||||
val nodeEventsAutoDisabledForEvent: StateFlow<Boolean>
|
||||
|
||||
fun setNodeEventsAutoDisabledForEvent(disabled: Boolean)
|
||||
|
||||
val lowBatteryEnabled: StateFlow<Boolean>
|
||||
|
||||
fun setLowBatteryEnabled(enabled: Boolean)
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.NodeInfo
|
||||
import org.meshtastic.core.model.util.NodeIdLookup
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
import org.meshtastic.proto.FirmwareEdition
|
||||
import org.meshtastic.proto.Paxcount
|
||||
import org.meshtastic.proto.StatusMessage
|
||||
import org.meshtastic.proto.Telemetry
|
||||
@@ -56,6 +57,12 @@ interface NodeManager : NodeIdLookup {
|
||||
/** Sets the local node number. */
|
||||
fun setMyNodeNum(num: Int?)
|
||||
|
||||
/** The firmware edition reported by the connected device. */
|
||||
val firmwareEdition: StateFlow<FirmwareEdition?>
|
||||
|
||||
/** Sets the firmware edition of the connected device. */
|
||||
fun setFirmwareEdition(edition: FirmwareEdition?)
|
||||
|
||||
/** Loads the cached node database from the repository. */
|
||||
fun loadCachedNodeDB()
|
||||
|
||||
|
||||
+6
@@ -32,6 +32,12 @@ class FakeNotificationPrefs : NotificationPrefs {
|
||||
nodeEventsEnabled.value = enabled
|
||||
}
|
||||
|
||||
override val nodeEventsAutoDisabledForEvent = MutableStateFlow(false)
|
||||
|
||||
override fun setNodeEventsAutoDisabledForEvent(disabled: Boolean) {
|
||||
nodeEventsAutoDisabledForEvent.value = disabled
|
||||
}
|
||||
|
||||
override val lowBatteryEnabled = MutableStateFlow(true)
|
||||
|
||||
override fun setLowBatteryEnabled(enabled: Boolean) {
|
||||
|
||||
+5
@@ -49,6 +49,7 @@ class DesktopNotificationManagerTest {
|
||||
) : NotificationPrefs {
|
||||
override val messagesEnabled = MutableStateFlow(messages)
|
||||
override val nodeEventsEnabled = MutableStateFlow(nodeEvents)
|
||||
override val nodeEventsAutoDisabledForEvent = MutableStateFlow(false)
|
||||
override val lowBatteryEnabled = MutableStateFlow(lowBattery)
|
||||
|
||||
override fun setMessagesEnabled(enabled: Boolean) {
|
||||
@@ -59,6 +60,10 @@ class DesktopNotificationManagerTest {
|
||||
nodeEventsEnabled.value = enabled
|
||||
}
|
||||
|
||||
override fun setNodeEventsAutoDisabledForEvent(disabled: Boolean) {
|
||||
nodeEventsAutoDisabledForEvent.value = disabled
|
||||
}
|
||||
|
||||
override fun setLowBatteryEnabled(enabled: Boolean) {
|
||||
lowBatteryEnabled.value = enabled
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user