diff --git a/ExceptionHandlerLib/.classpath b/ExceptionHandlerLib/.classpath
new file mode 100644
index 0000000..6c635c0
--- /dev/null
+++ b/ExceptionHandlerLib/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/ExceptionHandlerLib/.directory b/ExceptionHandlerLib/.directory
new file mode 100644
index 0000000..5c21695
--- /dev/null
+++ b/ExceptionHandlerLib/.directory
@@ -0,0 +1,6 @@
+[Dolphin]
+Timestamp=2011,10,24,10,7,6
+Version=2
+
+[Settings]
+ShowDotFiles=true
diff --git a/ExceptionHandlerLib/.project b/ExceptionHandlerLib/.project
new file mode 100644
index 0000000..0ca9b49
--- /dev/null
+++ b/ExceptionHandlerLib/.project
@@ -0,0 +1,33 @@
+
+
+ ExceptionHandlerLib
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/ExceptionHandlerLib/AndroidManifest.xml b/ExceptionHandlerLib/AndroidManifest.xml
new file mode 100644
index 0000000..5979ae5
--- /dev/null
+++ b/ExceptionHandlerLib/AndroidManifest.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ExceptionHandler.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ExceptionHandler.class
new file mode 100644
index 0000000..293c866
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ExceptionHandler.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ExceptionReportActivity$1.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ExceptionReportActivity$1.class
new file mode 100644
index 0000000..aa0f45d
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ExceptionReportActivity$1.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ExceptionReportActivity.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ExceptionReportActivity.class
new file mode 100644
index 0000000..d05a8b2
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ExceptionReportActivity.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$attr.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$attr.class
new file mode 100644
index 0000000..570a28a
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$attr.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$id.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$id.class
new file mode 100644
index 0000000..66169ad
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$id.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$layout.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$layout.class
new file mode 100644
index 0000000..1950b7d
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$layout.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$string.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$string.class
new file mode 100644
index 0000000..c510e71
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R$string.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R.class
new file mode 100644
index 0000000..9a49352
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/R.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/Report$1.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/Report$1.class
new file mode 100644
index 0000000..fce6433
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/Report$1.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/Report.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/Report.class
new file mode 100644
index 0000000..5755de2
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/Report.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportAdapter$ViewHolder.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportAdapter$ViewHolder.class
new file mode 100644
index 0000000..14f560b
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportAdapter$ViewHolder.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportAdapter.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportAdapter.class
new file mode 100644
index 0000000..9d76c43
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportAdapter.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportItem$1.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportItem$1.class
new file mode 100644
index 0000000..3069711
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportItem$1.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportItem.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportItem.class
new file mode 100644
index 0000000..80dc2c1
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/ReportItem.class differ
diff --git a/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/VersionInformationPreference.class b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/VersionInformationPreference.class
new file mode 100644
index 0000000..3b8ab95
Binary files /dev/null and b/ExceptionHandlerLib/bin/classes/com/TwentyCodes/android/exception/VersionInformationPreference.class differ
diff --git a/ExceptionHandlerLib/bin/exceptionhandlerlib.jar b/ExceptionHandlerLib/bin/exceptionhandlerlib.jar
new file mode 100644
index 0000000..6504a85
Binary files /dev/null and b/ExceptionHandlerLib/bin/exceptionhandlerlib.jar differ
diff --git a/ExceptionHandlerLib/exceptionhandler.properties b/ExceptionHandlerLib/exceptionhandler.properties
new file mode 100644
index 0000000..07e821f
--- /dev/null
+++ b/ExceptionHandlerLib/exceptionhandler.properties
@@ -0,0 +1,20 @@
+# exceptionhandler.properties
+# This is the default Twenty Codes, LLC Exception Handler properties file
+#
+# This file must be included in the main project's assets folder
+#
+# @author Twenty Codes, LLC
+# @author ricky barrette
+
+
+# The following is for using our custom server based exception handler web application
+# server is the physical web address for your server
+# file is the path to your filing script
+# get is the path to your json retrieval script
+server = http://powers.doesntexist.com:666/testing
+file = /index.php?post=1
+#get = /index.php?get=1
+
+# uncomment the following if you want your application to use email to file reports.
+# if this is uncommented, email will always be used.
+#email = twentycodes@gmail.com
\ No newline at end of file
diff --git a/ExceptionHandlerLib/gen/com/TwentyCodes/android/exception/R.java b/ExceptionHandlerLib/gen/com/TwentyCodes/android/exception/R.java
new file mode 100644
index 0000000..52b96c0
--- /dev/null
+++ b/ExceptionHandlerLib/gen/com/TwentyCodes/android/exception/R.java
@@ -0,0 +1,32 @@
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package com.TwentyCodes.android.exception;
+
+public final class R {
+ public static final class attr {
+ }
+ public static final class id {
+ public static int description=0x7f040001;
+ public static int exception_text=0x7f040003;
+ public static int exception_title=0x7f040002;
+ public static int send=0x7f040000;
+ }
+ public static final class layout {
+ public static int exception_activity=0x7f020000;
+ public static int exception_list_item=0x7f020001;
+ public static int list=0x7f020002;
+ }
+ public static final class string {
+ public static int crash=0x7f030000;
+ public static int description=0x7f030004;
+ public static int send=0x7f030003;
+ public static int sending=0x7f030002;
+ public static int sorry=0x7f030001;
+ public static int version=0x7f030005;
+ }
+}
diff --git a/ExceptionHandlerLib/proguard.cfg b/ExceptionHandlerLib/proguard.cfg
new file mode 100644
index 0000000..8ad7d33
--- /dev/null
+++ b/ExceptionHandlerLib/proguard.cfg
@@ -0,0 +1,34 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native ;
+}
+
+-keepclasseswithmembernames class * {
+ public (android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembernames class * {
+ public (android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
diff --git a/ExceptionHandlerLib/project.properties b/ExceptionHandlerLib/project.properties
new file mode 100644
index 0000000..5ca7d62
--- /dev/null
+++ b/ExceptionHandlerLib/project.properties
@@ -0,0 +1,12 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+android.library=true
+# Project target.
+target=android-14
diff --git a/ExceptionHandlerLib/res/layout/exception_activity.xml b/ExceptionHandlerLib/res/layout/exception_activity.xml
new file mode 100644
index 0000000..d0ad6d8
--- /dev/null
+++ b/ExceptionHandlerLib/res/layout/exception_activity.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/ExceptionHandlerLib/res/layout/exception_list_item.xml b/ExceptionHandlerLib/res/layout/exception_list_item.xml
new file mode 100644
index 0000000..65238cc
--- /dev/null
+++ b/ExceptionHandlerLib/res/layout/exception_list_item.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ExceptionHandlerLib/res/layout/list.xml b/ExceptionHandlerLib/res/layout/list.xml
new file mode 100644
index 0000000..67a4bb2
--- /dev/null
+++ b/ExceptionHandlerLib/res/layout/list.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/ExceptionHandlerLib/res/values/strings.xml b/ExceptionHandlerLib/res/values/strings.xml
new file mode 100644
index 0000000..a603675
--- /dev/null
+++ b/ExceptionHandlerLib/res/values/strings.xml
@@ -0,0 +1,9 @@
+
+
+ Application Fault
+ I\'m sorry, but we found a problem. Please click here.
+ Sending...
+ Send
+ Optional: Describe what happened
+ Version
+
diff --git a/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ExceptionHandler.java b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ExceptionHandler.java
new file mode 100644
index 0000000..b2fb251
--- /dev/null
+++ b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ExceptionHandler.java
@@ -0,0 +1,225 @@
+/**
+ * ExceptionHandler.java
+ * @date Feb 12, 2011
+ * @author ricky barrette
+ * @author Twenty Codes, LLC
+ */
+package com.TwentyCodes.android.exception;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Properties;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.os.Build;
+import android.util.Log;
+
+/**
+ * This is Twenty Codes, LLC Exception Handler of Awesomeness!
+ * This class will be used to generate reports that will be emailed to us via the users email client after the users approval
+ * @author ricky barrette
+ */
+public class ExceptionHandler implements UncaughtExceptionHandler, Runnable {
+
+ private static final String MSG_SUBJECT_TAG = "Exception Report";
+ private static final String MSG_BODY = "Just click send to help make this application better. "+
+ "No personal information is being sent (you can check by reading the rest of the email).";
+ protected static final int SIMPLE_NOTFICATION_ID = 45684645;
+ private Thread.UncaughtExceptionHandler mDefaultUEH;
+ private Activity mApp= null;
+ private Service mService = null;
+ private BroadcastReceiver mBroadcastReceiver = null;
+ private Context mContext;
+ private Report mReport;
+ private static final String TAG = "ExceptionHandler";
+ private String mURL = null;
+ private String mEmail;
+
+ /**
+ * Creates a new ExceptionHandler
+ * @param app
+ * @author ricky barrette
+ */
+ public ExceptionHandler(Activity app) {
+ this.mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler();
+ this.mApp = app;
+ this.mContext = app;
+ parseProperties();
+ }
+
+ /**
+ * Creates a new ExceptionHandler
+ * @param broadcastReceiver
+ * @author ricky barrette
+ */
+ public ExceptionHandler(BroadcastReceiver broadcastReceiver, Context context){
+ this.mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler();
+ this.mBroadcastReceiver = broadcastReceiver;
+ this.mContext = context;
+ parseProperties();
+ }
+
+ /**
+ * Creates a new ExceptionHandler
+ * @param service
+ * @author ricky barrette
+ */
+ public ExceptionHandler(Service service){
+ this.mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler();
+ this.mService = service;
+ this.mContext = service;
+ parseProperties();
+ }
+
+ /**
+ * Generates an email from the report
+ * @author ricky barrette
+ */
+ private void displayEmailNotification(){
+ Log.i(TAG, "displayEmailNotification");
+
+ CharSequence title = null;
+ if(mApp != null)
+ title = mApp.getTitle();
+
+ if(mService != null)
+ title = mService.getClass().getName();
+
+ if(mBroadcastReceiver != null)
+ title = mBroadcastReceiver.getClass().getName();
+
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ String theSubject = title + " " + MSG_SUBJECT_TAG;
+ String theBody = "\n\n"+MSG_BODY+this.mReport.toString();
+ intent.putExtra(Intent.EXTRA_EMAIL,new String[] {this.mEmail});
+ intent.putExtra(Intent.EXTRA_TEXT, theBody);
+ intent.putExtra(Intent.EXTRA_SUBJECT, theSubject);
+ intent.setType("message/rfc822");
+
+ displayNotification(intent);
+ }
+
+ /**
+ * displays an notification in the status bar, letting the user know that there was an issue
+ * @param generatedReportIntent
+ */
+ private void displayNotification(Intent generatedReportIntent) {
+ Log.i(TAG, "displayNotification");
+ Context context = mContext.getApplicationContext();
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ Notification notifyDetails = new Notification(android.R.drawable.stat_notify_error, context.getString(R.string.sorry), System.currentTimeMillis());
+ PendingIntent intent = PendingIntent.getActivity(context, 0, generatedReportIntent, android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
+ notifyDetails.setLatestEventInfo(context, context.getString(R.string.crash), context.getString(R.string.sorry), intent);
+ notifyDetails.flags |= Notification.FLAG_AUTO_CANCEL;
+ notificationManager.notify(SIMPLE_NOTFICATION_ID, notifyDetails);
+ }
+
+ /**
+ * parses in the exception handler options from the client application's assets folder. /assets/exceptionhandler.properties
+ * @author ricky barrette
+ */
+ private void parseProperties() {
+ Resources resources = this.mContext.getResources();
+ AssetManager assetManager = resources.getAssets();
+ // Read from the /assets directory
+ try {
+ InputStream inputStream = assetManager.open("exceptionhandler.properties");
+ Properties properties = new Properties();
+ properties.load(inputStream);
+ this.mURL = properties.getProperty("server") + properties.getProperty("file");
+ this.mEmail = properties.getProperty("email");
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to open exceptionhandler.properties");
+ e.printStackTrace();
+ }
+ }
+
+ public void run() {
+ if(this.mEmail == null)
+ displayNotification(new Intent(this.mContext, ExceptionReportActivity.class).putExtra("report", this.mReport));
+ else
+ displayEmailNotification();
+ }
+
+ /**
+ * Called when there is an uncaught exception.
+ * (non-Javadoc)
+ * @see java.lang.Thread.UncaughtExceptionHandler#uncaughtException(java.lang.Thread, java.lang.Throwable)
+ * @author ricky barrette
+ */
+ @Override
+ public void uncaughtException(Thread t, Throwable e) {
+ Log.d(TAG, "uncaughtException()");
+
+ Log.d(TAG,"mURL = "+ this.mURL);
+ Log.d(TAG,"mEmail = "+ this.mEmail);
+
+ Date theDate = new Date();
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss_zzz");
+ PackageManager pm = mContext.getPackageManager();
+
+ //app environment;
+ PackageInfo pi;
+ try {
+ pi = pm.getPackageInfo(mContext.getPackageName(), 0);
+ } catch (NameNotFoundException eNnf) {
+ //doubt this will ever run since we want info about our own package
+ pi = new PackageInfo();
+ pi.versionName = "unknown";
+ pi.versionCode = 69;
+ }
+
+ StringBuffer report = new StringBuffer();
+ for (StackTraceElement item : e.getStackTrace())
+ report.append("at "+item.toString() + "\n");
+
+ StringBuffer causereport = new StringBuffer();
+ Throwable cause = e.getCause();
+ if (cause != null) {
+ causereport.append(cause.toString() + "\n \n");
+ for (StackTraceElement item : cause.getStackTrace())
+ causereport.append("at "+item.toString() + "\n");
+ }
+
+ //generate the report
+ this.mReport = new Report(mURL).generateReport(e.toString(), report.toString(), causereport.toString(), sdf.format(theDate), Build.FINGERPRINT, pi.versionName+"b"+pi.versionCode, mContext.getPackageName());
+
+ //try to send file contents via email (need to do so via the UI thread)
+ if(this.mApp != null){
+ this.mApp.runOnUiThread(this);
+ }
+
+
+ if(this.mService != null){
+ if(this.mEmail == null)
+ displayNotification(new Intent(this.mContext, ExceptionReportActivity.class).putExtra("report", this.mReport));
+ else
+ displayEmailNotification();
+ }
+
+ if(this.mBroadcastReceiver != null){
+ if(this.mEmail == null)
+ displayNotification(new Intent(this.mContext, ExceptionReportActivity.class).putExtra("report", this.mReport));
+ else
+ displayEmailNotification();
+ }
+
+ //do not forget to pass this exception through up the chain
+ mDefaultUEH.uncaughtException(t,e);
+ }
+}
\ No newline at end of file
diff --git a/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ExceptionReportActivity.java b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ExceptionReportActivity.java
new file mode 100644
index 0000000..51d8a6d
--- /dev/null
+++ b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ExceptionReportActivity.java
@@ -0,0 +1,81 @@
+/**
+ * ExceptionActivity.java
+ * @date May 31, 2011
+ * @author Twenty Codes, LLC
+ * @author ricky barrette
+ */
+package com.TwentyCodes.android.exception;
+
+import java.io.IOException;
+
+import org.apache.http.client.ClientProtocolException;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.os.Bundle;
+import android.os.Looper;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.EditText;
+import android.widget.ListView;
+
+/**
+ * This activity will be used to present the user with the exception report, and allows them to send it, or not
+ * @author ricky barrette
+ */
+public class ExceptionReportActivity extends Activity implements OnClickListener {
+
+ private static final String TAG = "ExceptionActivity";
+ private Report mReport;
+
+ /**
+ * (non-Javadoc)
+ * @see android.app.Activity#onCreate(android.os.Bundle)
+ * @author ricky barrette
+ */
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ Log.d(TAG, "onCreate()");
+ super.onCreate(savedInstanceState);
+ this.mReport = (Report) this.getIntent().getParcelableExtra("report");
+
+ if(this.getIntent().hasExtra("display"))
+ this.setContentView(R.layout.list);
+ else {
+ this.setContentView(R.layout.exception_activity);
+ this.findViewById(R.id.send).setOnClickListener(this);
+ }
+ ListView list = (ListView) this.findViewById(android.R.id.list);
+ list.setAdapter(new ReportAdapter(this, this.mReport.getReport()));
+ list.setClickable(false);
+ }
+
+ /**
+ * (non-Javadoc)
+ * @see android.view.View.OnClickListener#onClick(android.view.View)
+ * @author ricky barrette
+ */
+ @Override
+ public void onClick(View v) {
+ EditText description = (EditText) findViewById(R.id.description);
+ this.mReport.setDescription(description.getText().toString());
+ v.setEnabled(false);
+ final ProgressDialog progress = ProgressDialog.show(this, "", getString(R.string.sending), true, true);
+ new Thread( new Runnable(){
+ @Override
+ public void run(){
+ Looper.prepare();
+ try {
+ Log.d(TAG, ExceptionReportActivity.this.mReport.file());
+ } catch (ClientProtocolException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ progress.dismiss();
+ ExceptionReportActivity.this.finish();
+ }
+ }).start();
+ }
+}
\ No newline at end of file
diff --git a/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/Report.java b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/Report.java
new file mode 100644
index 0000000..f658d9a
--- /dev/null
+++ b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/Report.java
@@ -0,0 +1,192 @@
+/**
+ * Report.java
+ * @date May 29, 2011
+ * @author Twenty Codes, LLC
+ * @author ricky barrette
+ */
+package com.TwentyCodes.android.exception;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class will be used to generate a report, and insert it into our exception report database
+ * @author ricky barrette
+ */
+public class Report implements Parcelable{
+
+ private String mUrl;
+ private ArrayList mReport;
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public Report createFromParcel(Parcel in) {
+ return new Report(in);
+ }
+
+ public Report[] newArray(int size) {
+ return new Report[size];
+ }
+ };
+
+ /**
+ * Creates a new Report
+ * @param in
+ * @author ricky barrette
+ */
+ public Report(Parcel in){
+ this.mUrl = in.readString();
+ this.mReport = new ArrayList();
+ in.readTypedList(this.mReport, ReportItem.CREATOR);
+ }
+
+ /**
+ * Creates a new Report
+ * @author ricky barrette
+ */
+ public Report(String mysqlUrl) {
+ this.mUrl = mysqlUrl;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Files the report with the remote database
+ * @author ricky barrette
+ * @throws IOException
+ * @throws ClientProtocolException
+ * @return String result
+ */
+ public String file() throws ClientProtocolException, IOException{
+ HttpClient httpclient = new DefaultHttpClient();
+ HttpPost httppost = new HttpPost(mUrl);
+ httppost.setEntity(new UrlEncodedFormEntity(getNameValuePairs()));
+
+ //return the results
+ HttpResponse response = httpclient.execute(httppost);
+ HttpEntity entity = response.getEntity();
+ InputStream is = entity.getContent();
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is,"iso-8859-1"),8);
+ StringBuilder sb = new StringBuilder();
+ sb.append(reader.readLine() + "\n");
+ String line="0";
+ while ((line = reader.readLine()) != null)
+ sb.append(line + "\n");
+ is.close();
+ reader.close();
+ return sb.toString();
+ }
+
+ /**
+ * Generates a report to be displayed form a downloaded JSON object
+ * @param report
+ * @return
+ * @author ricky barrette
+ * @throws JSONException
+ */
+ @SuppressWarnings("rawtypes")
+ public Report generateReport(JSONObject report) throws JSONException{
+ this.mReport = new ArrayList();
+ Iterator iter = report.keys();
+ while(iter.hasNext()){
+ String key = (String)iter.next();
+ this.mReport.add(new ReportItem(key , report.getString(key)));
+ }
+ return this;
+ }
+
+ /**
+ * Generates a report to be sent.
+ * @param msg
+ * @param stackTrace
+ * @param cause
+ * @param device
+ * @param appVersion
+ * @param app
+ * @return this
+ * @author ricky barrette
+ */
+ public Report generateReport(String msg, String stackTrace, String cause, String date, String device, String appVersion, String app){
+ this.mReport = new ArrayList();
+ this.mReport.add(new ReportItem("app",app));
+ this.mReport.add(new ReportItem("version",appVersion));
+ this.mReport.add(new ReportItem("date",date));
+ this.mReport.add(new ReportItem("msg",msg));
+ this.mReport.add(new ReportItem("stackTrace",stackTrace));
+ this.mReport.add(new ReportItem("cause",cause));
+ this.mReport.add(new ReportItem("device",device));
+ return this;
+ }
+
+ /**
+ * Extracts the name value pairs from the report bundle
+ * @return
+ * @author ricky barrette
+ */
+ private ArrayList getNameValuePairs() {
+ ArrayList list = new ArrayList();
+ for(ReportItem entry : this.mReport)
+ list.add(new BasicNameValuePair(entry.getKey(), (String) entry.getValue()));
+ return list;
+ }
+
+ /**
+ * @return the generated exception report
+ * @author ricky barrette
+ */
+ public ArrayList getReport(){
+ return getNameValuePairs();
+ }
+
+ /**
+ * Sets the optional users description of what happened
+ * @param string
+ * @author ricky barrette
+ */
+ public Report setDescription(String description) {
+ this.mReport.add(new ReportItem("description", description));
+ return this;
+ }
+
+ /**
+ * @return a human readable string of this report
+ * @author ricky barrette
+ */
+ @Override
+ public String toString(){
+ StringBuilder s = new StringBuilder();
+ for(ReportItem item : this.mReport){
+ s.append("\n\n-----"+ item.getKey()+"-----");
+ s.append("\n"+item.getValue());
+ }
+ return s.toString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(this.mUrl);
+ out.writeTypedList(this.mReport);
+ }
+}
\ No newline at end of file
diff --git a/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ReportAdapter.java b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ReportAdapter.java
new file mode 100644
index 0000000..1ec7cef
--- /dev/null
+++ b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ReportAdapter.java
@@ -0,0 +1,112 @@
+/**
+ * ReportAdapter.java
+ * @date May 31, 2011
+ * @author Twenty Codes, LLC
+ * @author ricky barrette
+ */
+package com.TwentyCodes.android.exception;
+
+import java.util.ArrayList;
+
+import org.apache.http.NameValuePair;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import com.TwentyCodes.android.exception.R;
+
+/**
+ * This class will be used to populate a custom Listview used to display the Generated exception report
+ * @author ricky barrette
+ */
+public class ReportAdapter extends BaseAdapter {
+
+ private ArrayList mReport;
+ private LayoutInflater mInflater;
+
+ /**
+ * Creates a new ReportAdapter
+ * @author ricky barrette
+ */
+ public ReportAdapter(Context context, ArrayList report) {
+ super();
+ // Cache the LayoutInflate to avoid asking for a new one each time.
+ this.mInflater = LayoutInflater.from(context);
+ this.mReport = report;
+ }
+
+ /**
+ * (non-Javadoc)
+ * @see android.widget.Adapter#getCount()
+ * @author ricky barrette
+ */
+ @Override
+ public int getCount() {
+ return this.mReport.size();
+ }
+
+ /**
+ * (non-Javadoc)
+ * @see android.widget.Adapter#getItem(int)
+ * @author ricky barrette
+ */
+ @Override
+ public NameValuePair getItem(int index) {
+ return this.mReport.get(index);
+ }
+
+ /**
+ * (non-Javadoc)
+ * @see android.widget.Adapter#getItemId(int)
+ * @author ricky barrette
+ */
+ @Override
+ public long getItemId(int index) {
+ return index;
+ }
+
+ /**
+ *
+ */
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+
+ // A ViewHolder keeps references to children views to avoid unnecessary calls to findViewById() on each row.
+ ViewHolder holder;
+
+ // When convertView is not null, we can reuse it directly, there is no need
+ // to reinflate it. We only inflate a new View when the convertView supplied
+ // by ListView is null.
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.exception_list_item, null);
+
+ // Creates a ViewHolder and store references to the two children views
+ // we want to bind data to.
+ holder = new ViewHolder();
+ holder.title = (TextView) convertView.findViewById(R.id.exception_title);
+ holder.body = (TextView) convertView.findViewById(R.id.exception_text);
+
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ /*
+ * Bind the data efficiently with the holder.
+ */
+ holder.title.setText(getItem(position).getName());
+ holder.body.setText(getItem(position).getValue());
+
+ return convertView;
+ }
+
+ class ViewHolder {
+ TextView title;
+ TextView body;
+ }
+
+}
diff --git a/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ReportItem.java b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ReportItem.java
new file mode 100644
index 0000000..21cd76b
--- /dev/null
+++ b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/ReportItem.java
@@ -0,0 +1,82 @@
+/**
+ * ReportItem.java
+ * @date July 13, 2010
+ * @author Twenty Codes, LLC
+ * @author ricky barrette
+ */
+package com.TwentyCodes.android.exception;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class will represent an individual report item. The ReportItems will be used in an array list that will be passed via intent.
+ * This will allow for our report items to stay in the proper order.
+ * @author ricky
+ */
+public class ReportItem implements Parcelable {
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public ReportItem createFromParcel(Parcel in) {
+ return new ReportItem(in);
+ }
+
+ public ReportItem[] newArray(int size) {
+ return new ReportItem[size];
+ }
+ };
+
+ private String mKey;
+ private String mValue;
+
+ /**
+ * Creates a new ReportItem
+ * @author ricky barrette
+ */
+ public ReportItem(String key, String value) {
+ this.mKey = key;
+ this.mValue = value;
+ }
+
+ /**
+ * Creates a new ReportItem from a parcel
+ * @param in
+ */
+ public ReportItem(Parcel in){
+ this.mKey = in.readString();
+ this.mValue = in.readString();
+ }
+
+ /* (non-Javadoc)
+ * @see android.os.Parcelable#describeContents()
+ */
+ @Override
+ public int describeContents() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ /* (non-Javadoc)
+ * @see android.os.Parcelable#writeToParcel(android.os.Parcel, int)
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(this.mKey);
+ dest.writeString(this.mValue);
+ }
+
+ /**
+ * @return the key
+ */
+ public String getKey() {
+ return this.mKey;
+ }
+
+ /**
+ * @return the value
+ */
+ public String getValue() {
+ return this.mValue;
+ }
+
+}
\ No newline at end of file
diff --git a/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/VersionInformationPreference.java b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/VersionInformationPreference.java
new file mode 100644
index 0000000..0765923
--- /dev/null
+++ b/ExceptionHandlerLib/src/com/TwentyCodes/android/exception/VersionInformationPreference.java
@@ -0,0 +1,116 @@
+/**
+ * @author Twenty Codes
+ * @author ricky barrette
+ * @date June 29, 2011
+ */
+package com.TwentyCodes.android.exception;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Typeface;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * this class will be a simple preference that contains only a text view that will display the application build information
+ * @author ricky barrette
+ */
+public class VersionInformationPreference extends Preference {
+
+ private Context mContext;
+
+
+ /**
+ * creates a preference that is nothing but a text view
+ * @param context
+ */
+ public VersionInformationPreference(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ /**
+ * creates a preference that is nothing but a text view
+ * @param context
+ * @param attrs
+ */
+ public VersionInformationPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ }
+
+ /**
+ * creates a preference that is nothing but a text view
+ * @param context
+ * @param attrs
+ * @param defStyle
+ */
+ public VersionInformationPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mContext = context;
+ }
+
+
+ /**
+ * creates a linear layout the contains only a textview.
+ * (non-Javadoc)
+ * @see android.preference.Preference#onCreateView(android.view.ViewGroup)
+ * @param parent
+ * @return
+ * @author ricky barrette
+ */
+ @Override
+ protected View onCreateView(ViewGroup parent){
+
+ /*
+ * get the build information, and build the string
+ */
+ PackageManager pm = mContext.getPackageManager();
+ PackageInfo pi;
+ try {
+ pi = pm.getPackageInfo(mContext.getPackageName(), 0);
+ } catch (NameNotFoundException eNnf) {
+ //doubt this will ever run since we want info about our own package
+ pi = new PackageInfo();
+ pi.versionName = "unknown";
+ pi.versionCode = 1;
+ }
+
+ /*
+ * create a vertical linear layout that width and height that wraps content
+ */
+ LinearLayout layout = new LinearLayout(getContext());
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+// params.gravity = Gravity.CENTER;
+ layout.setPadding(15, 5, 10, 5);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ layout.removeAllViews();
+
+ /*
+ * create a textview that will be used to display the application's name and build information
+ * and add it to the layout
+ */
+ TextView title = new TextView(getContext());
+ title.setText(mContext.getString(R.string.version)+" "+pi.versionName+" bulid "+pi.versionCode);
+ title.setTextSize(16);
+ title.setTypeface(Typeface.SANS_SERIF);
+ title.setGravity(Gravity.LEFT);
+ title.setLayoutParams(params);
+
+ /*
+ * add the title views to the layout
+ */
+ layout.addView(title);
+ layout.setId(android.R.id.widget_frame);
+
+ return layout;
+ }
+}