I'm playing with text to speech to make my testapp a little more fun. It works in the emulator but not on my phone since my default locale isn't english.
However, the texts are english so the tts should of course use english. As far as I know I can implement an autoninstall, something like
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
// Set preferred language to US english.
int result = mtts.setLanguage(Locale.US);
if (result == TextToSpeech.LANG_MISSING_DATA ||
result == TextToSpeech.LANG_NOT_SUPPORTED) {
// Lanuage data is missing or the language is not supported.
Log.e(TAG, "Language is not available.");
} else {
// The TTS engine has been successfully initialized.
speak();
}
} else {
// missing data, install it
Intent installIntent = new Intent();
installIntent.setAction(
TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
}
But, do I want to? Does installing locales take a lot of space? Does it mess up something else?
regards
You should execute this:
// missing data, install it
Intent installIntent = new Intent();
installIntent.setAction(
TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
when you get LANG_MISSING_DATA
I would only try the install in the case where "LANG_MISSING_DATA" not for "LANG_NOT_SUPPORTED". Since it starts another activity and the user can choose whether they download it or not, I wouldn't worry too much about it taking space. No, it shouldn't mess anything up.
Android allows you convert your text into voice. Not only you can convert it but it also allows you to speak text in variety of different languages.
Android provides TextToSpeech class for this purpose.
For more detail please follow this tutorial :-
http://a-droidtech.blogspot.in/2015/06/android-text-to-speech-tutorial-android.html
Related
Is there any way in Java to detect if an Android device has an offline speech recognition language installed, and if it does not prompt the user to download it?
I know you can ask to speech to text to prefer offline speech to text, but how do you know if the device has the language installed?
This question is not on how to use offline speech, this works.
The question is "how to detect and download/install offline speech languages" from Java app code. i.e. have the app detect if they have offline German language installed, and if not prompt the user to download/install it.
This is not the answer you are hoping for, as at the time of writing, I don't believe there is a straight forward solution to this. I very much hope to be proved wrong.
I requested an enhancement to provide this information programmatically a long time ago - here
The enhancement suggested an additional parameter RecognizerIntent.EXTRA_SUPPORTED_OFFLINE_LANGUAGES:
It would surely be trivial for this to be added and used in the following way:
final Intent vrIntent = new Intent(RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS);
getContext().sendOrderedBroadcast(vrIntent, null, new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final ArrayList<String> vrStringLocales = intent.getExtras().getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES);
// This would be nice
final ArrayList<String> vrStringOfflineLocales = intent.getExtras().getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_OFFLINE_LANGUAGES);
}
}, null, 1234, null, null);
Alas, it has never happened.
You do have two other options to attempt to handle this gracefully.
In the unlikely event you application runs with root permissions, you can check the location of /data/data/com.google.android.googlequicksearchbox/app_g3_models/ which contains the offline files, labelled quite handily by their locale.
The second involves knowing when the user needs a prompt to install the missing offline files.
From my experience, the recognition error of SpeechRecognizer.ERROR_SERVER most often denotes this, but it is not foolproof.
#Override
public void onError(final int error) {
switch (error) {
case SpeechRecognizer.ERROR_SERVER:
// TODO - prompt to install offline files
break;
}
}
When detected, you can guide the user to the correct installation screen.
public static final String PACKAGE_NAME_GOOGLE_NOW = "com.google.android.googlequicksearchbox";
public static final String ACTIVITY_INSTALL_OFFLINE_FILES = "com.google.android.voicesearch.greco3.languagepack.InstallActivity";
public static boolean showInstallOfflineVoiceFiles(#NonNull final Context ctx) {
final Intent intent = new Intent();
intent.setComponent(new ComponentName(PACKAGE_NAME_GOOGLE_NOW, ACTIVITY_INSTALL_OFFLINE_FILES));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
ctx.startActivity(intent);
return true;
} catch (final ActivityNotFoundException e) {
} catch (final Exception e) {
}
return false;
}
Using hard-coded values such as this, is of course not ideal, but neither is this situation!
Once you've messed around with all of the above and think you have a good interim solution - think again! Regardless of whether the user has correctly installed the missing offline files, it is highly likely it still won't work.....
My answer here describes the process I still have to guide my user's with. It's very frustrating.
Finally one more bug to throw into the mix - RecognitionListener.onError(int) can be thrown when there isn't an error. Check my gist from the answer here to use a BugRecognitionListener so you can check the callbacks are being sent in the correct order and ignore those that aren't. This remains a problem, despite my answer suggesting a fix in a previous release.
The above should keep you busy! Good luck....
To detect whether needed Language(German) is available, please follow below :
Iterate the Locale list and check whether Locale available for German language.
If you didn't get any Locale object in return, you can conclude that German language is not available offline. Then you can write code to download and do other stuff.
I did below implementation for my project. Hope below code helps you !!!
private TextToSpeech t1;
private void setForOtherLangAudio() {
Locale[] locales = Locale.getAvailableLocales();
Locale loc = null;
for (Locale locale : locales) {
// Replace XXX with your German codes
if (locale.getDisplayCountry().equals("XXX") && locale.getDisplayLanguage().equals("XXX")) {
loc = locale ;
break;
}
}
final Locale germanLocale = loc;
t1 = new TextToSpeech(getContext(), new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status != TextToSpeech.ERROR) {
t1.setLanguage(germanLocale);
}
}
});
}
I have found a similar question, but I want something different.
I noticed that, when you don't have any connectivity, and you try to start Speech Recognition in an app, say through the RecognizerIntent class, you get a "no network connectivity - tap to view connectivity status" (see attached image), and if you click, a new Card with connectivity status appears.
How can I copy this behaviour in my own Activity, using the GDK?
EDIT: here is my code to call the Speech Recognition:
Intent speechIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
if (speechIntent.resolveActivity(getPackageManager()) != null) {
speechIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Talk to set your title:");
speechIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
Log.d(TAG, "Starting to record speech title");
startActivityForResult(speechIntent, Constants.SPEECH_TITLE_REQUEST_CODE);
}
Ok, I later found an answer to my problem. I'm using the MessageDialog class provided by pif
Here is how I am calling the card:
MessageDialog localDialog = new MessageDialog.Builder(context)
.setMessage("No network connectivity")
.setSecondaryMessage("Tap to view connection settings")
.setIcon(R.drawable.ic_cloud_sad_medium)
.setIsError(true)
.setDismissable(true)
.setAutoHide(false)
.setExpanded(true)
.setShowProgress(false)
.setIsManual(false)
.setListener(new MessageDialog.SimpleListener() {
public boolean onConfirmed() {
Log.d(TAG+"_noConnDialog", "onConfirm");
return true;
}
public void onDismissed() {
Log.d(TAG+"_noConnDialog", "onDismissed");
((Activity)context).finish();
}
public void onDone() {
Log.d(TAG+"_noConnDialog", "onDone");
Intent localIntent = new Intent(Settings.ACTION_WIFI_SETTINGS);
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
localIntent.putExtra("settings_id", 0);
context.startActivity(localIntent);
((Activity)context).finish();
}
}).build();
localDialog.show();
Notice that, as indicated in pif's disclaimer,
This is just for educational purposes and should not be used in any production apps until Google releases something similar officially.
I hope, Google will publish a set of Google Glass Views in the future releases of GDK. We really need them! Especially that awesome progress bar!
AFAIK the Glass Developer Team has not released these functionalities in the GDK yet.
I have this code for text to speech in my application.
public void onInit(int status) {
// TODO Auto-generated method stub
if (status == TextToSpeech.SUCCESS) {
//Setting speech language
int result = tts.setLanguage(Locale.ENGLISH);
//If your device doesn't support language you set above
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
//Cook simple toast message with message
Toast.makeText(this, "Language not supported", Toast.LENGTH_LONG).show();
//Log.e("TTS", "Language is not supported");
}
//TTS is not initialized properly
} else {
Toast.makeText(this, "TTS Initilization Failed", Toast.LENGTH_LONG).show();
//Log.e("TTS", "Initilization Failed");
}
}
My application includes many different languages like English, Hindi, Marathi, Telugu, Tamil, etc. Since the default android tts engine does not support these languages, I downloaded eSpeak tts engine from this link and installed it on my phone.
Its default language is set as English. How do i change its language in my code so that it can read unicode texts of other languages as well?
Currently, for a word in hindi script, it speaks some numbers.
How do i make it recognise the language used in the text? It shows only the locales available in the default google tts. How do I change the tts engine to eSpeak tts?
Initialize your TextToSpeech using
TextToSpeech (Context context, TextToSpeech.OnInitListener listener, String engine)
That is
tts = new TextToSpeech(this, this, "com.googlecode.eyesfree.espeak");
engine Package name of the TTS engine to use, which you can get by calling getEngines.
Try changing the Locale according to your need.
Currently it is Locale.ENGLISH change this accordingly.
I am developing a very simple app in here. It's for my Cerebral Palsy daughter. It's just a big YES and NO buttons, so she can press them when requested.
Well... I am using SVOX Classic TTS Engine.
Everything was running smoothly until my tablet upgraded to ICS. Now, everytime I run the app, it opens the Market asking for me to install TTS. I hit "back" and then, my app speaks. This is VERY annoying.
Here is what Google API says:
*A successful check will be marked by a CHECK_VOICE_DATA_PASS result code, indicating this device is ready to speak, after the creation of our TextToSpeech object. If not, we need to let the user know to install the data that's required for the device to become a multi-lingual talking machine! Downloading and installing the data is accomplished by firing off the ACTION_INSTALL_TTS_DATA intent, which will take the user to Android Market, and will let her/him initiate the download. Installation of the data will happen automatically once the download completes. Here is an example of what your implementation of onActivityResult() would look like:*
Here is my code:
public class yesOunoActivity extends Activity implements OnInitListener{
ImageView yes;
ImageView no;
public TextToSpeech tts;
private int MY_DATA_CHECK_CODE = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent checkIntent = new Intent();
checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkIntent, MY_DATA_CHECK_CODE);
tts = new TextToSpeech(this, this);
setContentView(R.layout.yesorno);
yes = (ImageView) findViewById(R.id.yes);
no = (ImageView) findViewById(R.id.no);
yes.setClickable(true);
yes.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent arg1) {
if (arg1.getAction() == android.view.MotionEvent.ACTION_DOWN) {
tts.speak("yes!", TextToSpeech.QUEUE_ADD, null);
}
return true;
}
});
no.setClickable(true);
no.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent arg1) {
if (arg1.getAction() == android.view.MotionEvent.ACTION_DOWN) {
//Intent myIntent = new Intent(v.getContext(), ParametrosActivity.class);
tts.speak("no!", TextToSpeech.QUEUE_ADD, null);
}
return true;
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_DATA_CHECK_CODE) {
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
// success, create the TTS instance
tts = new TextToSpeech(this, this);
} else {
// missing data, install it
//ATTENTION: BELOW THIS GIVES ME PROBLEMS SINCE IT OPENS MARKET
//AND I HAVE TO HIT THE BACK BUTTON, THEN, IT SPEAKS!
//BTW TTS ENGINE "IS" INSTALLED!!
Intent installIntent = new Intent();
installIntent
.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
}
}
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
} else if (status == TextToSpeech.ERROR) {
}
}
#Override
public void onDestroy() {
if (tts != null) {
tts.stop();
tts.shutdown();
}
super.onDestroy();
System.gc();
}
}
If I remove the area with "ATTENTION" above (since I am SURE I have TTS installed), it works the first time I run the app, if I leave the app and I open it again, it says "speak failed: not bound to tts engine"
It's like it doesn't create the TTS object since the app is still in memory.
So, guys... what do you guys think that I should do??
This is driving me crazy and I really need to communicate to my daughter through the tablet!
Any help is appreciated!!
I had this trouble on my application as well: TTS works in 2.3, but when I tried 4.0, it had the same symptoms as your problem (which I just found now while searching for a solution). The engine would work if you force-closed the application through Settings and started it again but just "backing out" and going back made the TTS engine in ICS not bind.
I tried setting the TTS object (mTts) to null after running mTts.shutdown(). When I started the application again after backing out, I got a null error on my mTts.speak() line.
At least for ICS, something is not letting go of the TTS engine. My solution (for now) is that I have made my TTS object static:
// in Activity
private static TextToSpeech mTts;
.
.
.
// in onCreate()
mTts = new TextToSpeech(this, this);
.
.
.
// in onDestroy()
if (mTts != null) {
mTts.stop();
mTts.shutdown();
mTts = null;
}
I was already only using one TTS object for the application so I don't think there are too many downsides to this approach.
This is what I have in onActivityResult(...)
#Override
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
if (requestCode == MY_DATA_CHECK_CODE) {
/*
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
// success, create the TTS instance
mTts = new TextToSpeech(this, this);
} else {
// missing data, install it
Intent installIntent = new Intent();
installIntent.setAction(
TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
*/
if (mTts==null) {
Intent installIntent = new Intent();
installIntent.setAction(
TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
mTts = new TextToSpeech(this, this);
}
}
Instead of using if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {...}, I check if mTts has already been instantiated. You'll also have to set mTts as static, as was mentioned by jlquant and Rakesh in an earlier post, so you'll have only a single instance of it. For example, private static TextToSpeech mTts.
So, unless you "Force stop" the app or it stops working because of an error, it won't anymore call the startActivity(installIntent);-- the annoying culprit that asks you to install TTS every time.
I fixed this by installing ivona having both Tts engines cured all problems, though I'm finding other issues such as no default tts is installed using the two together makes one work not a great fix but its s fix,
Also I can't find the option to allow my phone to install non market apps ie apk from my SD card
I had the same problem and solved. Maybe it's a timing issue in bounding, not sure, but a simple action before speak helped me.
Anyway I did this:
mTts = new TextToSpeech(this, this);
String engine = mTts.getDefaultEngine();
mTts = new TextToSpeech(this, this,engine);
Log.d("","...something here...");
Then when I hit my speak button, it speaks. You should watch your variable status on OnInit method. Maybe a separate thread can help talking in the app.
By the way, if you are sure TTS is installed, you can remove the block Intent checkIntent = new Intent(); for checking.
I definitely hope this helps you.
in my app I also used checkintent.setAction(...) to check if the necessary tts files are installed (which was working like a charm before upgrading to ICS). In ICS it always returned that the files are missing. So now I just ignore this check: i am creating the object and it initializes fine.
Moreover I was using two instances for two different languages. This also seems to not work anymore.
Now when I set the language for one of the instances, the other instance of the object is set to the same language (behaves like one instance).
gingerbread allowed setting of default tts in voice input& output / default tts
gingerbread only allows 'preferred' tts in language and input / text to speech output.
so tts is preferred instead of default, which just means it is not as clear as to which gets used.
The default with application overrides where stated is a better option I think.
If I create an app that depends on another app or apps (eg: the Facebook and Twitter apps), yet they are not installed, is there a method of checking for those dependencies and installing them at the same time as my own app?
I did this in my application which requires the zxing scanner app to be installed.
You will want this inside your onclick or ontouch:
try{
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
intent.setPackage("com.google.zxing.client.android");
startActivityForResult(intent, 0);
} catch (Exception e) {
createAlert("Barcode Scanner not installed!", "This application uses " +
"the open source barcode scanner by ZXing Team, you need to install " +
"this before you can use this software!", true);
}
which calls
public void createAlert(String title, String message, Boolean button) {
// http://androidideasblog.blogspot.com/2010/02/how-to-add-messagebox-in-android.html
AlertDialog alertDialog;
alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setTitle(title);
alertDialog.setMessage(message);
if ((button == true)) {
alertDialog.setButton("Download Now",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
Intent browserIntent = new Intent(
Intent.ACTION_VIEW,
Uri.parse("market://search?q=pname:com.google.zxing.client.android"));
startActivity(browserIntent);
}
});
}
alertDialog.show();
}
Then after sorting out all that code out I realise you asked for it to be installed at the same time as your app. Not sure if i should post this code, but it may be helpful
Short answer: No, you cannot automatically install other applications as dependencies.
Longer answer:
Android Market does not let you declare other applications to install as a dependency. As a system, Market appears to be designed for single application installs -- not Linux distro style mega dependency graphs.
At runtime, you can test for installed apps and punt your user over to the Market if so. See the techniques suggested by #QuickNick (testing if an app is installed) and #TerryProbert (punting to market) if that's what you want.
Your best bet is probably to design your app to gracefully degrade if dependencies are not available, and suggest (or insist) that they head over to market to install them.
Start from this:
Intent mediaIntent = new Intent("com.example.intent.action.NAME");
// add needed categories
List<ResolveInfo> listResolveInfo = getPackageManager().queryIntentServices(mediaIntent, 0);
if (listResolveInfo.size() != 0) {
//normal behavior
} else {
//install what you need
}
I give you example of querying services. If you want to check activities, then you will call queryIntentActivities().
I think following the pattern outlined in this post on the Android Developer Blog will help you.
http://android-developers.blogspot.com/2009/01/can-i-use-this-intent.html
As TerryProbert points out if you know that the Intent is not available prompt the user to install the missing app.
Here's what I use to return the first mission activity that exists:
try {
Class<?> missionClass = Class.forName(mPackageName+".Mission"+mission);
Method missionDescription;
missionDescription = missionClass.getMethod("missionDescription");
mMissionDescription = (String) missionDescription.invoke(null);
if (mMissionDescription.length() > 0) {
nextMission = mission;
break;
}
} catch (Exception e) {
//DEBUG*/Log.v(this.getClass().getName(), "onResume: Mission no "+mission+" not found: "+e.getMessage());
}
Each mission is held in a separate class, derived from a Mission base class. Derived classes are called Mission1, Mission24 etc.
Not all missions are defined.
The base class has an abstract class missionDescription which returns a string describing the mission.
This code is inside a loop so tests mission=1 to 99, trying to call missionDescription. It returns when the Description for the first mission found is returned.