I'm trying to take some action after a TextToSpeech object in my Android app finishes speaking a sentence, but my UtteranceProgressListener.onDone() method is never called. I tried many things, including the suggestions from this post, but nothing has worked. Relevant code from my app is posted below. The TextToSpeech object correctly speaks the sentence I give it, but none of the callback functions in UtteranceProgressListener are called. Can someone please help me identify what's wrong? For example, should the utterance ID I provide to the TextToSpeech.speak() function need to be in some special format that I'm missing?
mtts = new TextToSpeech(myAct, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
mtts.setLanguage(Locale.US);
}
}
});
mtts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onDone(String utteranceId) {
Toast.makeText(myAct, "OnDone called", Toast.LENGTH_LONG).show();
}
#Override
public void onError(String utteranceId) {
Toast.makeText(myAct, "OnError called", Toast.LENGTH_LONG).show();
}
#Override
public void onStart(String utteranceId) {
Toast.makeText(myAct, "OnStart called", Toast.LENGTH_LONG).show();
}
});
Bundle params = new Bundle();
params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "");
myAct.mtts.speak(myText, TextToSpeech.QUEUE_FLUSH, params, "MyID");
Look at logcat, your code has probably fired: android.view.ViewRootImpl$CalledFromWrongThreadException
If you want to do some GUI-thread stuff, use handler and runnable like this:
public void onDone(String utteranceId) {
Log.v(TAG, "Speaking done"); // this is OK
// This is GUI-thread part
final View v = findViewById(R.id.txtStatus);
v.getHandler().post(new Runnable() {
#Override
public void run() {
txtStatus.setText("Speaking done");
}
});
}
And to start TTS speaking:
tts.speak("bla bla bla", TextToSpeech.QUEUE_FLUSH, null, "1");
If you want to add the call back UtteranceProgressListener, you have to give TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID as the utteranceId
It would look like this:
myAct.mtts.speak(myText, TextToSpeech.QUEUE_FLUSH, null, TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID);
See this post:
UtteranceProgressListener does not return error message
and check the engine web site: TTS Engine
Related
I have a function that requests data from an api and fills an array list.
Then i use the data from the arraylist in a textView. The problem that occurs is that the function takes time to load the data and the code in which i set the text view gets executed before the arraylist is populated resulting in a crash...I have used Countdown latch to tackle this problem but it isnt working
i have used it wrong most probably.
apirequest function
private void RequestDataFromApi() {
DotaAPIEndpoints textApiService= API_Client.getClient().create(DotaAPIEndpoints.class);
Call<List<Heroes>> call2 =textApiService.getHeroes();
call2.enqueue(new Callback<List<Heroes>>() {
#Override
public void onResponse(Call<List<Heroes>> call, Response<List<Heroes>> response) {
hero_list.clear();
hero_list.addAll(response.body());
}
#Override
public void onFailure(Call<List<Heroes>> call, Throwable t) {
Toast.makeText(MainActivity.this, "hero_list call failed!", Toast.LENGTH_SHORT).show();
}
});
requestLatch.countDown();
}
setText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
requestLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
textt.setText(hero_list.get(0).getHeroImg());
}
});
setText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
requestLatch.await();
You cannot call await on the UI thread. Calling await at this point in the above code is telling the UI thread to wait - if the UI thread is waiting, it cannot draw the screen updates, so the system will crash with an Activity Not Responding error.
Perhaps this helps, this is a way to safely allow the button to be clicked and not crash if the data has not loaded yet. (No need for a CountdownLatch at all)
setText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(hero_list.isEmpty()) {
Toast.makeText(MainActivity.this, "List not ready", Toast.LENGTH_SHORT).show();
return;
}
textt.setText(hero_list.get(0).getHeroImg());
}
});
I am trying to make a speech powered app, however I have run into a major problem.
My UtteranceProgressListener Class will not call any of the given methods regardless of where I place the Speak method.
Here is my code:
This is my OnCreate Method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
voiceBtn = (Button) findViewById(R.id.startListeningBtn);
voiceBtn.setEnabled(false);
textToSpeech = new TextToSpeech(mContext,new botListener());
}
This is the OnInitListner Imeplementation
public class botListener implements TextToSpeech.OnInitListener{
#Override
public void onInit(int i) {
if(i == TextToSpeech.SUCCESS)
{
int s = textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onStart(String s) {
Toast.makeText(getApplicationContext(),"Done Speaking",Toast.LENGTH_SHORT).show();
}
#Override
public void onDone(String s) {
Toast.makeText(getApplicationContext(),s,Toast.LENGTH_SHORT).show();
}
#Override
public void onError(String s) {
Toast.makeText(getApplicationContext(),"Done Speaking",Toast.LENGTH_SHORT).show();
}
});
Log.d(TAG,String.valueOf(s));
int result = textToSpeech.setLanguage(Locale.ENGLISH);
if(result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED){
Log.e(TAG,"Language not supported");
Intent installLanguage = new Intent(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installLanguage);
}
Log.d(TAG,"Started Voice Speaker");
}
else{
Log.e(TAG,"initialization failed");
}
}
}
Now, when I press the button, the event that fires is:
public void initVoiceRecog(View v){
//Toast.makeText(mContext,"Clicked",Toast.LENGTH_SHORT).show();
Speak("hello","1");
// does some other things here after that
}
private void Speak(String text,String identifierID){
if(Build.VERSION.SDK_INT>21) {
Bundle params = new Bundle();
params.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,identifierID);
textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, params, identifierID);
}
else{
// ttsMap is a HashMap
ttsMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,identifierID);
textToSpeech.speak(text,TextToSpeech.QUEUE_FLUSH,ttsMap );
}
}
My Question is, after saying hello, it does not fire the OnStart() or the OnError() or the OnDone() methods. Why is this happening?
I tried with the deprecated setOnUtteranceListner() as well, same result. It does not fire any of the methods, the Toasts don't show up.
Please tell a fix or a workaround for this.
The Devices I tried on are:
API 19 Micromax Canvas Nitro
API 21 Samsung S4
API 23(Marshmellow) ASUS Zenfone
I finally figured out why the callbacks were not working. Turns out, they were working and calling on a separate thread. So to execute the normal functionality, call the functions in the 'Activity.this.RunOnUiThread' and put this in the call back fuctions.
It has been a long time since I stopped by this problem: my FileObserver's onEvent method is not triggered, tested, and not even the "method entered" toast is being displayed.
FileObserver fileObserver = new FileObserver(android.os.Environment.getExternalStorageDirectory().toString() + "/Pictures/Screenshots") {
#Override
public void onEvent(int event, String path) {
Toast.makeText(getApplicationContext(), "method entered", Toast.LENGTH_SHORT).show();
if (event == FileObserver.CREATE) {
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "File created", Toast.LENGTH_SHORT).show();
}
});
}
}
};
fileObserver.startWatching();
Help me please! Thanks in advance.
Check existence of file prev, it should cause issue.
public void startWatching ()
Added in API level 1 Start watching for events. The monitored file or
directory must exist at this time, or else no events will be reported
(even if it appears later). If monitoring is already started, this
call has no effect.
I have the following problem: My app uses a function which executes all HTTP calls. As a quick fix I'd like to show the user a toast message whenever there is an ConnectionTimeout.
The problem is that this executeHttp() is called from several AsyncTasks and I can't figure out how to get the required context.
I read something about runOnUiThread but this also didn't seem to work for me...
Any ideas?
Thanks!
Update:
I'd like to have a solution which I can use in my executeHttp() function because else I have do add this code in 100 different places... Is this possible?
First, implement a Method to show a Toast to your activity:
class MyActivity extends Activity {
// some stuff
public void showToast(String text, int duration) {
Toast toast = Toast.makeText(this.getBaseContext(), text, duration);
toast.show();
}
}
The let your AsyncTask hold a reference to the activty which can then be called in the onProgressUpdate Method:
class MyAsyncTask extends AsyncTask {
MyActivity activity;
public MyAsyncTask(MyActivity a)
this.activity = a;
}
#Override
protected Object doInBackground(String... params) {
try {
// do your stuff here
} catch (ConnectionTimeoutException e) {
publishProgress("timeout");
}
#Override
protected void onProgressUpdate(String... values) {
if(values[0].equals("timeout")
activity.showToast("Ups, we have a timeout!", Toast.LENGTH_LONG); }
}
}
}
EDIT ------------
If you want it in your executeHttp() method, you have to pass the Context to it in order to show a Toast:
public ReturnValue executeHttp(Context context) {
try {
// ...
} catch(ConnectionTimeoutException e) {
Toast t = Toast.makeToast(context, message, duration);
t.show();
}
}
summary: no available context -> no toast
I have placed the parse method inside onCreate method. But my problem is how to show the Android Loading... Dialog??
Parse.initialize(this, "a", "b");
ParseQuery query = new ParseQuery("Category");
query.findInBackground(new FindCallback() {
#Override
public void done(List<ParseObject> catObjects, ParseException arg1) {
Log.d("Catlength", String.valueOf(catObjects.size()));
for(int i =0; i<catObjects.size(); i++){
Log.d("lengthName"+String.valueOf(i), String.valueOf(catObjects.get(i).getInt("Id")));
Category category = new Category();
category.Name= catObjects.get(i).getString("CatName");
category.id= catObjects.get(i).getInt("Id");
categories.add(category);
}
if(categories.size()>0){
setListAdapter(new CategoryArrayAdapter(CategoryListActivity.this, R.layout.row_category, categories));
}
else{
Toast.makeText(CategoryListActivity.this, "Our servers are busy. Hit refresh..", 3000).show();
}
}
});
Everything works fine in the above code but I couldn't figure out how to show the Dialog.
I'm unable to use AsycTask also as parse sdk invokes its own thread in the background and before the findInBackground execution finishes, the doInBackground completes the Asyc thread. That's why I invoked it in the main thread.
As the result I always get no results in my ArrayList.
Can someone please enlighten me.
I was in the same situation regarding the progress dialog, tried a few tricks and finally just declared a ProgressDialog class member:
protected ProgressDialog proDialog;
then created two methods:
protected void startLoading() {
proDialog = new ProgressDialog(this);
proDialog.setMessage("loading...");
proDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
proDialog.setCancelable(false);
proDialog.show();
}
protected void stopLoading() {
proDialog.dismiss();
proDialog = null;
}
and called startLoading() before the background operation and stopLoading()
inside the background operation after I got the the results.
startLoading();
ParseUser.logInInBackground(userName.getText().toString(), hashedPass, new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
Log.d(Constants.TAG, "User Loged in.");
ParseManager.sCurrentUser = user;
stopLoading();
finish();
} else {
stopLoading();
invalidCreds();
}
}
});
if you want to use AsyncTask don't call findInBackground() you can use find().
you can check it out in the api https://parse.com/docs/android/api/com/parse/ParseQuery.html#find()
hope this helps.
It's easy to get the progress of both uploads and downloads using ParseFile by passing a ProgressCallback to saveInBackground and getDataInBackground. For example:
byte[] data = "Working at Parse is great!".getBytes();
ParseFile file = new ParseFile("resume.txt", data);
file.saveInBackground(new SaveCallback() {
public void done(ParseException e) {
// Handle success or failure here ...
}
}, new ProgressCallback() {
public void done(Integer percentDone) {
// Update your progress spinner here. percentDone will be between 0 and 100.
}
});