Skip to content

Commit

Permalink
Improve CustomCrashDataCollector implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Ereza committed May 29, 2022
1 parent 496e1ae commit fe6a5eb
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 33 deletions.
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public void onCreate() {
.restartActivity(YourCustomActivity.class) //default: null (your app's launch activity)
.errorActivity(YourCustomErrorActivity.class) //default: null (default error activity)
.eventListener(new YourCustomEventListener()) //default: null
.customCrashDataCollector(new YourCustomCrashDataCollector()) //default: null
.apply();

//If you use Firebase Crashlytics or ACRA, please initialize them here as explained above.
Expand Down Expand Up @@ -181,6 +182,15 @@ eventListener(EventListener);
> If you set it to `null`, no event listener will be invoked.
> The default is `null`.
```java
customCrashDataCollector(CustomCrashDataCollector);
```
> This method allows you to specify a custom crash data collector that will be invoked when a crash occurs.
> This additional data will be added to the "error details" view on the default error activity, or you can use it in your custom error activity.
> The CustomCrashDataCollector you provide can not be an anonymous or non-static inner class, because it needs to be serialized by the library. The library will throw an exception if you try to set an invalid class.
> If you set it to `null`, no custom crash data will be collected.
> The default is `null`.
### Customization of the default activity
You can override several resources to customize the default activity:
Expand Down Expand Up @@ -223,15 +233,25 @@ You can provide new strings and translations for the default error activity stri
If you choose to create your own completely custom error activity, you can use these methods:
```java
CustomActivityOnCrash.getAllErrorDetailsFromIntent(getIntent());
```
> Returns several error details including the stack trace that caused the error, the activity log (if available) and the custom crash data (if available), as a string. This is used in the default error activity error details dialog.
```java
CustomActivityOnCrash.getStackTraceFromIntent(getIntent());
```
> Returns the stack trace that caused the error as a string.
```java
CustomActivityOnCrash.getAllErrorDetailsFromIntent(getIntent());
CustomActivityOnCrash.getActivityLogFromIntent(getIntent());
```
> Returns the activity log as a string if `trackActivities` was enabled, `null` otherwise.
```java
CustomActivityOnCrash.getCustomCrashDataFromIntent(getIntent());
```
> Returns several error details including the stack trace that caused the error, as a string. This is used in the default error activity error details dialog.
> Returns the custom crash data collected with your `CustomCrashDataCollector` if `customCrashDataCollector` was enabled, `null` otherwise.
```java
CustomActivityOnCrash.getConfigFromIntent(getIntent());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ public final class CustomActivityOnCrash {

//Extras passed to the error activity
private static final String EXTRA_CONFIG = "cat.ereza.customactivityoncrash.EXTRA_CONFIG";
private static final String EXTRA_CUSTOM_CRASH_DATA = "cat.ereza.customactivityoncrash.EXTRA_CUSTOM_CRASH_DATA";
private static final String EXTRA_STACK_TRACE = "cat.ereza.customactivityoncrash.EXTRA_STACK_TRACE";
private static final String EXTRA_ACTIVITY_LOG = "cat.ereza.customactivityoncrash.EXTRA_ACTIVITY_LOG";
private static final String EXTRA_CUSTOM_CRASH_DATA = "cat.ereza.customactivityoncrash.EXTRA_CUSTOM_CRASH_DATA";

//General constants
private static final String INTENT_ACTION_ERROR_ACTIVITY = "cat.ereza.customactivityoncrash.ERROR";
Expand Down Expand Up @@ -154,11 +154,15 @@ public static void install(@Nullable final Context context) {
}
intent.putExtra(EXTRA_STACK_TRACE, stackTraceString);

CustomCrashDataCollector collector = config.getCustomCrashDataCollector();
if (collector != null) {
intent.putExtra(EXTRA_CUSTOM_CRASH_DATA, collector.onCrash(intent));
CustomCrashDataCollector collector = config.getCustomCrashDataCollector();
if (collector != null) {
try {
intent.putExtra(EXTRA_CUSTOM_CRASH_DATA, collector.onCrash());
} catch (Throwable t) {
Log.e(TAG, "An unknown error occurred while invoking the custom crash data collector's onCrash. Please check your implementation.", t);
}

}

if (config.isTrackActivities()) {
StringBuilder activityLogStringBuilder = new StringBuilder();
while (!activityLog.isEmpty()) {
Expand Down Expand Up @@ -284,7 +288,7 @@ public static String getStackTraceFromIntent(@NonNull Intent intent) {
}

/**
* Given an Intent, returns the custom collector trace extra from it.
* Given an Intent, returns the custom crash data extra from it.
*
* @param intent The Intent. Must not be null.
* @return The custom collector trace, or null if not provided.
Expand Down Expand Up @@ -366,10 +370,10 @@ public static String getAllErrorDetailsFromIntent(@NonNull Context context, @Non
errorDetails += activityLog;
}

String customTrace = getCustomCrashDataFromIntent(intent);
if (customTrace != null) {
errorDetails += "\nCustom trace: \n";
errorDetails += customTrace;
String customCrashData = getCustomCrashDataFromIntent(intent);
if (customCrashData != null) {
errorDetails += "\nAdditional data: \n";
errorDetails += customCrashData;
}

return errorDetails;
Expand Down Expand Up @@ -755,9 +759,9 @@ public interface EventListener extends Serializable {
}

/**
* Interface to be called to register a custom crash data collector
* Interface to be called to collect additional crash data when a crash occurs.
*/
public interface CustomCrashDataCollector extends Serializable {
String onCrash(Intent intent);
String onCrash();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -295,23 +295,6 @@ public Builder errorActivity(@Nullable Class<? extends Activity> errorActivityCl
return this;
}

/**
* Sets the custom error data collector class to launch when a crash occurs.
* If null, the default error activity will be used.
*
* @param collector The data collector.
* @throws IllegalArgumentException if the collector is an inner or anonymous class
*/
@NonNull
public Builder customCrashDataCollector(@Nullable CustomActivityOnCrash.CustomCrashDataCollector collector) {
if (collector != null && collector.getClass().getEnclosingClass() != null && !Modifier.isStatic(collector.getClass().getModifiers())) {
throw new IllegalArgumentException("The event listener cannot be an inner or anonymous class, because it will need to be serialized. Change it to a class of its own, or make it a static inner class.");
} else {
config.customCrashDataCollector = collector;
}
return this;
}

/**
* Sets the main activity class that the error activity must launch when a crash occurs.
* If not set or set to null, the default launch activity will be used.
Expand Down Expand Up @@ -341,6 +324,23 @@ public Builder eventListener(@Nullable CustomActivityOnCrash.EventListener event
return this;
}

/**
* Sets the custom data collector class to invoke when a crash occurs.
* If not set or set to null, no custom data will be collected.
*
* @param collector The custom data collector.
* @throws IllegalArgumentException if the collector is an inner or anonymous class
*/
@NonNull
public Builder customCrashDataCollector(@Nullable CustomActivityOnCrash.CustomCrashDataCollector collector) {
if (collector != null && collector.getClass().getEnclosingClass() != null && !Modifier.isStatic(collector.getClass().getModifiers())) {
throw new IllegalArgumentException("The custom data collector cannot be an inner or anonymous class, because it will need to be serialized. Change it to a class of its own, or make it a static inner class.");
} else {
config.customCrashDataCollector = collector;
}
return this;
}

@NonNull
public CaocConfig get() {
return config;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ public void onCreate() {
// .errorActivity(CustomErrorActivity.class)
//This sets a EventListener to be notified of events regarding the error activity,
//so you can, for example, report them to Google Analytics.
// .eventListener(new CustomEventListener())
// .eventListener(new MyCustomEventListener())
//This sets a CustomCrashDataCollector that is invoked when a crash occurs. This allows you to add more
//data to the error details.
// .customCrashDataCollector(new MyCustomCrashDataCollector())
.apply();

//Initialize your other error handler as normal.
Expand All @@ -85,7 +88,7 @@ public void onCreate() {
//enable alsoReportToAndroidFramework=true when initializing it or CustomActivityOnCrash will not work.
}

private static class CustomEventListener implements CustomActivityOnCrash.EventListener {
private static class MyCustomEventListener implements CustomActivityOnCrash.EventListener {
@Override
public void onLaunchErrorActivity() {
Log.i(TAG, "onLaunchErrorActivity()");
Expand All @@ -101,4 +104,11 @@ public void onCloseAppFromErrorActivity() {
Log.i(TAG, "onCloseAppFromErrorActivity()");
}
}

private static class MyCustomCrashDataCollector implements CustomActivityOnCrash.CustomCrashDataCollector {
@Override
public String onCrash() {
return "This is additional data that will be shown in the error details.";
}
}
}

0 comments on commit fe6a5eb

Please sign in to comment.