diff --git a/app/build.gradle b/app/build.gradle index 8e5beda09..079c7b3ec 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -204,6 +204,7 @@ dependencies { } // Parceler implementation 'org.parceler:parceler-api:1.1.13' + implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0' annotationProcessor 'org.parceler:parceler:1.1.13' // Dagger 2 implementation 'com.google.dagger:dagger:2.53.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 28a0cf74e..ec3b5ab4c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -440,6 +440,15 @@ android:resource="@dimen/app_minimumsize_h" /> + + + + diff --git a/app/src/main/java/com/money/manager/ex/common/MmxBaseFragmentActivity.java b/app/src/main/java/com/money/manager/ex/common/MmxBaseFragmentActivity.java index e29bc5baa..53a7f65db 100644 --- a/app/src/main/java/com/money/manager/ex/common/MmxBaseFragmentActivity.java +++ b/app/src/main/java/com/money/manager/ex/common/MmxBaseFragmentActivity.java @@ -36,6 +36,7 @@ import com.money.manager.ex.R; import com.money.manager.ex.core.Core; import com.money.manager.ex.core.UIHelper; +import com.money.manager.ex.crashreport.CrashReporter; import com.money.manager.ex.log.ErrorRaisedEvent; import com.money.manager.ex.settings.AppSettings; @@ -60,6 +61,8 @@ public abstract class MmxBaseFragmentActivity @Override protected void onCreate(Bundle savedInstanceState) { + new CrashReporter(this); + setTheme(); AppSettings settings = new AppSettings(this); @@ -76,6 +79,7 @@ protected void onCreate(Bundle savedInstanceState) { this.compositeSubscription = new CompositeSubscription(); super.onCreate(savedInstanceState); + // Initialize the ActivityResultLauncher openDocumentLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { diff --git a/app/src/main/java/com/money/manager/ex/crashreport/CrashReportActivity.java b/app/src/main/java/com/money/manager/ex/crashreport/CrashReportActivity.java new file mode 100644 index 000000000..76d7e4b9d --- /dev/null +++ b/app/src/main/java/com/money/manager/ex/crashreport/CrashReportActivity.java @@ -0,0 +1,65 @@ +package com.money.manager.ex.crashreport; + + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.widget.Button; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +import com.money.manager.ex.R; + +public class CrashReportActivity extends AppCompatActivity { + private Intent intent = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_auth); + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + handleIntent(); + } + + + void handleIntent() { + if (intent != null) return; + + intent = getIntent(); + if (intent == null) return; + + String source = intent.getStringExtra("ERROR"); + String report = intent.getStringExtra(Intent.EXTRA_TEXT); + + TextView reportUI = findViewById(R.id.editTextReport); + reportUI.setText(report); + + Button openIssue = findViewById(R.id.buttonOpenIssue); + openIssue.setOnClickListener(v -> { + String body = "[Put here your description]\n" + report; + String uri = Uri.parse("https://github.com/moneymanagerex/android-money-manager-ex/issues/new") + .buildUpon() + .appendQueryParameter("label", "bug") +// .appendQueryParameter("title", "Your title here") + .appendQueryParameter("body", body) + .build().toString(); + Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri)); + this.startActivity(myIntent); + + closeActivity(); + + }); + + Button cancel = findViewById(R.id.buttonQuit); + cancel.setOnClickListener(view -> closeActivity()); + } + + private void closeActivity() { + this.finish(); + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(0); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/money/manager/ex/crashreport/CrashReporter.java b/app/src/main/java/com/money/manager/ex/crashreport/CrashReporter.java new file mode 100644 index 000000000..778740705 --- /dev/null +++ b/app/src/main/java/com/money/manager/ex/crashreport/CrashReporter.java @@ -0,0 +1,105 @@ +package com.money.manager.ex.crashreport; + + +import android.content.Context; +import android.content.Intent; +import android.os.Build; + +/** + * Activity based Exception handler ... + */ +public class CrashReporter implements Thread.UncaughtExceptionHandler { + + private final Context mContext; + private final Thread.UncaughtExceptionHandler rootHandler; + + public CrashReporter(Context context) { + mContext = context; + // we should store the current exception handler -- to invoke it for all not handled exceptions ... + rootHandler = Thread.getDefaultUncaughtExceptionHandler(); + // we replace the exception handler now with us -- we will properly dispatch the exceptions ... + Thread.setDefaultUncaughtExceptionHandler(this); + } + + + @Override + public void uncaughtException(final Thread thread, final Throwable ex) { + // note we can't just open in Android an dialog etc. we have to use Intents here + // http://stackoverflow.com/questions/13416879/show-a-dialog-in-thread-setdefaultuncaughtexceptionhandler + + Intent registerActivity = new Intent(mContext, CrashReportActivity.class); + registerActivity.setAction("HANDLE_ERROR"); + registerActivity.putExtra("ERROR", CrashReporter.class.getName()); + registerActivity.putExtra(Intent.EXTRA_TEXT, generateReport(thread,ex)); + registerActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + + mContext.startActivity(registerActivity); + + rootHandler.uncaughtException(thread, ex); +// // make sure we die, otherwise the app will hang ... +// android.os.Process.killProcess(android.os.Process.myPid()); +// // sometimes on older android version killProcess wasn't enough -- strategy pattern should be considered here +// System.exit(0); + + } + + public static String generateReport(final Thread t, final Throwable e) { + StackTraceElement[] arr = e.getStackTrace(); + final StringBuffer report = new StringBuffer(e.toString()); + final String lineSeperator = "-------------------------------\n\n"; + report.append("\n\n"); + report.append("--------- Stack trace ---------\n\n"); + for (int i = 0; i < arr.length; i++) { + report.append( " "); + report.append(arr[i].toString()); + report.append("\n"); + } + report.append(lineSeperator); + // If the exception was thrown in a background thread inside + // AsyncTask, then the actual exception can be found with getCause + report.append("--------- Cause ---------\n\n"); + Throwable cause = e.getCause(); + if (cause != null) { + report.append(cause.toString()); + report.append("\n\n"); + arr = cause.getStackTrace(); + for (int i = 0; i < arr.length; i++) { + report.append(" "); + report.append(arr[i].toString()); + report.append("\n"); + } + } + // Getting the Device brand,model and sdk verion details. + report.append(lineSeperator); + report.append("--------- Device ---------\n\n"); + report.append("Brand: "); + report.append(Build.BRAND); + report.append("\n"); + report.append("Device: "); + report.append(Build.DEVICE); + report.append("\n"); + report.append("Model: "); + report.append(Build.MODEL); + report.append("\n"); + report.append("Id: "); + report.append(Build.ID); + report.append("\n"); + report.append("Product: "); + report.append(Build.PRODUCT); + report.append("\n"); + report.append(lineSeperator); + report.append("--------- Firmware ---------\n\n"); + report.append("SDK: "); + report.append(Build.VERSION.SDK_INT); + report.append("\n"); + report.append("Release: "); + report.append(Build.VERSION.RELEASE); + report.append("\n"); + report.append("Incremental: "); + report.append(Build.VERSION.INCREMENTAL); + report.append("\n"); + report.append(lineSeperator); + return report.toString(); + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_auth.xml b/app/src/main/res/layout/activity_auth.xml new file mode 100644 index 000000000..3aaad4876 --- /dev/null +++ b/app/src/main/res/layout/activity_auth.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + +