i tried the following on the emulator but the as the app starts it gives a runtime error . could someone please help me on this . Heres' the code i tried
package com.example.TextSpeaker;
import java.util.Locale;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
public class TextSpeaker extends Activity {
/** Called when the activity is first created. */
int MY_DATA_CHECK_CODE = 0;
private TextToSpeech mtts;
String test1="hello world";
String test2="hi i am working fine";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent myintent = new Intent();
myintent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(myintent, MY_DATA_CHECK_CODE);
}
protected void onActivityResult(int requestcode,int resultcode,Intent data)
{
if(requestcode == MY_DATA_CHECK_CODE)
{
if(resultcode==TextToSpeech.Engine.CHECK_VOICE_DATA_PASS)
{
// success so create the TTS engine
mtts = new TextToSpeech(this,(OnInitListener) this);
mtts.setLanguage(Locale.ENGLISH);
mtts.speak(test1, TextToSpeech.QUEUE_FLUSH, null);
mtts.speak(test2, TextToSpeech.QUEUE_FLUSH, null);
}
else
{
//install the Engine
Intent install = new Intent();
install.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(install);
}
}
}
}
I've stumbled upon this question well over a year after it was posted, but I'm going to go ahead and answer anyway, in the sheer hope it'll help anyone else who ends up here in the future.
I'm writing this against 2.1, so apologies if you were working with <2.1 (no tags on question)
There are a few things I can spot immediately that may give you a little grief.
Firstly, the following :
mtts.speak(test1, TextToSpeech.QUEUE_FLUSH, null);
mtts.speak(test2, TextToSpeech.QUEUE_FLUSH, null);
If I understand the TextToSpeech API correctly, using QUEUE_FLUSH will flush out anything thats currently being spoken, so its possible that the second line is executing before the first has actually spoken, and you'd experience what you've stated above, that only the last one is being spoken.
Ideally, you only want one of those lines there, if the user puts in a different String, then just pass that through and let it flush out.
Next, you should invest in an onDestroy override, in here you can shutdown the mtts object, this prevents your app from hogging usage to the TTS engine, its always nice to free up resources when you're done with them, you wouldn't leave a ResultSet open now would you?!
#Override
public void onDestroy
() {
// Don't forget to shutdown!
if (mTts != null) {
mTts.stop();
mTts.shutdown();
}
super.onDestroy();
}
Also, as you state, it'll only speak English, because of the line you're using :
mtts.setLanguage(Locale.ENGLISH);
That's easy to correct, just set a different locale. Perhaps have some buttons and set the locale accordingly. I believe that the Google TTS engine currently only supports English, French, German, Italian and Spanish, but 3rd party TTS engines may offer more.
If all else fails, I wrote a tutorial here that might be of use.
Good luck!
Related
In my android app I have a TTS using Google engine.
Have something like this:
tts=new TextToSpeech(MyClass.this, status -> {
if(status == TextToSpeech.SUCCESS){
tts.setLanguage(locale);
tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onDone(String utteranceId) {
if (utteranceId.equals("***")) {
runOnUiThread(() -> {
Button view2 = findViewById(R.id.speech);
view2.setCompoundDrawablesWithIntrinsicBounds(R.drawable.play, 0, 0, 0);
});
}
}
#Override
public void onError(String utteranceId) {
}
#Override
public void onStart(String utteranceId) {
}
});
}
});
Basically I am using 2 languages, slovak and english. Both are working fine with Google TTS.
The problem is, Samsung devices have their own TTS engine set by default and therefore the app text to speech works not on those devices.
After the users changes their device settings to use Google TTS, then it is working.
But is there a way, that my code will support both TTS engines?
I found out that there might work something like this:
TextToSpeech(Context context, TextToSpeech.OnInitListener listener, String engine)
e.g. using com.google.android.tts as the engine parameter.
However in my code I have that like new TextToSpeech(MyClass.this, status -> {... and it doesn't accept engine as a 3rd parameter, and still I don't know how to detect when Samsung engine is needed and switch engines accordingly.
worth trying forcing TTS engine by passing this third param, so exchange very last line in posted snippet
});
to
}, "com.google.android.tts");
there are also two useful methods for you: getDefaultEngine() and getEngines(). just create at start some dummy new TextToSpeech with two params (empty listener) and check what possibilites you have.
also getAvailableLanguages() and isLanguageAvailable(Locale loc) may be useful when Google engine isn't present, but default one still may support your desired langs
I want to create a simple application which will make some tasks by voice commands. I want to start listening for commands with my own phrase like a "Hello device". Is it possible with Android speech recognition API? How to implement activation by my own phrase?
I was searching about this before asking, but couldn't find information about activation. I know about pocket-sphinx, but I need to implement it with Google APIs.
CMUSphinx is a real solution for this problem, continuous speech recognition takes too much resources and will drain your battery in an hour while keyword spotting mode is fast enough to detect just a keyphrase.
You might be interested that Google introduced new API in v21 for the similar task:
http://developer.android.com/reference/android/service/voice/AlwaysOnHotwordDetector.html
You could use that, but it will quite seriously restrict your userbase.
Send RecognizerIntent.
Here you have a tutorial how to implement voice recognition.
I want to start listening for commands with my own phrase like a
"Hello device". Is it possible with Android speech recognition API?
You cannot record a phrase, but you can listen to everything and then ask the recognition engine for words it heard.
Relevant code fragment from the tutorial:
// Populate the wordsList with the String values the recognition engine thought it heard
ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
So, you can check if it heard your plain English command, like "Hello device" and if yes, do something.
import android.speech.RecognizerIntent;
import android.content.Intent;
import java.util.ArrayList;
import java.util.List;
Step 1: Put this into a method that will start the speech recognizer, you can name anything meaningful like void startSpeech() or something.
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getClass().getPackage().getName());
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 3);
startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
Step 2: This will require us to override the onActivityResult() method to work with the above method.
Then start to implement the onActivityResult() method below:
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
String wordStr = null;
String[] words = null;
String firstWord = null;
String secondWord = null;
ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
if(requestCode == VOICE_RECOGNITION_REQUEST_CODE && resultCode == RESULT_OK)
{
wordStr = matches.get(0);
words = wordStr.split(" ");
firstWord = words[0];
secondWord = words[1];
}
if (firstWord.equals("open"))
{
// DO SOMETHING HERE
}
}
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.
I got problem with register. I use an if-else statement to check whether the user left any blank. If there is any blank, an error message will appear. The problem is, even with no blanks, all filled up, the error message still appears and thus prevents user from registering. I can't find any error.
Please help me spot my error.
package log1.log2;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class Login extends Activity {
DBAdapter db = new DBAdapter(this);
/** Called when the activity is first created. */
private EditText etUsername;
private EditText etPassword;
private Button btnLogin;
private Button btnRegister;
private TextView lblResult;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Get the EditText and Button References
etUsername = (EditText)findViewById(R.id.usernametxt);
etPassword = (EditText)findViewById(R.id.passwordtxt);
btnLogin = (Button)findViewById(R.id.btnLogin);
btnRegister = (Button)findViewById(R.id.btnRegister);
lblResult = (TextView)findViewById(R.id.msglbl);
//Cursor c = (Cursor) db.getAllTitles();
//Button btnArrival = (Button) findViewById(R.id.btnRegister);
//btnArrival.setOnClickListener(this);
// Set Click Listener
btnRegister.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(Login.this,Register.class);
startActivity(intent);
}
});
btnLogin.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
db.open();
Cursor c = (Cursor) db.getAllUser();
c.moveToFirst();
// Check Login
String username = etUsername.getText().toString();
String password = etPassword.getText().toString();
if(username.equals("") || password.equals(""))
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "FILL IN ALL FIELDS", duration);
toast.show();
}
else
{
if(username.equals(c.getString(1)))
{
if(password.equals(c.getString(2)))
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "LOGIN SUCCESS", duration);
toast.show();
long id;
id = db.insertTransaction(
new String(etUsername.getText().toString()));
Intent intent=new Intent(Login.this,Test.class);
startActivity(intent);
}
else
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "LOGIN FAIL", duration);
toast.show();
}
}
else
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "LOGIN FAIL", duration);
toast.show();
}
}
db.close();
}
});
}
}
Thank you very much.
Dayne,
I'm gonna try to help you here. Before I do, though, I want you to understand that you have been violating a lot of the conventional rules of stack overflow. I put a lot of time into trying to sort out your issues in this question, so I want to ask you to take a bit of time and try to understand what it is that you are doing wrong that makes others users on stack overflow (including me) very annoyed.
First, please don't use all caps. It is considered rude. Second, please don't post multiple questions on stack overflow that are all about the same issues. This is the 7th question that you have posted regarding this issue. That is also considered rude. Please post one question, and if the suggested answers do not work for you, then comment on them and ask for more help, specifying what part of their answer you used and what problems you are having still. Third, please do not post your entire file. If your entire file is needed the the commentors will ask you to post it, but don't post it up front. Consider that the people who are helping you with your questions are NOT getting paid. They are doing it for free, as a service to people trying to learn how to program. Posting your entire file up front is like you are asking someone to do your work for you, and the users on here are not interested in doing your work, they are interested in helping people learn. We want you to be able to do this stuff yourself. If you just want a solution that works and are not interested in learning why it works, you would be better off choosing a different community of people to ask questions to. Lastly, please try to research more! A lot of your questions betray that you are utterly clueless about how certain things work. Please, rather than simply posting on stackoverflow again and again, go spend a few hours reading up on how to create a login system in Android
That being said, you seem like a nice enough person to me. It looks like you are new to stack overflow and new to programming in general, so I am willing to forgive all those things you did that annoyed me, as long as you do your best to not do them again.
General Issues with your code
Ok, let's get into the general point of your code code. I have tried to fix your code to the point that it compiles and works. However, I want to point out that what you are trying to do is largely useless for any practical program. If I understand you correctly, you are trying to have a user login to some service or be able to register for that service. However, it looks like you are trying to use a database on the phone to log users in or register new users. If you have a database of usernames and passwords stored on a phone, then there is no way to have another user login. Let me give you an example. User A has a phone, and user B has a phone. If the database of usernames and passwords is stored on user A's phone, then how will user B login? Additionally, how would user B register for the service? There is reliable way to communicate between the two phones. On top of that, what if user A drops their phone and it breaks? Does that mean that your entire service is unavailable?
What you need to do, if you are providing login/registration for some service, is to have a server set up somewhere that phones can contact to perform login operations or registration operations. Setting up a server and a login/registration system is a big project, and you will need to read up on how to do that before anyone can really help you - right now I dont think you would understand most of the advice they would give you.
That being said, it is possible that you just want to get this local database login system to work for some reason (perhaps you just want something to work, all programmers have had a point where nothing they do seems to work and you are desperate to make anything work ;) ). So, let's see if we can make it work . . .
Separation of responsibility
You are trying to solve 2 main problems (I am ignoring registration for now. If you understand login then you can figure out registration). First, you want to provide some feedback to the user if they do not give you a username or a password. Second, you want to check if that person has provided a correct username / password combination. Right now you are trying to solve both of these problems within the Login Activity. I recommend separating these responsibilities - let the Login class handle providing feedback, and slightly modify your DBAdapter class so that it can handle checking the username/password.
Modify your DBAdapter class and add the following method:
public boolean isValidUser(String username, String password) {
Cursor c = <your SQLiteDatabase>.rawQuery("SELECT username FROM Users WHERE username='?' AND password='?'", new String[] {username, password});
boolean result = c.moveToFirst();
return result;
}
Please note that this method has a lot of problems, and should not be used in production code. I am assuming you just want this to work, and you don't care if it is perfect. If you can get this all working, perhaps ask a new question focused on verifying that a username / password combination is correct.
Note that you need to change the part that says <your SQLiteDatabase> to contain your database name.
Once you have added this method, your DBAdapter class can, given a username and password, inform you if that username and password combination is valid.
Making the Login Activity
Change the btnLogin onClickListener to this:
btnLogin.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String username = etUsername.getText().toString();
String password = etPassword.getText().toString();
if (username.trim().equals("") || password.trim().equals("")) {
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "FILL IN ALL FIELDS",
duration);
toast.show();
// Rather than having a huge else {} block, why not just add a
// return statement here? Then the rest of your code is a bit
// cleaner!
return;
}
db.open();
if (db.isValidUser(username, password))
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context,
"LOGIN SUCCESS", duration);
toast.show();
Intent intent = new Intent(Login.this, Test.class);
startActivity(intent);
} else {
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, "LOGIN FAIL",
duration);
toast.show();
}
db.close();
}
});
That should be all you need to get this to work! Note, however, that you didn't post your DBAdapter class here. I didn't want to look through the 7 posts to find it. Given the state of this post's code and the one other I looked at, it's likely that there are some errors in your DBAdapter. Read this section on the Android docs and try to debug that part yourself :) If you get stuck, you can ask a question about how to build a database on Android, and NOT a question about how to build a database/login on Android, since your login code should be mostly workable if you use the code I pasted here!
Final Points
Please consider the following comments I made when originally looking at your code
// NO!!!! Do not do this. You will end up with a problem
// very similar to http://stackoverflow.com/questions/3352957/
// why-does-not-this-work-android-oncreate/3352978#3352978
// Instead, say db = new DBAdapter(this) inside of the onCreate() method!
DBAdapter db = null; // new DBAdapter(this);
Also,
// This is an absolutely huge inner-class. It would be a lot better
// to extract this into a private member variable, by saying
// OnClickListener foo = new OnClickListener() { <put all code here> };
// btnLogin.setOnClickListener(foo);
btnLogin.setOnClickListener(new OnClickListener() {
Also,
// No!! If you are calling getAllUser(), you are likely returning a Cursor that points
// to a ton of users. The way your code is now, you are returning a list of all users
// in the application, and then checking to see if this data entered matches the first
// user. This would never work! If you have more than one user, then you need to check
// if the data entered matches ANY of your users. I am removing this code
// db.open();
// Cursor c = (Cursor) db.getAllUser();
// c.moveToFirst();
Cheers,
Hamilton
I think you need to do username.getText().equals(""), not just .equals because in that case you try to compare the empty string to the EditText object...
How can you read data, i.e. convert simple text strings to voice (speech) in Android?
Is there an API where I can do something like this:
TextToVoice speaker = new TextToVoice();
speaker.Speak("Hello World");
Using the TTS is a little bit more complicated than you expect, but it's easy to write a wrapper that gives you the API you desire.
There are a number of issues you must overcome to get it work nicely.
They are:
Always set the UtteranceId (or else
OnUtteranceCompleted will not be
called)
setting OnUtteranceCompleted
listener (only after the speech
system is properly initialized)
public class TextSpeakerDemo implements OnInitListener
{
private TextToSpeech tts;
private Activity activity;
private static HashMap DUMMY_PARAMS = new HashMap();
static
{
DUMMY_PARAMS.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "theUtId");
}
private ReentrantLock waitForInitLock = new ReentrantLock();
public TextSpeakerDemo(Activity parentActivity)
{
activity = parentActivity;
tts = new TextToSpeech(activity, this);
//don't do speak until initing
waitForInitLock.lock();
}
public void onInit(int version)
{ //unlock it so that speech will happen
waitForInitLock.unlock();
}
public void say(WhatToSay say)
{
say(say.toString());
}
public void say(String say)
{
tts.speak(say, TextToSpeech.QUEUE_FLUSH, null);
}
public void say(String say, OnUtteranceCompletedListener whenTextDone)
{
if (waitForInitLock.isLocked())
{
try
{
waitForInitLock.tryLock(180, TimeUnit.SECONDS);
}
catch (InterruptedException e)
{
Log.e("speaker", "interruped");
}
//unlock it here so that it is never locked again
waitForInitLock.unlock();
}
int result = tts.setOnUtteranceCompletedListener(whenTextDone);
if (result == TextToSpeech.ERROR)
{
Log.e("speaker", "failed to add utterance listener");
}
//note: here pass in the dummy params so onUtteranceCompleted gets called
tts.speak(say, TextToSpeech.QUEUE_FLUSH, DUMMY_PARAMS);
}
/**
* make sure to call this at the end
*/
public void done()
{
tts.shutdown();
}
}
Here you go . A tutorial on using the library The big downside is that it requires an SD card to store the voices.
A good working example of tts usage can be found in the "Pro Android 2 book". Have a look at their source code for chapter 15.
There are third-party text-to-speech engines. Rumor has it that Donut contains a text-to-speech engine, suggesting it will be available in future versions of Android. Beyond that, though, there is nothing built into Android for text-to-speech.
Donut has this: see the android.speech.tts package.