package yuku.kirimfidbek;
import android.os.Build;
import android.os.SystemClock;
import android.util.Log;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import yuku.afw.App;
import yuku.afw.storage.Preferences;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
public class CrashReporter {
public static final String TAG = CrashReporter.class.getSimpleName();
static class Entry {
String body;
int versionCode;
int timestamp;
int versionSdk;
String capjempol;
public Entry(String body, int versionCode, int timestamp, int versionSdk, String capjempol) {
this.body = body;
this.versionCode = versionCode;
this.timestamp = timestamp;
this.versionSdk = versionSdk;
this.capjempol = capjempol;
}
}
final AtomicBoolean isSending = new AtomicBoolean();
final CatchAllExceptions catchAllExceptions;
List<Entry> entries;
public CrashReporter() {
getUniqueId(); // trigger creation of uniqueId.
catchAllExceptions = new CatchAllExceptions();
}
public void activateDefaultUncaughtExceptionHandler() {
catchAllExceptions.activate();
}
public void add(String body) {
load();
entries.add(new Entry(body, App.getVersionCode(), getTimestamp(), Build.VERSION.SDK_INT, null));
save();
}
int getTimestamp() {
return (int) (new Date().getTime() / 1000L);
}
synchronized void save() {
if (entries == null) return;
Preferences.hold();
try {
final int sz = entries.size();
Preferences.setInt("crash_report/size", sz);
for (int i = 0; i < sz; i++) {
final Entry entry = entries.get(i);
Preferences.setString("crash_report/" + i + "/body", entry.body);
Preferences.setInt("crash_report/" + i + "/versionCode", entry.versionCode);
Preferences.setInt("crash_report/" + i + "/timestamp", entry.timestamp);
Preferences.setInt("crash_report/" + i + "/versionSdk", entry.versionSdk);
Preferences.setString("crash_report/" + i + "/capjempol", entry.capjempol);
}
// remove old entries (save space and xml processing time)
for (int i = sz; ; i++) {
if (Preferences.contains("crash_report/" + i + "/body")) {
Preferences.remove("crash_report/" + i + "/body");
Preferences.remove("crash_report/" + i + "/versionCode");
Preferences.remove("crash_report/" + i + "/timestamp");
Preferences.remove("crash_report/" + i + "/versionSdk");
Preferences.remove("crash_report/" + i + "/capjempol");
} else {
break;
}
}
} finally {
Preferences.unhold();
}
}
public synchronized void trySend() {
load();
if (entries.size() == 0) {
return;
}
if (!isSending.compareAndSet(false, true)) {
return;
}
new Sender().start();
}
synchronized void load() {
if (entries != null) {
return;
}
entries = new ArrayList<>();
final int size = Preferences.getInt("crash_report/size", 0);
for (int i = 0; i < size; i++) {
String body = Preferences.getString("crash_report/" + i + "/body", null);
int versionCode = Preferences.getInt("crash_report/" + i + "/versionCode", 0);
int timestamp = Preferences.getInt("crash_report/" + i + "/timestamp", 0);
int versionSdk = Preferences.getInt("crash_report/" + i + "/versionSdk", 0);
String capjempol = Preferences.getString("crash_report/" + i + "/capjempol", null);
entries.add(new Entry(body, versionCode, timestamp, versionSdk, capjempol));
}
}
class Sender extends Thread {
public Sender() {
}
@Override
public void run() {
boolean success = false;
Log.d(TAG, "tred pengirim dimulai. thread id = " + getId());
try {
final OkHttpClient client = new OkHttpClient();
final Request.Builder request = new Request.Builder();
request.url("http://www.kejut.com/prog/android/fidbek/kirim3.php");
final FormBody.Builder form = new FormBody.Builder();
for (Entry entry : entries) {
if (entry.body.length() > 100000) {
entry.body = entry.body.substring(0, 100000);
}
form
.add("uniqueId[]", getUniqueId())
.add("package_name[]", App.context.getPackageName())
.add("fidbek_isi[]", "" + entry.body)
.add("package_versionCode[]", String.valueOf(entry.versionCode))
.add("timestamp[]", String.valueOf(entry.timestamp))
.add("build_product[]", "" + Build.PRODUCT)
.add("build_device[]", "" + Build.DEVICE)
.add("version_sdk[]", String.valueOf(entry.versionSdk))
.add("capjempol[]", "" + entry.capjempol);
}
request.post(form.build());
final Response response = client.newCall(request.build()).execute();
InputStream content = response.body().byteStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
while (true) {
byte[] b = new byte[4096];
int read = content.read(b);
if (read <= 0) break;
baos.write(b, 0, read);
}
byte[] out = baos.toByteArray();
if (out.length >= 2 && out[0] == 'O' && out[1] == 'K') {
success = true;
}
} catch (IOException e) {
Log.w(TAG, "when posting", e);
}
if (success) {
synchronized (CrashReporter.this) {
entries.clear();
}
save();
}
Log.d(TAG, "Sender thread finished. success: " + success);
isSending.set(false);
}
}
String getUniqueId() {
String uniqueId = Preferences.getString("fidbek_uniqueId", null);
if (uniqueId == null) {
uniqueId = "u2:" + UUID.randomUUID().toString();
Preferences.setString("fidbek_uniqueId", uniqueId);
}
return uniqueId;
}
public class CatchAllExceptions {
public final String TAG = CatchAllExceptions.class.getSimpleName();
private Thread.UncaughtExceptionHandler originalHandler;
private Thread.UncaughtExceptionHandler handler = new Thread.UncaughtExceptionHandler() {
@Override public void uncaughtException(Thread t, Throwable e) {
final StringWriter sw = new StringWriter(4000);
e.printStackTrace(new PrintWriter(sw, true));
add("[DUEH2] thread: " + t.getName() + " (" + t.getId() + ") " + e.getClass().getName() + ": " + e.getMessage() + "\n" + sw.toString());
trySend();
// Try waiting for 3 seconds before letting the app completely crash
SystemClock.sleep(3000);
Log.w(TAG, "UncaughtExceptionHandler finished.");
// call the original exception handler (force close dialog)
if (originalHandler != null) {
originalHandler.uncaughtException(t, e);
}
}
};
public void activate() {
originalHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(handler);
}
}
}