Browse Source
Merge pull request #835 from ammargitham/add-sentry
Merge pull request #835 from ammargitham/add-sentry
Add sentry to github buildsrenovate/org.robolectric-robolectric-4.x
Austin Huang
4 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 556 additions and 217 deletions
-
1.gitignore
-
22app/build.gradle
-
13app/sentry.gradle
-
40app/src/fdroid/java/awais/instagrabber/fragments/settings/FlavorSettings.java
-
56app/src/fdroid/java/awaisomereport/CrashHandler.java
-
10app/src/github/AndroidManifest.xml
-
83app/src/github/java/awais/instagrabber/fragments/settings/FlavorSettings.java
-
59app/src/github/java/awaisomereport/CrashHandler.java
-
6app/src/github/res/values/strings.xml
-
39app/src/main/java/awais/instagrabber/InstaGrabberApplication.java
-
69app/src/main/java/awais/instagrabber/dialogs/ConfirmDialogFragment.java
-
8app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageSettingsFragment.java
-
10app/src/main/java/awais/instagrabber/fragments/settings/GeneralPreferencesFragment.java
-
14app/src/main/java/awais/instagrabber/fragments/settings/IFlavorSettings.java
-
1app/src/main/java/awais/instagrabber/fragments/settings/PreferenceKeys.java
-
6app/src/main/java/awais/instagrabber/fragments/settings/SettingCategory.java
-
2app/src/main/java/awais/instagrabber/utils/Constants.java
-
7app/src/main/java/awais/instagrabber/utils/SettingsHelper.java
-
179app/src/main/java/awaisomereport/CrashReporter.java
-
134app/src/main/java/awaisomereport/CrashReporterHelper.java
-
5app/src/main/java/awaisomereport/ErrorReporterActivity.java
-
7app/src/main/java/awaisomereport/ICrashHandler.java
-
2app/src/main/res/values/strings.xml
@ -0,0 +1,13 @@ |
|||
def dsnKey = 'DSN' |
|||
def defaultDsn = '\"\"' |
|||
|
|||
final Properties properties = new Properties() |
|||
File propertiesFile = rootProject.file('sentry.properties') |
|||
if (!propertiesFile.exists()) { |
|||
propertiesFile.createNewFile() |
|||
} |
|||
properties.load(new FileInputStream(propertiesFile)) |
|||
|
|||
ext{ |
|||
SENTRY_DSN = properties.getProperty(dsnKey, defaultDsn) |
|||
} |
@ -0,0 +1,40 @@ |
|||
package awais.instagrabber.fragments.settings; |
|||
|
|||
import android.content.Context; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.fragment.app.FragmentManager; |
|||
import androidx.preference.Preference; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
|
|||
import awais.instagrabber.fragments.settings.IFlavorSettings; |
|||
import awais.instagrabber.fragments.settings.SettingCategory; |
|||
|
|||
public final class FlavorSettings implements IFlavorSettings { |
|||
|
|||
private static FlavorSettings instance; |
|||
|
|||
private FlavorSettings() { |
|||
} |
|||
|
|||
public static FlavorSettings getInstance() { |
|||
if (instance == null) { |
|||
instance = new FlavorSettings(); |
|||
} |
|||
return instance; |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public List<Preference> getPreferences(@NonNull final Context context, |
|||
@NonNull final FragmentManager fragmentManager, |
|||
@NonNull final SettingCategory settingCategory) { |
|||
// switch (settingCategory) { |
|||
// default: |
|||
// break; |
|||
// } |
|||
return Collections.emptyList(); |
|||
} |
|||
} |
@ -0,0 +1,56 @@ |
|||
package awaisomereport; |
|||
|
|||
import android.app.Application; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
|
|||
public class CrashHandler implements ICrashHandler { |
|||
private static final String TAG = CrashHandler.class.getSimpleName(); |
|||
|
|||
private final Application application; |
|||
|
|||
public CrashHandler(@NonNull final Application application) { |
|||
this.application = application; |
|||
} |
|||
|
|||
@Override |
|||
public void uncaughtException(@NonNull final Thread t, |
|||
@NonNull final Throwable exception, |
|||
@NonNull final Thread.UncaughtExceptionHandler defaultEH) { |
|||
CrashReporterHelper.startErrorReporterActivity(application, exception); |
|||
// zipLogs(); |
|||
defaultEH.uncaughtException(t, exception); |
|||
} |
|||
|
|||
// public synchronized CrashReporter zipLogs() { |
|||
// final File logDir = Utils.logCollector != null ? Utils.logCollector.getLogDir() : |
|||
// new File(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? application.getDataDir() : application.getFilesDir(), "crashlogs"); |
|||
// |
|||
// try (final FileOutputStream fos = new FileOutputStream(crashLogsZip); |
|||
// final ZipOutputStream zos = new ZipOutputStream(fos)) { |
|||
// |
|||
// final File[] files = logDir.listFiles(); |
|||
// |
|||
// if (files != null) { |
|||
// zos.setLevel(5); |
|||
// byte[] buffer; |
|||
// for (final File file : files) { |
|||
// if (file != null && file.length() > 0) { |
|||
// buffer = new byte[1024]; |
|||
// try (final FileInputStream fis = new FileInputStream(file)) { |
|||
// zos.putNextEntry(new ZipEntry(file.getName())); |
|||
// int length; |
|||
// while ((length = fis.read(buffer)) > 0) zos.write(buffer, 0, length); |
|||
// zos.closeEntry(); |
|||
// } |
|||
// } |
|||
// } |
|||
// } |
|||
// |
|||
// } catch (final Exception e) { |
|||
// if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); |
|||
// } |
|||
// |
|||
// return this; |
|||
// } |
|||
} |
@ -0,0 +1,10 @@ |
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
|||
package="awais.instagrabber"> |
|||
|
|||
<application> |
|||
<meta-data |
|||
android:name="io.sentry.auto-init" |
|||
android:value="false" /> |
|||
</application> |
|||
|
|||
</manifest> |
@ -0,0 +1,83 @@ |
|||
package awais.instagrabber.fragments.settings; |
|||
|
|||
import android.content.Context; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.fragment.app.FragmentManager; |
|||
import androidx.preference.Preference; |
|||
|
|||
import com.google.common.collect.ImmutableList; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
|
|||
import awais.instagrabber.R; |
|||
import awais.instagrabber.dialogs.ConfirmDialogFragment; |
|||
|
|||
import static awais.instagrabber.fragments.settings.PreferenceKeys.PREF_ENABLE_SENTRY; |
|||
import static awais.instagrabber.utils.Utils.settingsHelper; |
|||
|
|||
public final class FlavorSettings implements IFlavorSettings { |
|||
|
|||
private static FlavorSettings instance; |
|||
|
|||
private FlavorSettings() { |
|||
} |
|||
|
|||
public static FlavorSettings getInstance() { |
|||
if (instance == null) { |
|||
instance = new FlavorSettings(); |
|||
} |
|||
return instance; |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public List<Preference> getPreferences(@NonNull final Context context, |
|||
@NonNull final FragmentManager fragmentManager, |
|||
@NonNull final SettingCategory settingCategory) { |
|||
switch (settingCategory) { |
|||
case GENERAL: |
|||
return getGeneralPrefs(context, fragmentManager); |
|||
default: |
|||
break; |
|||
} |
|||
return Collections.emptyList(); |
|||
} |
|||
|
|||
private List<Preference> getGeneralPrefs(@NonNull final Context context, |
|||
@NonNull final FragmentManager fragmentManager) { |
|||
return ImmutableList.of( |
|||
getSentryPreference(context, fragmentManager) |
|||
); |
|||
} |
|||
|
|||
private Preference getSentryPreference(@NonNull final Context context, |
|||
@NonNull final FragmentManager fragmentManager) { |
|||
if (!settingsHelper.hasPreference(PREF_ENABLE_SENTRY)) { |
|||
// disabled by default |
|||
settingsHelper.putBoolean(PREF_ENABLE_SENTRY, false); |
|||
} |
|||
return PreferenceHelper.getSwitchPreference( |
|||
context, |
|||
PREF_ENABLE_SENTRY, |
|||
R.string.enable_sentry, |
|||
R.string.sentry_summary, |
|||
false, |
|||
(preference, newValue) -> { |
|||
if (!(newValue instanceof Boolean)) return true; |
|||
final boolean enabled = (Boolean) newValue; |
|||
if (enabled) { |
|||
final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance( |
|||
111, |
|||
0, |
|||
R.string.sentry_start_next_launch, |
|||
R.string.ok, |
|||
0, |
|||
0); |
|||
dialogFragment.show(fragmentManager, "sentry_dialog"); |
|||
} |
|||
return true; |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,59 @@ |
|||
package awaisomereport; |
|||
|
|||
import android.app.Application; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
|
|||
import awais.instagrabber.BuildConfig; |
|||
import awais.instagrabber.fragments.settings.PreferenceKeys; |
|||
import io.sentry.SentryLevel; |
|||
import io.sentry.android.core.SentryAndroid; |
|||
import io.sentry.protocol.Contexts; |
|||
import io.sentry.protocol.Device; |
|||
|
|||
import static awais.instagrabber.utils.Utils.settingsHelper; |
|||
|
|||
public class CrashHandler implements ICrashHandler { |
|||
private static final String TAG = CrashHandler.class.getSimpleName(); |
|||
|
|||
private final Application application; |
|||
private final boolean enabled; |
|||
|
|||
public CrashHandler(@NonNull final Application application) { |
|||
this.application = application; |
|||
if (!settingsHelper.hasPreference(PreferenceKeys.PREF_ENABLE_SENTRY)) { |
|||
// disabled by default (change to true if we need enabled by default) |
|||
enabled = false; |
|||
} else { |
|||
enabled = settingsHelper.getBoolean(PreferenceKeys.PREF_ENABLE_SENTRY); |
|||
} |
|||
if (!enabled) return; |
|||
SentryAndroid.init(application, options -> { |
|||
options.setDsn(BuildConfig.dsn); |
|||
options.setDiagnosticLevel(SentryLevel.ERROR); |
|||
options.setBeforeSend((event, hint) -> { |
|||
// Removing unneeded info from event |
|||
final Contexts contexts = event.getContexts(); |
|||
final Device device = contexts.getDevice(); |
|||
device.setName(null); |
|||
device.setTimezone(null); |
|||
device.setCharging(null); |
|||
device.setBootTime(null); |
|||
device.setFreeStorage(null); |
|||
device.setBatteryTemperature(null); |
|||
return event; |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
@Override |
|||
public void uncaughtException(@NonNull final Thread t, |
|||
@NonNull final Throwable exception, |
|||
@NonNull final Thread.UncaughtExceptionHandler defaultEH) { |
|||
// When enabled, Sentry auto captures unhandled exceptions |
|||
if (!enabled) { |
|||
CrashReporterHelper.startErrorReporterActivity(application, exception); |
|||
} |
|||
defaultEH.uncaughtException(t, exception); |
|||
} |
|||
} |
@ -0,0 +1,6 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<resources> |
|||
<string name="enable_sentry">Enable Sentry</string> |
|||
<string name="sentry_summary">Sentry is a listener/handler for errors that asynchronously sends out the error/event to Sentry.io</string> |
|||
<string name="sentry_start_next_launch">Sentry will start on next launch</string> |
|||
</resources> |
@ -0,0 +1,14 @@ |
|||
package awais.instagrabber.fragments.settings; |
|||
|
|||
import android.content.Context; |
|||
|
|||
import androidx.fragment.app.FragmentManager; |
|||
import androidx.preference.Preference; |
|||
|
|||
import java.util.List; |
|||
|
|||
public interface IFlavorSettings { |
|||
List<Preference> getPreferences(Context context, |
|||
FragmentManager childFragmentManager, |
|||
SettingCategory settingCategory); |
|||
} |
@ -0,0 +1,6 @@ |
|||
package awais.instagrabber.fragments.settings; |
|||
|
|||
public enum SettingCategory { |
|||
GENERAL, |
|||
// add more as and when required |
|||
} |
@ -1,6 +1,8 @@ |
|||
package awais.instagrabber.utils; |
|||
|
|||
public final class Constants { |
|||
public static final String CRASH_REPORT_EMAIL = "[email protected]"; |
|||
|
|||
// string prefs |
|||
public static final String FOLDER_PATH = "custom_path"; |
|||
public static final String DATE_TIME_FORMAT = "date_time_format"; |
|||
|
@ -1,50 +1,35 @@ |
|||
package awaisomereport; |
|||
|
|||
import android.app.Application; |
|||
import android.content.Context; |
|||
import android.content.Intent; |
|||
import android.os.Build; |
|||
import android.os.Process; |
|||
import android.util.Log; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.core.content.FileProvider; |
|||
|
|||
import java.io.BufferedReader; |
|||
import java.io.File; |
|||
import java.io.FileInputStream; |
|||
import java.io.FileOutputStream; |
|||
import java.io.FileReader; |
|||
import java.io.PrintWriter; |
|||
import java.io.StringWriter; |
|||
import java.io.Writer; |
|||
import java.util.Date; |
|||
//import java.util.zip.ZipEntry; |
|||
//import java.util.zip.ZipOutputStream; |
|||
|
|||
import awais.instagrabber.BuildConfig; |
|||
import awais.instagrabber.utils.Utils; |
|||
|
|||
public final class CrashReporter implements Thread.UncaughtExceptionHandler { |
|||
private static final String TAG = CrashReporter.class.getSimpleName(); |
|||
|
|||
private static CrashReporter reporterInstance; |
|||
private final Application application; |
|||
private final String email; |
|||
// private final File crashLogsZip; |
|||
|
|||
// private final File crashLogsZip; |
|||
private final CrashHandler crashHandler; |
|||
|
|||
private boolean startAttempted = false; |
|||
private Thread.UncaughtExceptionHandler defaultEH; |
|||
|
|||
public static CrashReporter get(final Application application) { |
|||
if (reporterInstance == null) reporterInstance = new CrashReporter(application); |
|||
if (reporterInstance == null) { |
|||
reporterInstance = new CrashReporter(application); |
|||
} |
|||
return reporterInstance; |
|||
} |
|||
|
|||
private CrashReporter(@NonNull final Application application) { |
|||
this.application = application; |
|||
this.email = "[email protected]"; |
|||
// this.crashLogsZip = new File(application.getExternalCacheDir(), "crash_logs.zip"); |
|||
crashHandler = new CrashHandler(application); |
|||
// this.crashLogsZip = new File(application.getExternalCacheDir(), "crash_logs.zip"); |
|||
} |
|||
|
|||
public void start() { |
|||
if (!startAttempted) { |
|||
defaultEH = Thread.getDefaultUncaughtExceptionHandler(); |
|||
Thread.setDefaultUncaughtExceptionHandler(this); |
|||
startAttempted = true; |
|||
} |
|||
@ -52,140 +37,10 @@ public final class CrashReporter implements Thread.UncaughtExceptionHandler { |
|||
|
|||
@Override |
|||
public void uncaughtException(@NonNull final Thread t, @NonNull final Throwable exception) { |
|||
final StringBuilder reportBuilder = new StringBuilder(); |
|||
reportBuilder.append("IMPORTANT: If sending by email, your email address and the entire content will be made public on GitHub issues."); |
|||
reportBuilder.append("\r\nIMPORTANT: When possible, please describe the steps leading to this crash. Thank you for your cooperation."); |
|||
reportBuilder.append("\r\n\r\nError report collected on: ").append(new Date().toString()); |
|||
|
|||
reportBuilder |
|||
.append("\r\n\r\nInformation:\r\n==============") |
|||
.append("\r\nVERSION : ").append(BuildConfig.VERSION_NAME) |
|||
.append("\r\nVERSION_CODE : ").append(BuildConfig.VERSION_CODE) |
|||
.append("\r\nPHONE-MODEL : ").append(Build.MODEL) |
|||
.append("\r\nANDROID_VERS : ").append(Build.VERSION.RELEASE) |
|||
.append("\r\nANDROID_REL : ").append(Build.VERSION.SDK_INT) |
|||
.append("\r\nBRAND : ").append(Build.BRAND) |
|||
.append("\r\nMANUFACTURER : ").append(Build.MANUFACTURER) |
|||
.append("\r\nBOARD : ").append(Build.BOARD) |
|||
.append("\r\nDEVICE : ").append(Build.DEVICE) |
|||
.append("\r\nPRODUCT : ").append(Build.PRODUCT) |
|||
.append("\r\nHOST : ").append(Build.HOST) |
|||
.append("\r\nTAGS : ").append(Build.TAGS); |
|||
|
|||
reportBuilder.append("\r\n\r\nStack:\r\n==============\r\n"); |
|||
final Writer result = new StringWriter(); |
|||
try (final PrintWriter printWriter = new PrintWriter(result)) { |
|||
exception.printStackTrace(printWriter); |
|||
reportBuilder.append(result.toString()); |
|||
|
|||
reportBuilder.append("\r\nCause:\r\n=============="); |
|||
|
|||
// for AsyncTask crashes |
|||
Throwable cause = exception.getCause(); |
|||
while (cause != null) { |
|||
cause.printStackTrace(printWriter); |
|||
reportBuilder.append(result.toString()); |
|||
cause = cause.getCause(); |
|||
} |
|||
} |
|||
reportBuilder.append("\r\n\r\n**** End of current Report ***"); |
|||
|
|||
final String errorContent = reportBuilder.toString(); |
|||
try (final FileOutputStream trace = application.openFileOutput("stack-" + System.currentTimeMillis() + ".stacktrace", Context.MODE_PRIVATE)) { |
|||
trace.write(errorContent.getBytes()); |
|||
} catch (final Exception ex) { |
|||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", ex); |
|||
} |
|||
|
|||
application.startActivity(new Intent(application, ErrorReporterActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); |
|||
|
|||
// zipLogs(); |
|||
|
|||
Process.killProcess(Process.myPid()); |
|||
System.exit(10); |
|||
} |
|||
|
|||
// public synchronized CrashReporter zipLogs() { |
|||
// final File logDir = Utils.logCollector != null ? Utils.logCollector.getLogDir() : |
|||
// new File(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? application.getDataDir() : application.getFilesDir(), "crashlogs"); |
|||
// |
|||
// try (final FileOutputStream fos = new FileOutputStream(crashLogsZip); |
|||
// final ZipOutputStream zos = new ZipOutputStream(fos)) { |
|||
// |
|||
// final File[] files = logDir.listFiles(); |
|||
// |
|||
// if (files != null) { |
|||
// zos.setLevel(5); |
|||
// byte[] buffer; |
|||
// for (final File file : files) { |
|||
// if (file != null && file.length() > 0) { |
|||
// buffer = new byte[1024]; |
|||
// try (final FileInputStream fis = new FileInputStream(file)) { |
|||
// zos.putNextEntry(new ZipEntry(file.getName())); |
|||
// int length; |
|||
// while ((length = fis.read(buffer)) > 0) zos.write(buffer, 0, length); |
|||
// zos.closeEntry(); |
|||
// } |
|||
// } |
|||
// } |
|||
// } |
|||
// |
|||
// } catch (final Exception e) { |
|||
// if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); |
|||
// } |
|||
// |
|||
// return this; |
|||
// } |
|||
|
|||
@SuppressWarnings("ResultOfMethodCallIgnored") |
|||
public void startCrashEmailIntent(final Context context) { |
|||
try { |
|||
final String filePath = context.getFilesDir().getAbsolutePath(); |
|||
|
|||
String[] errorFileList; |
|||
|
|||
try { |
|||
final File dir = new File(filePath); |
|||
if (dir.exists() && !dir.isDirectory()) dir.delete(); |
|||
dir.mkdir(); |
|||
errorFileList = dir.list((d, name) -> name.endsWith(".stacktrace")); |
|||
} catch (final Exception e) { |
|||
errorFileList = null; |
|||
} |
|||
|
|||
if (errorFileList != null && errorFileList.length > 0) { |
|||
final StringBuilder errorStringBuilder; |
|||
|
|||
errorStringBuilder = new StringBuilder("\r\n\r\n"); |
|||
final int maxSendMail = 5; |
|||
|
|||
int curIndex = 0; |
|||
for (final String curString : errorFileList) { |
|||
final File file = new File(filePath + '/' + curString); |
|||
|
|||
if (curIndex++ <= maxSendMail) { |
|||
errorStringBuilder.append("New Trace collected:\r\n=====================\r\n"); |
|||
try (final BufferedReader input = new BufferedReader(new FileReader(file))) { |
|||
String line; |
|||
while ((line = input.readLine()) != null) |
|||
errorStringBuilder.append(line).append("\r\n"); |
|||
} |
|||
} |
|||
|
|||
file.delete(); |
|||
} |
|||
|
|||
errorStringBuilder.append("\r\n\r\n"); |
|||
|
|||
context.startActivity(Intent.createChooser(new Intent(Intent.ACTION_SEND).setType("message/rfc822") |
|||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION) |
|||
.putExtra(Intent.EXTRA_EMAIL, new String[]{email}) |
|||
// .putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(application, BuildConfig.APPLICATION_ID + ".provider", crashLogsZip)) |
|||
.putExtra(Intent.EXTRA_SUBJECT, "Barinsta Crash Report") |
|||
.putExtra(Intent.EXTRA_TEXT, errorStringBuilder.toString()), "Select an email app to send crash logs")); |
|||
} |
|||
} catch (final Exception e) { |
|||
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); |
|||
if (crashHandler == null) { |
|||
defaultEH.uncaughtException(t, exception); |
|||
return; |
|||
} |
|||
crashHandler.uncaughtException(t, exception, defaultEH); |
|||
} |
|||
} |
@ -0,0 +1,134 @@ |
|||
package awaisomereport; |
|||
|
|||
import android.app.Application; |
|||
import android.content.Context; |
|||
import android.content.Intent; |
|||
import android.content.res.Resources; |
|||
import android.os.Build; |
|||
import android.util.Log; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
|
|||
import java.io.BufferedReader; |
|||
import java.io.File; |
|||
import java.io.FileOutputStream; |
|||
import java.io.FileReader; |
|||
import java.io.PrintWriter; |
|||
import java.io.StringWriter; |
|||
import java.io.Writer; |
|||
import java.util.Date; |
|||
|
|||
import awais.instagrabber.BuildConfig; |
|||
import awais.instagrabber.R; |
|||
import awais.instagrabber.utils.Constants; |
|||
|
|||
public final class CrashReporterHelper { |
|||
private static final String TAG = CrashReporterHelper.class.getSimpleName(); |
|||
|
|||
public static void startErrorReporterActivity(@NonNull final Application application, |
|||
@NonNull final Throwable exception) { |
|||
final StringBuilder reportBuilder = new StringBuilder(); |
|||
reportBuilder.append("IMPORTANT: If sending by email, your email address and the entire content will be made public on GitHub issues.") |
|||
.append("\r\nIMPORTANT: When possible, please describe the steps leading to this crash. Thank you for your cooperation.") |
|||
.append("\r\n\r\nError report collected on: ").append(new Date().toString()) |
|||
.append("\r\n\r\nInformation:\r\n==============") |
|||
.append("\r\nVERSION : ").append(BuildConfig.VERSION_NAME) |
|||
.append("\r\nVERSION_CODE : ").append(BuildConfig.VERSION_CODE) |
|||
.append("\r\nPHONE-MODEL : ").append(Build.MODEL) |
|||
.append("\r\nANDROID_VERS : ").append(Build.VERSION.RELEASE) |
|||
.append("\r\nANDROID_REL : ").append(Build.VERSION.SDK_INT) |
|||
.append("\r\nBRAND : ").append(Build.BRAND) |
|||
.append("\r\nMANUFACTURER : ").append(Build.MANUFACTURER) |
|||
.append("\r\nBOARD : ").append(Build.BOARD) |
|||
.append("\r\nDEVICE : ").append(Build.DEVICE) |
|||
.append("\r\nPRODUCT : ").append(Build.PRODUCT) |
|||
.append("\r\nHOST : ").append(Build.HOST) |
|||
.append("\r\nTAGS : ").append(Build.TAGS); |
|||
|
|||
reportBuilder.append("\r\n\r\nStack:\r\n==============\r\n"); |
|||
final Writer result = new StringWriter(); |
|||
try (final PrintWriter printWriter = new PrintWriter(result)) { |
|||
exception.printStackTrace(printWriter); |
|||
reportBuilder.append(result.toString()); |
|||
reportBuilder.append("\r\nCause:\r\n=============="); |
|||
// for AsyncTask crashes |
|||
Throwable cause = exception.getCause(); |
|||
while (cause != null) { |
|||
cause.printStackTrace(printWriter); |
|||
reportBuilder.append(result.toString()); |
|||
cause = cause.getCause(); |
|||
} |
|||
} |
|||
reportBuilder.append("\r\n\r\n**** End of current Report ***"); |
|||
|
|||
final String errorContent = reportBuilder.toString(); |
|||
try (final FileOutputStream trace = application.openFileOutput("stack-" + System.currentTimeMillis() + ".stacktrace", Context.MODE_PRIVATE)) { |
|||
trace.write(errorContent.getBytes()); |
|||
} catch (final Exception ex) { |
|||
if (BuildConfig.DEBUG) Log.e(TAG, "", ex); |
|||
} |
|||
|
|||
application.startActivity(new Intent(application, ErrorReporterActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); |
|||
} |
|||
|
|||
public static void startCrashEmailIntent(final Context context) { |
|||
try { |
|||
final String filePath = context.getFilesDir().getAbsolutePath(); |
|||
|
|||
String[] errorFileList; |
|||
|
|||
try { |
|||
final File dir = new File(filePath); |
|||
if (dir.exists() && !dir.isDirectory()) { |
|||
//noinspection ResultOfMethodCallIgnored |
|||
dir.delete(); |
|||
} |
|||
//noinspection ResultOfMethodCallIgnored |
|||
dir.mkdirs(); |
|||
errorFileList = dir.list((d, name) -> name.endsWith(".stacktrace")); |
|||
} catch (final Exception e) { |
|||
errorFileList = null; |
|||
} |
|||
|
|||
if (errorFileList == null || errorFileList.length <= 0) { |
|||
return; |
|||
} |
|||
final StringBuilder errorStringBuilder; |
|||
|
|||
errorStringBuilder = new StringBuilder("\r\n\r\n"); |
|||
final int maxSendMail = 5; |
|||
int curIndex = 0; |
|||
for (final String curString : errorFileList) { |
|||
final File file = new File(filePath + '/' + curString); |
|||
|
|||
if (curIndex++ <= maxSendMail) { |
|||
errorStringBuilder.append("New Trace collected:\r\n=====================\r\n"); |
|||
try (final BufferedReader input = new BufferedReader(new FileReader(file))) { |
|||
String line; |
|||
while ((line = input.readLine()) != null) |
|||
errorStringBuilder.append(line).append("\r\n"); |
|||
} |
|||
} |
|||
//noinspection ResultOfMethodCallIgnored |
|||
file.delete(); |
|||
} |
|||
|
|||
errorStringBuilder.append("\r\n\r\n"); |
|||
final Resources resources = context.getResources(); |
|||
context.startActivity(Intent.createChooser( |
|||
new Intent(Intent.ACTION_SEND) |
|||
.setType("message/rfc822") |
|||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
|||
| Intent.FLAG_GRANT_READ_URI_PERMISSION |
|||
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION) |
|||
.putExtra(Intent.EXTRA_EMAIL, new String[]{Constants.CRASH_REPORT_EMAIL}) |
|||
// .putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(application, BuildConfig.APPLICATION_ID + ".provider", crashLogsZip)) |
|||
.putExtra(Intent.EXTRA_SUBJECT, resources.getString(R.string.crash_report_subject)) |
|||
.putExtra(Intent.EXTRA_TEXT, errorStringBuilder.toString()), |
|||
context.getResources().getString(R.string.crash_report_title)) |
|||
); |
|||
} catch (final Exception e) { |
|||
Log.e(TAG, "", e); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,7 @@ |
|||
package awaisomereport; |
|||
|
|||
public interface ICrashHandler { |
|||
void uncaughtException(Thread t, |
|||
Throwable exception, |
|||
Thread.UncaughtExceptionHandler defaultEH); |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue