This is caused by the Voice features being set to null. The fix in
Android Marshmallow is to make onGetFeaturesForLanguage return an
empty HashSet object. This does not work for eSpeak because:
1. eSpeak was overriding onGetVoices and initializing each Voice's
features to null;
2. the bug is still present on Lollipop.
Thus, the fix here is two-fold:
1. make onGetVoices use onGetFeaturesForLanguage;
2. make onGetFeaturesForLanguage return an empty HashSet, so that
eSpeak does not crash on Lollipop either.
As of Android 5.0, TextToSpeech.setLanguage calls the new
TextToSpeechService.onGetDefaultVoiceNameFor(lang,country,variant)
and uses the specified voice name.
The default Android 5.0 implementation of onGetDefaultVoiceNameFor
does not work with eSpeak. This provides a working implementation.
This fixes the TextToSpeechTest.testLanguages tests on Android 5.0.
SpeechSynthesis.java: expose the different voice options from eSpeak
This makes the following changes:
1. setVoice takes a Voice object instead of a language string.
This is to make the API cleaner and allows SpeechSynthesis
to pass the correct parameter (identifier for SetVoiceByName,
or name for SetVoiceByProperties) to espeak.
2. The espeak_SetVoiceByName API is also exposed to support passing
the voice variant to use.
3. The age parameter has been re-added with the constants:
* SpeechSynthesis.AGE_ANY
* SpeechSynthesis.AGE_YOUNG
* SpeechSynthesis.AGE_OLD
based on the behaviour of the eSpeak voice selection algorithm.
NOTE: Due to the way that voice selection is implemented in eSpeak,
if variant is specified, the age and gender cannot be specified and
vice versa.
SpeechSynthesis.java: further simplify the setVoice method.
This renames `setVoiceByProperties` to the more consise `setVoice`
and removes the name parameter as this is not used -- the voice is
set by the language and gender parameters only.
SpeechSynthesis.java: Simplify the SetVoiceByProperties parameters.
The `age` parameter is not useful as eSpeak does not use this when
selecting voices. This is always set to `0` by TtsService.java.
The `variant` parameter is not used to select the actual voice
variant (from the `!v` directory) but to select the n^th matching
voice from the list of matching voices. This is always set to
select the first matching voice by TtsService.java.
TtsService.java: ensure that the voice data is installed/upgraded correctly.
When using assistive technology like TalkBack and not accessing
either the eSpeak application or the Android TTS settings
directly, the voice data would previously not be installed/upgraded
correctly.
The approach here is to move the logic to onIsLanguageAvailable so
that if the espeak voice data is not installed or is upgradable
then trigger an install of the voice data and return
TextToSpeech.LANG_MISSING_DATA.