Search code examples
androidkotlinandroid-alertdialogtext-to-speech

Automatically show/dismiss alert dialog in Kotlin with a bool


I am creating a text-to-speech app and want a dialog to be displayed to the speaker when the tts object is speaking and automatically hide itself when the finished. Anybody got a way to do this? Below is where I'm at so far, any ideas?

private lateinit var textToSpeech: TextToSpeech
private lateinit var alertDialogBuilder: AlertDialog.Builder

class MainActivity : AppCompatActivity() {
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        alertDialogBuilder = AlertDialog.Builder(this)
        textToSpeech = TextToSpeech(applicationContext,
                TextToSpeech.OnInitListener {})
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun speakToMe(view: View) {
        alertDialogBuilder.setMessage("I'm speaking!")
        alertDialogBuilder.show()
        val charSeq = "Well hello there!" as CharSequence
        textToSpeech.speak(charSeq, TextToSpeech.QUEUE_FLUSH, null, "")
        while (!textToSpeech.isSpeaking){
            // alertDialogBuilder.dismiss() or some other fun I can't seem to find
        }
    }
}

Solution

  • You can't use while in this way from the main thread because it will lock up the UI and you can get an ANR (application not responding crash).

    When you start the speech, give it an ID, and then add a listener to respond to the result Since the listener might be called on another thread, you have to use runOnUiThread or a coroutine to go back to the main thread to manipulate your UI again.

    When you call dialogBuilder.show(), store the returned AlertDialog so you can close it later.

    By the way, there is no reason to cast the String to a CharSequence. You can just pass it to the function and it's recognized as a CharSequence by the compiler.

        fun speakToMe(view: View) {
            alertDialogBuilder.setMessage("I'm speaking!")
            val dialog = alertDialogBuilder.show()
            val charSeq = "Well hello there!"
            val id = "speechId"
            textToSpeech.speak(charSeq, TextToSpeech.QUEUE_FLUSH, null, id)
            textToSpeech.onUtteranceProgressListener = object: UtteranceProgressListener {
                override fun onDone(utteranceId: String) {
                    if (id == utteranceId) { 
                        runOnUiThread { dialog.dismiss() }
                    }
                }
            }
        }