Recently Written · git

subrep-android

Subrep on Android: live captions of the sound of the phone, made on the phone by Whisper, shared by link.

git clone https://github.com/equwal/subrep-android

Log | Files | Refs


commit 7ae2dd1f39a08ae0dd597d42dabb373f17338eda
equwal <truex@equwal.com>
2026-09-21 22:21:09 -0700

Keep one sound source checked, and show the state in dumpsys

Each radio button gets an id before it joins the group, and the group
selects one. Without the ids, a tap on the microphone left both buttons
checked, and the app captured the apps again.

The level meter redraws only when its bar count changes, at most twice a
second, for e-ink screens. The service prints its state for
'adb shell dumpsys activity service', for a bug report.

 app/src/main/kotlin/com/honjimaku/subrep/MainActivity.kt | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/app/src/main/kotlin/com/honjimaku/subrep/MainActivity.kt b/app/src/main/kotlin/com/honjimaku/subrep/MainActivity.kt
index 868fac6..dd883ce 100644
--- a/app/src/main/kotlin/com/honjimaku/subrep/MainActivity.kt
+++ b/app/src/main/kotlin/com/honjimaku/subrep/MainActivity.kt
@@ -36,6 +36,7 @@ class MainActivity : Activity(), Feed.Listener {
     private lateinit var engineField: EditText
     private lateinit var langField: EditText
     private lateinit var titleField: EditText
+    private lateinit var sourceGroup: RadioGroup
     private lateinit var screenRadio: RadioButton
     private lateinit var micRadio: RadioButton
     private lateinit var shareBox: CheckBox
@@ -84,20 +85,23 @@ class MainActivity : Activity(), Feed.Listener {
         langField = field(store.lang, "ja", InputType.TYPE_CLASS_TEXT)
 
         step(R.string.step_source, "")
+        // The group keeps one button checked only when each button has an id before it joins.
         screenRadio = RadioButton(this).apply {
+            id = SCREEN_ID
             text = getString(R.string.source_screen)
             setTextColor(Color.BLACK)
-            isChecked = store.screen
         }
         micRadio = RadioButton(this).apply {
+            id = MIC_ID
             text = getString(R.string.source_mic)
             setTextColor(Color.BLACK)
-            isChecked = !store.screen
         }
-        content.addView(RadioGroup(this).apply {
+        sourceGroup = RadioGroup(this).apply {
             addView(screenRadio)
             addView(micRadio)
-        }, wide())
+            check(if (store.screen) SCREEN_ID else MIC_ID)
+        }
+        content.addView(sourceGroup, wide())
 
         step(R.string.step_share, "")
         shareBox = CheckBox(this).apply {
@@ -158,7 +162,7 @@ class MainActivity : Activity(), Feed.Listener {
         store.engine = engineField.text.toString()
         store.lang = langField.text.toString()
         store.title = titleField.text.toString()
-        store.screen = screenRadio.isChecked
+        store.screen = sourceGroup.checkedRadioButtonId != MIC_ID
         store.share = shareBox.isChecked
         store.overlay = overlayBox.isChecked
     }
@@ -297,5 +301,7 @@ class MainActivity : Activity(), Feed.Listener {
     private companion object {
         const val REQUEST_PERMISSIONS = 1
         const val REQUEST_PROJECTION = 2
+        const val SCREEN_ID = 1
+        const val MIC_ID = 2
     }
 }