Search code examples
androidtext-to-speech

Text to Speech API not calling setOnUtteranceCompletedListener


What I want:
I want to be notified when TextToSpeech program has done speaking and I want to perform some GUI task when it finishes the speaking task.

What I know:

setOnUtteranceCompletedListener can be used as a call back which should notify me that it has findished speaking.It's depriciated in API level 15 but still it should work.

setOnUtteranceProgressListener is an other and a better way to receive call backs for starting finsishing and error notifications. Minimum API level 15 is required to implement this interface. I changed my minimum sdk version to 15 and tried this method as well but it didn't work for me as well.

Here is my code

    public class SpeakingNotepad extends AppCompatActivity  implements TextToSpeech.OnUtteranceCompletedListener{

    Button btnSpeak;
    EditText etText;
    TextToSpeech speaker;
    SpeechRecognizer voiceRecognizer;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_speaking_notepad);
        init();
    }

    private void init() {
        speaker = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                speaker.setLanguage(Locale.ENGLISH);
            }
        });
        speaker.setOnUtteranceCompletedListener(this);
        btnSpeak = (Button) findViewById(R.id.btnSpeak);
        btnSpeak.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(etText.getText().length()>0)
                   speaker.speak(etText.getText().toString(),TextToSpeech.QUEUE_FLUSH,null);
            }
        });
        etText = (EditText) findViewById(R.id.etText);

    }

    @Override
    public void onUtteranceCompleted(String utteranceId) {
        Log.d("textToSpeech","completed");
        Toast.makeText(this,"completed",Toast.LENGTH_LONG).show();
        btnSpeak.setBackgroundColor(Color.BLACK);
    }
}

Solution

  • EDIT : Use Handler instead of runOnUiThread() method.


    I recommend you OnUtteranceProgressListener because this API has more method to listen that TextToSpeech's state is changing.

    However, if you want to use OnUtteranceCompleted Listener, edit like as below:

     public class SpeakingNotepad extends AppCompatActivity  implements TextToSpeech.OnUtteranceCompletedListener{
        private final String UTTER_ID = "utterance";
        private final int TTS_DONE = 99;
    
        Button btnSpeak;
        EditText etText;
        TextToSpeech speaker;
        SpeechRecognizer voiceRecognizer;
    
        HashMap<String, String> ttsOptions;
        MainViewHandler g_hnd;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            g_hnd = new MainViewHandler(SpeakingNotepad.this);
            init();
        }
    
        private void init() {
            speaker = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
                @Override
                public void onInit(int status) {
                    ttsOptions = new HashMap<String, String>();
                    ttsOptions.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, UTTER_ID);
    
                    speaker.setLanguage(Locale.ENGLISH);
                }
            });
            speaker.setOnUtteranceCompletedListener(this);
            btnSpeak = (Button) findViewById(R.id.btnSpeak);
            btnSpeak.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(etText.getText().length()>0)
    //                    speaker.speak(etText.getText().toString(),TextToSpeech.QUEUE_FLUSH,null);
                        speaker.speak(etText.getText().toString(),TextToSpeech.QUEUE_FLUSH,ttsOptions);
                }
            });
            etText = (EditText) findViewById(R.id.etText);
        }
    
        @Override
        public void onUtteranceCompleted(String utteranceId) {
            if (utteranceId.equals(UTTER_ID)) {
                Log.d("textToSpeech", "completed");
                /*
                // for more common usage, use `Handler` instead of `runOnUiThread()`.
                // block
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(SpeakingNotepad.this, "completed", Toast.LENGTH_LONG).show();
                        btnSpeak.setBackgroundColor(Color.BLACK);
                    }
                });
                */
    
                // then, you just call `sendMessage()`.
                g_hnd.sendMessage(TTS_DONE);
            }
        }
    
        private static class MainViewHandler extends Handler {
            private final WeakReference<SpeakingNotepad> mAct;
    
            MainViewHandler(SpeakingNotepad act) {
                mAct = new WeakReference<SpeakingNotepad>(act);
            }
    
            public void handleMessage(Message msg) {
                SpeakingNotepad act = mAct.get();
                if (act != null) {
                    act.handleMessage(msg)
                }
            }
        }
    
        private void handleMessage(Message msg) {
            switch(msg.what) {
                case TTS_DONE:
                    Toast.makeText(SpeakingNotepad.this, "completed", Toast.LENGTH_LONG).show();
                    btnSpeak.setBackgroundColor(Color.BLACK);
                    break;
            }
        }
    }