package com.atomjack.vcfp; import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.speech.tts.TextToSpeech; import android.speech.tts.UtteranceProgressListener; import android.widget.Toast; import com.atomjack.shared.Logger; import com.atomjack.shared.Preferences; import java.util.HashMap; public class Feedback implements TextToSpeech.OnInitListener { public final static int FEEDBACK_VOICE = 0; public final static int FEEDBACK_TOAST = 1; private TextToSpeech feedbackTts = null; private TextToSpeech errorsTts = null; private Context context; private String feedbackQueue = null; private String errorsQueue = null; private Runnable onFinish = null; public Feedback(Context ctx) { context = ctx; errorsTts = new TextToSpeech(context, this); // errorsQueue = filterText(text); errorsTts.setOnUtteranceProgressListener(utteranceProgressListener); feedbackTts = new TextToSpeech(context, this); // feedbackQueue = filterText(text); feedbackTts.setOnUtteranceProgressListener(utteranceProgressListener); } private HashMap<String, String> map = new HashMap<String, String>(); private int utteranceId = 0; @Override public void onInit(int i) { Logger.d("Feedback onInit"); if(errorsTts != null) errorsTts.setLanguage(VoiceControlForPlexApplication.getVoiceLocale(VoiceControlForPlexApplication.getInstance().prefs.get(Preferences.ERRORS_VOICE, null))); if(feedbackTts != null) feedbackTts.setLanguage(VoiceControlForPlexApplication.getVoiceLocale(VoiceControlForPlexApplication.getInstance().prefs.get(Preferences.FEEDBACK_VOICE, null))); if(errorsQueue != null) { feedback(errorsQueue, true); errorsQueue = null; } if(feedbackQueue != null) { feedback(feedbackQueue, true); feedbackQueue = null; } } public void destroy() { if(errorsTts != null) errorsTts.shutdown(); if(feedbackTts != null) feedbackTts.shutdown(); } public void m(String text, Object... arguments) { text = String.format(text, arguments); m(text); } public void e(String text, Object... arguments) { text = String.format(text, arguments); e(text); } public void m(String text, Runnable _onFinish) { onFinish = _onFinish; feedback(text, false); } public void m(int id, Runnable _onFinish) { onFinish = _onFinish; feedback(context.getString(id), false); } public void m(String text) { feedback(text, false); } public void m(int id) { feedback(context.getString(id), false); } public void e(String text) { feedback(text, true); } public void e(int id) { feedback(context.getString(id), true); } public void t(int id) { feedback(context.getString(id), false, true); } public void v(int id) { feedback(context.getString(id), false, false, true); } public void v(String text) { feedback(text, false, false, true); } protected void feedback(String text, boolean errors) { feedback(text, errors, false); } protected void feedback(String text, boolean errors, boolean forceToast) { feedback(text, errors, forceToast, false); } protected void feedback(String text, boolean errors, boolean forceToast, boolean forceVoice) { if(forceVoice || (!forceToast && VoiceControlForPlexApplication.getInstance().prefs.get(errors ? Preferences.ERRORS : Preferences.FEEDBACK, FEEDBACK_TOAST) == FEEDBACK_VOICE)) { doVoice(text, errors); } else { doToast(text); } } private void doToast(String text) { Toast.makeText(context, text, Toast.LENGTH_SHORT).show(); if(onFinish != null) onFinish.run(); onFinish = null; } private void doVoice(String text, boolean errors) { TextToSpeech tts = errors ? errorsTts : feedbackTts; if (tts == null) { // This tts not set up yet, so initiate it and add the text to be spoken to the appropriate queue. // The text will be spoken when the tts is finished setting up (in onInit) if (errors) { errorsTts = new TextToSpeech(context, this); errorsQueue = filterText(text); errorsTts.setOnUtteranceProgressListener(utteranceProgressListener); } else { feedbackTts = new TextToSpeech(context, this); feedbackQueue = filterText(text); feedbackTts.setOnUtteranceProgressListener(utteranceProgressListener); } } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { ttsGreater21(tts, text); } else { ttsUnder20(tts, text); } if (errors) errorsQueue = null; else feedbackQueue = null; } } @SuppressWarnings("deprecation") private void ttsUnder20(TextToSpeech tts, String text) { map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, Integer.toString(utteranceId++)); tts.speak(text, TextToSpeech.QUEUE_FLUSH, map); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void ttsGreater21(TextToSpeech tts, String text) { String utteranceId = this.hashCode() + ""; tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, utteranceId); } // Filter out some extraneous patterns, like when a connection is refused, strip out the uri. private String filterText(String text) { text = text.replaceAll("to https?://([0-9]+\\.){3}[0-9]+:[0-9]+ refused", " refused"); return text; } @SuppressWarnings("deprecation") private UtteranceProgressListener utteranceProgressListener = new UtteranceProgressListener() { @Override public void onStart(String s) { } @Override public void onDone(String s) { if(onFinish != null) onFinish.run(); onFinish = null; } @Override public void onError(String s) { } }; }