Added function ignored Error when device reunlock/restart

This commit is contained in:
2022-05-09 23:31:25 +08:00
parent 9946d35e57
commit 652925297a
6 changed files with 82 additions and 9 deletions

View File

@@ -24,10 +24,14 @@
package com.fankes.apperrorstracking.hook.entity
import android.app.AlertDialog
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ApplicationInfo
import android.graphics.Color
import android.os.Message
import android.text.TextUtils
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
@@ -65,6 +69,35 @@ object FrameworkHooker : YukiBaseHooker() {
/** 已打开的错误对话框数组 */
private var openedErrorsDialogs = HashMap<String, AlertDialog>()
/** 已忽略错误的 APP 数组 - 直到重新解锁 */
private var ignoredErrorsIfUnlockApps = HashSet<String>()
/** 已忽略错误的 APP 数组 - 直到重新启动 */
private var ignoredErrorsIfRestartApps = HashSet<String>()
/** 是否已经注册广播 */
private var isRegisterReceiver = false
/** 用户解锁屏幕广播接收器 */
private val userPresentReceiver by lazy {
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
/** 解锁后清空已记录的忽略错误 APP */
ignoredErrorsIfUnlockApps.clear()
}
}
}
/**
* 注册广播接收器
* @param context 实例
*/
private fun registerReceiver(context: Context) {
if (isRegisterReceiver) return
context.registerReceiver(userPresentReceiver, IntentFilter().apply { addAction(Intent.ACTION_USER_PRESENT) })
isRegisterReceiver = true
}
/**
* 创建对话框按钮
* @param context 实例
@@ -88,6 +121,8 @@ object FrameworkHooker : YukiBaseHooker() {
addView(TextView(context).apply {
text = content
textSize = 16f
ellipsize = TextUtils.TruncateAt.END
setSingleLine()
setTextColor(if (context.isSystemInDarkMode) 0xFFDDDDDD.toInt() else 0xFF777777.toInt())
})
setPadding(19.dp(context), 16.dp(context), 19.dp(context), 16.dp(context))
@@ -158,8 +193,13 @@ object FrameworkHooker : YukiBaseHooker() {
/** 是否短时内重复错误 */
val isRepeating = AppErrorDialog_DataClass.clazz.field { name = "repeating" }.get(errData).boolean()
/** 判断在后台就不显示对话框 */
if (errResult == -2) return@afterHook
/** 注册广播 */
registerReceiver(context)
/** 打印错误日志 */
loggerE(msg = "Process \"$packageName\" has crashed${if (isRepeating) " again" else ""}")
/** 判断是否被忽略 - 在后台就不显示对话框 */
if (ignoredErrorsIfUnlockApps.contains(packageName) || ignoredErrorsIfRestartApps.contains(packageName) || errResult == -2)
return@afterHook
/** 关闭重复的对话框 */
openedErrorsDialogs[packageName]?.cancel()
/** 创建自定义对话框 */
@@ -194,6 +234,22 @@ object FrameworkHooker : YukiBaseHooker() {
createButtonItem(context, R.drawable.ic_baseline_bug_report, content = "错误详情") {
// TODO 待开发
}
/** 忽略按钮 - 直到解锁 */
val ignoredUntilUnlockButton =
createButtonItem(context, R.drawable.ic_baseline_eject, content = "忽略(直到设备重新解锁)") {
cancel()
ignoredErrorsIfUnlockApps.add(packageName)
context.toast(msg = "忽略“$appName”的错误直到设备重新解锁")
}
/** 忽略按钮 - 直到重启 */
val ignoredUntilRestartButton =
createButtonItem(context, R.drawable.ic_baseline_eject, content = "忽略(直到设备重新启动)") {
cancel()
ignoredErrorsIfRestartApps.add(packageName)
context.toast(msg = "忽略“$appName”的错误直到设备重新启动")
}
/** 判断进程是否为 APP */
if (isApp) {
addView(appInfoButton)
@@ -201,6 +257,9 @@ object FrameworkHooker : YukiBaseHooker() {
} else addView(closeAppButton)
/** 始终添加错误详情按钮 */
addView(errorDetailButton)
/** 始终添加忽略按钮 */
addView(ignoredUntilUnlockButton)
addView(ignoredUntilRestartButton)
/** 设置边距 */
setPadding(6.dp(context), 15.dp(context), 6.dp(context), 6.dp(context))
})
@@ -211,8 +270,6 @@ object FrameworkHooker : YukiBaseHooker() {
/** 设置取消对话框监听 */
setOnCancelListener { openedErrorsDialogs.remove(packageName) }
}.show()
/** 打印错误日志 */
loggerE(msg = "Process \"$packageName\" has crashed${if (isRepeating) " again" else ""}")
}
}
}

View File

@@ -56,6 +56,12 @@ fun Number.dp(context: Context) = dpFloat(context).toInt()
*/
fun Number.dpFloat(context: Context) = toFloat() * context.resources.displayMetrics.density
/**
* 弹出 [Toast]
* @param msg 提示内容
*/
fun Context.toast(msg: String) = Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
/**
* 跳转 APP 自身设置界面
* @param packageName 包名
@@ -66,7 +72,7 @@ fun Context.openSelfSetting(packageName: String = this.packageName) = runCatchin
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
data = Uri.fromParts("package", packageName, null)
})
}.onFailure { Toast.makeText(this, "无法打开 $packageName 的设置界面", Toast.LENGTH_SHORT).show() }
}.onFailure { toast(msg = "无法打开 $packageName 的设置界面") }
/**
* 当前 APP 是否可被启动
@@ -83,4 +89,4 @@ fun Context.openApp(packageName: String = this.packageName) = runCatching {
startActivity(packageManager.getLaunchIntentForPackage(packageName)?.apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
}.onFailure { Toast.makeText(this, "无法启动 $packageName", Toast.LENGTH_SHORT).show() }
}.onFailure { toast(msg = "无法启动 $packageName") }

View File

@@ -1,7 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:tint="#ffffff"
android:viewportWidth="24"
android:viewportHeight="24">
<path

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M5,17h14v2L5,19zM12,5L5.33,15h13.34z" />
</vector>

View File

@@ -1,7 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:tint="#ffffff"
android:viewportWidth="24"
android:viewportHeight="24">
<path

View File

@@ -1,7 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:tint="#ffffff"
android:viewportWidth="24"
android:viewportHeight="24">
<path