Skip to content

Commit b35c72d

Browse files
committed
feat(CrashReport): add crash handler and report activity
1 parent ca9e13b commit b35c72d

6 files changed

Lines changed: 304 additions & 3 deletions

File tree

app/src/main/AndroidManifest.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@
8585
android:name=".activities.AboutActivity"
8686
android:theme="@style/AppTheme" />
8787

88+
<activity
89+
android:name=".activities.CrashReportActivity"
90+
android:exported="true"
91+
android:theme="@style/AppTheme" />
92+
8893
<activity
8994
android:name=".activities.TextEditorActivity"
9095
android:theme="@style/AppTheme" />
@@ -191,4 +196,4 @@
191196
</application>
192197

193198

194-
</manifest>
199+
</manifest>

app/src/main/java/com/wmods/wppenhacer/App.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
import android.os.Environment;
1111
import android.os.Handler;
1212
import android.os.Looper;
13+
import android.util.Log;
1314

1415
import androidx.appcompat.app.AppCompatDelegate;
1516
import androidx.core.app.ActivityCompat;
1617
import androidx.preference.PreferenceManager;
1718

1819
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
20+
import com.wmods.wppenhacer.activities.CrashReportActivity;
1921

2022
import java.io.File;
2123
import java.util.Locale;
@@ -53,11 +55,41 @@ public static void showRequestStoragePermission(Activity activity) {
5355
public void onCreate() {
5456
super.onCreate();
5557
instance = this;
58+
installCrashHandler();
5659
var sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
5760
var mode = Integer.parseInt(sharedPreferences.getString("thememode", "0"));
5861
setThemeMode(mode);
5962
changeLanguage(this);
60-
// criar um banco de dados
63+
}
64+
65+
private void installCrashHandler() {
66+
var previousHandler = Thread.getDefaultUncaughtExceptionHandler();
67+
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
68+
try {
69+
var intent = new Intent(this, CrashReportActivity.class);
70+
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
71+
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
72+
intent.putExtra(CrashReportActivity.EXTRA_CRASH_INFO, buildCrashInfo());
73+
intent.putExtra(CrashReportActivity.EXTRA_CRASH_TRACE, Log.getStackTraceString(throwable));
74+
startActivity(intent);
75+
} catch (Throwable ignored) {
76+
} finally {
77+
if (previousHandler != null) {
78+
previousHandler.uncaughtException(thread, throwable);
79+
} else {
80+
Runtime.getRuntime().exit(2);
81+
}
82+
}
83+
});
84+
}
85+
86+
private String buildCrashInfo() {
87+
var androidVersion = Build.VERSION.RELEASE + " (API " + Build.VERSION.SDK_INT + ")";
88+
var deviceModel = (Build.MANUFACTURER + " " + Build.MODEL).trim();
89+
return "WAE version: " + BuildConfig.VERSION_NAME + "\n" +
90+
"WAE package: " + getPackageName() + "\n" +
91+
getString(R.string.crash_android_version) + ": " + androidVersion + "\n" +
92+
getString(R.string.device_model) + ": " + deviceModel;
6193
}
6294

6395
public static void setThemeMode(int mode) {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.wmods.wppenhacer.activities
2+
3+
import android.content.ClipData
4+
import android.content.ClipboardManager
5+
import android.content.Context
6+
import android.content.Intent
7+
import android.os.Bundle
8+
import android.widget.Toast
9+
import com.wmods.wppenhacer.R
10+
import com.wmods.wppenhacer.activities.base.BaseActivity
11+
import com.wmods.wppenhacer.databinding.ActivityCrashReportBinding
12+
13+
class CrashReportActivity : BaseActivity() {
14+
15+
private lateinit var binding: ActivityCrashReportBinding
16+
private lateinit var reportText: String
17+
18+
override fun onCreate(savedInstanceState: Bundle?) {
19+
super.onCreate(savedInstanceState)
20+
binding = ActivityCrashReportBinding.inflate(layoutInflater)
21+
setContentView(binding.root)
22+
setSupportActionBar(binding.toolbar)
23+
supportActionBar?.setDisplayHomeAsUpEnabled(true)
24+
supportActionBar?.title = getString(R.string.whatsapp_crash_report)
25+
26+
val crashInfo = intent.getStringExtra(EXTRA_CRASH_INFO).orEmpty()
27+
val crashTrace = intent.getStringExtra(EXTRA_CRASH_TRACE).orEmpty()
28+
reportText = "$crashInfo\n\n$crashTrace"
29+
30+
binding.toolbar.setNavigationOnClickListener { finish() }
31+
binding.tvCrashInfo.text = crashInfo
32+
binding.tvCrashTrace.text = crashTrace
33+
binding.btnCopy.setOnClickListener { copyReport() }
34+
binding.btnShare.setOnClickListener { shareReport() }
35+
}
36+
37+
override fun onSupportNavigateUp(): Boolean {
38+
finish()
39+
return true
40+
}
41+
42+
private fun copyReport() {
43+
reportText = "${binding.tvCrashInfo.text}\n\n${binding.tvCrashTrace.text}"
44+
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
45+
clipboard.setPrimaryClip(ClipData.newPlainText(getString(R.string.whatsapp_crash_report), reportText))
46+
Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show()
47+
}
48+
49+
private fun shareReport() {
50+
reportText = "${binding.tvCrashInfo.text}\n\n${binding.tvCrashTrace.text}"
51+
val intent = Intent(Intent.ACTION_SEND)
52+
.setType("text/plain")
53+
.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.whatsapp_crash_report))
54+
.putExtra(Intent.EXTRA_TEXT, reportText)
55+
startActivity(Intent.createChooser(intent, getString(R.string.share)))
56+
}
57+
58+
companion object {
59+
const val EXTRA_CRASH_INFO = "crash_info"
60+
const val EXTRA_CRASH_TRACE = "crash_trace"
61+
}
62+
}

app/src/main/java/com/wmods/wppenhacer/xposed/core/FeatureLoader.kt

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@ import android.app.Instrumentation
77
import android.content.BroadcastReceiver
88
import android.content.ClipData
99
import android.content.ClipboardManager
10+
import android.content.ComponentName
1011
import android.content.Context
1112
import android.content.Intent
1213
import android.content.IntentFilter
14+
import android.os.Build
1315
import android.os.Bundle
16+
import android.util.Log
1417
import android.widget.Toast
1518
import androidx.core.content.ContextCompat
1619
import com.wmods.wppenhacer.App
1720
import com.wmods.wppenhacer.BuildConfig
1821
import com.wmods.wppenhacer.R
1922
import com.wmods.wppenhacer.UpdateChecker
23+
import com.wmods.wppenhacer.activities.CrashReportActivity
2024
import com.wmods.wppenhacer.xposed.core.components.AlertDialogWpp
2125
import com.wmods.wppenhacer.xposed.core.components.FMessageWpp
2226
import com.wmods.wppenhacer.xposed.core.components.FStatusWpp
@@ -114,6 +118,7 @@ class FeatureLoader {
114118
private val list = ArrayList<ErrorItem>()
115119
private var supportedVersions: List<String>? = null
116120
private var currentVersion: String? = null
121+
private var crashHandlerInstalled = false
117122

118123
@JvmStatic
119124
fun start(loader: ClassLoader, pref: XSharedPreferences, sourceDir: String) {
@@ -145,6 +150,7 @@ class FeatureLoader {
145150
val packageInfo = packageManager.getPackageInfo(application.packageName, 0)
146151
XposedBridge.log(packageInfo.versionName)
147152
currentVersion = packageInfo.versionName
153+
installCrashHandler(application, packageInfo.versionName.orEmpty())
148154

149155
val resIdArray = if (application.packageName == PACKAGE_WPP)
150156
R.array.supported_versions_wpp
@@ -242,6 +248,52 @@ class FeatureLoader {
242248
})
243249
}
244250

251+
private fun installCrashHandler(application: Application, whatsAppVersion: String) {
252+
if (crashHandlerInstalled) return
253+
crashHandlerInstalled = true
254+
255+
val previousHandler = Thread.getDefaultUncaughtExceptionHandler()
256+
Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
257+
try {
258+
val crashInfo = buildCrashInfo(application, whatsAppVersion)
259+
val intent = Intent().apply {
260+
component = ComponentName(
261+
BuildConfig.APPLICATION_ID,
262+
CrashReportActivity::class.java.name
263+
)
264+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
265+
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
266+
putExtra(CrashReportActivity.EXTRA_CRASH_INFO, crashInfo)
267+
putExtra(CrashReportActivity.EXTRA_CRASH_TRACE, Log.getStackTraceString(throwable))
268+
}
269+
application.startActivity(intent)
270+
} catch (e: Throwable) {
271+
XposedBridge.log(e)
272+
} finally {
273+
if (previousHandler != null) {
274+
previousHandler.uncaughtException(thread, throwable)
275+
} else {
276+
Runtime.getRuntime().exit(2)
277+
}
278+
}
279+
}
280+
}
281+
282+
private fun buildCrashInfo(application: Application, whatsAppVersion: String): String {
283+
val androidVersion = "${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT})"
284+
val deviceModel = listOf(Build.MANUFACTURER, Build.MODEL)
285+
.filter { it.isNotBlank() }
286+
.joinToString(" ")
287+
288+
return listOf(
289+
"${application.getString(R.string.whatsapp_version)}: $whatsAppVersion",
290+
"${application.getString(R.string.whatsapp_package)}: ${application.packageName}",
291+
"${application.getString(R.string.wae_version)}: ${BuildConfig.VERSION_NAME}",
292+
"${application.getString(R.string.crash_android_version)}: $androidVersion",
293+
"${application.getString(R.string.device_model)}: $deviceModel"
294+
).joinToString("\n")
295+
}
296+
245297

246298
@JvmStatic
247299
@Throws(Exception::class)
@@ -535,4 +587,4 @@ class FeatureLoader {
535587
""".trimIndent()
536588
}
537589
}
538-
}
590+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent"
6+
android:background="?android:attr/windowBackground"
7+
android:orientation="vertical">
8+
9+
<com.google.android.material.appbar.AppBarLayout
10+
android:layout_width="match_parent"
11+
android:layout_height="wrap_content"
12+
android:background="@android:color/transparent"
13+
app:elevation="4dp">
14+
15+
<com.google.android.material.appbar.MaterialToolbar
16+
android:id="@+id/toolbar"
17+
android:layout_width="match_parent"
18+
android:layout_height="?attr/actionBarSize"
19+
android:background="@drawable/toolbar_background"
20+
app:navigationIcon="@drawable/abc_ic_ab_back_material"
21+
app:navigationIconTint="@color/text_on_gradient"
22+
app:title="@string/whatsapp_crash_report"
23+
app:titleTextColor="@color/text_on_gradient" />
24+
25+
</com.google.android.material.appbar.AppBarLayout>
26+
27+
<ScrollView
28+
android:layout_width="match_parent"
29+
android:layout_height="0dp"
30+
android:layout_weight="1"
31+
android:fillViewport="true">
32+
33+
<LinearLayout
34+
android:layout_width="match_parent"
35+
android:layout_height="wrap_content"
36+
android:orientation="vertical"
37+
android:padding="@dimen/spacing_medium">
38+
39+
<com.google.android.material.card.MaterialCardView
40+
style="@style/CardInfoStyle"
41+
android:layout_width="match_parent"
42+
android:layout_height="wrap_content"
43+
android:layout_marginBottom="@dimen/spacing_medium"
44+
app:cardBackgroundColor="@color/surface_container">
45+
46+
<LinearLayout
47+
android:layout_width="match_parent"
48+
android:layout_height="wrap_content"
49+
android:orientation="vertical"
50+
android:padding="@dimen/spacing_medium">
51+
52+
<com.google.android.material.textview.MaterialTextView
53+
android:layout_width="match_parent"
54+
android:layout_height="wrap_content"
55+
android:text="@string/crash_info"
56+
android:textColor="@color/text_primary"
57+
android:textSize="18sp"
58+
android:textStyle="bold" />
59+
60+
<com.google.android.material.textview.MaterialTextView
61+
android:id="@+id/tvCrashInfo"
62+
android:layout_width="match_parent"
63+
android:layout_height="wrap_content"
64+
android:layout_marginTop="@dimen/spacing_small"
65+
android:lineSpacingExtra="3dp"
66+
android:textColor="@color/text_secondary"
67+
android:textIsSelectable="true"
68+
android:textSize="14sp" />
69+
70+
</LinearLayout>
71+
72+
</com.google.android.material.card.MaterialCardView>
73+
74+
<com.google.android.material.card.MaterialCardView
75+
style="@style/CardInfoStyle"
76+
android:layout_width="match_parent"
77+
android:layout_height="wrap_content"
78+
app:cardBackgroundColor="@color/surface_container_high">
79+
80+
<LinearLayout
81+
android:layout_width="match_parent"
82+
android:layout_height="wrap_content"
83+
android:orientation="vertical">
84+
85+
<com.google.android.material.textview.MaterialTextView
86+
android:layout_width="match_parent"
87+
android:layout_height="wrap_content"
88+
android:paddingStart="@dimen/spacing_medium"
89+
android:paddingTop="@dimen/spacing_medium"
90+
android:paddingEnd="@dimen/spacing_medium"
91+
android:text="@string/crash_trace"
92+
android:textColor="@color/text_primary"
93+
android:textSize="18sp"
94+
android:textStyle="bold" />
95+
96+
<com.google.android.material.textview.MaterialTextView
97+
android:id="@+id/tvCrashTrace"
98+
android:layout_width="match_parent"
99+
android:layout_height="wrap_content"
100+
android:fontFamily="monospace"
101+
android:lineSpacingExtra="2dp"
102+
android:padding="@dimen/spacing_medium"
103+
android:scrollHorizontally="false"
104+
android:singleLine="false"
105+
android:textColor="@color/text_primary"
106+
android:textIsSelectable="true"
107+
android:textSize="12sp" />
108+
109+
</LinearLayout>
110+
111+
</com.google.android.material.card.MaterialCardView>
112+
113+
</LinearLayout>
114+
115+
</ScrollView>
116+
117+
<LinearLayout
118+
android:layout_width="match_parent"
119+
android:layout_height="wrap_content"
120+
android:orientation="horizontal"
121+
android:padding="@dimen/spacing_medium">
122+
123+
<com.google.android.material.button.MaterialButton
124+
android:id="@+id/btnCopy"
125+
style="@style/ModernButton.Outlined"
126+
android:layout_width="0dp"
127+
android:layout_height="wrap_content"
128+
android:layout_marginEnd="@dimen/spacing_small"
129+
android:layout_weight="1"
130+
android:text="@string/copy_to_clipboard" />
131+
132+
<com.google.android.material.button.MaterialButton
133+
android:id="@+id/btnShare"
134+
style="@style/ModernButton"
135+
android:layout_width="0dp"
136+
android:layout_height="wrap_content"
137+
android:layout_marginStart="@dimen/spacing_small"
138+
android:layout_weight="1"
139+
android:text="@string/share" />
140+
141+
</LinearLayout>
142+
143+
</LinearLayout>

app/src/main/res/values/strings.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,13 @@
202202
<string name="copy_to_clipboard">Copy to clipboard</string>
203203
<string name="copied_to_clipboard">Copied to clipboard</string>
204204
<string name="error_detected">Error detected</string>
205+
<string name="whatsapp_crash_report">WhatsApp crash report</string>
206+
<string name="crash_info">Crash info</string>
207+
<string name="crash_trace">Trace</string>
208+
<string name="whatsapp_version">WhatsApp version</string>
209+
<string name="whatsapp_package">WhatsApp package</string>
210+
<string name="wae_version">WAE version</string>
211+
<string name="crash_android_version">Android version</string>
205212
<string name="rebooting">Rebooting</string>
206213
<string name="deleted_message">deleted a message</string>
207214
<string name="deleted_status">deleted a status</string>

0 commit comments

Comments
 (0)