package org.acra.dialog;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.widget.Toast;
import org.acra.ACRA;
import org.acra.ACRAConstants;
import org.acra.collector.CrashReportData;
import org.acra.config.ACRAConfiguration;
import org.acra.file.BulkReportDeleter;
import org.acra.file.CrashReportPersister;
import org.acra.sender.SenderServiceStarter;
import org.acra.util.ToastSender;
import org.json.JSONException;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import static org.acra.ACRA.LOG_TAG;
import static org.acra.ReportField.USER_COMMENT;
import static org.acra.ReportField.USER_EMAIL;
/**
* Activity which implements the base functionality for a CrashReportDialog.
*
* Activities which extend from this class can override init to create a custom view.
*
* The methods sendCrash(comment, userEmail) and cancelReports() can be used to send or cancel
* sending of reports respectively.
*
* This Activity will be instantiated with 3 (or 4) arguments:
* <ol>
* <li>{@link ACRAConstants#EXTRA_REPORT_FILE}</li>
* <li>{@link ACRAConstants#EXTRA_REPORT_EXCEPTION}</li>
* <li>{@link ACRAConstants#EXTRA_REPORT_CONFIG}</li>
* <li>{@link ACRAConstants#EXTRA_FORCE_CANCEL} (optional)</li>
* </ol>
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public abstract class BaseCrashReportDialog extends FragmentActivity {
private File reportFile;
private ACRAConfiguration config;
private Throwable exception;
/**
* NB if you were previously creating and showing your dialog in this method,
* you should move that code to {@link #init(Bundle)}.
*
* @param savedInstanceState If the activity is being re-initialized after
* previously being shut down then this Bundle contains the data it most
* recently supplied in {@link #onSaveInstanceState}. <b><i>Note: Otherwise it is null.</i></b>
*/
@Override
protected final void onCreate(@Nullable Bundle savedInstanceState) {
preInit(savedInstanceState);
super.onCreate(savedInstanceState);
if (ACRA.DEV_LOGGING) {
ACRA.log.d(LOG_TAG, "CrashReportDialog extras=" + getIntent().getExtras());
}
final Serializable sConfig = getIntent().getSerializableExtra(ACRAConstants.EXTRA_REPORT_CONFIG);
final Serializable sReportFile = getIntent().getSerializableExtra(ACRAConstants.EXTRA_REPORT_FILE);
final Serializable sException = getIntent().getSerializableExtra(ACRAConstants.EXTRA_REPORT_EXCEPTION);
final boolean forceCancel = getIntent().getBooleanExtra(ACRAConstants.EXTRA_FORCE_CANCEL, false);
if (forceCancel) {
if (ACRA.DEV_LOGGING) ACRA.log.d(LOG_TAG, "Forced reports deletion.");
cancelReports();
finish();
} else if ((sConfig instanceof ACRAConfiguration) && (sReportFile instanceof File) && ((sException instanceof Throwable) || sException == null)) {
config = (ACRAConfiguration) sConfig;
reportFile = (File) sReportFile;
exception = (Throwable) sException;
init(savedInstanceState);
} else {
ACRA.log.w(LOG_TAG, "Illegal or incomplete call of BaseCrashReportDialog.");
finish();
}
}
/**
* Handle any necessary pre-onCreate() setup here.
*
* @param savedInstanceState If the activity is being re-initialized after
* previously being shut down then this Bundle contains the data it most
* recently supplied in {@link #onSaveInstanceState}. <b><i>Note: Otherwise it is null.</i></b>
*/
protected void preInit(@Nullable Bundle savedInstanceState) {
}
/**
* Responsible for creating and showing the crash report dialog.
*
* @param savedInstanceState If the activity is being re-initialized after
* previously being shut down then this Bundle contains the data it most
* recently supplied in {@link #onSaveInstanceState}. <b><i>Note: Otherwise it is null.</i></b>
*/
protected void init(@Nullable Bundle savedInstanceState) {
}
/**
* Cancel any pending crash reports.
*/
protected final void cancelReports() {
new BulkReportDeleter(getApplicationContext()).deleteReports(false, 0);
}
/**
* Send crash report given user's comment and email address. If none should be empty strings
*
* @param comment Comment (may be null) provided by the user.
* @param userEmail Email address (may be null) provided by the client.
*/
protected final void sendCrash(@Nullable String comment, @Nullable String userEmail) {
final CrashReportPersister persister = new CrashReportPersister();
try {
if (ACRA.DEV_LOGGING) ACRA.log.d(LOG_TAG, "Add user comment to " + reportFile);
final CrashReportData crashData = persister.load(reportFile);
crashData.putString(USER_COMMENT, comment == null ? "" : comment);
crashData.putString(USER_EMAIL, userEmail == null ? "" : userEmail);
persister.store(crashData, reportFile);
} catch (IOException e) {
ACRA.log.w(LOG_TAG, "User comment not added: ", e);
} catch (JSONException e) {
ACRA.log.w(LOG_TAG, "User comment not added: ", e);
}
// Start the report sending task
final SenderServiceStarter starter = new SenderServiceStarter(getApplicationContext(), config);
starter.startService(false, true);
// Optional Toast to thank the user
final int toastId = config.resDialogOkToast();
if (toastId != 0) {
ToastSender.sendToast(getApplicationContext(), toastId, Toast.LENGTH_LONG);
}
}
protected final ACRAConfiguration getConfig() {
return config;
}
protected final Throwable getException() {
return exception;
}
}