From d30cbbcbe8276934322a1c8db496604b197d7a08 Mon Sep 17 00:00:00 2001 From: Brian Whitmer Date: Thu, 28 Sep 2017 11:35:47 -0600 Subject: [PATCH] Catch tts.getVoices error On Samsung Galaxy S4 there is an unexpected error that happens sometimes when users are using the Samsung default voice and tts.getVoices is called. This catches the error and notes the problem, falling back to the old approach to getting a list of locales since the voice list is not available. --- src/android/SpeechSynthesis.java | 53 ++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/src/android/SpeechSynthesis.java b/src/android/SpeechSynthesis.java index cfa0406..8449d26 100644 --- a/src/android/SpeechSynthesis.java +++ b/src/android/SpeechSynthesis.java @@ -32,6 +32,7 @@ public class SpeechSynthesis extends CordovaPlugin implements OnInitListener, On private static final int STARTED = 2; private TextToSpeech mTts = null; private int state = STOPPED; + private boolean retrieval_error = false; private CallbackContext startupCallbackContext; private CallbackContext callbackContext; @@ -60,7 +61,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo voiceCode = voice.optString("voiceURI", null); } } - if (voiceCode != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (voiceCode != null && voiceList != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { for (Voice v : this.voiceList) { if (voiceCode.equals(v.getName())) { mTts.setVoice(v); @@ -138,8 +139,9 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo PluginResult pluginResult = new PluginResult(status, SpeechSynthesis.INITIALIZING); pluginResult.setKeepCallback(true); startupCallbackContext.sendPluginResult(pluginResult); + } else if(action.equals("error_check")) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, retrieval_error)); } - else if (action.equals("shutdown")) { @@ -168,26 +170,37 @@ private void getVoices(CallbackContext callbackContext) { JSONObject voice; //List engines = mTts.getEngines(); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { - this.voiceList = mTts.getVoices(); - for (Voice v : this.voiceList) { - Locale locale = v.getLocale(); - voice = new JSONObject(); - try { - voice.put("voiceURI", v.getName()); - voice.put("name", locale.getDisplayLanguage(locale) + " " + locale.getDisplayCountry(locale)); - //voice.put("features", v.getFeatures()); - //voice.put("displayName", locale.getDisplayLanguage(locale) + " " + locale.getDisplayCountry(locale)); - voice.put("lang", locale.getLanguage()+"-"+locale.getCountry()); - voice.put("localService", !v.isNetworkConnectionRequired()); - voice.put("quality", v.getQuality()); - voice.put("default", false); - } catch (JSONException e) { - // should never happen + boolean retrieved = false; + try { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + this.voiceList = mTts.getVoices(); + for (Voice v : this.voiceList) { + Locale locale = v.getLocale(); + voice = new JSONObject(); + try { + voice.put("voiceURI", v.getName()); + voice.put("name", locale.getDisplayLanguage(locale) + " " + locale.getDisplayCountry(locale)); + //voice.put("features", v.getFeatures()); + //voice.put("displayName", locale.getDisplayLanguage(locale) + " " + locale.getDisplayCountry(locale)); + voice.put("lang", locale.getLanguage()+"-"+locale.getCountry()); + voice.put("localService", !v.isNetworkConnectionRequired()); + voice.put("quality", v.getQuality()); + voice.put("default", false); + } catch (JSONException e) { + // should never happen + } + voices.put(voice); } - voices.put(voice); + retrieved = true; } - }else{ + } catch(IllegalArgumentException e) { + // java.lang.IllegalArgumentException is raised on some Galaxy S4 devices when trying to retrieve tts voices. + // The ultimate fix is to clear the cache on the voice or delete the system's Samsung voice, but at least + // this will prevent apps from crashing. + retrieval_error = true; + } + + if(!retrieved) { //Iterator list = voiceList.iterator(); Locale[] list = Locale.getAvailableLocales(); Locale locale;