diff --git a/Android/app/src/main/AndroidManifest.xml b/Android/app/src/main/AndroidManifest.xml
index 280f7f72..cf791a22 100644
--- a/Android/app/src/main/AndroidManifest.xml
+++ b/Android/app/src/main/AndroidManifest.xml
@@ -43,6 +43,11 @@
android:theme="@style/Theme.AppCompat"
/>
+
+
= Build.VERSION_CODES.M) {
@@ -210,6 +210,11 @@ public class Apple2Activity extends AppCompatActivity implements Apple2DiskChoos
mDisksMenu = new Apple2DisksMenu(this);
}
+ @Override
+ public void onEmailerFinished() {
+ Apple2CrashHandler.getInstance().cleanCrashData(this);
+ }
+
@Override
public void onDisksChosen(DiskArgs args) {
final String name = args.name;
@@ -258,9 +263,6 @@ public class Apple2Activity extends AppCompatActivity implements Apple2DiskChoos
logMessage(LogType.DEBUG, TAG, "onResume()");
showSplashScreen(/*dismissable:*/true);
- if (!mSwitchingToPortrait.get()) {
- Apple2CrashHandler.getInstance().checkForCrashes(this); // NOTE : needs to be called again to clean-up
- }
if (mDisksMenu == null) {
break;
diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2CrashHandler.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2CrashHandler.java
index 545548c0..e37fd5fd 100644
--- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2CrashHandler.java
+++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2CrashHandler.java
@@ -15,7 +15,6 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import androidx.appcompat.app.AlertDialog;
@@ -205,32 +204,29 @@ public class Apple2CrashHandler {
}
public void checkForCrashes(final Apple2Activity activity) {
+
+ File oldCrashFile = _getCrashLogFile(activity);
+ if (oldCrashFile.exists()) {
+ oldCrashFile.delete();
+ }
+
if (!areCrashesPresent(activity)) {
return;
}
Apple2Preferences.load(activity);
if (!(boolean) Apple2Preferences.getJSONPref(Apple2SettingsMenu.SETTINGS.CRASH)) {
- _cleanCrashData(activity);
+ cleanCrashData(activity);
return;
}
boolean previouslyRanCrashCheck = mAlreadyRanCrashCheck.getAndSet(true);
-
- boolean previouslySentReport = mAlreadySentReport.get();
- if (previouslySentReport) {
- mAlreadySentReport.set(false);
- // here we assume that the crash data was previously sent via email ... if not then we lost it =P
- _cleanCrashData(activity);
- return;
- }
-
if (previouslyRanCrashCheck) {
// don't keep asking on return from backgrounding
return;
}
- final AlertDialog crashDialog = new AlertDialog.Builder(activity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.crasher_send).setMessage(R.string.crasher_send_message).setNegativeButton(R.string.no, null).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
+ final AlertDialog crashDialog = new AlertDialog.Builder(activity).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.crasher_send).setMessage(R.string.crasher_send_message).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
@@ -240,7 +236,7 @@ public class Apple2CrashHandler {
activity.registerAndShowDialog(crashDialog);
}
- public static void emailCrashesAndLogs(final Apple2Activity activity) {
+ public void emailCrashesAndLogs(final Apple2Activity activity) {
final Apple2SplashScreen splashScreen = activity.getSplashScreen();
if (splashScreen != null) {
splashScreen.setDismissable(false);
@@ -384,13 +380,41 @@ public class Apple2CrashHandler {
}
File[] allCrashesAry = new File[allCrashFiles.size()];
- File nativeCrashesZip = Apple2Utils.zipFiles(allCrashFiles.toArray(allCrashesAry), _getCrashFile(activity, ALL_CRASH_FILE));
+ File nativeCrashesZip = Apple2Utils.zipFiles(allCrashFiles.toArray(allCrashesAry), _getCrashLogFile(activity));
// send report with all the data
_sendEmailToDeveloperWithCrashData(activity, summary, nativeCrashesZip);
}
}).start();
}
+ public void cleanCrashData(Apple2Activity activity) {
+
+ Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Cleaning up crash data ...");
+ File[] nativeCrashes = _nativeCrashFiles(activity);
+ for (File crash : nativeCrashes) {
+
+ if (!crash.delete()) {
+ Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Could not unlink crash : " + crash);
+ }
+
+ File processed = new File(_dumpPath2ProcessedPath(crash.getAbsolutePath()));
+ if (!processed.delete()) {
+ Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Could not unlink processed : " + processed);
+ }
+ }
+
+ File javaCrashFile = _javaCrashFile(activity);
+ if (!javaCrashFile.delete()) {
+ Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Could not unlink java crash : " + javaCrashFile);
+ }
+
+ /* HACK NOTE -- don't delete the crash log file here ... possibly the email sender program still needs the link!
+ File allCrashFile = _getCrashLogFile(activity);
+ Apple2Utils.writeFile(new StringBuilder(), allCrashFile);
+ allCrashFile.delete();
+ */
+ }
+
public void performCrash(int crashType) {
if (BuildConfig.DEBUG) {
nativePerformCrash(crashType);
@@ -445,11 +469,11 @@ public class Apple2CrashHandler {
} while (attempts < maxAttempts);
}
- private static File _javaCrashFile(Apple2Activity activity) {
+ private File _javaCrashFile(Apple2Activity activity) {
return new File(homeDir, javaCrashFileName);
}
- private static File[] _nativeLogs(Apple2Activity activity) {
+ private File[] _nativeLogs(Apple2Activity activity) {
FilenameFilter logFilter = new FilenameFilter() {
public boolean accept(File dir, String name) {
File file = new File(dir, name);
@@ -464,7 +488,7 @@ public class Apple2CrashHandler {
return new File(homeDir).listFiles(logFilter);
}
- private static File[] _nativeCrashFiles(Apple2Activity activity) {
+ private File[] _nativeCrashFiles(Apple2Activity activity) {
FilenameFilter dmpFilter = new FilenameFilter() {
public boolean accept(File dir, String name) {
File file = new File(dir, name);
@@ -489,31 +513,34 @@ public class Apple2CrashHandler {
return new File(homeDir).listFiles(dmpFilter);
}
- private static String _dumpPath2ProcessedPath(String crashPath) {
+ private String _dumpPath2ProcessedPath(String crashPath) {
return crashPath.substring(0, crashPath.length() - 4) + ".txt";
}
- private static File _getCrashFile(Apple2Activity activity, String fileName) {
+ private File _getCrashLogFile(Apple2Activity activity) {
File file;
String storageState = Environment.getExternalStorageState();
if (storageState.equals(Environment.MEDIA_MOUNTED)) {
- file = new File(Environment.getExternalStorageDirectory(), fileName);
+ file = new File(Environment.getExternalStorageDirectory(), ALL_CRASH_FILE);
} else {
- file = new File(Apple2Utils.getDataDir(activity), fileName);
+ file = new File(Apple2Utils.getDataDir(activity), ALL_CRASH_FILE);
}
return file;
}
- private static void _sendEmailToDeveloperWithCrashData(Apple2Activity activity, StringBuilder summary, File nativeCrashesZip) {
- mAlreadySentReport.set(true);
+ private void _sendEmailToDeveloperWithCrashData(Apple2Activity activity, StringBuilder summary, File nativeCrashesZip) {
+ final boolean alreadyChoosing = Apple2EmailerActivity.sEmailerIsEmailing.getAndSet(true);
+ if (alreadyChoosing) {
+ return;
+ }
// ... the disaster that is early Android ... there does not appear to be a reliable way to start an
// email Intent to send both text and an attachment, but we make a valiant (if futile) effort to do so here.
// And the reason to send an attachment is that you trigger an android.os.TransactionTooLargeException with too
// much text data in the EXTRA_TEXT ...
- Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", "apple2ix_crash@deadcode.org"/*non-zero variant is correct endpoint at the moment*/, null));
- emailIntent.putExtra(Intent.EXTRA_SUBJECT, "A2IX Report");
+ Intent emailIntent = new Intent(activity, Apple2EmailerActivity.class);
+ emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK/* | Intent.FLAG_ACTIVITY_CLEAR_TOP */);
final int maxCharsEmail = 4096;
int len = summary.length();
@@ -525,51 +552,22 @@ public class Apple2CrashHandler {
Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Oops, could not set crash file data readable!");
}
- emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(nativeCrashesZip));
+ emailIntent.putExtra(Apple2EmailerActivity.EXTRA_STREAM_PATH, nativeCrashesZip.getAbsolutePath());
- Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "STARTING CHOOSER FOR EMAIL ...");
- activity.startActivity(Intent.createChooser(emailIntent, "Send email"));
- Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "AFTER START ACTIVITY ...");
- }
+ Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "STARTING EMAILER ACTIVITY ...");
+ Apple2EmailerActivity.sEmailerCallback = activity;
- private static void _cleanCrashData(Apple2Activity activity) {
-
- Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Cleaning up crash data ...");
- int idx = 0;
- File[] nativeCrashes = _nativeCrashFiles(activity);
- for (File crash : nativeCrashes) {
-
- if (!crash.delete()) {
- Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Could not unlink crash : " + crash);
- }
-
- File processed = new File(_dumpPath2ProcessedPath(crash.getAbsolutePath()));
- if (!processed.delete()) {
- Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Could not unlink processed : " + processed);
- }
- }
-
- File javaCrashFile = _javaCrashFile(activity);
- if (!javaCrashFile.delete()) {
- Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "Could not unlink java crash : " + javaCrashFile);
- }
-
- // remove previous crash files
- File allCrashFile = _getCrashFile(activity, ALL_CRASH_FILE);
- Apple2Utils.writeFile(new StringBuilder(), allCrashFile);
- allCrashFile.delete();
+ activity.startActivityForResult(emailIntent, Apple2EmailerActivity.SEND_REQUEST_CODE);
}
private final static String TAG = "Apple2CrashHandler";
private final static Apple2CrashHandler sCrashHandler = new Apple2CrashHandler();
- private static String homeDir;
+ private String homeDir;
private Thread.UncaughtExceptionHandler mDefaultExceptionHandler;
private AtomicBoolean mAlreadyRanCrashCheck = new AtomicBoolean(false);
- private static AtomicBoolean mAlreadySentReport = new AtomicBoolean(false);
private static native void nativePerformCrash(int crashType); // testing
private static native void nativeProcessCrash(String crashFilePath, String crashProcessedPath);
-
}
diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2EmailerActivity.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2EmailerActivity.java
new file mode 100644
index 00000000..f142eb85
--- /dev/null
+++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2EmailerActivity.java
@@ -0,0 +1,143 @@
+/*
+ * Apple // emulator for *nix
+ *
+ * This software package is subject to the GNU General Public License
+ * version 3 or later (your choice) as published by the Free Software
+ * Foundation.
+ *
+ * Copyright 2019 Aaron Culliney
+ *
+ */
+
+package org.deadc0de.apple2ix;
+
+import android.content.Intent;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.Bundle;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class Apple2EmailerActivity extends AppCompatActivity {
+
+ public static final String EXTRA_STREAM_PATH = Intent.EXTRA_STREAM + "-PATH";
+
+ public static final int SEND_REQUEST_CODE = 46;
+
+ public static final AtomicBoolean sEmailerIsEmailing = new AtomicBoolean(false);
+ public static Callback sEmailerCallback;
+
+ public interface Callback {
+ void onEmailerFinished();
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle inState) {
+ super.onRestoreInstanceState(inState);
+ mExtraText = inState.getString(Intent.EXTRA_TEXT);
+ mExtraStreamPath = inState.getString(EXTRA_STREAM_PATH);
+ mExtraStream = inState.getParcelable(Intent.EXTRA_STREAM);
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ outState.putBoolean("ran", true);
+ outState.putString(Intent.EXTRA_TEXT, mExtraText);
+ outState.putString(EXTRA_STREAM_PATH, mExtraStreamPath);
+ outState.putParcelable(Intent.EXTRA_STREAM, mExtraStream);
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedState) {
+ super.onCreate(savedState);
+
+ Bundle b;
+ {
+ Intent intent = getIntent();
+ Bundle extras = null;
+ if (intent != null) {
+ extras = intent.getExtras();
+ }
+
+ if (savedState != null) {
+ b = savedState;
+ } else if (extras != null) {
+ b = extras;
+ } else {
+ b = new Bundle();
+ }
+ }
+
+ final boolean ran = b.getBoolean("ran");
+ mExtraText = b.getString(Intent.EXTRA_TEXT);
+ mExtraStreamPath = b.getString(EXTRA_STREAM_PATH);
+
+ MediaScannerConnection.scanFile(this,
+ /*paths:*/new String[] { mExtraStreamPath },
+ /*mimeTypes:*/new String[] { "application/zip" },
+ new MediaScannerConnection.OnScanCompletedListener() {
+ public void onScanCompleted(String path, Uri uri) {
+
+ mExtraStream = uri;
+ Intent emailIntent = new Intent(Intent.ACTION_SEND);
+
+ try {
+ emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { "apple2ix_crash@deadcode.org" });
+ emailIntent.putExtra(Intent.EXTRA_SUBJECT, "A2IX Report To apple2ix_crash@deadcode.org");
+ emailIntent.putExtra(Intent.EXTRA_TEXT, mExtraText);
+ emailIntent.putExtra(Intent.EXTRA_STREAM, mExtraStream);
+ emailIntent.setType("message/rfc822");
+
+ if (!ran) {
+ Apple2Activity.logMessage(Apple2Activity.LogType.DEBUG, TAG, "STARTING EMAIL ACTIVITY ...");
+ startActivityForResult(emailIntent, SEND_REQUEST_CODE);
+ }
+ } catch (Throwable t) {
+ Apple2Activity.logMessage(Apple2Activity.LogType.ERROR, TAG, "OOPS : " + t);
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ if (resultCode != RESULT_CANCELED) {
+ // Do something?
+ }
+
+ if (mExtraStream != null) {
+ int deleted = getContentResolver().delete(mExtraStream, null, null);
+ }
+
+ sEmailerCallback.onEmailerFinished();
+
+ setResult(RESULT_OK);
+ finish();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public void finish() {
+ sEmailerIsEmailing.set(false);
+ super.finish();
+ }
+
+ private String mExtraText;
+
+ private String mExtraStreamPath;
+
+ private Uri mExtraStream;
+
+ private static final String TAG = "A2EmailerActivity";
+}
diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2SettingsMenu.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2SettingsMenu.java
index 62a47672..7cbf286e 100644
--- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2SettingsMenu.java
+++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2SettingsMenu.java
@@ -373,7 +373,7 @@ public class Apple2SettingsMenu extends Apple2AbstractMenu {
@Override
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
- Apple2CrashHandler.emailCrashesAndLogs(activity);
+ Apple2CrashHandler.getInstance().emailCrashesAndLogs(activity);
}
},
CRASH {