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