šŸ—£ An overlay that gets your userā€™s voice permission and input as text in a customizable UI

Overview

Voice Overlay for Android

Platform Android License: MIT Android Arsenal

Overview

Voice overlay helps you turn your user's voice into text, providing a polished UX while handling for you the necessary permission.

       

Demo

You can clone this repo, then run the Demo project by doing ./gradlew app:installDebug and launching the application:

Installation

The Voice overlay is available as a gradle dependency via JCenter. To install it, add the following line to your app's build.gradle:

dependencies {
    // [...]
    implementation 'com.algolia.instantsearch:voice:1.0.0-beta02'
    // [...]
}

Usage

Basic usage

  1. In your Activity, check if you have the permission and show the appropriate Dialog:
if (!isRecordAudioPermissionGranted()) {
    VoicePermissionDialogFragment().show(supportFragmentManager, "DIALOG_PERMISSION")
} else {
    VoiceInputDialogFragment().show(supportFragmentManager, "DIALOG_INPUT")
}

See it implemented in the demo app.

This will display the permission dialog if the RECORD_AUDIO permission was not yet granted, then the voice input dialog once the permission is granted.

Once the user speaks, you will get their input back by implementing VoiceSpeechRecognizer.ResultsListener:

override fun onResults(possibleTexts: Array<out String>) {
    // Do something with the results, for example:
    resultView.text = possibleTexts.firstOrNull()?.capitalize()
}

See it implemented in the demo app.

When the permission is not granted

If the user didn't accept the permission, you should explain the permission's rationale. If they deny the permission, you need to guide them into manually enabling it if they want to use the voice-input feature.

Voice overlay makes it easy to handle all these cases:

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (Voice.isRecordPermissionWithResults(requestCode, grantResults)) {
        when {
            Voice.isPermissionGranted(grantResults) -> showVoiceDialog()
                shouldExplainPermission() -> showPermissionRationale(getPermissionView())
                else -> Voice.showPermissionManualInstructions(getPermissionView())
        }
    }
    // [...] eventual handling of other permissions requested by your app 
}

See it implemented in the demo app.

This will display the permission rationale when the user doesn't allow it, and the manual instructions in case they denied it.

Customization

You can customize your voice overlay in the following ways:

Behavior

Several options let you adapt the voice overlay's behavior to your needs.

Suggestions

You can provide suggestions of what the user could say, to give them some examples.

voiceInputDialogFragment.setSuggestions(
    "64GB Smartphone",
    "Red running shoes",
    "Cheap TV screen"
)

AutoStart

You can prevent the overlay from automatically listening to user input.

/// Requires the user to click the mic to start listening. 
voiceInputDialogFragment.autoStart = false
// [...]
// you can also start listening programmatically with
voiceInputDialogFragment.start()

Copy text

You can change any text displayed in the overlay by overriding its resource in your strings.xml:

<!-- VoiceInputDialogFragment -->
<string name="input_title_listening">Listeningā€¦</string>
<string name="input_subtitle_listening">Say something like:</string>
<string name="input_title_error">Sorry, we didn\'t quite get that.</string>
<string name="input_subtitle_error">Try repeating your request.</string>
<string name="input_hint_error">Try again</string>

<!-- VoicePermissionDialogFragment -->
<string name="permission_title">You can use voice search to find products.</string>
<string name="permission_subtitle">May we access your deviceā€™s microphone to enable voice search?</string>
<string name="permission_button_allow">Allow microphone access</string>
<string name="permission_button_reject">No</string>

<!-- Rationale/Try Again -->
<string name="permission_rationale">Voice search requires this permission.</string>
<string name="permission_button_again">Request again?</string>

<!-- Manual Instructions -->
<string name="permission_enable_rationale">Permission denied, allow it to use voice search.</string>
<string name="permission_button_enable">Allow recording</string>
<string name="permission_enable_instructions">On the next screen, tap Permissions then Microphone.</string>

Layouts

You can replace the voice overlay's layouts by your own, as long as they respect the following structure:

Permission

Create a layout called voice_input.xml with

  • A ViewGroup container with id @+id/voicePermission
  • A View with id @+id/close for closing the overlay when clicked
  • A TextView with id @+id/title
  • A TextView with id @+id/subtitle

Input

Create a layout called voice_permission.xml with

  • A ViewGroup container with id @+id/voiceInput
  • A VoiceMicrophone with id @+id/microphone to handle the voice input
  • A TextView with id @+id/suggestions to display eventual suggestions
  • A View with id @+id/close for closing the overlay when clicked
  • A TextView with id @+id/title
  • A TextView with id @+id/subtitle
  • An eventual TextView with id @+id/hint to display a hint on error
  • An eventual RippleView with id @+id/ripple if you want to keep the animation

Getting Help

Getting involved

License

The VoiceOverlay is available under the MIT license. See the LICENSE file for more info.

Comments
  • Separate voice input from presenting fragment

    Separate voice input from presenting fragment

    Main feature:

    • Separate VoiceInput from VoiceDialogFragment acting as its presenter

    Other features:

    • Improve wrapping API to expose some SpeechRecognizer settings

    Fixes:

    • 1b5f5a1 - avoid race condition in a defensive programming way (@q-litzler let me know your thoughts on this!)

    Refactor:

    • Improve layouts
    • Simplify some logic, use templated Strings
    opened by PLNech 1
  • Feat/v2

    Feat/v2

    Voice library V2

    • [x] Integrate @q-litzler's ripple design

    • [x] Refactor Fragments to Kotlin

    • VoiceDialogFragment:

      • [x] Improve state handling
      • [x] Refactor suggestions handling (support vararg params, simpler logic)
      • [x] Centralize UI Updates
      • [x] Remove unneccesary logs
      • [x] Better errors
    • PermissionDialogFragment:

      • [x] Simplify while converting (LOC /2)
    • [x] Move demo's helper functions in the library as Voice.foo()

    opened by PLNech 1
  • refact: library revamp

    refact: library revamp

    • Update Kotlin version to 1.4.31
    • Replace deprecated plugin kotlin-android-extension
    • Migrate from android support to androidx
    • Disable stop listening button click for Android 9 and 10 (due to this bug)
    • Replace deprecated release process
    opened by Aallam 0
  • refactor: optional suggestions

    refactor: optional suggestions

    Feat

    • Make suggestions optional (adapting subtitle when any)

    UI

    • Hide "Try again" when the user clicks the button but already uttered something

    Style

    • Block body to avoid returning sth
    opened by PLNech 0
  • Feature/update coroutines and dependencies

    Feature/update coroutines and dependencies

    Use latest coroutine version and API change. Tie coroutine lifecycle to attach / detach method calls. General dependencies update Change min SDK to 14

    opened by q-litzler 0
  • Feat/customization

    Feat/customization

    • Expose autoStop
    • Expose Extension functions whenever valuable

      e.g. I felt turning isPermissionGranted(grantResult: IntArray) into IntArray.isPermissionGranted() would make sense, but only if done consistently with isRecordPermissionWithResults. As both Int.isRecordPermissionWithResults(grantResults: IntArray) and IntArray.isRecordPermissionWithResults(requestCode: Int) would feel weird, I stuck with staticness for both functions.

    • Add @JVMOverloads when it improves Java DX
    opened by PLNech 0
  • feat: Instructions for manual enabling of permission

    feat: Instructions for manual enabling of permission

    Feature

    Flow for manual enabling of recording permission.

    • Implementation in app, with default UI:
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (Voice.isRecordPermissionWithResults(requestCode, grantResults)) {
            when {
                Voice.isPermissionGranted(grantResults) -> showVoiceDialog()
                Voice.shouldExplainPermission(this) -> Voice.showPermissionRationale(getPermissionView(), this)
                else -> Voice.showPermissionManualInstructions(getPermissionView())
            }
        }
    }
    
    • Users can customize the rationale's message/CTA (whyAllow, buttonAllow), and the manual instructions' message/CTA/instructions (whyEnable, buttonEnable, howEnable)
    • If one wants a different UI, they can call Voice.openAppSettings() from their own UI logic

    Questions

    • As showPermissionRationale and showPermissionManualInstructions have two overloads for String and StringRes parameters, default arguments caused an Overload resolution ambiguity. The solution I found was a third overload with the minimum amount of arguments, but let me know if you have a better approach!

    • WDYT of refactoring all those as Activity.* extension methods? I feel it improves DX by allowing this.showX() instead of Voice.showX(this), but might pollute the scope/prevent discoverability (for example with Activity.openAppSettings()). @q-litzler what's your take on this?

    • Documenting overloads results in duplicated documentation. Is there a way to avoid that or is it a necessary evil? :thinking:

    opened by PLNech 0
  • feat(VoiceDialogFragment): Persist suggestions

    feat(VoiceDialogFragment): Persist suggestions

    Persistence of VoiceDialogFragment's state. I considered persisting VoiceInput.State too, but realized that it would require moving away from

        override fun onPause() {
            super.onPause()
            input.stopVoiceRecognition()
        }
    
        override fun onResume() {
            super.onResume()
            input.startVoiceRecognition()
        }
    

    to a more complicated handling of state. I feel it doesn't deserve the added complexity, as on fragment recreation we likely want to listen anyway (if there was an error/pause before the change, what's the value that restoring this state brings versus just listening again for input?)

    opened by PLNech 0
  • refactor: Permission dialog now uses arguments.

    refactor: Permission dialog now uses arguments.

    • Use arguments instead of public variables in fragment
    • I'm more in favor of camel casing const variables: RequestPermissionAudio rather than REQUEST_PERMISSION_AUDIO No need to yell (caps) and I always found that Kotlin required a more "smooth" approach šŸ˜†
    opened by q-litzler 0
  • Feature/feat/kotlin guidelines

    Feature/feat/kotlin guidelines

    Sorry about the "feature/feat".

    Should have been just "feature", which is the default name proposed by git flow.

    Takeaway:

    • 4 spaces continuation indent instead of 8 (please šŸ™ )
    • Use object instead of class with a companion object
    • Line breaks after class declaration
    • Line breaks in constructor parameters
    • Use = Unit for non empty methods
    • Use = ... Syntax for function with simple return values (see Voice)
    opened by q-litzler 0
  • v2.1: Some fixes and a demo app

    v2.1: Some fixes and a demo app

    Update: separated VoiceInput from presenter, see #5 Refactoring:

    • Update import value
    • Leverage requireActivity in PDF

    API Improvements:

    • only require List in VDF's listener

    Fixes:

    • fix missing negation in Voice.hasRecordPermission
    opened by PLNech 0
Releases(1.1.0)
Owner
Algolia
Open source tools for building search. Learn more at community.algolia.com
Algolia
šŸ”‘A customizable EditText for Android with a switchable eye which shows or hides the password

Sweet Password A customizable password component for Android Setup Gradle repositories { jCenter() } dependencies { compile 'mx.jesusmartinoz

JesĆŗs Alberto MartĆ­nez Mendoza 19 Apr 11, 2022
šŸ—£ An overlay that gets your userā€™s voice permission and input as text in a customizable UI

Overview Voice overlay helps you turn your user's voice into text, providing a polished UX while handling for you the necessary permission. Demo You c

Algolia 228 Nov 25, 2022
Extensible Android mobile voice framework: wakeword, ASR, NLU, and TTS. Easily add voice to any Android app!

Spokestack is an all-in-one solution for mobile voice interfaces on Android. It provides every piece of the speech processing puzzle, including voice

Spokestack 57 Nov 20, 2022
Dark-souls-overlay - Stream overlay for e.g. a death counter in dark souls

(Dark Souls) Text Overlay Stream-overlay to include in Dark-Souls sessions for e

Florian Mƶtz 0 Dec 15, 2022
Ask Permission - Simple RunTime permission manager

Ask Permission https://kishanjvaghela.github.io/Ask-Permission/ Simple RunTime permission manager How to use Add url to your gradle file compile 'com.

Kishan Vaghela 77 Nov 18, 2022
AndroidPermissions 4.2 0.0 Java Android M was added to check Permission. but Permission check processing is so dirty.

Android Permissions Checker Android M was added to check Permission. but Permission check processing is so dirty. This Project is to be simple, Checki

Steve SeongUg Jung 340 Nov 11, 2022
Ask Permission - Simple RunTime permission manager

Ask Permission https://kishanjvaghela.github.io/Ask-Permission/ Simple RunTime permission manager How to use Add url to your gradle file compile 'com.

Kishan Vaghela 77 Nov 18, 2022
Location-permission-handler - Location Permission Handler For Android

Location Permission Handler Easy way to check location permissions for Android 9

null 1 Feb 1, 2022
Speech-Text Converter is a simple task that enable the user to convert the speech to text or convert text to speech (by Mic)

Speech-Text Converter About Speech-Text Converter is a simple task that enable the user to convert the speech to text or convert text to speech (by Mi

Kareem Saeed 1 Oct 21, 2021
Add text masking functionality to Android EditText. It will prevent user from inserting not allowed signs, and format input as well.

MaskFormatter MaskFormatter adds mask functionality to your EditText. It will prevent user from inserting not allowed signs, and format input as well.

Azimo Labs 161 Nov 25, 2022
The ShowcaseView library is designed to highlight and showcase specific parts of apps to the user with an attractive and flat overlay.

The ShowcaseView library is designed to highlight and showcase specific parts of apps to the user with an attractive and flat overlay.

Mohammad Reza Eram 484 Dec 26, 2022
A library that gives full control over text related technologies such as bidirectional algorithm, open type shaping, text typesetting and text rendering

Tehreer-Android Tehreer is a library which gives full control over following text related technologies. Bidirectional Algorithm OpenType Shaping Engin

Tehreer 61 Dec 15, 2022
A new canvas drawing library for Android. Aims to be the Fabric.js for Android. Supports text, images, and hand/stylus drawing input. The library has a website and API docs, check it out

FabricView - A new canvas drawing library for Android. The library was born as part of a project in SD Hacks (www.sdhacks.io) on October 3rd. It is cu

Antwan Gaggi 1k Dec 13, 2022
A simple screen that is shown when your app gets crashed instead of the normal crash dialog. It's very similar to the one in Flutter.

Red Screen Of Death What A simple screen that is shown when your app gets crashed instead of the normal crash dialog. It's very similar to the one in

Ahmad Melegy 178 Dec 9, 2022
Android library contain custom realisation of EditText component for masking and formatting input text

Masked-Edittext Masked-Edittext android library EditText widget wrapper add masking and formatting input text functionality. Install Maven <dependency

Evgeny Safronov 600 Nov 29, 2022
A set of Android-UI components to make it easier to request permission in a user friendly way.

Permission UI A set of Android-UI components to make it easier to request permission in a user friendly way. Access background location A jetpack comp

Stefan WƤrting 54 Nov 3, 2022
User input masking library repo.

More GIFs [~3 MB] Migration Guide: v.6 This update brings breaking changes. Namely, the autocomplete flag is now a part of the CaretGravity enum, thus

red_mad_robot 1.2k Dec 20, 2022
A simple library for validating user input in forms using annotations.

ValidationKomensky for Android A simple library for validating user input in forms using annotations. Features: Validate all views at once and show fe

Inmite s.r.o. 512 Nov 20, 2022
User input masking library repo.

More GIFs [~3 MB] Migration Guide: v.6 This update brings breaking changes. Namely, the autocomplete flag is now a part of the CaretGravity enum, thus

red_mad_robot 1.2k Dec 20, 2022
My Maps displays a list of maps, each of which show user-defined markers with a title, description, and location. The user can also create a new map. The user can save maps and load them in from previous usages of the app.

My Maps Bryant Jimenez My Maps displays a list of maps, each of which show user-defined markers with a title, description, and location. The user can

null 0 Nov 1, 2021