package org.opensatnav.util;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.opensatnav.OpenSatNavConstants;
import android.app.Activity;
import android.util.Log;
/**
* Convenience class used to send Bug Report when Exceptions (caught or
* uncaught) happen. May be used in a try / catch block to send Exception by
* email or/and may be registered as a Thread.UncaughtExceptionHandler
*
* @author zerog
*
*/
public class BugReportExceptionHandler {
private static final String ERROR_PATH = OpenSatNavConstants.DATA_ROOT_DEVICE
.getAbsolutePath()
+ "/" + OpenSatNavConstants.ERROR_PATH;
private static final class ExceptionHandler implements
Thread.UncaughtExceptionHandler {
private UncaughtExceptionHandler defaultExceptionHandler;
/**
* Rely on defaultExceptionHandler after having done what we need with the caught exceptions.
* @param defaultExceptionHandler
*/
public ExceptionHandler(UncaughtExceptionHandler defaultExceptionHandler) {
this.defaultExceptionHandler = defaultExceptionHandler;
}
@Override
public void uncaughtException(final Thread thread, final Throwable ex) {
saveBugReport(ex);
// default action will close faulted Activity
defaultExceptionHandler.uncaughtException(thread, ex);
}
}
public static void register(final Activity parent) {
parent.runOnUiThread(new Runnable() {
@Override
public void run() {
String[] stacktraceFiles = searchForStackTraces();
if (stacktraceFiles != null)
for (String stacktraceFile : stacktraceFiles) {
Log.i(OpenSatNavConstants.LOG_TAG, "Error file found : " + stacktraceFile);
// Read contents of stacktrace
StringBuilder contents = new StringBuilder();
String line;
BufferedReader input;
try {
input = new BufferedReader(new FileReader(ERROR_PATH
+ "/" + stacktraceFile));
while ((line = input.readLine()) != null) {
contents.append(line);
contents.append(System.getProperty("line.separator"));
}
input.close();
new File(ERROR_PATH + "/" +stacktraceFile).delete();
} catch (IOException e) {
Log.e(OpenSatNavConstants.LOG_TAG, e.getMessage(), e);
}
new BugReportSender(parent).sendBugReportAtRestart(contents.toString());
}
}
});
UncaughtExceptionHandler handler = Thread
.getDefaultUncaughtExceptionHandler();
// set this ExceptionHandler if not already done
if (!(handler instanceof BugReportExceptionHandler.ExceptionHandler))
Thread
.setDefaultUncaughtExceptionHandler(new BugReportExceptionHandler.ExceptionHandler(
handler));
}
/**
* Save the error as a file that will be sent to OSN at next start of the
* application
*
* @param ex
*/
private static void saveBugReport(Throwable ex) {
ArrayList<Throwable> al = new ArrayList<Throwable>();
al.add(ex);
try {
// Random number to avoid duplicate files
Random generator = new Random();
int random = generator.nextInt(99999);
File dir = new File(ERROR_PATH + "/");
// Try to create the files folder if it doesn't exist
if (!dir.exists())
dir.mkdirs();
String filename = "OpenSatNav-errors-" + Integer.toString(random);
BufferedWriter bos = new BufferedWriter(new FileWriter(ERROR_PATH
+ "/" + filename + ".stacktrace"));
bos.write(buildStackTraceMessage(al));
bos.flush();
// Close up everything
bos.close();
} catch (Exception ebos) {
// Nothing much we can do about this - the game is over
Log.e(OpenSatNavConstants.LOG_TAG, ebos.getMessage(), ebos);
}
}
protected static String buildStackTraceMessage(List<Throwable> exceptions) {
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
for (Throwable e : exceptions) {
e.printStackTrace(printWriter);
}
return result.toString();
}
/**
* Search for stack trace files.
*
* @return
*/
private static String[] searchForStackTraces() {
File dir = new File(ERROR_PATH + "/");
// Try to create the files folder if it doesn't exist
if (!dir.exists())
dir.mkdirs();
// Filter for ".stacktrace" files
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".stacktrace");
}
};
return dir.list(filter);
}
}