1package eu.siacs.conversations.utils;
2
3import android.support.v7.app.AlertDialog;
4import android.content.Context;
5import android.content.DialogInterface;
6import android.content.DialogInterface.OnClickListener;
7import android.content.SharedPreferences;
8import android.content.pm.PackageInfo;
9import android.content.pm.PackageManager;
10import android.content.pm.Signature;
11import android.preference.PreferenceManager;
12import android.util.Log;
13
14import java.io.BufferedReader;
15import java.io.FileInputStream;
16import java.io.IOException;
17import java.io.InputStreamReader;
18import java.io.OutputStream;
19import java.text.SimpleDateFormat;
20import java.util.Date;
21import java.util.List;
22import java.util.Locale;
23
24import eu.siacs.conversations.Config;
25import eu.siacs.conversations.R;
26import eu.siacs.conversations.entities.Account;
27import eu.siacs.conversations.entities.Conversation;
28import eu.siacs.conversations.entities.Message;
29import eu.siacs.conversations.services.XmppConnectionService;
30import eu.siacs.conversations.ui.XmppActivity;
31import rocks.xmpp.addr.Jid;
32
33public class ExceptionHelper {
34
35 private static final String FILENAME = "stacktrace.txt";
36 private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
37
38 public static void init(Context context) {
39 if (!(Thread.getDefaultUncaughtExceptionHandler() instanceof ExceptionHandler)) {
40 Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(
41 context));
42 }
43 }
44
45 public static boolean checkForCrash(XmppActivity activity) {
46 try {
47 final XmppConnectionService service = activity == null ? null : activity.xmppConnectionService;
48 if (service == null) {
49 return false;
50 }
51 final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
52 boolean neverSend = preferences.getBoolean("never_send", false);
53 if (neverSend || Config.BUG_REPORTS == null) {
54 return false;
55 }
56 List<Account> accounts = service.getAccounts();
57 Account account = null;
58 for (int i = 0; i < accounts.size(); ++i) {
59 if (accounts.get(i).isEnabled()) {
60 account = accounts.get(i);
61 break;
62 }
63 }
64 if (account == null) {
65 return false;
66 }
67 final Account finalAccount = account;
68 FileInputStream file = activity.openFileInput(FILENAME);
69 InputStreamReader inputStreamReader = new InputStreamReader(file);
70 BufferedReader stacktrace = new BufferedReader(inputStreamReader);
71 final StringBuilder report = new StringBuilder();
72 PackageManager pm = activity.getPackageManager();
73 PackageInfo packageInfo;
74 try {
75 packageInfo = pm.getPackageInfo(activity.getPackageName(), PackageManager.GET_SIGNATURES);
76 report.append("Version: ").append(packageInfo.versionName).append('\n');
77 report.append("Last Update: ").append(DATE_FORMAT.format(new Date(packageInfo.lastUpdateTime))).append('\n');
78 Signature[] signatures = packageInfo.signatures;
79 if (signatures != null && signatures.length >= 1) {
80 report.append("SHA-1: ").append(CryptoHelper.getFingerprintCert(packageInfo.signatures[0].toByteArray())).append('\n');
81 }
82 report.append('\n');
83 } catch (Exception e) {
84 e.printStackTrace();
85 return false;
86 }
87 String line;
88 while ((line = stacktrace.readLine()) != null) {
89 report.append(line);
90 report.append('\n');
91 }
92 file.close();
93 activity.deleteFile(FILENAME);
94 AlertDialog.Builder builder = new AlertDialog.Builder(activity);
95 builder.setTitle(activity.getString(R.string.crash_report_title));
96 builder.setMessage(activity.getText(R.string.crash_report_message));
97 builder.setPositiveButton(activity.getText(R.string.send_now),
98 new OnClickListener() {
99
100 @Override
101 public void onClick(DialogInterface dialog, int which) {
102
103 Log.d(Config.LOGTAG, "using account="
104 + finalAccount.getJid().asBareJid()
105 + " to send in stack trace");
106 Conversation conversation = null;
107 try {
108 conversation = service.findOrCreateConversation(finalAccount,
109 Jid.of(Config.BUG_REPORTS), false, true);
110 } catch (final IllegalArgumentException ignored) {
111 }
112 Message message = new Message(conversation, report
113 .toString(), Message.ENCRYPTION_NONE);
114 service.sendMessage(message);
115 }
116 });
117 builder.setNegativeButton(activity.getText(R.string.send_never),
118 new OnClickListener() {
119
120 @Override
121 public void onClick(DialogInterface dialog, int which) {
122 preferences.edit().putBoolean("never_send", true)
123 .apply();
124 }
125 });
126 builder.create().show();
127 return true;
128 } catch (final IOException ignored) {
129 return false;
130 }
131 }
132
133 public static void writeToStacktraceFile(Context context, String msg) {
134 try {
135 OutputStream os = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
136 os.write(msg.getBytes());
137 os.flush();
138 os.close();
139 } catch (IOException ignored) {
140 }
141 }
142}