diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f6e9a1f..5e65874 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -54,6 +54,16 @@
+
+
+ *
+ * This file is Created by fankes on 2022/5/10.
+ */
+package com.fankes.apperrorstracking.bean
+
+import java.io.Serializable
+
+/**
+ * 应用异常信息显示 bean
+ * @param packageName APP 包名
+ * @param appName APP 名称
+ * @param title 标题
+ * @param isApp 是否为 APP
+ * @param isShowReopenButton 是否显示重新打开按钮
+ */
+data class AppErrorsDisplayBean(
+ var packageName: String,
+ var appName: String,
+ var title: String,
+ var isApp: Boolean,
+ var isShowReopenButton: Boolean
+) : Serializable
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/apperrorstracking/hook/entity/FrameworkHooker.kt b/app/src/main/java/com/fankes/apperrorstracking/hook/entity/FrameworkHooker.kt
index 3be0652..4e1b7b2 100644
--- a/app/src/main/java/com/fankes/apperrorstracking/hook/entity/FrameworkHooker.kt
+++ b/app/src/main/java/com/fankes/apperrorstracking/hook/entity/FrameworkHooker.kt
@@ -27,22 +27,14 @@ import android.app.ApplicationErrorReport
import android.content.Context
import android.content.Intent
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
-import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.TextView
-import androidx.core.content.res.ResourcesCompat
-import com.fankes.apperrorstracking.R
+import com.fankes.apperrorstracking.bean.AppErrorsDisplayBean
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
import com.fankes.apperrorstracking.locale.LocaleString
-import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsDetailActivity
-import com.fankes.apperrorstracking.utils.drawable.drawabletoolbox.DrawableBuilder
-import com.fankes.apperrorstracking.utils.factory.*
+import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsDisplayActivity
+import com.fankes.apperrorstracking.utils.factory.appName
+import com.fankes.apperrorstracking.utils.factory.isAppCanOpened
+import com.fankes.apperrorstracking.utils.factory.openApp
import com.fankes.apperrorstracking.utils.tool.FrameworkTool
import com.highcapable.yukihookapi.hook.bean.VariousClass
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
@@ -72,9 +64,6 @@ object FrameworkHooker : YukiBaseHooker() {
"com.android.server.am.ErrorDialogController"
)
- /** 已打开的错误对话框数组 */
- private var openedErrorsDialogs = hashMapOf()
-
/** 已忽略错误的 APP 数组 - 直到重新解锁 */
private var ignoredErrorsIfUnlockApps = hashSetOf()
@@ -84,45 +73,6 @@ object FrameworkHooker : YukiBaseHooker() {
/** 已记录的 APP 异常信息数组 - 直到重新启动 */
private val appErrorsRecords = arrayListOf()
- /**
- * 获取最新的 APP 错误信息
- * @param packageName 包名
- * @return [AppErrorsInfoBean] or null
- */
- private fun lastAppErrorsInfo(packageName: String) =
- appErrorsRecords.takeIf { it.isNotEmpty() }?.filter { it.packageName == packageName }?.get(0)
-
- /**
- * 创建对话框按钮
- * @param context 实例
- * @param drawableId 按钮图标
- * @param content 按钮文本
- * @param it 点击事件回调
- * @return [LinearLayout]
- */
- private fun createButtonItem(context: Context, drawableId: Int, content: String, it: () -> Unit) =
- LinearLayout(context).apply {
- background = DrawableBuilder().rounded().cornerRadius(15.dp(context)).ripple().rippleColor(0xFFAAAAAA.toInt()).build()
- gravity = Gravity.CENTER or Gravity.START
- layoutParams =
- ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
- addView(ImageView(context).apply {
- setImageDrawable(ResourcesCompat.getDrawable(moduleAppResources, drawableId, null))
- layoutParams = ViewGroup.LayoutParams(25.dp(context), 25.dp(context))
- setColorFilter(if (context.isSystemInDarkMode) Color.WHITE else Color.BLACK)
- })
- addView(View(context).apply { layoutParams = ViewGroup.LayoutParams(15.dp(context), 0) })
- 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))
- setOnClickListener { it() }
- }
-
/** 注册 */
private fun register() {
onAppLifecycle {
@@ -132,9 +82,12 @@ object FrameworkHooker : YukiBaseHooker() {
registerReceiver(Intent.ACTION_LOCALE_CHANGED) { _, _ -> refreshModuleAppResources() }
}
FrameworkTool.Host.with(instance = this) {
+ onOpenAppUsedFramework { appContext.openApp(it) }
onPushAppErrorsInfoData { appErrorsRecords }
onRemoveAppErrorsInfoData { appErrorsRecords.remove(it) }
onClearAppErrorsInfoData { appErrorsRecords.clear() }
+ onIgnoredErrorsIfUnlock { ignoredErrorsIfUnlockApps.add(it) }
+ onIgnoredErrorsIfRestart { ignoredErrorsIfRestartApps.add(it) }
}
}
@@ -214,74 +167,16 @@ object FrameworkHooker : YukiBaseHooker() {
/** 判断是否被忽略 - 在后台就不显示对话框 */
if (ignoredErrorsIfUnlockApps.contains(packageName) || ignoredErrorsIfRestartApps.contains(packageName) || errResult == -2)
return@afterHook
- /** 关闭重复的对话框 */
- openedErrorsDialogs[packageName]?.cancel()
- /** 创建自定义对话框 */
- context.showDialog {
- title = if (isRepeating) LocaleString.aerrRepeatedTitle(appName) else LocaleString.aerrTitle(appName)
- view = LinearLayout(context).apply {
- orientation = LinearLayout.VERTICAL
- /** 应用信息按钮 */
- val appInfoButton =
- createButtonItem(context, R.drawable.ic_baseline_info, LocaleString.appInfo) {
- cancel()
- context.openSelfSetting(packageName)
- }
-
- /** 关闭应用按钮 */
- val closeAppButton =
- createButtonItem(context, R.drawable.ic_baseline_close, LocaleString.closeApp) { cancel() }
-
- /** 重新打开按钮 */
- val reOpenButton =
- createButtonItem(context, R.drawable.ic_baseline_refresh, LocaleString.reopenApp) {
- cancel()
- context.openApp(packageName)
- }
-
- /** 错误详情按钮 */
- val errorDetailButton =
- createButtonItem(context, R.drawable.ic_baseline_bug_report, LocaleString.errorDetail) {
- cancel()
- lastAppErrorsInfo(packageName)?.let { AppErrorsDetailActivity.start(context, it, isOutSide = true) }
- ?: context.toast(msg = "Invalid AppErrorsInfo")
- }
-
- /** 忽略按钮 - 直到解锁 */
- val ignoredUntilUnlockButton =
- createButtonItem(context, R.drawable.ic_baseline_eject, LocaleString.ignoreIfUnlock) {
- cancel()
- ignoredErrorsIfUnlockApps.add(packageName)
- context.toast(LocaleString.ignoreIfUnlockTip(appName))
- }
-
- /** 忽略按钮 - 直到重启 */
- val ignoredUntilRestartButton =
- createButtonItem(context, R.drawable.ic_baseline_eject, LocaleString.ignoreIfRestart) {
- cancel()
- ignoredErrorsIfRestartApps.add(packageName)
- context.toast(LocaleString.ignoreIfRestartTip(appName))
- }
- /** 判断进程是否为 APP */
- if (isApp) {
- addView(appInfoButton)
- addView(if (isRepeating.not() && context.isAppCanOpened(packageName)) reOpenButton else closeAppButton)
- } else addView(closeAppButton)
- /** 始终添加错误详情按钮 */
- addView(errorDetailButton)
- /** 始终添加忽略按钮 */
- addView(ignoredUntilUnlockButton)
- addView(ignoredUntilRestartButton)
- /** 设置边距 */
- setPadding(6.dp(context), 15.dp(context), 6.dp(context), 6.dp(context))
- }
- /** 设置取消对话框监听 */
- onCancel { openedErrorsDialogs.remove(packageName) }
- /** 记录实例 */
- openedErrorsDialogs[packageName] = this
- /** 只有 SystemUid 才能响应系统级别的对话框 */
- makeSystemAlert()
- }
+ /** 启动错误对话框显示窗口 */
+ AppErrorsDisplayActivity.start(
+ context, AppErrorsDisplayBean(
+ packageName = packageName,
+ appName = appName,
+ title = if (isRepeating) LocaleString.aerrRepeatedTitle(appName) else LocaleString.aerrTitle(appName),
+ isApp = isApp,
+ isShowReopenButton = isRepeating.not() && context.isAppCanOpened(packageName)
+ )
+ )
}
}
injectMember {
diff --git a/app/src/main/java/com/fankes/apperrorstracking/ui/activity/base/BaseActivity.kt b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/base/BaseActivity.kt
index 057f40c..c2d027d 100644
--- a/app/src/main/java/com/fankes/apperrorstracking/ui/activity/base/BaseActivity.kt
+++ b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/base/BaseActivity.kt
@@ -31,6 +31,7 @@ import androidx.core.view.ViewCompat
import androidx.viewbinding.ViewBinding
import com.fankes.apperrorstracking.R
import com.fankes.apperrorstracking.utils.factory.isNotSystemInDarkMode
+import com.fankes.apperrorstracking.utils.factory.toast
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
import java.lang.reflect.ParameterizedType
@@ -69,4 +70,13 @@ abstract class BaseActivity : AppCompatActivity() {
/** 回调 [onCreate] 方法 */
abstract fun onCreate()
+
+ /**
+ * 弹出提示并退出
+ * @param name 名称
+ */
+ fun toastAndFinish(name: String) {
+ toast(msg = "Invalid $name, exit")
+ finish()
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsDetailActivity.kt b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsDetailActivity.kt
index d80ad03..89836e7 100644
--- a/app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsDetailActivity.kt
+++ b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsDetailActivity.kt
@@ -54,10 +54,9 @@ class AppErrorsDetailActivity : BaseActivity() {
* 启动 [AppErrorsDetailActivity]
* @param context 实例
* @param appErrorsInfo 应用异常信息
- * @param isOutSide 是否从外部启动
*/
- fun start(context: Context, appErrorsInfo: AppErrorsInfoBean, isOutSide: Boolean = false) =
- context.navigate(isOutSide) { putExtra(EXTRA_APP_ERRORS_INFO, appErrorsInfo) }
+ fun start(context: Context, appErrorsInfo: AppErrorsInfoBean) =
+ context.navigate { putExtra(EXTRA_APP_ERRORS_INFO, appErrorsInfo) }
}
/** 预导出的异常堆栈 */
@@ -89,7 +88,7 @@ class AppErrorsDetailActivity : BaseActivity() {
override fun onCreate() {
val appErrorsInfo = runCatching { intent?.getSerializableExtra(EXTRA_APP_ERRORS_INFO) as? AppErrorsInfoBean }.getOrNull()
- ?: return toastAndFinish()
+ ?: return toastAndFinish(name = "AppErrorsInfo")
binding.appInfoItem.setOnClickListener { openSelfSetting(appErrorsInfo.packageName) }
binding.titleBackIcon.setOnClickListener { onBackPressed() }
binding.printIcon.setOnClickListener {
@@ -129,12 +128,6 @@ class AppErrorsDetailActivity : BaseActivity() {
contentResolver?.registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, observer)
}
- /** 弹出提示并退出 */
- private fun toastAndFinish() {
- toast(msg = "Invalid AppErrorsInfo, exit")
- finish()
- }
-
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == WRITE_REQUEST_CODE && resultCode == Activity.RESULT_OK) runCatching {
diff --git a/app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsDisplayActivity.kt b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsDisplayActivity.kt
new file mode 100644
index 0000000..06ffd7a
--- /dev/null
+++ b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsDisplayActivity.kt
@@ -0,0 +1,108 @@
+/*
+ * AppErrorsTracking - Added more features to app's crash dialog, fixed custom rom deleted dialog, the best experience to Android developer.
+ * Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
+ * https://github.com/KitsunePie/AppErrorsTracking
+ *
+ * This software is non-free but opensource software: you can redistribute it
+ * and/or modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This software 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * and eula along with this software. If not, see
+ *
+ *
+ * This file is Created by fankes on 2022/6/1.
+ */
+package com.fankes.apperrorstracking.ui.activity.errors
+
+import android.content.Context
+import androidx.core.view.isVisible
+import com.fankes.apperrorstracking.bean.AppErrorsDisplayBean
+import com.fankes.apperrorstracking.databinding.ActivityAppErrorsDisplayBinding
+import com.fankes.apperrorstracking.databinding.DiaAppErrorsDisplayBinding
+import com.fankes.apperrorstracking.locale.LocaleString
+import com.fankes.apperrorstracking.ui.activity.base.BaseActivity
+import com.fankes.apperrorstracking.utils.factory.navigate
+import com.fankes.apperrorstracking.utils.factory.openSelfSetting
+import com.fankes.apperrorstracking.utils.factory.showDialog
+import com.fankes.apperrorstracking.utils.factory.toast
+import com.fankes.apperrorstracking.utils.tool.FrameworkTool
+
+class AppErrorsDisplayActivity : BaseActivity() {
+
+ companion object {
+
+ /** 当前实例 - 单例运行 */
+ private var instance: AppErrorsDisplayActivity? = null
+
+ /** [AppErrorsDisplayBean] 传值 */
+ private const val EXTRA_APP_ERRORS_DISPLAY = "app_errors_display_extra"
+
+ /**
+ * 启动 [AppErrorsDisplayActivity]
+ * @param context 实例
+ * @param appErrorsDisplay 应用异常信息显示
+ */
+ fun start(context: Context, appErrorsDisplay: AppErrorsDisplayBean) =
+ context.navigate(isOutSide = true) { putExtra(EXTRA_APP_ERRORS_DISPLAY, appErrorsDisplay) }
+ }
+
+ override fun onCreate() {
+ instance?.finish()
+ instance = this
+ val appErrorsDisplay = runCatching { intent?.getSerializableExtra(EXTRA_APP_ERRORS_DISPLAY) as? AppErrorsDisplayBean }.getOrNull()
+ ?: return toastAndFinish(name = "AppErrorsDisplay")
+ /** 显示对话框 */
+ showDialog {
+ title = appErrorsDisplay.title
+ bind().apply {
+ appInfoItem.isVisible = appErrorsDisplay.isApp
+ reopenAppItem.isVisible = appErrorsDisplay.isShowReopenButton
+ closeAppItem.isVisible = appErrorsDisplay.isShowReopenButton.not()
+ appInfoItem.setOnClickListener {
+ cancel()
+ openSelfSetting(appErrorsDisplay.packageName)
+ }
+ closeAppItem.setOnClickListener { cancel() }
+ reopenAppItem.setOnClickListener {
+ FrameworkTool.openAppUsedFramework(context, appErrorsDisplay.packageName)
+ cancel()
+ }
+ errorDetailItem.setOnClickListener {
+ FrameworkTool.fetchAppErrorsInfoData(context) { appErrorsInfos ->
+ appErrorsInfos.takeIf { it.isNotEmpty() }
+ ?.filter { it.packageName == appErrorsDisplay.packageName }
+ ?.takeIf { it.isNotEmpty() }?.get(0)?.let {
+ AppErrorsDetailActivity.start(context, it)
+ cancel()
+ } ?: toast(msg = "No errors founded")
+ }
+ }
+ ignoreIfUnlockItem.setOnClickListener {
+ FrameworkTool.ignoredErrorsIfUnlock(context, appErrorsDisplay.packageName) {
+ toast(LocaleString.ignoreIfUnlockTip(appErrorsDisplay.appName))
+ cancel()
+ }
+ }
+ ignoreIfRestartItem.setOnClickListener {
+ FrameworkTool.ignoredErrorsIfRestart(context, appErrorsDisplay.packageName) {
+ toast(LocaleString.ignoreIfRestartTip(appErrorsDisplay.appName))
+ cancel()
+ }
+ }
+ }
+ onCancel { finish() }
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ instance = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsRecordActivity.kt b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsRecordActivity.kt
index 5f5784d..d5f0f31 100644
--- a/app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsRecordActivity.kt
+++ b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/errors/AppErrorsRecordActivity.kt
@@ -82,7 +82,7 @@ class AppErrorsRecordActivity : BaseActivity() {
}
}
/** 设置列表元素和 Adapter */
- binding.listView.apply { // 改成 recycleview?
+ binding.listView.apply {
adapter = object : BaseAdapter() {
override fun getCount() = listData.size
diff --git a/app/src/main/java/com/fankes/apperrorstracking/ui/view/ItemLinearLayout.kt b/app/src/main/java/com/fankes/apperrorstracking/ui/view/ItemLinearLayout.kt
new file mode 100644
index 0000000..9c3ac30
--- /dev/null
+++ b/app/src/main/java/com/fankes/apperrorstracking/ui/view/ItemLinearLayout.kt
@@ -0,0 +1,42 @@
+/*
+ * AppErrorsTracking - Added more features to app's crash dialog, fixed custom rom deleted dialog, the best experience to Android developer.
+ * Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
+ * https://github.com/KitsunePie/AppErrorsTracking
+ *
+ * This software is non-free but opensource software: you can redistribute it
+ * and/or modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This software 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * and eula along with this software. If not, see
+ *
+ *
+ * This file is Created by fankes on 2022/6/1.
+ */
+package com.fankes.apperrorstracking.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.Gravity
+import android.widget.LinearLayout
+import com.fankes.apperrorstracking.utils.drawable.drawabletoolbox.DrawableBuilder
+import com.fankes.apperrorstracking.utils.factory.dp
+
+class ItemLinearLayout(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
+
+ init {
+ gravity = Gravity.CENTER or Gravity.START
+ background = DrawableBuilder()
+ .rounded()
+ .cornerRadius(15.dp(context))
+ .ripple()
+ .rippleColor(0xFFAAAAAA.toInt())
+ .build()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/apperrorstracking/utils/factory/DialogBuilderFactory.kt b/app/src/main/java/com/fankes/apperrorstracking/utils/factory/DialogBuilderFactory.kt
index 29aabad..9c247f9 100644
--- a/app/src/main/java/com/fankes/apperrorstracking/utils/factory/DialogBuilderFactory.kt
+++ b/app/src/main/java/com/fankes/apperrorstracking/utils/factory/DialogBuilderFactory.kt
@@ -19,7 +19,7 @@
*
* This file is Created by fankes on 2022/5/12.
*/
-@file:Suppress("unused", "DEPRECATION")
+@file:Suppress("unused", "DEPRECATION", "OPT_IN_USAGE", "EXPERIMENTAL_API_USAGE")
package com.fankes.apperrorstracking.utils.factory
@@ -29,16 +29,20 @@ import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.InsetDrawable
import android.view.Gravity
+import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.view.WindowManager
import android.widget.LinearLayout
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
+import androidx.viewbinding.ViewBinding
import com.fankes.apperrorstracking.locale.LocaleString
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.shape.MaterialShapeDrawable
+import com.highcapable.yukihookapi.annotation.CauseProblemsApi
+import com.highcapable.yukihookapi.hook.factory.method
+import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
/**
* 构造对话框
@@ -55,13 +59,12 @@ class DialogBuilder(val context: Context) {
private var instanceAndroidX: androidx.appcompat.app.AlertDialog.Builder? = null // 实例对象
private var instanceAndroid: android.app.AlertDialog.Builder? = null // 实例对象
- private var isSystemAlert = false // 标识为系统级别的对话框
-
private var onCancel: (() -> Unit)? = null // 对话框取消监听
private var dialogInstance: Dialog? = null // 对话框实例
- private var customLayoutView: View? = null // 自定义布局
+ @CauseProblemsApi
+ var customLayoutView: View? = null // 自定义布局
/**
* 是否需要使用 AndroidX 风格对话框
@@ -89,15 +92,6 @@ class DialogBuilder(val context: Context) {
else runCatching { instanceAndroid?.setCancelable(false) }
}
- /**
- * 设置为系统级别对话框
- *
- * - ❗仅可在系统级别的 APP 中生效
- */
- fun makeSystemAlert() {
- isSystemAlert = true
- }
-
/** 设置对话框标题 */
var title
get() = ""
@@ -137,13 +131,15 @@ class DialogBuilder(val context: Context) {
/**
* 设置对话框自定义布局
- * @return [customLayoutView]
+ * @return [ViewBinding]
*/
- var view
- get() = customLayoutView
- set(value) {
- customLayoutView = value
- }
+ inline fun bind() =
+ T::class.java.method {
+ name = "inflate"
+ param(LayoutInflaterClass)
+ }.get().invoke(LayoutInflater.from(context))?.apply {
+ customLayoutView = root
+ } ?: error("binding failed")
/**
* 设置对话框确定按钮
@@ -196,8 +192,6 @@ class DialogBuilder(val context: Context) {
customLayoutView?.let { setView(it) }
dialogInstance = this
setOnCancelListener { onCancel?.invoke() }
- /** 只有 SystemUid 才能响应系统级别的对话框 */
- if (isSystemAlert) runCatching { window?.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT) }
}?.show()
} else runCatching {
instanceAndroid?.create()?.apply {
@@ -217,8 +211,6 @@ class DialogBuilder(val context: Context) {
)
dialogInstance = this
setOnCancelListener { onCancel?.invoke() }
- /** 只有 SystemUid 才能响应系统级别的对话框 */
- if (isSystemAlert) runCatching { window?.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT) }
}?.show()
}
}
diff --git a/app/src/main/java/com/fankes/apperrorstracking/utils/tool/FrameworkTool.kt b/app/src/main/java/com/fankes/apperrorstracking/utils/tool/FrameworkTool.kt
index a1fdfa6..1034f27 100644
--- a/app/src/main/java/com/fankes/apperrorstracking/utils/tool/FrameworkTool.kt
+++ b/app/src/main/java/com/fankes/apperrorstracking/utils/tool/FrameworkTool.kt
@@ -46,9 +46,14 @@ object FrameworkTool {
private const val CALL_APP_ERRORS_DATA_REMOVE_RESULT = "call_app_errors_data_remove_result"
private const val CALL_APP_ERRORS_DATA_CLEAR = "call_app_errors_data_clear"
private const val CALL_APP_ERRORS_DATA_CLEAR_RESULT = "call_app_errors_data_clear_result"
+ private const val CALL_IGNORED_ERRORS_IF_UNLOCK_RESULT = "call_ignored_errors_if_unlock_result"
+ private const val CALL_IGNORED_ERRORS_IF_RESTART_RESULT = "call_ignored_errors_if_restart_result"
+ private val CALL_OPEN_SPECIFY_APP = ChannelData("call_open_specify_app")
private val CALL_APP_ERRORS_DATA_REMOVE = ChannelData("call_app_errors_data_remove")
private val CALL_APP_ERRORS_DATA_GET_RESULT = ChannelData>("call_app_errors_data_get_result")
+ private val CALL_IGNORED_ERRORS_IF_UNLOCK = ChannelData("call_ignored_errors_if_unlock")
+ private val CALL_IGNORED_ERRORS_IF_RESTART = ChannelData("call_ignored_errors_if_restart")
/**
* 宿主注册监听
@@ -66,6 +71,12 @@ object FrameworkTool {
*/
fun with(instance: PackageParam, initiate: Host.() -> Unit) = apply { this.instance = instance }.apply(initiate)
+ /**
+ * 监听使用系统框架打开 APP
+ * @param result 回调包名
+ */
+ fun onOpenAppUsedFramework(result: (String) -> Unit) = instance?.dataChannel?.wait(CALL_OPEN_SPECIFY_APP) { result(it) }
+
/**
* 监听发送 APP 异常信息数组
* @param result 回调数据
@@ -99,6 +110,32 @@ object FrameworkTool {
}
}
}
+
+ /**
+ * 监听忽略 APP 的错误直到设备重新解锁
+ * @param result 回调包名
+ */
+ fun onIgnoredErrorsIfUnlock(result: (String) -> Unit) {
+ instance?.dataChannel?.with {
+ wait(CALL_IGNORED_ERRORS_IF_UNLOCK) {
+ result(it)
+ put(CALL_IGNORED_ERRORS_IF_UNLOCK_RESULT)
+ }
+ }
+ }
+
+ /**
+ * 监听忽略 APP 的错误直到设备重新启动
+ * @param result 回调包名
+ */
+ fun onIgnoredErrorsIfRestart(result: (String) -> Unit) {
+ instance?.dataChannel?.with {
+ wait(CALL_IGNORED_ERRORS_IF_RESTART) {
+ result(it)
+ put(CALL_IGNORED_ERRORS_IF_RESTART_RESULT)
+ }
+ }
+ }
}
/**
@@ -129,6 +166,14 @@ object FrameworkTool {
*/
fun checkingActivated(context: Context, result: (Boolean) -> Unit) = context.dataChannel(SYSTEM_FRAMEWORK_NAME).checkingVersionEquals(result)
+ /**
+ * 使用系统框架打开 [packageName]
+ * @param context 实例
+ * @param packageName APP 包名
+ */
+ fun openAppUsedFramework(context: Context, packageName: String) =
+ context.dataChannel(SYSTEM_FRAMEWORK_NAME).put(CALL_OPEN_SPECIFY_APP, packageName)
+
/**
* 获取 APP 异常信息数组
* @param context 实例
@@ -165,4 +210,30 @@ object FrameworkTool {
put(CALL_APP_ERRORS_DATA_CLEAR)
}
}
+
+ /**
+ * 忽略 [packageName] 的错误直到设备重新解锁
+ * @param context 实例
+ * @param packageName APP 包名
+ * @param callback 成功后回调
+ */
+ fun ignoredErrorsIfUnlock(context: Context, packageName: String, callback: () -> Unit) {
+ context.dataChannel(SYSTEM_FRAMEWORK_NAME).with {
+ wait(CALL_IGNORED_ERRORS_IF_UNLOCK_RESULT) { callback() }
+ put(CALL_IGNORED_ERRORS_IF_UNLOCK, packageName)
+ }
+ }
+
+ /**
+ * 忽略 [packageName] 的错误直到设备重新启动
+ * @param context 实例
+ * @param packageName APP 包名
+ * @param callback 成功后回调
+ */
+ fun ignoredErrorsIfRestart(context: Context, packageName: String, callback: () -> Unit) {
+ context.dataChannel(SYSTEM_FRAMEWORK_NAME).with {
+ wait(CALL_IGNORED_ERRORS_IF_RESTART_RESULT) { callback() }
+ put(CALL_IGNORED_ERRORS_IF_RESTART, packageName)
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_app_errors_display.xml b/app/src/main/res/layout/activity_app_errors_display.xml
new file mode 100644
index 0000000..98f2dc5
--- /dev/null
+++ b/app/src/main/res/layout/activity_app_errors_display.xml
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dia_app_errors_display.xml b/app/src/main/res/layout/dia_app_errors_display.xml
new file mode 100644
index 0000000..dc08da5
--- /dev/null
+++ b/app/src/main/res/layout/dia_app_errors_display.xml
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8680cca..232a50c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,6 +1,7 @@
AppErrorsTracking
Added more features to app\'s crash dialog, fixed custom rom deleted dialog, the best experience to Android developer.
+
App\'s Info
Reopen App
Error Detail
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index a8d6a1c..603bd03 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -13,4 +13,15 @@
- ?attr/colorPrimaryVariant
+
+
+
\ No newline at end of file