package de.greenrobot.event.util;
|
|
import android.annotation.TargetApi;
|
import android.app.Activity;
|
import android.app.Application;
|
import android.os.Build;
|
import android.os.Bundle;
|
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentManager;
|
import android.util.Log;
|
import org.greenrobot.eventbus.EventBus;
|
|
/**
|
* Central class for app that want to use event based error dialogs.<br/>
|
* <br/>
|
* How to use:
|
* <ol>
|
* <li>Set the {@link #factory} to configure dialogs for your app, typically in {@link Application#onCreate()}</li>
|
* <li>Use one of {@link #attachTo(Activity)}, {@link #attachTo(Activity, boolean)} or
|
* {@link #attachTo(Activity, boolean, Bundle)} in your Activity, typically in onCreate.</li>
|
* </ol>
|
*
|
* For more complex mappings, you can supply your own {@link ErrorDialogFragmentFactory}.
|
*
|
* @author Markus
|
*/
|
public class ErrorDialogManager {
|
|
public static class SupportManagerFragment extends Fragment {
|
protected boolean finishAfterDialog;
|
protected Bundle argumentsForErrorDialog;
|
private EventBus eventBus;
|
private boolean skipRegisterOnNextResume;
|
private Object executionScope;
|
|
@Override
|
public void onCreate(Bundle savedInstanceState) {
|
super.onCreate(savedInstanceState);
|
eventBus = ErrorDialogManager.factory.config.getEventBus();
|
eventBus.register(this);
|
skipRegisterOnNextResume = true;
|
}
|
|
@Override
|
public void onResume() {
|
super.onResume();
|
if (skipRegisterOnNextResume) {
|
// registered in onCreate, skip registration in this run
|
skipRegisterOnNextResume = false;
|
} else {
|
eventBus = ErrorDialogManager.factory.config.getEventBus();
|
eventBus.register(this);
|
}
|
}
|
|
@Override
|
public void onPause() {
|
eventBus.unregister(this);
|
super.onPause();
|
}
|
|
@Subscribe
|
public void onEventMainThread(ThrowableFailureEvent event) {
|
if (!isInExecutionScope(executionScope, event)) {
|
return;
|
}
|
checkLogException(event);
|
// Execute pending commits before finding to avoid multiple error fragments being shown
|
FragmentManager fm = getFragmentManager();
|
fm.executePendingTransactions();
|
|
DialogFragment existingFragment = (DialogFragment) fm.findFragmentByTag(TAG_ERROR_DIALOG);
|
if (existingFragment != null) {
|
// Just show the latest error
|
existingFragment.dismiss();
|
}
|
|
DialogFragment errorFragment = (DialogFragment) factory
|
.prepareErrorFragment(event, finishAfterDialog, argumentsForErrorDialog);
|
if (errorFragment != null) {
|
errorFragment.show(fm, TAG_ERROR_DIALOG);
|
}
|
}
|
|
public static void attachTo(Activity activity, Object executionScope, boolean finishAfterDialog,
|
Bundle argumentsForErrorDialog) {
|
FragmentManager fm = ((FragmentActivity) activity).getSupportFragmentManager();
|
SupportManagerFragment fragment = (SupportManagerFragment) fm.findFragmentByTag(TAG_ERROR_DIALOG_MANAGER);
|
if (fragment == null) {
|
fragment = new SupportManagerFragment();
|
fm.beginTransaction().add(fragment, TAG_ERROR_DIALOG_MANAGER).commit();
|
fm.executePendingTransactions();
|
}
|
fragment.finishAfterDialog = finishAfterDialog;
|
fragment.argumentsForErrorDialog = argumentsForErrorDialog;
|
fragment.executionScope = executionScope;
|
}
|
}
|
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
public static class HoneycombManagerFragment extends android.app.Fragment {
|
protected boolean finishAfterDialog;
|
protected Bundle argumentsForErrorDialog;
|
private EventBus eventBus;
|
private Object executionScope;
|
|
@Override
|
public void onResume() {
|
super.onResume();
|
eventBus = ErrorDialogManager.factory.config.getEventBus();
|
eventBus.register(this);
|
}
|
|
@Override
|
public void onPause() {
|
eventBus.unregister(this);
|
super.onPause();
|
}
|
|
@Subscribe
|
public void onEventMainThread(ThrowableFailureEvent event) {
|
if (!isInExecutionScope(executionScope, event)) {
|
return;
|
}
|
checkLogException(event);
|
|
// Execute pending commits before finding to avoid multiple error fragments being shown
|
android.app.FragmentManager fm = getFragmentManager();
|
fm.executePendingTransactions();
|
|
android.app.DialogFragment existingFragment = (android.app.DialogFragment) fm
|
.findFragmentByTag(TAG_ERROR_DIALOG);
|
if (existingFragment != null) {
|
// Just show the latest error
|
existingFragment.dismiss();
|
}
|
|
android.app.DialogFragment errorFragment = (android.app.DialogFragment) factory.prepareErrorFragment(event,
|
finishAfterDialog, argumentsForErrorDialog);
|
if (errorFragment != null) {
|
errorFragment.show(fm, TAG_ERROR_DIALOG);
|
}
|
}
|
|
public static void attachTo(Activity activity, Object executionScope, boolean finishAfterDialog, Bundle argumentsForErrorDialog) {
|
android.app.FragmentManager fm = activity.getFragmentManager();
|
HoneycombManagerFragment fragment = (HoneycombManagerFragment) fm
|
.findFragmentByTag(TAG_ERROR_DIALOG_MANAGER);
|
if (fragment == null) {
|
fragment = new HoneycombManagerFragment();
|
fm.beginTransaction().add(fragment, TAG_ERROR_DIALOG_MANAGER).commit();
|
fm.executePendingTransactions();
|
}
|
fragment.finishAfterDialog = finishAfterDialog;
|
fragment.argumentsForErrorDialog = argumentsForErrorDialog;
|
fragment.executionScope = executionScope;
|
}
|
}
|
|
/** Must be set by the application. */
|
public static ErrorDialogFragmentFactory<?> factory;
|
|
protected static final String TAG_ERROR_DIALOG = "de.greenrobot.eventbus.error_dialog";
|
protected static final String TAG_ERROR_DIALOG_MANAGER = "de.greenrobot.eventbus.error_dialog_manager";
|
|
public static final String KEY_TITLE = "de.greenrobot.eventbus.errordialog.title";
|
public static final String KEY_MESSAGE = "de.greenrobot.eventbus.errordialog.message";
|
public static final String KEY_FINISH_AFTER_DIALOG = "de.greenrobot.eventbus.errordialog.finish_after_dialog";
|
public static final String KEY_ICON_ID = "de.greenrobot.eventbus.errordialog.icon_id";
|
public static final String KEY_EVENT_TYPE_ON_CLOSE = "de.greenrobot.eventbus.errordialog.event_type_on_close";
|
|
/** Scope is limited to the activity's class. */
|
public static void attachTo(Activity activity) {
|
attachTo(activity, false, null);
|
}
|
|
/** Scope is limited to the activity's class. */
|
public static void attachTo(Activity activity, boolean finishAfterDialog) {
|
attachTo(activity, finishAfterDialog, null);
|
}
|
|
/** Scope is limited to the activity's class. */
|
public static void attachTo(Activity activity, boolean finishAfterDialog, Bundle argumentsForErrorDialog) {
|
Object executionScope = activity.getClass();
|
attachTo(activity, executionScope, finishAfterDialog, argumentsForErrorDialog);
|
}
|
|
public static void attachTo(Activity activity, Object executionScope, boolean finishAfterDialog, Bundle argumentsForErrorDialog) {
|
if (factory == null) {
|
throw new RuntimeException("You must set the static factory field to configure error dialogs for your app.");
|
}
|
if (isSupportActivity(activity)) {
|
SupportManagerFragment.attachTo(activity, executionScope, finishAfterDialog, argumentsForErrorDialog);
|
} else {
|
HoneycombManagerFragment.attachTo(activity, executionScope, finishAfterDialog, argumentsForErrorDialog);
|
}
|
}
|
|
private static boolean isSupportActivity(Activity activity) {
|
boolean isSupport = false;
|
for (Class<?> c = activity.getClass().getSuperclass();; c = c.getSuperclass()) {
|
if (c == null) {
|
throw new RuntimeException("Illegal activity type: " + activity.getClass());
|
}
|
String name = c.getName();
|
if (name.equals("android.support.v4.app.FragmentActivity")) {
|
isSupport = true;
|
break;
|
} else if (name.startsWith("com.actionbarsherlock.app")
|
&& (name.endsWith(".SherlockActivity") || name.endsWith(".SherlockListActivity") || name
|
.endsWith(".SherlockPreferenceActivity"))) {
|
throw new RuntimeException("Please use SherlockFragmentActivity. Illegal activity: " + name);
|
} else if (name.equals("android.app.Activity")) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
throw new RuntimeException(
|
"Illegal activity without fragment support. Either use Android 3.0+ or android.support.v4.app.FragmentActivity.");
|
}
|
break;
|
}
|
}
|
return isSupport;
|
}
|
|
protected static void checkLogException(ThrowableFailureEvent event) {
|
if (factory.config.logExceptions) {
|
String tag = factory.config.tagForLoggingExceptions;
|
if (tag == null) {
|
tag = EventBus.TAG;
|
}
|
Log.i(tag, "Error dialog manager received exception", event.throwable);
|
}
|
}
|
|
private static boolean isInExecutionScope(Object executionScope, ThrowableFailureEvent event) {
|
if (event != null) {
|
Object eventExecutionScope = event.getExecutionScope();
|
if (eventExecutionScope != null && !eventExecutionScope.equals(executionScope)) {
|
// Event not in our scope, do nothing
|
return false;
|
}
|
}
|
return true;
|
}
|
|
}
|