ExceptionHelper.java

  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}