package com.markupartist.iglaset.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Date;
import java.util.Random;
import com.markupartist.iglaset.R;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Environment;
import android.os.StatFs;
/**
* Error reporter.
* http://androidblogger.blogspot.com/2009/12/how-to-improve-your-application-crash.html
*/
public class ErrorReporter implements Thread.UncaughtExceptionHandler {
String mVersionName;
String mPackageName;
String mFilePath;
String mPhoneModel;
String mAndroidVersion;
String mBoard;
String mBrand;
// String CPU_ABI;
String mDevice;
String mDisplay;
String mFingerPrint;
String mHost;
String mId;
String mManufacturer;
String mModel;
String mProduct;
String mTags;
long mTime;
String mType;
String mUser;
private Thread.UncaughtExceptionHandler mPreviousHandler;
private Context mCurContext;
public void init(Context context) {
mPreviousHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
recoltInformations(context);
mCurContext = context;
}
public long getAvailableInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
public long getTotalInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
}
void recoltInformations(Context context) {
PackageManager pm = context.getPackageManager();
try {
PackageInfo pi;
// Version
pi = pm.getPackageInfo(context.getPackageName(), 0);
mVersionName = pi.versionName;
// Package name
mPackageName = pi.packageName;
// Files dir for storing the stack traces
mFilePath = context.getFilesDir().getAbsolutePath();
// Device model
mPhoneModel = android.os.Build.MODEL;
// Android version
mAndroidVersion = android.os.Build.VERSION.RELEASE;
mBoard = android.os.Build.BOARD;
mBrand = android.os.Build.BRAND;
// CPU_ABI = android.os.Build.;
mDevice = android.os.Build.DEVICE;
mDisplay = android.os.Build.DISPLAY;
mFingerPrint = android.os.Build.FINGERPRINT;
mHost = android.os.Build.HOST;
mId = android.os.Build.ID;
mModel = android.os.Build.MODEL;
mManufacturer = android.os.Build.MANUFACTURER;
mProduct = android.os.Build.PRODUCT;
mTags = android.os.Build.TAGS;
mTime = android.os.Build.TIME;
mType = android.os.Build.TYPE;
mUser = android.os.Build.USER;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
private void appendLog(StringBuilder builder, String key, String value) {
builder.append(key).append(" : ").append(value).append("\n");
}
public String createInformationString() {
StringBuilder builder = new StringBuilder();
appendLog(builder, "Version", mVersionName);
appendLog(builder, "Package", mPackageName);
appendLog(builder, "FilePath", mFilePath);
appendLog(builder, "Phone Model", mPhoneModel);
appendLog(builder, "Android Version", mAndroidVersion);
appendLog(builder, "Board", mBoard);
appendLog(builder, "Brand", mBrand);
appendLog(builder, "Device", mDevice);
appendLog(builder, "Display", mDisplay);
appendLog(builder, "Finger Print", mFingerPrint);
appendLog(builder, "Host", mHost);
appendLog(builder, "ID", mId);
appendLog(builder, "Model", mModel);
appendLog(builder, "Manufacturer", mManufacturer);
appendLog(builder, "Product", mProduct);
appendLog(builder, "Tags", mTags);
appendLog(builder, "Time", Long.toString(mTime));
appendLog(builder, "Type", mType);
appendLog(builder, "User", mUser);
appendLog(builder, "Total Internal Memory", Long.toString(getTotalInternalMemorySize()));
appendLog(builder, "Available Internal Memory", Long.toString(getAvailableInternalMemorySize()));
return builder.toString();
}
public void uncaughtException(Thread t, Throwable e) {
Date CurDate = new Date();
StringBuffer report = new StringBuffer();
report.append("Error Report collected on : ").append(CurDate.toString());
report.append("\n");
report.append("\n");
report.append("Informations :");
report.append("\n");
report.append("==============");
report.append("\n");
report.append("\n");
report.append(createInformationString());
report.append("\n\n");
report.append("Stack : \n");
report.append("======= \n");
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
e.printStackTrace(printWriter);
String stacktrace = result.toString();
report.append(stacktrace);
report.append("\n");
report.append("Cause : \n");
report.append("======= \n");
// If the exception was thrown in a background thread inside
// AsyncTask, then the actual exception can be found with getCause
Throwable cause = e.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
report.append(result.toString());
cause = cause.getCause();
}
printWriter.close();
report.append("**** End of current Report ***");
saveAsFile(report.toString());
// SendErrorMail( Report );
mPreviousHandler.uncaughtException(t, e);
}
private static class SingletonHolder {
public static final ErrorReporter instance = new ErrorReporter();
}
public static ErrorReporter getInstance() {
return SingletonHolder.instance;
}
private void sendErrorMail(Context context, String ErrorContent) {
Intent sendIntent = new Intent(Intent.ACTION_SEND);
String subject = context.getResources().getString(
R.string.crash_report_mail_subject);
String body = context.getResources().getString(
R.string.crash_report_mail_body)
+ "\n\n" + ErrorContent + "\n\n";
sendIntent.putExtra(Intent.EXTRA_EMAIL,
new String[] { context.getResources().getString(
R.string.crash_report_email) });
sendIntent.putExtra(Intent.EXTRA_TEXT, body);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
sendIntent.setType("message/rfc822");
context.startActivity(Intent.createChooser(sendIntent, "Title:"));
}
private void saveAsFile(String ErrorContent) {
try {
Random generator = new Random();
int random = generator.nextInt(99999);
String FileName = "stack-" + random + ".stacktrace";
FileOutputStream trace = mCurContext.openFileOutput(FileName,
Context.MODE_PRIVATE);
trace.write(ErrorContent.getBytes());
trace.close();
} catch (IOException ioe) {
// ...
}
}
private String[] getErrorFileList() {
File dir = new File(mFilePath + "/");
// Try to create the files folder if it doesn't exist
dir.mkdir();
// Filter for ".stacktrace" files
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".stacktrace");
}
};
return dir.list(filter);
}
private boolean isThereAnyErrorFile() {
return getErrorFileList().length > 0;
}
public void checkErrorAndSendMail(Context context) {
try {
if (isThereAnyErrorFile()) {
StringBuffer buffer = new StringBuffer();
String[] ErrorFileList = getErrorFileList();
int curIndex = 0;
// We limit the number of crash reports to send ( in order not
// to be too slow )
final int MaxSendMail = 5;
for (String curString : ErrorFileList) {
if (curIndex++ <= MaxSendMail) {
buffer.append("New Trace collected :\n");
buffer.append("=====================\n ");
String filePath = mFilePath + "/" + curString;
BufferedReader input = new BufferedReader(
new FileReader(filePath));
String line;
while ((line = input.readLine()) != null) {
buffer.append(line).append("\n");
}
input.close();
}
// DELETE FILES !!!!
//File curFile = new File(FilePath + "/" + curString);
//curFile.delete();
deleteFile(curString);
}
sendErrorMail(context, buffer.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void deleteFile(String file) {
// DELETE FILES !!!!
File curFile = new File(mFilePath + "/" + file);
curFile.delete();
}
public void checkErrorAndReport(final Context context) {
try {
if (isThereAnyErrorFile()) {
new AlertDialog.Builder(context)
.setTitle(context.getText(R.string.crash_report_dialog_title))
.setMessage(context.getText(R.string.crash_report_dialog_message))
.setPositiveButton(context.getText(R.string.yes), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
checkErrorAndSendMail(context);
}
}).setNegativeButton(context.getText(R.string.cancel), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
try {
if (isThereAnyErrorFile()) {
String[] ErrorFileList = getErrorFileList();
for (String curString : ErrorFileList) {
deleteFile(curString);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
})
.show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}