Simple Android app for voice dictation that sends text to Linux via relay server.
This is a complete, buildable Android project with the following structure:
android-app/
├── app/
│ ├── src/main/
│ │ ├── java/com/utter/android/
│ │ │ ├── MainActivity.kt # Main UI and logic
│ │ │ └── WebSocketClient.kt # WebSocket connection handler
│ │ ├── res/
│ │ │ ├── layout/
│ │ │ │ └── activity_main.xml # UI layout
│ │ │ └── values/
│ │ │ ├── strings.xml # String resources
│ │ │ └── colors.xml # Color definitions
│ │ └── AndroidManifest.xml # App manifest with permissions
│ ├── build.gradle.kts # App-level build config
│ └── proguard-rules.pro # ProGuard rules
├── gradle/wrapper/ # Gradle wrapper files
├── build.gradle.kts # Root build config
├── settings.gradle.kts # Project settings
├── gradle.properties # Gradle properties
├── gradlew # Gradle wrapper script (Unix)
├── gradlew.bat # Gradle wrapper script (Windows)
├── .mise.toml # Java 17 configuration
├── build.sh # Build helper script
└── README.md # This file
- Voice input using Google Keyboard speech-to-text
- WebSocket connection to relay server
- Auto-send on timeout or manual send
- Connection status indicator
- Open Android Studio
- File → New → New Project
- Select "Empty Activity"
- Name:
UtterAndroid - Package name:
com.utter.android - Language: Kotlin
- Minimum SDK: API 24 (Android 7.0)
- Click Finish
Add to app/build.gradle.kts:
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
// WebSocket
implementation("com.squareup.okhttp3:okhttp:4.12.0")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
// JSON
implementation("org.json:json:20231013")
}Add to AndroidManifest.xml (inside <manifest> tag, before <application>):
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />Copy the following files from this directory to your Android Studio project:
MainActivity.kt→app/src/main/java/com/utter/android/MainActivity.ktWebSocketClient.kt→app/src/main/java/com/utter/android/WebSocketClient.ktactivity_main.xml→app/src/main/res/layout/activity_main.xml
- Connect Android device or start emulator
- Click "Run" (green play button)
- App should install and launch
- Enter relay server URL (e.g.,
ws://192.168.1.100:8080for local network) - Click "Connect"
- Wait for "Connected" status
- Tap the text input field
- Use voice input from keyboard
- Text will auto-send after 2 seconds, or click "Send" button
Edit in MainActivity.kt:
private val AUTO_SEND_DELAY = 2000L // Auto-send after 2 seconds-
Start relay server on your computer:
cd relay-server npm run dev -
Start Linux client:
cd utterd python utterd -
Find your computer's local IP:
ip addr show | grep inet -
In Android app, enter server URL:
ws://YOUR_IP:8080 -
Connect and test voice input
- Check that relay server is running
- Verify IP address is correct
- Make sure Android and computer are on same WiFi network
- Check firewall settings on computer
- Grant microphone permission when prompted
- Make sure Google Voice Typing is enabled in keyboard settings
- Try using Gboard (Google Keyboard)
- Check connection status shows "Connected"
- Look at relay server logs for errors
- Verify WebSocket URL format:
ws://host:port(nothttp://)
For Phase 2+ with cloud relay server:
- Deploy relay server to Railway/Render/Fly.io
- Get the public URL (e.g.,
wss://utter-relay.railway.app) - Update server URL in Android app to use
wss://instead ofws:// - Rebuild and deploy
Important: This project requires Java 17 (not Java 25). The build is configured to use mise for Java version management.
./build.shDebug APK:
mise exec -- ./gradlew assembleDebugRelease APK (requires signing):
mise exec -- ./gradlew assembleReleaseAPK location: app/build/outputs/apk/debug/app-debug.apk
adb install app/build/outputs/apk/debug/app-debug.apkOr use Android Studio: File → Open → Select android-app folder