GitHub - notune/android_transcribe_app: Offline voice input keyboard & live subtitle tool for Android

5 min read Original article ↗

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.

Get it on GitHub Get it on Google Play

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)

  1. 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.
  2. 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/Sdk

If 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.apk

Release APK

./gradlew assembleRelease
# Output: app/build/outputs/apk/release/app-release.apk

Release AAB (Google Play)

./gradlew bundleRelease
# Output: app/build/outputs/bundle/release/app-release.aab

Signing

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

License

MIT