๐Ÿค– Android AI and Generative AI

Speech-to-Text and AI Voice Features on Android

Voice input is faster than typing for many users and essential for accessibility. Android offers platform speech recognition, on-device options, and cloud models that transcribe and understand. Here's how to add speech-to-text, AI-powered voice actions and text-to-speech responsibly.

โœ๏ธ Yunok Tech ๐Ÿ“… Updated โฑ 3 min read ๐ŸŽฏ Intermediate
On this page
  1. Your options
  2. Platform SpeechRecognizer as a Flow
  3. From transcript to action with AI
  4. Speaking responses: TextToSpeech
  5. Permissions and privacy
  6. Use cases
  7. Frequently asked questions
  8. Conclusion

Users dictate messages while walking, search hands-free in the kitchen, and record voice notes in meetings. Good voice features are fast, accurate in the user's language and accent, respectful of privacy, and always have a typing fallback.

Your options

OptionStrengthsLimits
Platform SpeechRecognizerBuilt in, streaming partial results, many languages; on-device recognition on newer Android versionsShort utterances; behaviour depends on the device's recognition service
ML Kit GenAI Speech RecognitionOn-device transcription (alpha at the time of writing)Device and mode support varies; alpha API
Cloud multimodal model (e.g. Gemini with audio input)Transcribe and summarise, translate or extract in one stepNetwork, cost, privacy considerations
Dedicated cloud speech APIsLong-form, diarization, specialised modelsBackend integration and cost
Voice feature pipeline The microphone captures audio after RECORD_AUDIO permission. Speech-to-text produces a transcript, shown live to the user. Optionally an AI model interprets the transcript into an intent or summary. The app confirms and performs the action, and text-to-speech can speak a response. ๐ŸŽ™ Micpermission Speech-to-textpartial results AI (optional)intent / summary Confirm + actuser in control ๐Ÿ”Š TTSoptional
Show the transcript as it forms and confirm before acting. Speech recognition makes mistakes.

Platform SpeechRecognizer as a Flow

SpeechInput.ktKotlin
sealed interface SpeechEvent {
    data class Partial(val text: String) : SpeechEvent
    data class Final(val text: String) : SpeechEvent
    data class Error(val code: Int) : SpeechEvent
}

@RequiresPermission(Manifest.permission.RECORD_AUDIO)
fun Context.listen(languageTag: String = Locale.getDefault().toLanguageTag()): Flow<SpeechEvent> = callbackFlow {
    val recognizer =
        if (Build.VERSION.SDK_INT >= 31 && SpeechRecognizer.isOnDeviceRecognitionAvailable(this@listen))
            SpeechRecognizer.createOnDeviceSpeechRecognizer(this@listen)   // audio stays on device
        else SpeechRecognizer.createSpeechRecognizer(this@listen)

    recognizer.setRecognitionListener(object : RecognitionListener {
        override fun onPartialResults(b: Bundle) {
            b.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)?.firstOrNull()?.let { trySend(SpeechEvent.Partial(it)) }
        }
        override fun onResults(b: Bundle) {
            trySend(SpeechEvent.Final(b.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)?.firstOrNull().orEmpty()))
            close()
        }
        override fun onError(error: Int) { trySend(SpeechEvent.Error(error)); close() }
        override fun onReadyForSpeech(p: Bundle?) {}
        override fun onBeginningOfSpeech() {}
        override fun onRmsChanged(rms: Float) {}
        override fun onBufferReceived(b: ByteArray?) {}
        override fun onEndOfSpeech() {}
        override fun onEvent(t: Int, b: Bundle?) {}
    })
    recognizer.startListening(Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
        putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
        putExtra(RecognizerIntent.EXTRA_LANGUAGE, languageTag)            // e.g. "hi-IN", "en-IN"
        putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true)
    })
    awaitClose { recognizer.destroy() }
}.flowOn(Dispatchers.Main)   // SpeechRecognizer must be used from the main thread

From transcript to action with AI

A transcript like "remind me to call the plumber tomorrow at 10" can be turned into a structured intent by a model, using structured output or function calling. See Function Calling.

Parse a voice command into a structured reminderKotlin
@Serializable data class ReminderIntent(val title: String, val dateTimeIso: String?)

suspend fun parseReminder(model: GenerativeModel, transcript: String, nowIso: String): ReminderIntent? {
    val response = model.generateContent(
        "Current time: $nowIso. Extract a reminder from the user's words as JSON with fields " +
        "title and dateTimeIso (ISO-8601, null if no time). User said: <said>$transcript</said>"
    )
    return runCatching { Json { ignoreUnknownKeys = true }.decodeFromString<ReminderIntent>(response.text.orEmpty()) }.getOrNull()
}
// Always show: "Create reminder 'Call the plumber' for tomorrow 10:00?" โ†’ user confirms.

Speaking responses: TextToSpeech

Speaker.ktKotlin
class Speaker(context: Context) : TextToSpeech.OnInitListener {
    private val tts = TextToSpeech(context, this)
    private var ready = false
    override fun onInit(status: Int) { ready = status == TextToSpeech.SUCCESS }
    fun say(text: String, locale: Locale = Locale.getDefault()) {
        if (!ready) return
        tts.language = locale
        tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, "utt-${text.hashCode()}")
    }
    fun shutdown() = tts.shutdown()
}

Permissions and privacy

  • Request RECORD_AUDIO in context, when the user taps the mic, and explain why.
  • Show a clear recording indicator, and stop listening when the user leaves the screen.
  • Prefer on-device recognition for sensitive content. Disclose any cloud processing and retention.
  • Never record in the background without explicit, ongoing user awareness.

Use cases

Dictation in forms

Mic button on text fields, with partial results shown live and editable.

Voice notes

Record, transcribe and summarise. See AI Voice-Notes App.

Hands-free commands

Transcribe, parse the intent, confirm, act, speak the result.

Frequently asked questions

Does SpeechRecognizer support Indian languages?

Support depends on the recognition service and language packs on the device. Many devices support Hindi and other Indian languages. Test on target devices, and fall back to typing.

Can I transcribe long recordings?

SpeechRecognizer is designed for short utterances. For long recordings, record audio to a file and transcribe it with an on-device model or a cloud service.

Is audio sent to Google?

With on-device recognizers, audio is processed locally. Other recognition services or cloud APIs may send audio to servers, so check the service and disclose it to users.

Conclusion

Voice features combine speech-to-text (platform, on-device or cloud), optional AI interpretation into structured intents, confirmation before actions, and optional text-to-speech. Request the microphone in context, prefer on-device for privacy, and always keep a typing path.

Next step: generate useful content with AI in Using AI to Generate App Content Dynamically.

Official references

๐Ÿ“ฑ Apps built by Yunok Tech

Real Android apps on Google Play, free to download.

See all our apps โ†’

Ready to build real Android applications?

Every AI feature still runs inside an Android app that has to be fast, reliable and well structured. Strengthen the Kotlin, Jetpack Compose and architecture skills that AI integrations depend on, then apply these AI concepts with confidence.

Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.

Explore the Android course and take your next step as an Android developer.

Share: LinkedIn X / Twitter WhatsApp