An offline, privacy-focused speech-to-text tool for Android, built with Rust. Tap the microphone on the keyboard you already use — your speech is transcribed entirely on-device and typed into any app. Also includes live subtitles and an optional dedicated voice keyboard.
Features
- Voice input in any app: Tap the microphone on the keyboard you already use (SwiftKey, etc.) or a website's voice search, and your speech is transcribed straight into the text field. The app registers as your device's speech-to-text provider.
- 100% offline & private: The Parakeet TDT model runs entirely on-device — no audio ever leaves your phone, and no network is required.
- Live Subtitles: Real-time captions for any audio/video playing on your device.
- Optional voice keyboard: A built-in keyboard you can switch to for voice input wherever you prefer it.
- Supported Languages: Bulgarian, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hungarian, Italian, Latvian, Lithuanian, Maltese, Polish, Portuguese, Romanian, Slovak, Slovenian, Spanish, Swedish, Russian, Ukrainian.
- Rust Backend: Efficient and safe native code using transcribe-rs.
Screenshots
Usage
Voice input in any app (recommended)
- Open Offline Voice Input once and grant the microphone permission. The home screen shows a Voice input status — green when you're ready to go.
- In any app, tap the microphone on your keyboard (e.g. Microsoft SwiftKey) or the voice-search mic on a website. A compact panel slides up over the app you're in, you speak, and your words are inserted as text. Tap to stop — or enable Auto-stop after silence in the app's settings to have it stop by itself.
The app plugs into Android's speech-to-text in three ways, so it works with a wide range of keyboards and apps:
| Path | Who uses it | What happens |
|---|---|---|
Voice-input popup (RECOGNIZE_SPEECH) |
SwiftKey, website voice search, many apps | The compact bottom panel opens over the current app |
System speech service (RecognitionService) |
Keyboards/apps using Android's SpeechRecognizer |
Recognition runs invisibly in the background with automatic endpointing |
| Voice keyboard (IME) | Any keyboard, via the keyboard switcher — also HeliBoard/AnySoftKeyboard-style "switch to voice IME" mic keys | The dedicated voice keyboard opens |
Tap Try voice input on the home screen to test the whole flow in one tap.
Keyboard notes:
- SwiftKey: works out of the box. If SwiftKey's own voice typing opens instead, go to SwiftKey Settings → Rich input → turn off Multi-modal voice typing.
- HeliBoard / AnySoftKeyboard / OpenBoard: their mic key switches to the system voice input keyboard — enable the Offline Voice Input keyboard (see below) and it will be used automatically.
- Gboard: only uses Google's own voice typing, so it can't hand speech to this app. Use one of the keyboards above, or the built-in voice keyboard.
- If Android shows a chooser, pick Offline Voice Input and tap Always. If another app always opens, clear its default in Settings → Apps.
Dedicated voice keyboard (optional)
Prefer voice input as its own keyboard? Enable the Offline Voice Input keyboard via Open Keyboard Settings on the home screen, switch to it from your keyboard switcher, then tap Tap to Record. By default the recording keeps running even if you switch apps or the keyboard closes (turn off Record in background in settings if you don't want that) — the text is inserted when you come back.
Live subtitles
Tap Start Live Subtitles and choose Share entire screen to get real-time, on-device captions for any audio or video playing on your device.
Prerequisites
| Dependency | Installation |
|---|---|
| JDK 17 | Android Studio (bundled) or sudo pacman -S jdk17-openjdk |
| Android SDK | Via Android Studio or sdkmanager |
| Android NDK | sdkmanager "ndk;28.0.13004108" |
| Rust | rustup.rs + rustup target add aarch64-linux-android |
| cargo-ndk | cargo install cargo-ndk |
Local Configuration
Create a local.properties file in the project root (this file is gitignored):
sdk.dir=/path/to/your/Android/SdkIf your default Java is not JDK 17, uncomment and set org.gradle.java.home in gradle.properties:
org.gradle.java.home=/path/to/jdk17 # Examples: # /opt/android-studio/jbr (Android Studio bundled JBR) # /usr/lib/jvm/java-17-openjdk (System JDK 17)
Building
Debug APK
./gradlew assembleDebug
# Output: app/build/outputs/apk/debug/app-debug.apkRelease APK
./gradlew assembleRelease
# Output: app/build/outputs/apk/release/app-release.apkRelease AAB (Google Play)
./gradlew bundleRelease
# Output: app/build/outputs/bundle/release/app-release.aabSigning
For release builds, place a release.keystore in the project root and set these environment variables:
export KEY_ALIAS=release export KEY_PASS=yourpassword export STORE_PASS=yourpassword
Model Assets
The Parakeet TDT model files (~670 MB) are automatically downloaded from HuggingFace during the first build via a Gradle task. Checksums are verified with SHA-256. No manual download is needed.
Project Structure
├── app/
│ └── src/main/
│ ├── AndroidManifest.xml
│ ├── java/dev/notune/transcribe/ # Android Java code
│ ├── res/ # Resources (layouts, drawables, etc.)
│ ├── assets/ # Model files (downloaded at build time)
│ └── jniLibs/ # Native .so files (built by cargo-ndk)
├── src/ # Rust source code (cdylib)
├── transcribe-rs/ # Rust transcription library (submodule)
├── Cargo.toml # Rust workspace
├── build.gradle.kts # Root Gradle config
├── app/build.gradle.kts # App module config (AGP 8.7.3)
├── settings.gradle.kts
├── gradle.properties
└── fastlane/metadata/android/ # F-Droid metadata
Acknowledgments
- Speech Model: Parakeet TDT 0.6b v3 by NVIDIA.
- Inference Backend: transcribe-rs by CJ Pais.




