forked from organicmaps/organicmaps
Merge pull request #2818 from trashkalmar/tts-crash-guards
[android] fix: Prevent crash if the TTS is corrupted.
This commit is contained in:
commit
a99bc4a938
3 changed files with 69 additions and 23 deletions
|
@ -10,8 +10,8 @@ import java.util.Locale;
|
|||
*/
|
||||
public class LanguageData
|
||||
{
|
||||
public static class NotAvailableException extends Exception {
|
||||
public NotAvailableException(Locale locale)
|
||||
static class NotAvailableException extends Exception {
|
||||
NotAvailableException(Locale locale)
|
||||
{
|
||||
super("Locale \"" + locale + "\" is not supported by current TTS engine");
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ public class LanguageData
|
|||
public final String internalCode;
|
||||
public final boolean downloaded;
|
||||
|
||||
public LanguageData(String line, String name, TextToSpeech tts) throws NotAvailableException
|
||||
LanguageData(String line, String name, TextToSpeech tts) throws NotAvailableException, IllegalArgumentException
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
|
@ -36,6 +36,7 @@ public class LanguageData
|
|||
String country = (parts.length > 1 ? parts[1] : "");
|
||||
locale = new Locale(language, country);
|
||||
|
||||
// tts.isLanguageAvailable() may throw IllegalArgumentException if the TTS is corrupted internally.
|
||||
int status = tts.isLanguageAvailable(locale);
|
||||
if (status < TextToSpeech.LANG_MISSING_DATA)
|
||||
throw new NotAvailableException(locale);
|
||||
|
@ -43,7 +44,7 @@ public class LanguageData
|
|||
downloaded = (status >= TextToSpeech.LANG_AVAILABLE);
|
||||
}
|
||||
|
||||
public boolean matchesLocale(Locale locale)
|
||||
boolean matchesLocale(Locale locale)
|
||||
{
|
||||
String lang = locale.getLanguage();
|
||||
if (!lang.equals(this.locale.getLanguage()))
|
||||
|
@ -61,7 +62,7 @@ public class LanguageData
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean matchesInternalCode(String internalCode)
|
||||
boolean matchesInternalCode(String internalCode)
|
||||
{
|
||||
return this.internalCode.equals(internalCode);
|
||||
}
|
||||
|
|
|
@ -7,15 +7,17 @@ import android.support.annotation.NonNull;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.mapswithme.maps.Framework;
|
||||
import com.mapswithme.maps.MwmApplication;
|
||||
import com.mapswithme.maps.R;
|
||||
import com.mapswithme.util.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.mapswithme.maps.Framework;
|
||||
import com.mapswithme.maps.MwmApplication;
|
||||
import com.mapswithme.maps.R;
|
||||
import com.mapswithme.util.Config;
|
||||
import com.mapswithme.util.statistics.Statistics;
|
||||
|
||||
/**
|
||||
* {@code TtsPlayer} class manages available TTS voice languages.
|
||||
* Single TTS language is described by {@link LanguageData} item.
|
||||
|
@ -46,6 +48,13 @@ public enum TtsPlayer
|
|||
|
||||
TtsPlayer() {}
|
||||
|
||||
private static void reportFailure(IllegalArgumentException e, String location)
|
||||
{
|
||||
Statistics.INSTANCE.trackEvent(Statistics.EventName.TTS_FAILURE_LOCATION,
|
||||
Statistics.params().add(Statistics.EventParam.ERR_MSG, e.getMessage())
|
||||
.add(Statistics.EventParam.FROM, location));
|
||||
}
|
||||
|
||||
private static @Nullable LanguageData findSupportedLanguage(String internalCode, List<LanguageData> langs)
|
||||
{
|
||||
if (TextUtils.isEmpty(internalCode))
|
||||
|
@ -70,17 +79,27 @@ public enum TtsPlayer
|
|||
return null;
|
||||
}
|
||||
|
||||
private void setLanguageInternal(LanguageData lang)
|
||||
private boolean setLanguageInternal(LanguageData lang)
|
||||
{
|
||||
mTts.setLanguage(lang.locale);
|
||||
nativeSetTurnNotificationsLocale(lang.internalCode);
|
||||
Config.setTtsLanguage(lang.internalCode);
|
||||
try
|
||||
{
|
||||
mTts.setLanguage(lang.locale);
|
||||
nativeSetTurnNotificationsLocale(lang.internalCode);
|
||||
Config.setTtsLanguage(lang.internalCode);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
reportFailure(e, "setLanguageInternal(): " + lang.locale);
|
||||
lockDown();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setLanguage(LanguageData lang)
|
||||
public boolean setLanguage(LanguageData lang)
|
||||
{
|
||||
if (lang != null)
|
||||
setLanguageInternal(lang);
|
||||
return (lang != null && setLanguageInternal(lang));
|
||||
}
|
||||
|
||||
private static @Nullable LanguageData getDefaultLanguage(List<LanguageData> langs)
|
||||
|
@ -147,8 +166,16 @@ public enum TtsPlayer
|
|||
private void speak(String textToSpeak)
|
||||
{
|
||||
if (Config.isTtsEnabled())
|
||||
//noinspection deprecation
|
||||
mTts.speak(textToSpeak, TextToSpeech.QUEUE_ADD, null);
|
||||
try
|
||||
{
|
||||
//noinspection deprecation
|
||||
mTts.speak(textToSpeak, TextToSpeech.QUEUE_ADD, null);
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
reportFailure(e, "speak()");
|
||||
lockDown();
|
||||
}
|
||||
}
|
||||
|
||||
public void playTurnNotifications()
|
||||
|
@ -164,7 +191,15 @@ public enum TtsPlayer
|
|||
public void stop()
|
||||
{
|
||||
if (isReady())
|
||||
mTts.stop();
|
||||
try
|
||||
{
|
||||
mTts.stop();
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
reportFailure(e, "stop()");
|
||||
lockDown();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled()
|
||||
|
@ -178,7 +213,7 @@ public enum TtsPlayer
|
|||
nativeEnableTurnNotifications(enabled);
|
||||
}
|
||||
|
||||
private void getUsableLanguages(List<LanguageData> outList)
|
||||
private boolean getUsableLanguages(List<LanguageData> outList)
|
||||
{
|
||||
Resources resources = MwmApplication.get().getResources();
|
||||
String[] codes = resources.getStringArray(R.array.tts_languages_supported);
|
||||
|
@ -189,14 +224,23 @@ public enum TtsPlayer
|
|||
try
|
||||
{
|
||||
outList.add(new LanguageData(codes[i], names[i], mTts));
|
||||
} catch (LanguageData.NotAvailableException ignored)
|
||||
{}
|
||||
}
|
||||
catch (LanguageData.NotAvailableException ignored) {}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
reportFailure(e, "getUsableLanguages()");
|
||||
lockDown();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private @Nullable LanguageData refreshLanguagesInternal(List<LanguageData> outList)
|
||||
{
|
||||
getUsableLanguages(outList);
|
||||
if (!getUsableLanguages(outList))
|
||||
return null;
|
||||
|
||||
if (outList.isEmpty())
|
||||
{
|
||||
|
|
|
@ -98,6 +98,7 @@ public enum Statistics
|
|||
public static final String DOWNLOAD_COUNTRY_NOTIFICATION_CLICKED = "Download country notification clicked";
|
||||
public static final String ACTIVE_CONNECTION = "Connection";
|
||||
public static final String STATISTICS_STATUS_CHANGED = "Statistics status changed";
|
||||
public static final String TTS_FAILURE_LOCATION = "TTS failure location";
|
||||
// routing
|
||||
public static final String ROUTING_BUILD = "Routing. Build";
|
||||
public static final String ROUTING_START_SUGGEST_REBUILD = "Routing. Suggest rebuild";
|
||||
|
|
Loading…
Add table
Reference in a new issue