android radio: release volume PTT on focus loss and option disable
This commit is contained in:
1 parent
1805b3dd27
commit
40e6bd36c3
2 files changed
+42
-18
No files matched your search
@@ -39,6 +39,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.lifecycle.compose.LifecycleStartEffect
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.utun.chat.data.Channel
|
||||
import com.utun.chat.data.IncomingCallManager
|
||||
import com.utun.chat.data.InviteData
|
||||
@@ -48,12 +49,14 @@ import com.utun.chat.data.ConversationTarget
|
||||
import com.utun.chat.data.NativeLib
|
||||
import com.utun.chat.data.RadioOverlayService
|
||||
import com.utun.chat.data.RadioAudioEngine
|
||||
import com.utun.chat.data.RadioPttSource
|
||||
import com.utun.chat.headless.HeadlessService
|
||||
import com.utun.chat.ui.theme.VibeChatTheme
|
||||
import com.utun.chat.ui.components.ActiveCallBanner
|
||||
import com.utun.chat.ui.screens.*
|
||||
import com.utun.chat.viewmodel.ChatViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.flow.collect
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
enum class Screen { ChannelList, Chat, MemberList, Settings, Logs, VideoRecord, PhotoRecord, Call, Dm }
|
||||
@@ -129,6 +132,11 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
lifecycleScope.launch {
|
||||
ChatApplication.instance.configProvider.radioVolumePttEnabled.collect { enabled ->
|
||||
if (!enabled) releaseVolumePtt("option-disabled")
|
||||
}
|
||||
}
|
||||
|
||||
LogManager.addLog("INFO", "LANGUAGE",
|
||||
"UI language applied: selected=${AppLanguage.selectedTag().ifEmpty { "system" }} " +
|
||||
@@ -479,6 +487,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
releaseVolumePtt("activity-paused")
|
||||
RadioOverlayService.setActivityVisible(false)
|
||||
super.onPause()
|
||||
}
|
||||
@@ -544,31 +553,39 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
/** Volume-кнопки (удержание) → PTT рации, при активной рации и включённой опции. */
|
||||
private var pttHoldCount = 0
|
||||
private val pttVolumeKeys = mutableSetOf<Int>()
|
||||
|
||||
private fun releaseVolumePtt(reason: String) {
|
||||
if (pttVolumeKeys.isEmpty()) return
|
||||
pttVolumeKeys.clear()
|
||||
RadioAudioEngine.instance().cancelTalk(RadioPttSource.VOLUME)
|
||||
LogManager.addLog("INFO", "PTT", "Volume hold cancelled: $reason")
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
if (!hasFocus) releaseVolumePtt("window-focus-lost")
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
}
|
||||
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
val isVol = event.keyCode == KeyEvent.KEYCODE_VOLUME_UP || event.keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
|
||||
val pttOn = ChatApplication.instance.configProvider.getRadioVolumePtt()
|
||||
&& RadioAudioEngine.instance().isActive()
|
||||
if (!pttOn || !isVol) {
|
||||
pttHoldCount = 0
|
||||
return super.dispatchKeyEvent(event)
|
||||
}
|
||||
if (!pttOn) releaseVolumePtt("disabled-or-radio-inactive")
|
||||
if (!pttOn || !isVol) return super.dispatchKeyEvent(event)
|
||||
when (event.action) {
|
||||
KeyEvent.ACTION_DOWN -> {
|
||||
if (event.repeatCount == 0) {
|
||||
if (pttHoldCount == 0 && !RadioAudioEngine.instance().talkBegin()) return true
|
||||
pttHoldCount++
|
||||
LogManager.addLog("DEBUG", "PTT", "key=${event.keyCode} down hold=$pttHoldCount")
|
||||
if (event.repeatCount == 0 && event.keyCode !in pttVolumeKeys) {
|
||||
if (pttVolumeKeys.isEmpty() && !RadioAudioEngine.instance().talkBegin(RadioPttSource.VOLUME)) return true
|
||||
pttVolumeKeys.add(event.keyCode)
|
||||
LogManager.addLog("DEBUG", "PTT", "key=${event.keyCode} down held=$pttVolumeKeys")
|
||||
}
|
||||
return true
|
||||
}
|
||||
KeyEvent.ACTION_UP -> {
|
||||
if (pttHoldCount > 0) {
|
||||
pttHoldCount--
|
||||
if (pttHoldCount == 0) RadioAudioEngine.instance().talkEnd()
|
||||
}
|
||||
LogManager.addLog("DEBUG", "PTT", "key=${event.keyCode} up hold=$pttHoldCount")
|
||||
if (pttVolumeKeys.remove(event.keyCode) && pttVolumeKeys.isEmpty())
|
||||
RadioAudioEngine.instance().talkEnd(RadioPttSource.VOLUME)
|
||||
LogManager.addLog("DEBUG", "PTT", "key=${event.keyCode} up held=$pttVolumeKeys cancelled=${event.isCanceled}")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.net.Inet6Address
|
||||
import java.net.InetAddress
|
||||
import java.net.NetworkInterface
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ThreadLocalRandom
|
||||
|
||||
@@ -330,7 +331,7 @@ class ConfigProvider(private val context: Context) {
|
||||
/* ── Рация: volume-кнопки PTT и оверлей ── */
|
||||
|
||||
/* Кэш быстрых настроек рации: чтение не блокирует главный поток.
|
||||
* Ленивая загрузка один раз, дальше — из памяти; set обновляет кэш сразу. */
|
||||
* Ленивая загрузка один раз, дальше — из памяти; set обновляет кэш после сохранения. */
|
||||
@Volatile private var radioVolumePttCached = false
|
||||
@Volatile private var radioVolumePttLoaded = false
|
||||
|
||||
@@ -343,11 +344,17 @@ class ConfigProvider(private val context: Context) {
|
||||
}
|
||||
|
||||
suspend fun setRadioVolumePtt(enabled: Boolean) {
|
||||
radioVolumePttCached = enabled
|
||||
radioVolumePttLoaded = true
|
||||
context.dataStore.edit { prefs -> prefs[radioVolumePttKey] = enabled }
|
||||
try {
|
||||
context.dataStore.edit { prefs -> prefs[radioVolumePttKey] = enabled }
|
||||
radioVolumePttCached = enabled
|
||||
radioVolumePttLoaded = true
|
||||
LogManager.addLog("INFO", "PTT", "Volume PTT enabled=$enabled")
|
||||
} catch (e: IOException) {
|
||||
LogManager.addLog("ERROR", "PTT", "Cannot save volume PTT enabled=$enabled: $e")
|
||||
}
|
||||
}
|
||||
|
||||
val radioVolumePttEnabled: Flow<Boolean> = context.dataStore.data.map { it[radioVolumePttKey] ?: false }
|
||||
val radioOverlayEnabled: Flow<Boolean> = context.dataStore.data.map { it[radioOverlayKey] ?: false }
|
||||
val radioVadEnabled: Flow<Boolean> = context.dataStore.data.map { (it[radioVadEnabledKey] ?: 0) != 0 }
|
||||
|
||||
|
||||
Reference in new issue
Block a user