Android Wait until Text to Speech OnInit is called - java

I had an issue where Text to Speech would not speak anything. I realised this was due to the fact that I was attempting to call 'Speak()' before TTS had initialised.
I need to wait until TTS has initialised, so that I can call 'Speak()' successfully. I thought doing something along the lines of this would work:
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
mTTSInitialised = true;
} else {
Log.e("TTS", "Initialisation Failed!");
}
}
...
while(!mTTSInitialised){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
But this fails to initialise at all. Is there a way to do this effectively?

The initialisation of the Text to Speech engine is asynchronous, which is why you realised you have to 'wait' for it to complete, before requesting that it processes an utterance.
Even when it eventually initialises successfully, it can be subsequently killed by the system, or it can of course fail to initialise, so you always need to be ready to handle a request to speak, where the engine isn't prepared.
Add the following helper class
public class PendingTTS {
private String pendingUtterance;
private int pendingQueueType;
public String getPendingUtterance() {
return this.pendingUtterance;
}
public void setPendingUtterance(#NonNull final String pendingUtterance) {
this.pendingUtterance = pendingUtterance;
}
public int getPendingQueueType() {
return this.pendingQueueType;
}
public void setPendingQueueType(final int pendingQueueType) {
this.pendingQueueType = pendingQueueType;
}
}
Assuming you're using an Activity, you need to declare the following variables:
private volatile PendingTTS pendingTTS;
private static final int MAX_INIT_ATTEMPTS = 4;
private volatile int initCount;
and initialise the Text to Speech object in onCreate()
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
In your onInitListener you would check if there is any pending speech:
#Override
public void onInit(final int status) {
switch (status) {
case TextToSpeech.SUCCESS:
initCount = 0;
// Set up tts stuff
tts.setOnUtteranceProgressListener(YOURprogressListener);
if (pendingTTS != null) {
// We have pending speech, process it and check the result
int speechResult = tts.speak(pendingTTS.getPendingUtterance(),pendingTTS.getPendingQueueType(),
// remaining tts variables here)
switch (speechResult){
case TextToSpeech.SUCCESS:
// Result was successful
pendingTTS = null;
break;
case TextToSpeech.ERROR:
// Speech failed
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
} else {
// there was nothing to process
}
break;
case TextToSpeech.ERROR:
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
I've glued the above together from my code - where the speech and initialisation methods are all separated, but I tried to give you an overview above of everything you need to handle.
Elsewhere in your code, when you make a tts.speak(//stuff here) request, you need to check the result as demonstrated above, to make sure it was successful. Again, in my code, this is separated into one single method. If it does fail, you need to set the PendingTTS parameters prior to attempting to initialise again:
pendingTTS = new PendingTTS();
pendingTTS.setPendingQueueType(// your queue type);
pendingTTS.setPendingUtterance(// your utterance);
It is is successful, make sure pendingTTS is set to null.
The overall design is that if the initialisation failed, it will attempt to initialise again, up to the maximum allowed attempts. If the speech fails, it will attempt to initialise the engine again, firstly setting the PendingTTS parameters.
Hope you managed to follow that.

Hmm..
Not a very good idea.
You can try to add the text to the TTS queue and let it do it's work. This snippet can be inside button click, etc as:
tts.speak(toSpeak, TextToSpeech.QUEUE_ADD, null);
Small tutorial that would help.

Related

How to handle async calls and transferring information

So I'm completely lost on this one, it might be obvious solution or I'm just trying somethin that's not possible but here it is.
I have two classes one is being used as e listener class and second one is the one that handles queue(i will only include relevant code).
Handler class:
public void check() {
for (Queueable queueable : queue) {
if (!doesReceiverHavePlayers(queueable)) continue;
}
}
private boolean doesReceiverHavePlayers(Queueable queueable) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("PlayerCount");
out.writeUTF(queueable.getReceiver());
Player player = Iterables.getFirst(Bukkit.getOnlinePlayers(), null);
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
return /*response*/ > 0;
}
Listener class:
#Override
public void onPluginMessageReceived(String channel, #NotNull Player player, byte[] message) {
if (!channel.equals("BungeeCord")) return;
ByteArrayDataInput in = ByteStreams.newDataInput(message);
String subChannel = in.readUTF();
switch (subChannel) {
case "PlayerCount":
int response = in.readInt();
break;
}
}
The check method is called every 5 seconds and doesReceiverHavePlayers requests player count from a certain server to see if there are any players on it, but the 'response' arrives in the listener class onPluginMessageReceived method. But as you can see I'm trying to use response in the doesReceiverHavePlayers method and return boolean value. Is there any way I can achieve this and how should I do it?
In onPluginMessageReceived store the result in a ConcurrentHashMap and then lookup the value in doesReceiverHavePlayers instead of making a blocking call.
Something like this:
ConcurrentHashMap<String, Integer> playerCounts = new ConcurrentHashMap<>();
void onPluginMessageReceived() {
playerCounts.put(subChannel, response);
}
boolean doesReceiverHavePlayers() {
return playerCounts.get(queueable.getReceiver()) > 0;
}

Strange LiveData behaviour?

Im trying to implement MVVM architecture using ViewModel and LiveData. These two methods are inside a Activity:
private void handleResult(BoardViewModel vm) {
vm.getLiveDataSingleObj("Result").observe(this, new Observer<Object>() {
#Override
public void onChanged(#Nullable Object resultObj) {
Result result = (Result) resultObj;
if (!result.isCompleted()) return;
gotoResult();
}
});
}
And
private void gotoResult() {
Log.w(LOG_TAG, "Result: Moving to next activity");
Intent intent = new Intent(boardActivity, ResultActivity.class);
intent.putExtra("LEVEL", levelIndex);
intent.putExtra("MAP", mapIndex);
startActivity(intent);
}
The handleResult method is setup to listen for result objects that indicate that the game has ended and it is time to move on to the next activity ("gotoResult"). However, this completely breaks the navigation of the app, when i go back and then say attempt to start a new game session i instead instantly go to the next activity telling me I've already won.
Any ideas as to why it fires multiple times and eventually stops, letting me start a new session. To clarify, if I remove the gotoResult the logic works every single time no errors with indexes out of bounds or what have you, it's only when I add the goto that everything breaks.
ViewModel:
private void setupHashTypes() {
hashLiveData.put(KEY_BOARD, liveDataBoardQuery);
hashLiveData.put(KEY_STEPS_COUNTER, game.getStepsTakenLiveData());
hashLiveData.put(KEY_PATH_CHANGE, game.getPathChangedLiveData());
hashLiveData.put(KEY_VALUE_CHANGE, game.getValueChangeLiveData());
hashLiveData.put(KEY_TIMER, game.getTimerLiveData());
hashLiveData.put(KEY_SELECTED, game.getSelectedLiveData());
hashLiveData.put(KEY_DESELECTED, game.getDeselectedLiveData());
hashLiveData.put(KEY_HOLD, game.getHoldLiveData());
hashLiveData.put(KEY_UNHOLD, game.getUnholdLiveData());
hashLiveData.put(KEY_RESULT, game.getResultLiveData());
}
public LiveData<Object> getLiveDataSingleObj(String type) {
if (hashLiveData.containsKey(type)) {
return (LiveData<Object>) hashLiveData.get(type);
}
throw new IllegalArgumentException("Invalid: key was not found: " + type);
}
And the Model has getters, example:
private final SingleLiveEvent<Result> resultLiveData = new SingleLiveEvent<>();
public LiveData<Result> getResultLiveData() {
return resultLiveData;
}
you should remove the observer in onDestroy() method
Changing from MutableLiveData which always resends the previous set values to new subscribers, to SingleLiveEvent which doesn't have this behaviour, solved the problem.
The class can be found here: https://github.com/googlesamples/android-architecture/tree/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp

Dial multiple numbers one by one programmatically | Android

I am trying to develop a feature for an app where you have a list of "codes" that you enter and that are dialed one by one. I have looked over TelephonyManager and followed a tutorial on developing a broadcast receiver with a listener for responses but it does not always work as it should.
One idea was to store all the numbers necessary in SharedPref. If the Activity (only created for the intent towards dialer) went into onStop() (meaning that above, the dialer screen was on) and then into onResume() (call ended and activity resumed), I would remove the number last dialed from the SharedPref and then, if any remained, open the dialer again. The broadcast made sure than once the state flow of the TelephonyManager was "OFFHOOK => IDLE", it would return the user to the Activity . Short story, it did not always perform as it should have.
How should I tackle the problem ?
EDIT
My curent solution was to
Create a doPhoneCall() function that would handle the intent creation and deployment itself.
#Override
protected void doPhoneCall(){
super.onResume();
wentIntoCall = false;
/** More code here for dialing */
}
Place this function into the onResume(). Even if the onResume will be called multiple times, the wentIntoCall boolean will make sure that the function won't be called multiple times.
#Override
protected void onResume() {
super.onResume();
if(wentIntoCall)
doPhoneCall();
}
Having in mind that after a call, the phone should return to its previous state, so it would return to the Activity in which we are doing are call, we will add to the activity a CallListener, and in the case of IDLE, based on the tutorial linked above, we make the wentIntoCall be true. ( The activity will go into onResume() and, upon seeing that the boolean is true, it will initialize the next call ).
case TelephonyManager.CALL_STATE_IDLE:
Log.e(TAG, "CALL_STATE_IDLE==>"+incoming_number);
if((prev_state == TelephonyManager.CALL_STATE_OFFHOOK)){
prev_state=state;
wentIntoCall = true;
//Answered Call which is ended
}
if((prev_state == TelephonyManager.CALL_STATE_RINGING)){
prev_state=state;
wentIntoCall = true;
//Rejected or Missed call
}
My final question : is this the right way to handle this functionality, or should I try to come up with another implementation of it ?
EDIT 2
Looks like my "codes", being USSD codes, are not behaving like normal phone calls.. So for normal phone calls the code above seems to work, but for dialing codes, not that much. I have "downgraded" my solution to a simple for-loop. Seems to be working fine now.
I dont know for android O , but for android 6.0 > You cant detect answer in direct way . Call no exist number and see PhoneStateListener what will trigger in one case and track successed call also.
Make public static array , add all your numbers intro array .
I made services . Insert permissions in manifest make your own action also ( NEXT_CALL for example ) .
Than easy make intent for startServices :
SharedPreferences settings;
SharedPreferences.Editor SAVES;
Intent serviceIntent = new Intent(MainActivity.this, ServiceForCalls.class);
serviceIntent.setAction("xxx.xxx.NEXT_CALL");
startService(serviceIntent);
isCalling = true;
SAVES.putBoolean( "isCalling" , isCalling );
SAVES.commit();
SAVES.apply();
You must use timeout interval about 10 sec for next call.
Heres little help func - end call and phoneState handler :
void END_CALL () throws InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException {
tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Class c = null;
try {
c = Class.forName(tm.getClass().getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method m = null;
try {
m = c.getDeclaredMethod("getITelephony");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
m.setAccessible(true);
Object telephonyService = m.invoke(tm); // Get the internal ITelephony object
c = Class.forName(telephonyService.getClass().getName()); // Get its class
m = c.getDeclaredMethod("endCall"); // Get the "endCall()" method
m.setAccessible(true); // Make it accessible
m.invoke(telephonyService); // invoke endCall()
if ( SIGNAL_STOP == false ) {
timerHandlerServicesStartNewNumber.postDelayed(timerRunnableServicesStartNewNumber, 1000);
}
}
private class PhoneStateChangeListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch(state){
case TelephonyManager.CALL_STATE_RINGING:
Log.println( Log.INFO , "RINGING" , "SERVICES%%%%%%%%%%%%%%%%RINGING%%%%%%%%%%%%%%%%%%");
wasRinging = true;
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%%");
if (!wasRinging) {
// Start your new activity
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%");
if (SIGNAL_STOP == false) {
timerHandlerServices.postDelayed(timerRunnableServices, 10000);
}
} else {
// Cancel your old activity
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
}
// this should be the last piece of code before the break
wasRinging = true;
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.println( Log.INFO , "IDLE BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%IDLE%%%%%%%%%%%%%%%%%%%");
// this should be the last piece of code before the break
wasRinging = false;
break;
}
}
}
Thanks for : "meaning that above, the dialer screen was on" nice catch.
As a side note, in the Android O developer preview there is a new API which allows you to send a USSD request and register a callback to receive its results. For newer versions of Android this might meet your needs better.

Matlab & Java: Execute matlab asynchronously

so, here is my today problem:
First of all, please note that I do NOT have the Matlab parallel toolbox available.
I am running java code witch interact with Matlab. Sometime Matlab directly call some java functions, sometimes it is the opposite. In this case, we use a notification system which comes from here:
http://undocumentedmatlab.com/blog/matlab-callbacks-for-java-events
We then address the notification in proper callbacks.
Here is a simple use case:
My user select a configuration file using the java interface, loaded into Matlab.
Using an interface listener, we notify Matlab that the configuration file has been selected, it then run a certain number of functions that will analyzes the file
Once the analysis is done, it is pushed into the java runtime, which will populate interface tables with the result. This step involve that matlab will call a java function.
Finally, java request the interface to be switched to an arbitrary decided tab.
This is the order of which things would happen in an ideal world, however, here is the code of the listener actionPerformed method:
#Override
public void actionPerformed(ActionEvent arg0) {
Model wModel = controller.getModel();
Window wWindow = controller.getWindow();
MatlabStructure wStructure = new MatlabStructure();
if(null != wModel) {
wModel.readMatlabData(wStructure);
wModel.notifyMatlab(wStructure, MatlabAction.UpdateCircuit);
}
if(null != wWindow) {
wWindow.getTabContainer().setSelectedComponent(wWindow.getInfosPannel());
}
}
What happen here, is that, when the notifyMatlab method is called, the code does not wait for it to be completed before it continues. So what happen is that the method complete and switch to an empty interface page (setSelectedComponent), and then the component is filled with values.
What I would like to, is for java to wait that my notifyMatlab returns a "I have completed !!" signal, and then pursue. Which involves asynchrounous code since Matlab will code java methods during its execution too ...
So far here is what I tried:
In the MatlabEventObject class, I added an isAcknowledge member, so now the class (which I originaly found in the above link), look like this (I removed all unchanged code from the original class):
public class MatlabEventObject extends java.util.EventObject {
private static final long serialVersionUID = 1L;
private boolean isAcknowledged = false;
public void onNotificationReceived() {
if (source instanceof MatlabEvent) {
System.out.println("Catched a MatlabEvent Pokemon !");
MatlabEvent wSource = (MatlabEvent) source;
wSource.onNotificationReceived();
}
}
public boolean isAcknowledged() {
return isAcknowledged;
}
public void acknowledge() {
isAcknowledged = true;
}
}
In the MatlabEvent class, I have added a future task which goal is to wait for acknowledgement, the methods now look like this:
public class MatlabEvent {
private Vector<IMatlabListener> data = new Vector<IMatlabListener>();
private Vector<MatlabEventObject> matlabEvents = new Vector<MatlabEventObject>();
public void notifyMatlab(final Object obj, final MatlabAction action) {
final Vector<IMatlabListener> dataCopy;
matlabEvents.clear();
synchronized (this) {
dataCopy = new Vector<IMatlabListener>(data);
}
for (int i = 0; i < dataCopy.size(); i++) {
matlabEvents.add(new MatlabEventObject(this, obj, action));
((IMatlabListener) dataCopy.elementAt(i)).testEvent(matlabEvents.get(i));
}
}
public void onNotificationReceived() {
ExecutorService service = Executors.newSingleThreadExecutor();
long timeout = 15;
System.out.println("Executing runnable.");
Runnable r = new Runnable() {
#Override
public void run() {
waitForAcknowledgement(matlabEvents);
}
};
try {
Future<?> task = service.submit(r);
task.get(timeout, TimeUnit.SECONDS);
System.out.println("Notification acknowledged.");
} catch (Exception e) {
e.printStackTrace();
}
}
private void waitForAcknowledgement(final Vector<MatlabEventObject> matlabEvents) {
boolean allEventsAcknowledged = false;
while(!allEventsAcknowledged) {
allEventsAcknowledged = true;
for(MatlabEventObject eventObject : matlabEvents) {
if(!eventObject.isAcknowledged()) {
allEventsAcknowledged = false;
}
break;
}
}
}
}
What happen is that I discover that Matlab actually WAIT for the java code to be completed. So my waitForAcknowledgement method always wait until it timeouts.
In addition, I must say that I have very little knowledge in parallel computing, but I think our java is single thread, so having java waiting for matlab code to complete while matlab is issuing calls to java functions may be an issue. But I can't be sure : ]
If you have any idea on how to solve this issue in a robust way, it will be much much appreciated.

Return value from child thread

I'm writing an Android app that communicates with a website. Any time I hit the website, I'm displaying a ProcessDialog so that the user knows something's happening. Most of my website communication is one-way, so I don't usually expect any return data.
There is one point however where I need to get information back, but the results are not being stored when I exit the child thread. In a nutshell, I need to call a thread, let it process the results, and store the results in a couple of fields.
Here's what I've got so far - I have two variables, String[] Account and boolean AccountRetrievalSuccess:
public void GetAccount() {
MyDialog = ProgressDialog.show( MyContext, "Retrieving Account" , "We're retrieving your account information. Please wait...", true);
Thread T = new GetAccountThread();
T.start();
}
public class GetAccountThread extends Thread {
#Override
public void run() {
try {
String resp = GetPage(BaseURL+MainPage+"?P="+PhoneID+"&K="+WebAccessKey+"&A=ACCOUNT");
if (resp.contains("FAILURE|")){
failhandler.sendEmptyMessage(0);
} else {
resp = resp.replace("SUCCESS|", "");
Account = resp.split("\\|");
handler.sendEmptyMessage(0);
}
} catch (Exception e) {
failhandler.sendEmptyMessage(0);
}
};
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
AccountRetrievalSuccess = true;
MyDialog.dismiss();
}
};
private Handler failhandler = new Handler() {
#Override
public void handleMessage(Message msg) {
AccountRetrievalSuccess = false;
MyDialog.dismiss();
ShowWtf();
}
};
}
Any idea what I'd need to do to be able to store the Account and AccountRetrievalSuccess values so that I can access them from elsewhere in the code?
Looks like a perfect job for AsyncTask!
This class allows you to run a task on a background thread and return the results back to the UI thread whilst reporting progress on the task at hand.
Not expecting a result in a mobile app might be a bad idea by the way, due to nature of mobile network connections you'd never know for sure if your server actually got the thing you sent it (and the server might have failed while processing and your app would never know...)
Do not use threads. You should use executors for that. Implement a Callable<> interface, create an ExecutorService and run it. Have a look to the java.util.concurrent package.
Make those global variables in the containing Activity and then pass them to the handler:
Message m = Message.obtain();
m.obj = Account;
handler.sendMessageDelayed(m, 1);
Then in the handler you can cast m.obj back to the Account type and its nice and available.
Scott.. You should not have more than one handler per activity. Instead switch on what. You can send data (or objects) in messages as in:
Message msg= Message.obtainMessage(0);
Bundle b= new Bundle();
b.putString("stringData",outString);
msg.setData(b);
handler.sendMessage(msg);
You can switch on multiple messages in the handler as in.
public void handleMessage(Message msg){
switch(msg.what){
case BUTTON_ONE_UP_SELECTED:
this.removeMessages(BUTTON_ONE_UP_SELECTED);
buttonLarger01.setImageResource(R.drawable.btn_zoom_up_selected);
break;
case BUTTON_ONE_UP_NORMAL:
this.removeMessages(BUTTON_ONE_UP_NORMAL);
buttonLarger01.setImageResource(R.drawable.btn_zoom_up_normal);
break;
case BUTTON_TWO_UP_SELECTED:
this.removeMessages(BUTTON_TWO_UP_SELECTED);
buttonLarger02.setImageResource(R.drawable.btn_zoom_up_selected);
break;
case BUTTON_TWO_UP_NORMAL:
this.removeMessages(BUTTON_TWO_UP_NORMAL);
buttonLarger02.setImageResource(R.drawable.btn_zoom_up_normal);
break;
case BUTTON_ONE_DOWN_SELECTED:
this.removeMessages(BUTTON_ONE_DOWN_SELECTED);
buttonSmaller01.setImageResource(R.drawable.btn_zoom_down_selected);
break;
case BUTTON_ONE_DOWN_NORMAL:
this.removeMessages(BUTTON_ONE_DOWN_NORMAL);
buttonSmaller01.setImageResource(R.drawable.btn_zoom_down_normal);
break;
case BUTTON_TWO_DOWN_SELECTED:
this.removeMessages(BUTTON_TWO_DOWN_SELECTED);
buttonSmaller02.setImageResource(R.drawable.btn_zoom_down_selected);
break;
case BUTTON_TWO_DOWN_NORMAL:
this.removeMessages(BUTTON_TWO_DOWN_NORMAL);
buttonSmaller02.setImageResource(R.drawable.btn_zoom_down_normal);
break;
default:
super.handleMessage(msg);
break;
}
}
};
So in your case you could define SUCCESS as what 0 and FAILURE as what 1 etc.

Categories

Resources