init commit

This commit is contained in:
2011-12-17 16:05:20 +00:00
parent 140bdaff43
commit 8d76751061
34 changed files with 1053 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@@ -0,0 +1,6 @@
[Dolphin]
Timestamp=2011,10,24,10,7,6
Version=2
[Settings]
ShowDotFiles=true

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ExceptionHandlerLib</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.TwentyCodes.android.exception"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="14" />
<application >
</application>
</manifest>

Binary file not shown.

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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 <methods>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(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 *;
}

View File

@@ -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

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff">
<Button
android:id="@+id/send"
android:text="@string/send"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/description"
android:id="@+id/description"
android:layout_below="@id/send"
android:freezesText="true"
/>
<ListView
android:layout_below="@id/description"
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</RelativeLayout>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#ffffff">
<TextView
android:text="title"
android:id="@+id/exception_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center_vertical"
android:textColor="#99CC00"
/>
<TextView
android:text="body"
android:id="@+id/exception_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
/>
</LinearLayout>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView android:id="@android:id/empty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center_vertical"
android:textColor="#99CC00"
android:text="No Reports"
/>
</LinearLayout>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="crash">Application Fault</string>
<string name="sorry">I\'m sorry, but we found a problem. Please click here.</string>
<string name="sending">Sending...</string>
<string name="send">Send</string>
<string name="description">Optional: Describe what happened</string>
<string name="version">Version</string>
</resources>

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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<ReportItem> mReport;
public static final Parcelable.Creator<Report> CREATOR = new Parcelable.Creator<Report>() {
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<ReportItem>();
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<ReportItem>();
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<ReportItem>();
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<NameValuePair> getNameValuePairs() {
ArrayList<NameValuePair> list = new ArrayList<NameValuePair>();
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<NameValuePair> 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);
}
}

View File

@@ -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<NameValuePair> mReport;
private LayoutInflater mInflater;
/**
* Creates a new ReportAdapter
* @author ricky barrette
*/
public ReportAdapter(Context context, ArrayList<NameValuePair> 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;
}
}

View File

@@ -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<ReportItem> CREATOR = new Parcelable.Creator<ReportItem>() {
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;
}
}

View File

@@ -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;
}
}