From e53186ea52c35e1d4e8a02816fc2f47e1396a364 Mon Sep 17 00:00:00 2001 From: ua1zbe Date: Tue, 18 Aug 2026 15:42:52 +0300 Subject: [PATCH] Fix group monitoring: per-group 15s idle timeout, drop priority lock --- .../java/ru/ua1zbe/svxremote/MainActivity.kt | 51 +++++++++++-------- .../ua1zbe/svxremote/proto/ReflectorClient.kt | 5 +- app/src/main/res/values/strings.xml | 1 - 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/ru/ua1zbe/svxremote/MainActivity.kt b/app/src/main/java/ru/ua1zbe/svxremote/MainActivity.kt index 5814bd2..47ca25f 100644 --- a/app/src/main/java/ru/ua1zbe/svxremote/MainActivity.kt +++ b/app/src/main/java/ru/ua1zbe/svxremote/MainActivity.kt @@ -77,9 +77,13 @@ class MainActivity : Activity(), SvxService.Listener { private var connected = false private var monitoring = false private var connectedSettings: ConnectionSettings? = null - private var priorityActive = false private var settings: ConnectionSettings = ConnectionSettings("", 5300, "", "", 11) + // Динамический мониторинг: если на группе нет голоса 15 секунд, + // возвращаемся к мониторингу всех групп (базовая группа). + private val MONITOR_IDLE_MS = 15_000L + private var monitorIdleTask: Runnable? = null + private var svc: SvxService? = null private val svcConn = object : ServiceConnection { override fun onServiceConnected(name: ComponentName, binder: IBinder) { @@ -259,7 +263,6 @@ class MainActivity : Activity(), SvxService.Listener { if (prev != settings && connectedSettings != null) { if (settings.host.isBlank() || settings.callsign.isBlank()) { monitoring = false - priorityActive = false updateMonitorButton() updatePttEnabled() svc?.disconnect() @@ -397,20 +400,13 @@ class MainActivity : Activity(), SvxService.Listener { while (talkLog.size > TALK_LOG_MAX) { talkLog.removeFirst() } - val priority = monitoring && settings.groups.firstOrNull() == tg - if (priority) { - priorityActive = true - } - if (priority || !priorityActive) { + // Мониторинг: переключаемся на группу, где началась передача, + // и даём ей 15 секунд; после тишины вернёмся ко всем группам. + if (monitoring) { svc?.selectGroup(tg) - lblTalkerTitle.text = when { - priority -> getString(R.string.talker_mon_priority, callsign, tg) - monitoring -> getString(R.string.talker_mon, callsign, tg) - else -> getString(R.string.talker_now, callsign) - } - lblTalkerTitle.setTextColor( - if (priority) getColor(R.color.danger) else getColor(R.color.text_secondary) - ) + resetMonitorIdle() + lblTalkerTitle.text = getString(R.string.talker_mon, callsign, tg) + lblTalkerTitle.setTextColor(getColor(R.color.text_secondary)) lblTalker.text = callsign } } @@ -418,11 +414,6 @@ class MainActivity : Activity(), SvxService.Listener { override fun onTalkerStop(tg: Long, callsign: String) { // последний говоривший остаётся на экране - mainHandler.post { - if (monitoring && settings.groups.firstOrNull() == tg) { - priorityActive = false - } - } } override fun onNodeJoined(callsign: String, tg: Long?) { @@ -484,10 +475,26 @@ class MainActivity : Activity(), SvxService.Listener { micMeter.setLevel(level) } else { // SRC_SPEAKER rxMeter.setLevel(level) + // Голос на текущей группе — откладываем возврат ко всем группам + if (monitoring && connected && level > 0.03f) { + resetMonitorIdle() + } } } } + /** Сбросить таймер молчания: группа жива — продолжаем её слушать. */ + private fun resetMonitorIdle() { + monitorIdleTask?.let { mainHandler.removeCallbacks(it) } + val task = Runnable { + if (monitoring && connected) { + svc?.selectGroup(settings.talkGroup) + } + } + monitorIdleTask = task + mainHandler.postDelayed(task, MONITOR_IDLE_MS) + } + override fun onError(detail: String) { mainHandler.post { toast(detail) @@ -537,7 +544,6 @@ class MainActivity : Activity(), SvxService.Listener { showToast(R.string.monitor_off) } monitoring = enabling - priorityActive = false updateMonitorButton() updatePttEnabled() if (connected) { @@ -578,7 +584,6 @@ class MainActivity : Activity(), SvxService.Listener { Prefs.setActiveProfile(this, which) settings = Prefs.load(this) monitoring = false - priorityActive = false updateMonitorButton() updatePttEnabled() refreshUi() @@ -615,6 +620,8 @@ class MainActivity : Activity(), SvxService.Listener { svc?.selectGroup(tg) if (!monitoring) { svc?.setMonitorTgs(listOf(tg)) + } else { + resetMonitorIdle() } } diff --git a/app/src/main/java/ru/ua1zbe/svxremote/proto/ReflectorClient.kt b/app/src/main/java/ru/ua1zbe/svxremote/proto/ReflectorClient.kt index 5508ad4..ca2abca 100644 --- a/app/src/main/java/ru/ua1zbe/svxremote/proto/ReflectorClient.kt +++ b/app/src/main/java/ru/ua1zbe/svxremote/proto/ReflectorClient.kt @@ -410,7 +410,10 @@ class ReflectorClient( sendTcp(socket, MsgBuilder.selectTg(s.talkGroup)) sendTcp(socket, MsgBuilder.tgMonitor(listOf(s.talkGroup))) } else { - sendTcp(socket, MsgBuilder.selectTg(monitor.first())) + // Мониторинг: сидим на базовой группе и слушаем + // уведомления обо всех группах (аудио идёт только + // с выбранной, поэтому переключение — в MainActivity). + sendTcp(socket, MsgBuilder.selectTg(s.talkGroup)) sendTcp(socket, MsgBuilder.tgMonitor(monitor)) } openUdp(s) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bdc676c..0568dee 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -42,7 +42,6 @@ Мониторинг групп включен (нажмите, чтобы выключить) Мониторинг: %1$s Говорит: %1$s · TG%2$d - ПРИОРИТЕТ: %1$s · TG%2$d DISCONNECTED CONNECTED ПЕРЕДАЧА