From 7dc08afdc67c6c6da90ff05c8fff9af8769c8a10 Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Mon, 3 Jan 2022 13:50:58 +0530 Subject: [PATCH] Show crash report in another activity --- .idea/misc.xml | 1 + app/build.gradle | 6 +- app/src/main/AndroidManifest.xml | 14 +- .../androidide/CrashHandlerActivity.java | 92 +++++++++ .../com/itsaky/androidide/MainActivity.java | 13 +- .../com/itsaky/androidide/app/StudioApp.java | 28 ++- .../res/layout/activity_crash_handler.xml | 131 +++++++++++++ app/src/main/res/values/strings.xml | 184 +++++++++--------- .../androidide/app/BaseApplication.java | 20 +- 9 files changed, 370 insertions(+), 119 deletions(-) create mode 100644 app/src/main/java/com/itsaky/androidide/CrashHandlerActivity.java create mode 100644 app/src/main/res/layout/activity_crash_handler.xml diff --git a/.idea/misc.xml b/.idea/misc.xml index 301599295..7207878c3 100755 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -9,6 +9,7 @@ + diff --git a/app/build.gradle b/app/build.gradle index 995806549..ddc6dd93d 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -79,7 +79,11 @@ android { } dependencies { - // Annotation processors + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.google.android.material:material:1.3.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + + // Annotation processors annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' implementation common.utilcode diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5fe5c97a1..c95afbbd6 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,12 +21,20 @@ android:supportsRtl="true" android:theme="@style/AppTheme" tools:ignore="UnusedAttribute,MediaCapabilities"> + + + + + + - @@ -54,6 +62,7 @@ android:name=".TerminalActivity" android:configChanges="orientation|screenSize|uiMode" android:windowSoftInputMode="adjustResize" /> + @@ -61,6 +70,7 @@ + + @@ -79,4 +90,5 @@ android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/cms_channel_id_devs" /> + \ No newline at end of file diff --git a/app/src/main/java/com/itsaky/androidide/CrashHandlerActivity.java b/app/src/main/java/com/itsaky/androidide/CrashHandlerActivity.java new file mode 100644 index 000000000..b0944b98b --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/CrashHandlerActivity.java @@ -0,0 +1,92 @@ +/* + * This file is part of AndroidIDE. + * + * AndroidIDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AndroidIDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AndroidIDE. If not, see . + */ + +package com.itsaky.androidide; + +import static com.blankj.utilcode.util.AppUtils.getAppVersionCode; +import static com.blankj.utilcode.util.AppUtils.getAppVersionName; +import static com.blankj.utilcode.util.DeviceUtils.getManufacturer; +import static com.blankj.utilcode.util.DeviceUtils.getModel; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.NonNull; + +import com.blankj.utilcode.util.ClipboardUtils; +import com.itsaky.androidide.app.BaseApplication; +import com.itsaky.androidide.app.StudioActivity; +import com.itsaky.androidide.databinding.ActivityCrashHandlerBinding; + +public class CrashHandlerActivity extends StudioActivity { + + private ActivityCrashHandlerBinding binding; + + public static final String REPORT_ACTION = "com.itsaky.androidide.REPORT_CRASH"; + public static final String TRACE_KEY = "crash_trace"; + + @Override + protected View bindLayout () { + binding = ActivityCrashHandlerBinding.inflate (getLayoutInflater ()); + return binding.getRoot (); + } + + @Override + protected void onCreate (Bundle savedInstanceState) { + super.onCreate (savedInstanceState); + binding.closeButton.setOnClickListener (v -> finishAffinity ()); + + final var extra = getIntent ().getExtras (); + if (extra == null) { + binding.closeButton.performClick (); + return; + } + + final var report = buildReportText (extra.getString (TRACE_KEY, "Unable to get logs.")); + binding.logText.setText (report); + binding.reportButton.setOnClickListener (v -> reportTrace (report)); + } + + private void reportTrace (String report) { + ClipboardUtils.copyText ("AndroidIDE CrashLog", report); + final var url = BaseApplication.GITHUB_URL.concat ("/issues"); + final var intent = new Intent (); + intent.setAction(Intent.ACTION_VIEW); + intent.setData (Uri.parse (url)); + intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity (intent); + } + + @NonNull + private String buildReportText (String trace) { + return "AndroidIDE crash report\n" + + "Manufacturer: " + + getManufacturer () + + "\n" + + "Device: " + + getModel () + + "\n" + + "App version: " + + getAppVersionName () + + " (" + + getAppVersionCode () + + ")\n\n Stacktrace: \n" + + trace; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/itsaky/androidide/MainActivity.java b/app/src/main/java/com/itsaky/androidide/MainActivity.java index 997c1e67a..6ce79e01a 100755 --- a/app/src/main/java/com/itsaky/androidide/MainActivity.java +++ b/app/src/main/java/com/itsaky/androidide/MainActivity.java @@ -140,11 +140,11 @@ public class MainActivity extends StudioActivity implements View.OnClickListener @Override public void onClick(View p1) { - if (p1.getId() == binding.createProject.getId()) + if (p1.getId() == binding.createProject.getId()) { showCreateProject(); - else if (p1.getId() == createBinding.createprojectClose.getId()) + } else if (p1.getId() == createBinding.createprojectClose.getId()) { hideCreateProject(); - else if (p1.getId() == createLayoutBinding.nextCard.getId()) { + } else if (p1.getId() == createLayoutBinding.nextCard.getId()) { currentTemplateIndex++; if (currentTemplateIndex >= mTemplates.size()) currentTemplateIndex = 0; showTemplate(currentTemplateIndex); @@ -152,13 +152,16 @@ public class MainActivity extends StudioActivity implements View.OnClickListener currentTemplateIndex--; if (currentTemplateIndex < 0) currentTemplateIndex = mTemplates.size() - 1; showTemplate(currentTemplateIndex); - } else if (p1.getId() == createLayoutBinding.createprojectCreate.getId()) + } else if (p1.getId() == createLayoutBinding.createprojectCreate.getId()) { createNewProject(); - else if (p1.getId() == binding.gotoPreferences.getId()) { + } else if (p1.getId() == binding.gotoPreferences.getId()) { gotoSettings(); } else if (p1.getId() == binding.openProject.getId()) { pickProject(); } else if(p1.getId() == binding.openTerminal.getId()) { + if (true) { + throw new RuntimeException ("hello. this is a crash handler test"); + } startActivity(new Intent(this, TerminalActivity.class)); } } diff --git a/app/src/main/java/com/itsaky/androidide/app/StudioApp.java b/app/src/main/java/com/itsaky/androidide/app/StudioApp.java index 213114b1b..ab70727a5 100755 --- a/app/src/main/java/com/itsaky/androidide/app/StudioApp.java +++ b/app/src/main/java/com/itsaky/androidide/app/StudioApp.java @@ -17,7 +17,11 @@ **************************************************************************************/ package com.itsaky.androidide.app; +import android.content.Intent; + +import com.blankj.utilcode.util.ThrowableUtils; import com.google.firebase.messaging.FirebaseMessaging; +import com.itsaky.androidide.CrashHandlerActivity; import com.itsaky.androidide.language.xml.completion.XMLCompletionService; import com.itsaky.androidide.project.ProjectResourceFinder; import com.itsaky.androidide.services.IDELogService; @@ -38,15 +42,14 @@ import java.util.Set; public class StudioApp extends BaseApplication { private static StudioApp instance; - private boolean stopGradleDaemon = true; private static ApiInfo mApiInfo; private static AttrInfo mAttrInfo; private static WidgetInfo mWidgetInfo; private IResourceFinder mResFinder; - private XMLCompletionService mXmlCompletionService; private ILayoutInflater mLayoutInflater; + private Thread.UncaughtExceptionHandler uncaughtExceptionHandler; public static final boolean DEBUG = com.itsaky.androidide.BuildConfig.DEBUG; @@ -55,6 +58,8 @@ public class StudioApp extends BaseApplication { @Override public void onCreate() { instance = this; + this.uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(this::handleCrash); super.onCreate(); FirebaseMessaging.getInstance().subscribeToTopic(MessagingService.TOPIC_UPDATE); @@ -63,6 +68,24 @@ public class StudioApp extends BaseApplication { initializeApiInformation(); } + private void handleCrash(Thread thread, Throwable th) { + writeException(th); + + try { + final var intent = new Intent (); + intent.setAction (CrashHandlerActivity.REPORT_ACTION); + intent.putExtra (CrashHandlerActivity.TRACE_KEY, ThrowableUtils.getFullStackTrace (th)); + intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity (intent); + + if(this.uncaughtExceptionHandler != null) { + this.uncaughtExceptionHandler.uncaughtException(thread, th); + } + } catch (Throwable error) { + LOG.error ("Unable to show crash handler activity", error); + } + } + public void createInflater (LayoutInflaterConfiguration config) { this.mLayoutInflater = ILayoutInflater.newInstance(config); } @@ -127,7 +150,6 @@ public class StudioApp extends BaseApplication { } public void setStopGradleDaemon(boolean startGradleDaemon) { - this.stopGradleDaemon = startGradleDaemon; } public static StudioApp getInstance() { diff --git a/app/src/main/res/layout/activity_crash_handler.xml b/app/src/main/res/layout/activity_crash_handler.xml new file mode 100644 index 000000000..815bcb359 --- /dev/null +++ b/app/src/main/res/layout/activity_crash_handler.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +