I created a small TTS app implementing OnUtteranceCompleteListener and, while things seem to be working exactly as expected, I noticed the following on LogCat (one for each completed utterance):
03-01 20:47:06.436:
VERBOSE/TtsService(381): TTS callback:
dispatch completed to 1
Again, this seems to be benign but I don't understand what '1' means. All such lines for all utterances say "completed to 1", even for utterance IDs that are greater than 1.
What does '1' mean in this log?
BTW, this message is not generated by my code but rather by the TTS engine (Pico) itself.
Looking at the TTSService.java source code available at http://eyes-free.googlecode.com you can find the function dispatchUtteranceCompletedCallback():
private void dispatchUtteranceCompletedCallback(String utteranceId, String packageName) {
/* Legacy support for TTS */
final int oldN = mCallbacksOld.beginBroadcast();
for (int i = 0; i < oldN; i++) {
try {
mCallbacksOld.getBroadcastItem(i).markReached("");
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
try {
mCallbacksOld.finishBroadcast();
} catch (IllegalStateException e) {
// May get an illegal state exception here if there is only
// one app running and it is trying to quit on completion.
// This is the exact scenario triggered by MakeBagel
return;
}
/* End of legacy support for TTS */
ITtsCallbackBeta cb = mCallbacksMap.get(packageName);
if (cb == null) {
return;
}
Log.v(SERVICE_TAG, "TTS callback: dispatch started");
// Broadcast to all clients the new value.
final int N = mCallbacks.beginBroadcast();
try {
cb.utteranceCompleted(utteranceId);
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
mCallbacks.finishBroadcast();
Log.v(SERVICE_TAG, "TTS callback: dispatch completed to " + N);
}
1 is the current value of N, which is initialized by the return value from mCallbacks.beginBroadcast().
beginBroadcast() is a method of the class RemoteCallbackList and its documentation states that it:
Returns the number of callbacks in the
broadcast, to be used with
getBroadcastItem(int) to determine the
range of indices you can supply
Does this help?
Related
I am using android videoview to display a loop of videos, as per our requirement the video loop should continue even if one of the videos gives an error.
To catch any exception, I have included the relevant code in a try-catch block as shown in the below code. However, while testing all scenarios, I gave the wrong path to the videoview.setVideopath() but the exception is not caught. I can see in the android studio console that it reports the data source not found error, but catch block does not catch the exception. I also tried implementing onerrorlistener, it is also not called when this happens.
Could you please help me, I am attaching the relevant code and exception log, many thanks for your help.
private void DisplayVideo_VideoView(){
try {
adplayer = (ResizableVideoView) findViewById(R.id.adplayer);
String MediaStorePath = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/Videos";
// String videoPath = MediaStorePath + "/" + Root2Util.Videopathlist.get(CurrentMediaIndex).getFileName();
String videoPath = MediaStorePath + "/1" + Root2Util.Videopathlist.get(CurrentMediaIndex).getFileName();
//adplayer.setVideoPath(videopath[CurrentMediaIndex]);
adplayer.setVideoPath(videoPath);
adplayer.changeVideoSize(Root2Util.SCREEN_WIDTH, Root2Util.SCREEN_HEIGHT);
adplayer.setVisibility(View.VISIBLE);
adplayer.start();
adplayer.setKeepScreenOn(true);
adplayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
CurrentMediaIndex++;
//mp.reset();
if (CurrentMediaIndex == Root2Util.Videopathlist.size()) {
CurrentMediaIndex = 0;
}
playMedia();
// ErrorHandlerAsyncTask ErrorTask=new ErrorHandlerAsyncTask();
// ErrorTask.execute((Object)getApplicationContext(),(Object)String.valueOf(what));
return false;
}
});
} catch(Exception e) {
ErrorHandlerAsyncTask ErrorTask=new ErrorHandlerAsyncTask();
ErrorTask.execute((Object)getApplicationContext(),(Object)e.getMessage());
}
Exception log from the console :
W/VideoView: Unable to open content: /storage/emulated/0/Download/Videos/1f0a9106d-d7d5-470c-
b287-3e3cad7d13fb.mp4
java.io.IOException: setDataSource failed.
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1091)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1065)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1019)
at android.widget.VideoView.openVideo(VideoView.java:352)
at android.widget.VideoView.access$2100(VideoView.java:72)
at android.widget.VideoView$7.surfaceCreated(VideoView.java:628)
at android.view.SurfaceView.updateWindow(SurfaceView.java:580)
at android.view.SurfaceView.setVisibility(SurfaceView.java:256)
at root2tech.cloudplayer.HomepageActivity.DisplayVideo_VideoView(HomepageActivity.java:728)
at root2tech.cloudplayer.HomepageActivity.playMedia(HomepageActivity.java:958)
at root2tech.cloudplayer.HomepageActivity.access$200(HomepageActivity.java:78)
at root2tech.cloudplayer.HomepageActivity$5.run(HomepageActivity.java:571)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:935)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:730)
So, I just faced a similar issue, I needed to use a VideoView to play the video from a URL without any knowledge of if the URL was a valid video or not. I understand why you're asking about catching every exception as well. My VideoView would print out an IOException and another which I can't quite remember at the moment of this answer. To fix this, I used a very similar code to yours but in a different order. The setOnErrorListener is what solved my issue for me but I placed my OnErrorListener directly after my VideoPlayer initialization and before the setVideoPath.
This works because the setVideoPath is where the errors are handled, unfortunately, VideoView will print these errors to the log but it will not throw anything to crash the app (which I don't agree with or like one bit). Because of this, your setOnErrorListener should at least go before you set the path or there will be nothing for it to catch as the error would have been thrown already (The errors aren't thrown on start oddly enough.
To apply my solution to your code, I would change it to this:
private void DisplayVideo_VideoView(){
//initialize adplayer
adplayer = (ResizableVideoView) findViewById(R.id.adplayer);
//begin listening for errors
adplayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
CurrentMediaIndex++;
if (CurrentMediaIndex == Root2Util.Videopathlist.size()) {
CurrentMediaIndex = 0;
}
playMedia();
return false;
}
});
//build variables for readability
String MediaStorePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/Videos";
String videoPath = MediaStorePath + "/1" + Root2Util.Videopathlist.get(CurrentMediaIndex).getFileName();
//set path - If there is an issue with videoPath, the error should be thrown here
adplayer.setVideoPath(videoPath);
//final adplayer customizations
adplayer.changeVideoSize(Root2Util.SCREEN_WIDTH, Root2Util.SCREEN_HEIGHT);
adplayer.setVisibility(View.VISIBLE);
//begin the adplayer
adplayer.start();
adplayer.setKeepScreenOn(true);
}
It is not a good style of code to catch a raw Exception, it is too broad to handle different error cases. However, for most of the IO operations IOException is the base exception, it is recommended to catch this.
As per java docs, we also need to consider IO operations can throw IOError. Error is not under the hierarchy of Exception, but both IOException and Error share Throwable as the base class. With this consideration, you can write your try-catch block as:
try {
// Your code
} catch (Throwable throwable) {
if (throwable instanceof IOException) {
// handle IOException here
} else if (throwable instanceof Error) {
if (t instanceof IOError) {
// handle IOError here
}
} else {
//This else will be reached only if you have any custom exceptions
}
}
For more readability of the code, you can use multiple catch blocks:
try {
// Your code
} catch (IOException ioException) {
// handle IOException here
} catch (IOError ioError) {
// handle IOError here
}
Also, you can add throws clause to your method if you want to handle these exceptions later:
public void displayVideo() throws Throwable {
// Your code here
}
Note: This is not the perfect solution to capture all exceptions for your scenario. But, since your code also includes IO operations on the file, hence have used the above examples to explain how you can possibly implement your exception handling.
On a bluetooth socket created with device.createRfcommSocketToServiceRecord(MY_UUID) I wish that after an certain amount of time when nothing arrives, to run some code, but still be able to process the bytes as soon as they arrive.
The description of .setSoTimeout explains exactly what I am willing to do:
With this option set to a non-zero timeout, a read() call on the InputStream associated with this Socket will block for only this amount of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the Socket is still valid.
So it looks like the perfect opportunity to put my code in the catch statement.
But unfortunately .setSoTimeout does not work with Bluetooth sockets according to my Android Studio. How can I implement such functionality without such method?
Thread.sleep is obviously also not a option, because I cannot lock the thread.
I solved it with Thread.sleep anyway, by using small intervals for the sleep and so trying to mimic the .setSoTimeout operation:
short sleep, check for incoming data, cycle until the timeout is reached then execute the timeout code.
I suppose there are better solutions, but this works for now.
The code given will execute the "timeout code" every second (set by the int timeOut), when no byte arrives on the input stream. If a byte arrives, then it resets the timer.
// this belongs to my "ConnectedThread" as in the Android Bluetooth-Chat example
public void run() {
byte[] buffer = new byte[1024];
int bytes = 0;
int timeOut = 1000;
int currTime = 0;
int interval = 50;
boolean letsSleep = false;
// Keep listening to the InputStream
while (true) {
try {
if (mmInStream.available() > 0) { // something just arrived?
buffer[bytes] = (byte) mmInStream.read();
currTime = 0; // resets the timeout
// .....
// do something with the data
// ...
} else if (currTime < timeOut) { // do we have to wait some more?
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
// ...
// exception handling code
}
currTime += interval;
} else { // timeout detected
// ....
// timeout code
// ...
currTime = 0; // resets the timeout
}
} catch (IOException e) {
// ...
// exception handling code
}
}
}
I want to play a horn sound in the app without any lag. I am using Media player class but its giving lag while playing file again.
code to run:
thread to improve the lag:(mp_horn is the media player instance we made from sound file) Below thread gives us much better result then making mediaplayer.setloop(true)
#Override
public void run() {
try {
if (mp_horn != null && mp_horn.isPlaying()) {
final long durationTotal_horn = mp_horn
.getDuration();
long durationCurrent_horn = mp_horn
.getCurrentPosition();
if (durationCurrent_horn >= (.90) * durationTotal_horn) {
// mp_engineContiue.seekTo((int)
// durationCurrent_back);
Log.v("arrrrrr", durationCurrent_horn
+ "......."
+ durationTotal_horn);
// mp_engineContiue.pause();
mp_horn.seekTo((int) (durationTotal_horn * .0000001));
}
}
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Probably
if (mp_horn != null && mp_horn.isPlaying())
should be :
if (mp_horn != null && !mp_horn.isPlaying())
otherwise while the Horn is playing you are doing all these calculations all over again, which I am guessing is causing the lag
I have an activity with a listview that displays the products registered with the images of the SDCARD. Some users are reporting that they receive the error "The application closed" while on this activity.
I've done all the tests to try to simulate it, and the error did not occur.
I thought it might be something with the device memory or something.
Here's a class I developed long ago for catching errors in a jar file I had distributed to several friends. It catches output to std out and stderr and writes it to a file.
If your users can use a file manager to find the file that is written they could send it to you. I've done some preliminary testing on an app and it worked for me.
if you use it and have problems, please let me know.
package com.normstools;
import java.io.*;
//------------------------------------------------------------------------
public class SaveStdOutput extends PrintStream {
final static boolean debug = false; // controls debug output
static OutputStream logfile;
static PrintStream oldStdout = null;
static PrintStream oldStderr = null;
private boolean echoOutput = true; //Also output to old setting
// Constructor - we're the only one that can use it!
private SaveStdOutput(PrintStream ps, boolean echoOutput) {
super(ps);
this.echoOutput = echoOutput;
// System.out.println("SaveStdOutput constructor called");
} // end Constructor
//------------------------------------------------------------
// Starts copying stdout and stderr to the file f.
public static void start(String f) throws IOException {
// Create/Open logfile.
OutputStream os = new PrintStream(
new BufferedOutputStream(
new FileOutputStream(f, true))); // append to current
doCommon(os, true);
} // end start()
// Copy STDOUT and STDERR to an output stream
public static void start(OutputStream os) {
doCommon(os, true);
} // end start()
public static void start(OutputStream os, boolean eO) {
doCommon(os, eO);
} // end start()
//-------------------------------------------------------
// Finish up
private static void doCommon(OutputStream os, boolean echoOutput) {
// Only allow to be called once
if (oldStdout != null) {
if (debug)
System.err.println("SaveStdOutput start() called twice");
return; // Exit if already open
}
logfile = os;
// Save old settings.
oldStdout = System.out;
oldStderr = System.err;
// Start redirecting the output.
System.setOut(new SaveStdOutput(System.out, echoOutput));
System.setErr(new SaveStdOutput(System.err, echoOutput));
} // end doCommon()
//--------------------------------------
// Restores the original settings.
public static void stop() {
if (oldStdout == null) {
if (debug)
System.err.println("SaveStdOutput stop() called before start()");
return;
}
System.setOut(oldStdout);
oldStdout = null; //Clear
System.setErr(oldStderr);
try {
logfile.close();
} catch (Exception ex) {
System.err.println("SaveStdOutput stop() ex " + ex.getMessage());
ex.printStackTrace();
}
} // end stop()
// Override the PrintStream write methods
public void write(int b) {
try {
logfile.write(b);
} catch (Exception e) {
e.printStackTrace();
setError();
}
if (echoOutput)
super.write(b);
} // end write()
// PrintStream override.
public void write(byte buf[], int off, int len) {
try {
logfile.write(buf, off, len);
} catch (Exception e) {
e.printStackTrace();
setError();
}
if (echoOutput)
super.write(buf, off, len);
} // end write()
//-------------------------------------------------------------------
// Following for testing SaveStdOutput class: Comment out when done!
public static void main(String[] args) {
try {
// Start capturing characters into the log file.
SaveStdOutput.start("log.txt");
// Test it.
System.out.println("Here's is some stuff to stdout. "
+ new java.util.Date());
System.err.println("Here's is some stuff to stderr.");
System.out.println("Let's throw an exception...");
new Exception().printStackTrace();
throw new Exception("this is thrown");
} catch (Exception e) {
e.printStackTrace();
} finally {
// Stop capturing characters into the log file
// and restore old setup.
SaveStdOutput.stop();
}
System.out.println("This should be to console only!");
} // end main() */
} // end class SaveStdOutput
The main() method has sample usage.
Call the start() method in onStart() and the close() method in onStop(),
or add menu items to control it. Add a few calls to System.out.println()
and some try{}catch blocks with printStackTrace().
Error "The application closed" occurs most of the time when Android detects your application is not loading or responding within 3-5 Seconds, you should try to check the availability of the SD card, space available, permission or even run some of the process in the background. Rewrite your code to handle these situations and it should work.
I use the following snippet to vibrate the phone in a specific pattern, but it throws and ArrayIndexOutOfBoundsException.
vibrator.vibrate(new long[] { selectedDuration, CONSTANT_DELAY }, REPEAT);
But
vibrator.vibrate(VIBRATE_DURATION);
works fine. Any pointers?
The docs say:
If you want to repeat, pass the index into the pattern at which to start the repeat.
Means REPEAT is only allowed to be 0 or 1 in your case.
This is the implementation:
public void vibrate(long[] pattern, int repeat)
{
// catch this here because the server will do nothing. pattern may
// not be null, let that be checked, because the server will drop it
// anyway
if (repeat < pattern.length) {
try {
mService.vibratePattern(pattern, repeat, mToken);
} catch (RemoteException e) {
}
} else {
throw new ArrayIndexOutOfBoundsException();
}
}