From 0a97dd95fb12d251b15ac73654f0a7c7d74a98ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Miret?= Date: Wed, 26 Nov 2025 15:53:58 +0100 Subject: [PATCH 1/2] Add suport for Bell messages --- .../java/com/gaurav/avnc/vnc/VncClientTest.kt | 1 + .../com/gaurav/avnc/ui/prefs/PrefsActivity.kt | 36 ++++++++++++++++++- .../com/gaurav/avnc/util/AppPreferences.kt | 19 ++++++++++ .../main/java/com/gaurav/avnc/util/Tones.kt | 17 +++++++++ .../com/gaurav/avnc/viewmodel/VncViewModel.kt | 8 ++++- .../java/com/gaurav/avnc/vnc/VncClient.kt | 5 ++- app/src/main/res/values-fr/strings.xml | 6 ++++ app/src/main/res/values/arrays.xml | 18 +++++++++- app/src/main/res/values/strings.xml | 6 ++++ app/src/main/res/xml/pref_appearance.xml | 10 ++++++ 10 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/com/gaurav/avnc/util/Tones.kt diff --git a/app/src/androidTest/java/com/gaurav/avnc/vnc/VncClientTest.kt b/app/src/androidTest/java/com/gaurav/avnc/vnc/VncClientTest.kt index 6598a489..8ac3024e 100644 --- a/app/src/androidTest/java/com/gaurav/avnc/vnc/VncClientTest.kt +++ b/app/src/androidTest/java/com/gaurav/avnc/vnc/VncClientTest.kt @@ -28,6 +28,7 @@ class VncClientTest { override fun onGotXCutText(text: String) { cutText = text } + override fun onBell() {} } diff --git a/app/src/main/java/com/gaurav/avnc/ui/prefs/PrefsActivity.kt b/app/src/main/java/com/gaurav/avnc/ui/prefs/PrefsActivity.kt index c7e24170..b3df983c 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/prefs/PrefsActivity.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/prefs/PrefsActivity.kt @@ -8,6 +8,7 @@ package com.gaurav.avnc.ui.prefs +import android.content.Context import android.content.SharedPreferences.OnSharedPreferenceChangeListener import android.content.pm.PackageManager import android.os.Build @@ -16,9 +17,12 @@ import androidx.annotation.Keep import androidx.appcompat.app.AppCompatActivity import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat +import androidx.preference.PreferenceManager import androidx.preference.SwitchPreference import com.gaurav.avnc.R +import com.gaurav.avnc.util.AppPreferences import com.gaurav.avnc.util.DeviceAuthPrompt +import com.gaurav.avnc.util.Tones import com.google.android.material.appbar.MaterialToolbar class PrefsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { @@ -77,7 +81,37 @@ class PrefsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreference } @Keep class Main : PrefFragment(R.xml.pref_main) - @Keep class Appearance : PrefFragment(R.xml.pref_appearance) + @Keep class Appearance : PrefFragment(R.xml.pref_appearance) { + + private var listener: OnSharedPreferenceChangeListener? = null + + override fun onAttach(context: Context) { + super.onAttach(context) + val prefs = AppPreferences(context) + listener = OnSharedPreferenceChangeListener { _, key -> + if (key == "bell") { + prefs.ui.bell?.let { Tones.notify(it) } + } + } + } + + override fun onStart() { + super.onStart() + context?.let { + PreferenceManager.getDefaultSharedPreferences(it) + .registerOnSharedPreferenceChangeListener(listener) + } + } + + override fun onStop() { + super.onStop() + context?.let { + PreferenceManager.getDefaultSharedPreferences(it) + .unregisterOnSharedPreferenceChangeListener(listener) + } + } + + } @Keep class Viewer : PrefFragment(R.xml.pref_viewer) { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/gaurav/avnc/util/AppPreferences.kt b/app/src/main/java/com/gaurav/avnc/util/AppPreferences.kt index b7b1f972..36d308e6 100644 --- a/app/src/main/java/com/gaurav/avnc/util/AppPreferences.kt +++ b/app/src/main/java/com/gaurav/avnc/util/AppPreferences.kt @@ -10,6 +10,7 @@ package com.gaurav.avnc.util import android.content.Context import android.content.SharedPreferences +import android.media.ToneGenerator import androidx.core.content.edit import androidx.lifecycle.LiveData import androidx.preference.PreferenceManager @@ -24,6 +25,7 @@ class AppPreferences(context: Context) { inner class UI { val theme = StringLivePref("theme", "system") + var bell by IntPref("bell", ToneGenerator.TONE_PROP_BEEP) var preferAdvancedEditor by BooleanPref("prefer_advanced_editor", false) val sortServerList = BooleanLivePref("sort_server_list", false) } @@ -118,6 +120,23 @@ class AppPreferences(context: Context) { inner class BooleanPref(val key: String, default: Boolean) : Pref({ getBoolean(key, default) }, { putBoolean(key, it) }) inner class StringPref(val key: String, default: String?) : Pref({ getString(key, default) }, { putString(key, it) }) inner class FloatPref(val key: String, default: Float) : Pref({ getFloat(key, default) }, { putFloat(key, it) }) + inner class IntPref(val key: String, default: Int?) : Pref( + { + val string = getString(key, null) + if (string == "none") { + null + } else { + string?.toIntOrNull() ?: default + } + }, + { + if (it == null) { + putString(key, "none") + } else { + putString(key, it.toString()) + } + }, + ) /** * For some preference changes we want to provide live feedback to user. diff --git a/app/src/main/java/com/gaurav/avnc/util/Tones.kt b/app/src/main/java/com/gaurav/avnc/util/Tones.kt new file mode 100644 index 00000000..43fc3860 --- /dev/null +++ b/app/src/main/java/com/gaurav/avnc/util/Tones.kt @@ -0,0 +1,17 @@ +package com.gaurav.avnc.util + +import android.media.AudioManager +import android.media.ToneGenerator +import android.util.Log + +object Tones { + private val notifications = ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100) + + /** + * @param tone a `TONE_` constant from [ToneGenerator]. + */ + fun notify(tone: Int) { + Log.i("Tones", "Notify with tone $tone") + notifications.startTone(tone) + } +} diff --git a/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt b/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt index 9a69a2b0..b773ed95 100644 --- a/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt +++ b/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt @@ -20,6 +20,7 @@ import com.gaurav.avnc.ui.vnc.FrameScroller import com.gaurav.avnc.ui.vnc.FrameState import com.gaurav.avnc.ui.vnc.FrameView import com.gaurav.avnc.util.LiveRequest +import com.gaurav.avnc.util.Tones import com.gaurav.avnc.util.broadcastWoLPackets import com.gaurav.avnc.util.getClipboardText import com.gaurav.avnc.util.getUnknownCertificateMessage @@ -507,4 +508,9 @@ class VncViewModel(app: Application) : BaseViewModel(app), VncClient.Observer { override fun onPointerMoved(x: Int, y: Int) { frameViewRef.get()?.requestRender() } -} \ No newline at end of file + + override fun onBell() { + pref.ui.bell?.let { Tones.notify(it) } + } + +} diff --git a/app/src/main/java/com/gaurav/avnc/vnc/VncClient.kt b/app/src/main/java/com/gaurav/avnc/vnc/VncClient.kt index 797b5782..1ab7f9ef 100644 --- a/app/src/main/java/com/gaurav/avnc/vnc/VncClient.kt +++ b/app/src/main/java/com/gaurav/avnc/vnc/VncClient.kt @@ -53,8 +53,7 @@ class VncClient(private val observer: Observer) { fun onFramebufferUpdated() fun onFramebufferSizeChanged(width: Int, height: Int) fun onPointerMoved(x: Int, y: Int) - - //fun onBell() + fun onBell() } /** @@ -428,7 +427,7 @@ class VncClient(private val observer: Observer) { @Keep - private fun cbBell() = Unit // observer.onBell() + private fun cbBell() = observer.onBell() @Keep private fun cbHandleCursorPos(x: Int, y: Int) { diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 630e81f1..4b16cfa4 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -118,6 +118,7 @@ Faire défiler le contenu distant Faire glisser le contenu distant Ouvrir le clavier + Non-acquittement Ouvrir directement les options avancées du serveur Journaux Picture-in-picture @@ -240,4 +241,9 @@ Style de geste \'Touchpad\' est actif Désactivé par la valeur actuelle du geste Pression longue Faites glisser depuis le bord pour ouvrir + Sonnerie + Son joué quand le serveur VNC envoie un message BELL. Ce son est joué avec le volume Android des notifications. + Acquittement + Bip + Double bip diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 98eed7fd..e69fa4ae 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -19,6 +19,22 @@ light + + + @string/title_none + @string/pref_tone_ack + @string/pref_tone_beep + @string/pref_tone_beep2 + @string/pref_tone_nack + + + none + 25 + 24 + 28 + 26 + + @string/pref_orientation_option_auto @string/pref_orientation_option_portrait @@ -227,4 +243,4 @@ Item 2 Item 3 - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b222d57e..43890428 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -181,6 +181,12 @@ System Dark Light + Bell + Sound played when the VNC server issues a BELL message. It is played with the Android notification volume. + Acknowledgment + Beep + Double beep + Non-acknowledgment Directly open advanced server options Sort saved servers by name Gestures diff --git a/app/src/main/res/xml/pref_appearance.xml b/app/src/main/res/xml/pref_appearance.xml index bb5a95b5..41c8a3c0 100644 --- a/app/src/main/res/xml/pref_appearance.xml +++ b/app/src/main/res/xml/pref_appearance.xml @@ -17,6 +17,16 @@ app:title="@string/pref_theme" app:useSimpleSummaryProvider="true" /> + + Date: Tue, 2 Dec 2025 09:15:52 +0100 Subject: [PATCH 2/2] Configure bell with a simple boolean setting --- .../com/gaurav/avnc/ui/prefs/PrefsActivity.kt | 36 +------------------ .../com/gaurav/avnc/util/AppPreferences.kt | 19 +--------- .../com/gaurav/avnc/viewmodel/VncViewModel.kt | 5 ++- app/src/main/res/values-fr/strings.xml | 5 --- app/src/main/res/values/arrays.xml | 16 --------- app/src/main/res/values/strings.xml | 5 --- app/src/main/res/xml/pref_appearance.xml | 13 +++---- 7 files changed, 10 insertions(+), 89 deletions(-) diff --git a/app/src/main/java/com/gaurav/avnc/ui/prefs/PrefsActivity.kt b/app/src/main/java/com/gaurav/avnc/ui/prefs/PrefsActivity.kt index b3df983c..c7e24170 100644 --- a/app/src/main/java/com/gaurav/avnc/ui/prefs/PrefsActivity.kt +++ b/app/src/main/java/com/gaurav/avnc/ui/prefs/PrefsActivity.kt @@ -8,7 +8,6 @@ package com.gaurav.avnc.ui.prefs -import android.content.Context import android.content.SharedPreferences.OnSharedPreferenceChangeListener import android.content.pm.PackageManager import android.os.Build @@ -17,12 +16,9 @@ import androidx.annotation.Keep import androidx.appcompat.app.AppCompatActivity import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat -import androidx.preference.PreferenceManager import androidx.preference.SwitchPreference import com.gaurav.avnc.R -import com.gaurav.avnc.util.AppPreferences import com.gaurav.avnc.util.DeviceAuthPrompt -import com.gaurav.avnc.util.Tones import com.google.android.material.appbar.MaterialToolbar class PrefsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { @@ -81,37 +77,7 @@ class PrefsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreference } @Keep class Main : PrefFragment(R.xml.pref_main) - @Keep class Appearance : PrefFragment(R.xml.pref_appearance) { - - private var listener: OnSharedPreferenceChangeListener? = null - - override fun onAttach(context: Context) { - super.onAttach(context) - val prefs = AppPreferences(context) - listener = OnSharedPreferenceChangeListener { _, key -> - if (key == "bell") { - prefs.ui.bell?.let { Tones.notify(it) } - } - } - } - - override fun onStart() { - super.onStart() - context?.let { - PreferenceManager.getDefaultSharedPreferences(it) - .registerOnSharedPreferenceChangeListener(listener) - } - } - - override fun onStop() { - super.onStop() - context?.let { - PreferenceManager.getDefaultSharedPreferences(it) - .unregisterOnSharedPreferenceChangeListener(listener) - } - } - - } + @Keep class Appearance : PrefFragment(R.xml.pref_appearance) @Keep class Viewer : PrefFragment(R.xml.pref_viewer) { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/gaurav/avnc/util/AppPreferences.kt b/app/src/main/java/com/gaurav/avnc/util/AppPreferences.kt index 36d308e6..3d2bb148 100644 --- a/app/src/main/java/com/gaurav/avnc/util/AppPreferences.kt +++ b/app/src/main/java/com/gaurav/avnc/util/AppPreferences.kt @@ -25,7 +25,7 @@ class AppPreferences(context: Context) { inner class UI { val theme = StringLivePref("theme", "system") - var bell by IntPref("bell", ToneGenerator.TONE_PROP_BEEP) + var bell by BooleanPref("bell_enabled", true) var preferAdvancedEditor by BooleanPref("prefer_advanced_editor", false) val sortServerList = BooleanLivePref("sort_server_list", false) } @@ -120,23 +120,6 @@ class AppPreferences(context: Context) { inner class BooleanPref(val key: String, default: Boolean) : Pref({ getBoolean(key, default) }, { putBoolean(key, it) }) inner class StringPref(val key: String, default: String?) : Pref({ getString(key, default) }, { putString(key, it) }) inner class FloatPref(val key: String, default: Float) : Pref({ getFloat(key, default) }, { putFloat(key, it) }) - inner class IntPref(val key: String, default: Int?) : Pref( - { - val string = getString(key, null) - if (string == "none") { - null - } else { - string?.toIntOrNull() ?: default - } - }, - { - if (it == null) { - putString(key, "none") - } else { - putString(key, it.toString()) - } - }, - ) /** * For some preference changes we want to provide live feedback to user. diff --git a/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt b/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt index b773ed95..67172b9d 100644 --- a/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt +++ b/app/src/main/java/com/gaurav/avnc/viewmodel/VncViewModel.kt @@ -10,6 +10,7 @@ package com.gaurav.avnc.viewmodel import android.app.Application import android.graphics.RectF +import android.media.ToneGenerator import android.util.Log import android.widget.Toast import androidx.lifecycle.MutableLiveData @@ -510,7 +511,9 @@ class VncViewModel(app: Application) : BaseViewModel(app), VncClient.Observer { } override fun onBell() { - pref.ui.bell?.let { Tones.notify(it) } + if (pref.ui.bell) { + Tones.notify(ToneGenerator.TONE_PROP_BEEP) + } } } diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 4b16cfa4..b804100d 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -118,7 +118,6 @@ Faire défiler le contenu distant Faire glisser le contenu distant Ouvrir le clavier - Non-acquittement Ouvrir directement les options avancées du serveur Journaux Picture-in-picture @@ -242,8 +241,4 @@ Désactivé par la valeur actuelle du geste Pression longue Faites glisser depuis le bord pour ouvrir Sonnerie - Son joué quand le serveur VNC envoie un message BELL. Ce son est joué avec le volume Android des notifications. - Acquittement - Bip - Double bip diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index e69fa4ae..e3cd979d 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -19,22 +19,6 @@ light - - - @string/title_none - @string/pref_tone_ack - @string/pref_tone_beep - @string/pref_tone_beep2 - @string/pref_tone_nack - - - none - 25 - 24 - 28 - 26 - - @string/pref_orientation_option_auto @string/pref_orientation_option_portrait diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 43890428..5d6cf486 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -182,11 +182,6 @@ Dark Light Bell - Sound played when the VNC server issues a BELL message. It is played with the Android notification volume. - Acknowledgment - Beep - Double beep - Non-acknowledgment Directly open advanced server options Sort saved servers by name Gestures diff --git a/app/src/main/res/xml/pref_appearance.xml b/app/src/main/res/xml/pref_appearance.xml index 41c8a3c0..878ff5d4 100644 --- a/app/src/main/res/xml/pref_appearance.xml +++ b/app/src/main/res/xml/pref_appearance.xml @@ -17,15 +17,10 @@ app:title="@string/pref_theme" app:useSimpleSummaryProvider="true" /> - +