Permalink
Browse files

Added crash reports and user feedback via email.

This is done by the usage of the library ACRA.
Crash reports will now be send to a php script that will send the report via email to me.
I also added a dialog for sending feedback (about wrong exercises).
  • Loading branch information...
chaosbastler committed Jun 1, 2014
1 parent aec89e3 commit 19e52b76b8370e78b9d67e4110d04463d1cd2ad6
View
@@ -5,5 +5,6 @@
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="lib" path="libs/acra-4.5.0.jar"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>
View
@@ -18,7 +18,7 @@
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar" >
android:theme="@style/Theme.AppCompat.Light.DarkActionBar" android:name="de.skubware.opentraining.activity.acra.OpenTrainingApplication">
<activity
android:name="de.skubware.opentraining.activity.MainActivity"
android:label="@string/app_name">
@@ -94,7 +94,12 @@
android:label="@string/create_exercise_activity_title"
android:icon="@drawable/icon_dumbbell" >
</activity>
<activity android:name="org.acra.CrashReportDialog"
android:theme="@android:style/Theme.Dialog"
android:launchMode="singleInstance"
android:excludeFromRecents="true"
android:finishOnTaskLaunch="true" />
<service android:enabled="true" android:name="de.skubware.opentraining.activity.settings.sync.OpenTrainingSyncService" />
</application>
View
Binary file not shown.
@@ -0,0 +1,51 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/my_frame"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Issue:"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Spinner
android:id="@+id/exercise_update_reason_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/textView1" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Your suggestion:"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
<EditText
android:id="@+id/edittext_user_suggestion"
android:layout_width="match_parent"
android:layout_height="163dp"
android:ems="10"
android:inputType="textMultiLine" >
<requestFocus />
</EditText>
</LinearLayout>
@@ -22,4 +22,10 @@
android:visible="false"
android:title="@string/delete_exercise"
yourapp:showAsAction="never"/>
<item
android:id="@+id/menu_item_send_exercise_feedback"
android:visible="false"
android:title="@string/send_exercise_feedback"
yourapp:showAsAction="never"/>
</menu>
@@ -0,0 +1,16 @@
<resources>
<!-- exercise detail menu -->
<string name="send_exercise_feedback">Fehler melden</string>
<!-- SendExerciseFeedbackDialog -->
<string name="send_feedback_for_exercise">Feedback zu: %1$s</string>
<!-- ACRA crash report dialog -->
<string name="crash_dialog_text">Ein unerwarteter Fehler brachte die Anwendung leider zum Absturz. Bitte hilf bei der Fehlerbehebung indem du uns die Fehlerdaten mit \'OK\' zusendest.</string>
<string name="crash_dialog_comment_prompt">Du kannst zusätzlich noch einen Kommentar zu dem Fehler hinzufügen:</string>
<string name="crash_dialog_ok_toast">Der Fehlerbericht wurde gesendet. Vielen Dank für die Mithilfe.</string>
</resources>
@@ -0,0 +1,16 @@
<resources>
<!-- exercise detail menu -->
<string name="send_exercise_feedback">Report error</string>
<!-- SendExerciseFeedbackDialog -->
<string name="send_feedback_for_exercise">Feedback for: %1$s</string>
<!-- ACRA crash report dialog -->
<string name="crash_dialog_text">An unexpected error occurred forcing the application to stop. Please help by sending us error date by clicking \'OK\'.</string>
<string name="crash_dialog_comment_prompt">You might add your comments abouth the problem below:</string>
<string name="crash_dialog_ok_toast">Report has been sent. Thank you for helping.</string>
</resources>
@@ -0,0 +1,129 @@
package de.skubware.opentraining.activity.acra;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.acra.collector.CrashReportData;
import org.acra.ReportField;
import org.acra.sender.ReportSender;
import org.acra.sender.ReportSenderException;
import org.apache.http.NameValuePair;
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.apache.http.protocol.HTTP;
import android.util.Log;
/**
* Based on acra-mailer(https://github.com/d-a-n/acra-mailer) of d-a-n.
*/
public class ACRACrashReportMailer implements ReportSender {
private final static String BASE_URL = "http://skubware.de/opentraining/acra_crash.php";
private final static String SHARED_SECRET = "my_on_github_with_everyone_shared_secret";
private Map<String, String> custom_data = null;
public ACRACrashReportMailer() {
}
public ACRACrashReportMailer(HashMap<String, String> custom_data) {
this.custom_data = custom_data;
}
@Override
public void send(CrashReportData report) throws ReportSenderException {
String url = getUrl();
Log.e("xenim", url);
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
if (custom_data != null) {
for (Map.Entry<String, String> entry : custom_data.entrySet()) {
parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
}
parameters.add(new BasicNameValuePair("DATE", new Date().toString()));
parameters.add(new BasicNameValuePair("REPORT_ID", report.get(ReportField.REPORT_ID)));
parameters.add(new BasicNameValuePair("APP_VERSION_CODE", report.get(ReportField.APP_VERSION_CODE)));
parameters.add(new BasicNameValuePair("APP_VERSION_NAME", report.get(ReportField.APP_VERSION_NAME)));
parameters.add(new BasicNameValuePair("PACKAGE_NAME", report.get(ReportField.PACKAGE_NAME)));
parameters.add(new BasicNameValuePair("FILE_PATH", report.get(ReportField.FILE_PATH)));
parameters.add(new BasicNameValuePair("PHONE_MODEL", report.get(ReportField.PHONE_MODEL)));
parameters.add(new BasicNameValuePair("ANDROID_VERSION", report.get(ReportField.ANDROID_VERSION)));
parameters.add(new BasicNameValuePair("BUILD", report.get(ReportField.BUILD)));
parameters.add(new BasicNameValuePair("BRAND", report.get(ReportField.BRAND)));
parameters.add(new BasicNameValuePair("PRODUCT", report.get(ReportField.PRODUCT)));
parameters.add(new BasicNameValuePair("TOTAL_MEM_SIZE", report.get(ReportField.TOTAL_MEM_SIZE)));
parameters.add(new BasicNameValuePair("AVAILABLE_MEM_SIZE", report.get(ReportField.AVAILABLE_MEM_SIZE)));
parameters.add(new BasicNameValuePair("CUSTOM_DATA", report.get(ReportField.CUSTOM_DATA)));
parameters.add(new BasicNameValuePair("STACK_TRACE", report.get(ReportField.STACK_TRACE)));
parameters.add(new BasicNameValuePair("INITIAL_CONFIGURATION", report.get(ReportField.INITIAL_CONFIGURATION)));
parameters.add(new BasicNameValuePair("CRASH_CONFIGURATION", report.get(ReportField.CRASH_CONFIGURATION)));
parameters.add(new BasicNameValuePair("DISPLAY", report.get(ReportField.DISPLAY)));
parameters.add(new BasicNameValuePair("USER_COMMENT", report.get(ReportField.USER_COMMENT)));
parameters.add(new BasicNameValuePair("USER_APP_START_DATE", report.get(ReportField.USER_APP_START_DATE)));
parameters.add(new BasicNameValuePair("USER_CRASH_DATE", report.get(ReportField.USER_CRASH_DATE)));
parameters.add(new BasicNameValuePair("DUMPSYS_MEMINFO", report.get(ReportField.DUMPSYS_MEMINFO)));
parameters.add(new BasicNameValuePair("DROPBOX", report.get(ReportField.DROPBOX)));
parameters.add(new BasicNameValuePair("LOGCAT", report.get(ReportField.LOGCAT)));
parameters.add(new BasicNameValuePair("EVENTSLOG", report.get(ReportField.EVENTSLOG)));
parameters.add(new BasicNameValuePair("RADIOLOG", report.get(ReportField.RADIOLOG)));
parameters.add(new BasicNameValuePair("IS_SILENT", report.get(ReportField.IS_SILENT)));
parameters.add(new BasicNameValuePair("DEVICE_ID", report.get(ReportField.DEVICE_ID)));
parameters.add(new BasicNameValuePair("INSTALLATION_ID", report.get(ReportField.INSTALLATION_ID)));
parameters.add(new BasicNameValuePair("USER_EMAIL", report.get(ReportField.USER_EMAIL)));
parameters.add(new BasicNameValuePair("DEVICE_FEATURES", report.get(ReportField.DEVICE_FEATURES)));
parameters.add(new BasicNameValuePair("ENVIRONMENT", report.get(ReportField.ENVIRONMENT)));
parameters.add(new BasicNameValuePair("SETTINGS_SYSTEM", report.get(ReportField.SETTINGS_SYSTEM)));
parameters.add(new BasicNameValuePair("SETTINGS_SECURE", report.get(ReportField.SETTINGS_SECURE)));
parameters.add(new BasicNameValuePair("SHARED_PREFERENCES", report.get(ReportField.SHARED_PREFERENCES)));
parameters.add(new BasicNameValuePair("APPLICATION_LOG", report.get(ReportField.APPLICATION_LOG)));
parameters.add(new BasicNameValuePair("MEDIA_CODEC_LIST", report.get(ReportField.MEDIA_CODEC_LIST)));
parameters.add(new BasicNameValuePair("THREAD_DETAILS", report.get(ReportField.THREAD_DETAILS)));
httpPost.setEntity(new UrlEncodedFormEntity(parameters, HTTP.UTF_8));
httpClient.execute(httpPost);
} catch (Exception e) {
e.printStackTrace();
}
}
private String getUrl() {
String token = getToken();
String key = getKey(token);
return String.format("%s?token=%s&key=%s&", BASE_URL, token, key);
}
private String getKey(String token) {
return md5(String.format("%s+%s", SHARED_SECRET, token));
}
private String getToken() {
return md5(UUID.randomUUID().toString());
}
public static String md5(String s) {
MessageDigest m = null;
try {
m = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
m.update(s.getBytes(), 0, s.length());
String hash = new BigInteger(1, m.digest()).toString(16);
return hash;
}
}
@@ -0,0 +1,102 @@
package de.skubware.opentraining.activity.acra;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.acra.collector.CrashReportData;
import org.acra.ACRA;
import org.acra.ReportField;
import org.acra.sender.ReportSender;
import org.acra.sender.ReportSenderException;
import org.apache.http.NameValuePair;
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.apache.http.protocol.HTTP;
import android.util.Log;
/**
* Based on acra-mailer(https://github.com/d-a-n/acra-mailer) of d-a-n.
*/
public class ACRAFeedbackMailer implements ReportSender {
private final static String BASE_URL = "http://skubware.de/opentraining/acra_feedback.php";
private final static String SHARED_SECRET = "my_on_github_with_everyone_shared_secret";
private Map<String, String> custom_data = null;
public ACRAFeedbackMailer() {
}
public ACRAFeedbackMailer(HashMap<String, String> custom_data) {
this.custom_data = custom_data;
}
@Override
public void send(CrashReportData report) throws ReportSenderException {
String url = getUrl();
Log.e("xenim", url);
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
if (custom_data != null) {
for (Map.Entry<String, String> entry : custom_data.entrySet()) {
parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
}
parameters.add(new BasicNameValuePair("DATE", new Date().toString()));
parameters.add(new BasicNameValuePair("APP_VERSION_NAME", report.get(ReportField.APP_VERSION_NAME)));
parameters.add(new BasicNameValuePair("CUSTOM_DATA", report.get(ReportField.CUSTOM_DATA)));
httpPost.setEntity(new UrlEncodedFormEntity(parameters, HTTP.UTF_8));
httpClient.execute(httpPost);
// set the crash report sender again after sending the feedback
ACRA.getErrorReporter().removeAllReportSenders();
ACRA.getErrorReporter().setReportSender(new ACRACrashReportMailer());
} catch (Exception e) {
e.printStackTrace();
}
}
private String getUrl() {
String token = getToken();
String key = getKey(token);
return String.format("%s?token=%s&key=%s&", BASE_URL, token, key);
}
private String getKey(String token) {
return md5(String.format("%s+%s", SHARED_SECRET, token));
}
private String getToken() {
return md5(UUID.randomUUID().toString());
}
public static String md5(String s) {
MessageDigest m = null;
try {
m = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
m.update(s.getBytes(), 0, s.length());
String hash = new BigInteger(1, m.digest()).toString(16);
return hash;
}
}
Oops, something went wrong.

0 comments on commit 19e52b7

Please sign in to comment.