mirror of
https://github.com/KitsunePie/AppErrorsTracking.git
synced 2025-09-04 18:25:19 +08:00
Added function ignored Error when device reunlock/restart
This commit is contained in:
@@ -24,10 +24,14 @@
|
|||||||
package com.fankes.apperrorstracking.hook.entity
|
package com.fankes.apperrorstracking.hook.entity
|
||||||
|
|
||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Message
|
import android.os.Message
|
||||||
|
import android.text.TextUtils
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -65,6 +69,35 @@ object FrameworkHooker : YukiBaseHooker() {
|
|||||||
/** 已打开的错误对话框数组 */
|
/** 已打开的错误对话框数组 */
|
||||||
private var openedErrorsDialogs = HashMap<String, AlertDialog>()
|
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 实例
|
* @param context 实例
|
||||||
@@ -88,6 +121,8 @@ object FrameworkHooker : YukiBaseHooker() {
|
|||||||
addView(TextView(context).apply {
|
addView(TextView(context).apply {
|
||||||
text = content
|
text = content
|
||||||
textSize = 16f
|
textSize = 16f
|
||||||
|
ellipsize = TextUtils.TruncateAt.END
|
||||||
|
setSingleLine()
|
||||||
setTextColor(if (context.isSystemInDarkMode) 0xFFDDDDDD.toInt() else 0xFF777777.toInt())
|
setTextColor(if (context.isSystemInDarkMode) 0xFFDDDDDD.toInt() else 0xFF777777.toInt())
|
||||||
})
|
})
|
||||||
setPadding(19.dp(context), 16.dp(context), 19.dp(context), 16.dp(context))
|
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()
|
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()
|
openedErrorsDialogs[packageName]?.cancel()
|
||||||
/** 创建自定义对话框 */
|
/** 创建自定义对话框 */
|
||||||
@@ -194,6 +234,22 @@ object FrameworkHooker : YukiBaseHooker() {
|
|||||||
createButtonItem(context, R.drawable.ic_baseline_bug_report, content = "错误详情") {
|
createButtonItem(context, R.drawable.ic_baseline_bug_report, content = "错误详情") {
|
||||||
// TODO 待开发
|
// 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 */
|
/** 判断进程是否为 APP */
|
||||||
if (isApp) {
|
if (isApp) {
|
||||||
addView(appInfoButton)
|
addView(appInfoButton)
|
||||||
@@ -201,6 +257,9 @@ object FrameworkHooker : YukiBaseHooker() {
|
|||||||
} else addView(closeAppButton)
|
} else addView(closeAppButton)
|
||||||
/** 始终添加错误详情按钮 */
|
/** 始终添加错误详情按钮 */
|
||||||
addView(errorDetailButton)
|
addView(errorDetailButton)
|
||||||
|
/** 始终添加忽略按钮 */
|
||||||
|
addView(ignoredUntilUnlockButton)
|
||||||
|
addView(ignoredUntilRestartButton)
|
||||||
/** 设置边距 */
|
/** 设置边距 */
|
||||||
setPadding(6.dp(context), 15.dp(context), 6.dp(context), 6.dp(context))
|
setPadding(6.dp(context), 15.dp(context), 6.dp(context), 6.dp(context))
|
||||||
})
|
})
|
||||||
@@ -211,8 +270,6 @@ object FrameworkHooker : YukiBaseHooker() {
|
|||||||
/** 设置取消对话框监听 */
|
/** 设置取消对话框监听 */
|
||||||
setOnCancelListener { openedErrorsDialogs.remove(packageName) }
|
setOnCancelListener { openedErrorsDialogs.remove(packageName) }
|
||||||
}.show()
|
}.show()
|
||||||
/** 打印错误日志 */
|
|
||||||
loggerE(msg = "Process \"$packageName\" has crashed${if (isRepeating) " again" else ""}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -56,6 +56,12 @@ fun Number.dp(context: Context) = dpFloat(context).toInt()
|
|||||||
*/
|
*/
|
||||||
fun Number.dpFloat(context: Context) = toFloat() * context.resources.displayMetrics.density
|
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 自身设置界面
|
* 跳转 APP 自身设置界面
|
||||||
* @param packageName 包名
|
* @param packageName 包名
|
||||||
@@ -66,7 +72,7 @@ fun Context.openSelfSetting(packageName: String = this.packageName) = runCatchin
|
|||||||
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||||
data = Uri.fromParts("package", packageName, null)
|
data = Uri.fromParts("package", packageName, null)
|
||||||
})
|
})
|
||||||
}.onFailure { Toast.makeText(this, "无法打开 $packageName 的设置界面", Toast.LENGTH_SHORT).show() }
|
}.onFailure { toast(msg = "无法打开 $packageName 的设置界面") }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前 APP 是否可被启动
|
* 当前 APP 是否可被启动
|
||||||
@@ -83,4 +89,4 @@ fun Context.openApp(packageName: String = this.packageName) = runCatching {
|
|||||||
startActivity(packageManager.getLaunchIntentForPackage(packageName)?.apply {
|
startActivity(packageManager.getLaunchIntentForPackage(packageName)?.apply {
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
})
|
})
|
||||||
}.onFailure { Toast.makeText(this, "无法启动 $packageName", Toast.LENGTH_SHORT).show() }
|
}.onFailure { toast(msg = "无法启动 $packageName") }
|
@@ -1,7 +1,7 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="#000000"
|
android:tint="#ffffff"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
|
10
app/src/main/res/drawable/ic_baseline_eject.xml
Normal file
10
app/src/main/res/drawable/ic_baseline_eject.xml
Normal 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>
|
@@ -1,7 +1,7 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="#000000"
|
android:tint="#ffffff"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="#000000"
|
android:tint="#ffffff"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
|
Reference in New Issue
Block a user