From c4d1c42faa775709b8fcf69bf4536bce7a0fd603 Mon Sep 17 00:00:00 2001 From: Fankesyooni Date: Thu, 12 May 2022 14:15:19 +0800 Subject: [PATCH] Added errors record clear all function and changed receiver mode --- README.md | 2 +- .../fankes/apperrorstracking/const/Const.kt | 13 +- .../hook/entity/FrameworkHooker.kt | 28 +++-- .../ui/activity/AppErrorsRecordActivity.kt | 65 ++++------ .../ui/activity/base/BaseActivity.kt | 9 ++ .../utils/factory/FunctionFactory.kt | 8 +- .../utils/tool/FrameworkTool.kt | 111 ++++++++++++++++++ app/src/main/res/drawable/ic_android.xml | 15 +++ .../res/layout/activity_app_errors_record.xml | 6 +- 9 files changed, 194 insertions(+), 63 deletions(-) create mode 100644 app/src/main/java/com/fankes/apperrorstracking/utils/tool/FrameworkTool.kt create mode 100644 app/src/main/res/drawable/ic_android.xml diff --git a/README.md b/README.md index da3dddf..e76ce0d 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Added more features to app's crash dialog, fixed custom rom deleted dialog, the 此项目依然在开发中,现在未解决的问题和包含的问题如下 -- 排除列表和异常历史记录导出、清空功能正在开发 +- 排除列表和异常历史记录导出功能正在开发 - 后台进程可能依然会弹出崩溃对话框且开发者选项里的设置无效,还在排查 diff --git a/app/src/main/java/com/fankes/apperrorstracking/const/Const.kt b/app/src/main/java/com/fankes/apperrorstracking/const/Const.kt index 0fa6628..7cb03c4 100644 --- a/app/src/main/java/com/fankes/apperrorstracking/const/Const.kt +++ b/app/src/main/java/com/fankes/apperrorstracking/const/Const.kt @@ -37,12 +37,15 @@ object Const { /** 宿主接收广播 */ const val ACTION_HOST_HANDLER_RECEIVER = "host_handler_action" - /** [AppErrorsInfoBean] 控制数据 */ - const val TYPE_APP_ERRORS_DATA_CONTROL = "app_errors_data_control_type" + /** 模块与宿主交互数据 */ + const val KEY_MODULE_HOST_FETCH = "module_host_data_fetch_key" - /** [AppErrorsInfoBean] 获取数据 */ - const val TYPE_APP_ERRORS_DATA_CONTROL_GET_DATA = "app_errors_data_control_get_data_type" + /** 获取 [AppErrorsInfoBean] 数据 */ + const val TYPE_APP_ERRORS_DATA_GET = "app_errors_data_get_type" - /** [AppErrorsInfoBean] 获取到的数据内容 */ + /** 清空 [AppErrorsInfoBean] 数据 */ + const val TYPE_APP_ERRORS_DATA_CLEAR = "app_errors_data_clear_type" + + /** 获取到的 [AppErrorsInfoBean] 数据内容 */ const val TAG_APP_ERRORS_DATA_CONTENT = "app_errors_data_content_tag" } \ 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 bcdc516..0931d47 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 @@ -76,13 +76,13 @@ object FrameworkHooker : YukiBaseHooker() { ) /** 已打开的错误对话框数组 */ - private var openedErrorsDialogs = HashMap() + private var openedErrorsDialogs = hashMapOf() /** 已忽略错误的 APP 数组 - 直到重新解锁 */ - private var ignoredErrorsIfUnlockApps = HashSet() + private var ignoredErrorsIfUnlockApps = hashSetOf() /** 已忽略错误的 APP 数组 - 直到重新启动 */ - private var ignoredErrorsIfRestartApps = HashSet() + private var ignoredErrorsIfRestartApps = hashSetOf() /** 已记录的 APP 异常信息数组 - 直到重新启动 */ private val appErrorsRecords = arrayListOf() @@ -115,13 +115,21 @@ object FrameworkHooker : YukiBaseHooker() { object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { if (intent == null) return - when (intent.getStringExtra(Const.TYPE_APP_ERRORS_DATA_CONTROL)) { - Const.TYPE_APP_ERRORS_DATA_CONTROL_GET_DATA -> - context?.sendBroadcast(Intent().apply { - action = Const.ACTION_MODULE_HANDLER_RECEIVER - putExtra(Const.TYPE_APP_ERRORS_DATA_CONTROL, Const.TYPE_APP_ERRORS_DATA_CONTROL_GET_DATA) - putExtra(Const.TAG_APP_ERRORS_DATA_CONTENT, appErrorsRecords) - }) + intent.getStringExtra(Const.KEY_MODULE_HOST_FETCH)?.also { + if (it.isNotBlank()) context?.sendBroadcast(Intent().apply { + action = Const.ACTION_MODULE_HANDLER_RECEIVER + when (it) { + Const.TYPE_APP_ERRORS_DATA_GET -> { + putExtra(Const.TAG_APP_ERRORS_DATA_CONTENT, appErrorsRecords) + putExtra(Const.KEY_MODULE_HOST_FETCH, Const.TYPE_APP_ERRORS_DATA_GET) + } + Const.TYPE_APP_ERRORS_DATA_CLEAR -> { + appErrorsRecords.clear() + putExtra(Const.KEY_MODULE_HOST_FETCH, Const.TYPE_APP_ERRORS_DATA_CLEAR) + } + else -> {} + } + }) } } } diff --git a/app/src/main/java/com/fankes/apperrorstracking/ui/activity/AppErrorsRecordActivity.kt b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/AppErrorsRecordActivity.kt index ccb9107..e5a5964 100644 --- a/app/src/main/java/com/fankes/apperrorstracking/ui/activity/AppErrorsRecordActivity.kt +++ b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/AppErrorsRecordActivity.kt @@ -19,14 +19,8 @@ * * This file is Created by fankes on 2022/5/11. */ -@file:Suppress("UNCHECKED_CAST") - package com.fankes.apperrorstracking.ui.activity -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -34,13 +28,15 @@ import android.widget.BaseAdapter import androidx.core.view.isVisible import com.fankes.apperrorstracking.R import com.fankes.apperrorstracking.bean.AppErrorsInfoBean -import com.fankes.apperrorstracking.const.Const import com.fankes.apperrorstracking.databinding.ActivityAppErrorsRecordBinding import com.fankes.apperrorstracking.databinding.AdapterAppErrorsRecordBinding +import com.fankes.apperrorstracking.locale.LocaleString import com.fankes.apperrorstracking.ui.activity.base.BaseActivity import com.fankes.apperrorstracking.utils.factory.appIcon import com.fankes.apperrorstracking.utils.factory.appName +import com.fankes.apperrorstracking.utils.factory.showDialog import com.fankes.apperrorstracking.utils.factory.toast +import com.fankes.apperrorstracking.utils.tool.FrameworkTool import java.text.SimpleDateFormat import java.util.* @@ -49,14 +45,23 @@ class AppErrorsRecordActivity : BaseActivity() { /** 回调适配器改变 */ private var onChanged: (() -> Unit)? = null - /** 全部的 APP 异常数据 */ - private val listData = ArrayList() + /** 全部的 APP 异常信息 */ + private val listData = arrayListOf() override fun onCreate() { binding.titleBackIcon.setOnClickListener { onBackPressed() } binding.clearAllIcon.setOnClickListener { - // TODO 待实现 - toast(msg = "Coming soon") + showDialog { + title = LocaleString.notice + msg = LocaleString.areYouSureClearErrors + confirmButton { + FrameworkTool.clearAppErrorsInfoData(context) { + refreshData() + toast(LocaleString.allErrorsClearSuccess) + } + } + cancelButton() + } } binding.exportAllIcon.setOnClickListener { // TODO 待实现 @@ -97,34 +102,18 @@ class AppErrorsRecordActivity : BaseActivity() { onChanged = { notifyDataSetChanged() } } } - /** 注册广播 */ - registerReceiver(moduleHandlerReceiver, IntentFilter().apply { addAction(Const.ACTION_MODULE_HANDLER_RECEIVER) }) } /** 更新列表数据 */ private fun refreshData() { - sendBroadcast(Intent().apply { - action = Const.ACTION_HOST_HANDLER_RECEIVER - putExtra(Const.TYPE_APP_ERRORS_DATA_CONTROL, Const.TYPE_APP_ERRORS_DATA_CONTROL_GET_DATA) - }) - } - - /** 模块广播接收器 */ - private val moduleHandlerReceiver by lazy { - object : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - if (intent == null) return - when (intent.getStringExtra(Const.TYPE_APP_ERRORS_DATA_CONTROL)) { - Const.TYPE_APP_ERRORS_DATA_CONTROL_GET_DATA -> - (intent.getSerializableExtra(Const.TAG_APP_ERRORS_DATA_CONTENT) as? ArrayList)?.also { - listData.clear() - it.takeIf { e -> e.isNotEmpty() }?.forEach { e -> listData.add(e) } - onChanged?.invoke() - binding.listView.isVisible = listData.isNotEmpty() - binding.listNoDataView.isVisible = listData.isEmpty() - } - } - } + FrameworkTool.fetchAppErrorsInfoData(context = this) { + listData.clear() + it.takeIf { e -> e.isNotEmpty() }?.forEach { e -> listData.add(e) } + onChanged?.invoke() + binding.clearAllIcon.isVisible = listData.isNotEmpty() + binding.exportAllIcon.isVisible = listData.isNotEmpty() + binding.listView.isVisible = listData.isNotEmpty() + binding.listNoDataView.isVisible = listData.isEmpty() } } @@ -133,10 +122,4 @@ class AppErrorsRecordActivity : BaseActivity() { /** 执行更新 */ refreshData() } - - override fun onDestroy() { - super.onDestroy() - /** 取消注册 */ - unregisterReceiver(moduleHandlerReceiver) - } } \ No newline at end of file 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 1c676a5..e3d7db9 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 @@ -28,6 +28,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.viewbinding.ViewBinding import com.fankes.apperrorstracking.R import com.fankes.apperrorstracking.utils.factory.isNotSystemInDarkMode +import com.fankes.apperrorstracking.utils.tool.FrameworkTool import com.gyf.immersionbar.ktx.immersionBar import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass @@ -60,10 +61,18 @@ abstract class BaseActivity : AppCompatActivity() { navigationBarDarkIcon(isNotSystemInDarkMode) fitsSystemWindows(true) } + /** 注册 */ + FrameworkTool.registerReceiver(context = this) /** 装载子类 */ onCreate() } /** 回调 [onCreate] 方法 */ abstract fun onCreate() + + override fun onDestroy() { + super.onDestroy() + /** 取消 */ + FrameworkTool.unregisterReceiver(context = this) + } } \ No newline at end of file diff --git a/app/src/main/java/com/fankes/apperrorstracking/utils/factory/FunctionFactory.kt b/app/src/main/java/com/fankes/apperrorstracking/utils/factory/FunctionFactory.kt index 95ff29f..a83a6b9 100644 --- a/app/src/main/java/com/fankes/apperrorstracking/utils/factory/FunctionFactory.kt +++ b/app/src/main/java/com/fankes/apperrorstracking/utils/factory/FunctionFactory.kt @@ -28,13 +28,13 @@ import android.app.Service import android.content.* import android.content.pm.PackageManager import android.content.res.Configuration -import android.graphics.Color -import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.net.Uri import android.provider.Settings import android.widget.Toast +import androidx.core.content.res.ResourcesCompat import com.fankes.apperrorstracking.BuildConfig +import com.fankes.apperrorstracking.R import com.fankes.apperrorstracking.locale.LocaleString /** @@ -82,7 +82,7 @@ fun Context.appName(packageName: String) = fun Context.appVersion(packageName: String) = runCatching { packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA)?.let { "${it.versionName} (${it.versionCode})" } - }.getOrNull() ?: "unknown" + }.getOrNull() ?: "" /** * 获取 APP 图标 @@ -93,7 +93,7 @@ fun Context.appIcon(packageName: String) = runCatching { packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA) .applicationInfo.loadIcon(packageManager) - }.getOrNull() ?: ColorDrawable(Color.WHITE) + }.getOrNull() ?: ResourcesCompat.getDrawable(resources, R.drawable.ic_android, null) /** * 弹出 [Toast] 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 new file mode 100644 index 0000000..ba6f116 --- /dev/null +++ b/app/src/main/java/com/fankes/apperrorstracking/utils/tool/FrameworkTool.kt @@ -0,0 +1,111 @@ +/* + * 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/5/12. + */ +@file:Suppress("UNCHECKED_CAST") + +package com.fankes.apperrorstracking.utils.tool + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import com.fankes.apperrorstracking.bean.AppErrorsInfoBean +import com.fankes.apperrorstracking.const.Const + +/** + * 系统框架控制工具 + */ +object FrameworkTool { + + /** 回调获取的 APP 异常信息 */ + private var onAppErrorsInfoDataCallback: ((ArrayList) -> Unit)? = null + + /** 回调 APP 异常信息是否清空 */ + private var onClearAppErrorsInfoDataCallback: (() -> Unit)? = null + + /** 模块广播接收器 */ + private val moduleHandlerReceiver by lazy { + object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (intent == null) return + intent.getStringExtra(Const.KEY_MODULE_HOST_FETCH)?.also { + if (it.isNotBlank()) when (it) { + Const.TYPE_APP_ERRORS_DATA_GET -> runCatching { + onAppErrorsInfoDataCallback?.invoke( + intent.getSerializableExtra(Const.TAG_APP_ERRORS_DATA_CONTENT) as ArrayList + ) + }.onFailure { onAppErrorsInfoDataCallback?.invoke(arrayListOf()) } + Const.TYPE_APP_ERRORS_DATA_CLEAR -> onClearAppErrorsInfoDataCallback?.invoke() + else -> {} + } + } + } + } + } + + /** + * 发送广播 + * @param context 实例 + * @param type 类型 + */ + private fun pushReceiver(context: Context, type: String) { + context.sendBroadcast(Intent().apply { + action = Const.ACTION_HOST_HANDLER_RECEIVER + putExtra(Const.KEY_MODULE_HOST_FETCH, type) + }) + } + + /** + * 获取 APP 异常信息数组 + * @param context 实例 + * @param it 回调数据 + */ + fun fetchAppErrorsInfoData(context: Context, it: (ArrayList) -> Unit) { + onAppErrorsInfoDataCallback = it + pushReceiver(context, Const.TYPE_APP_ERRORS_DATA_GET) + } + + /** + * 清空 APP 异常信息数组 + * @param context 实例 + * @param it 成功后回调 + */ + fun clearAppErrorsInfoData(context: Context, it: () -> Unit) { + onClearAppErrorsInfoDataCallback = it + pushReceiver(context, Const.TYPE_APP_ERRORS_DATA_CLEAR) + } + + /** + * 注册广播 + * @param context 实例 + */ + fun registerReceiver(context: Context) = runCatching { + context.registerReceiver(moduleHandlerReceiver, IntentFilter().apply { addAction(Const.ACTION_MODULE_HANDLER_RECEIVER) }) + } + + /** + * 取消注册 + * @param context 实例 + */ + fun unregisterReceiver(context: Context) = runCatching { + context.unregisterReceiver(moduleHandlerReceiver) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_android.xml b/app/src/main/res/drawable/ic_android.xml new file mode 100644 index 0000000..8831e5a --- /dev/null +++ b/app/src/main/res/drawable/ic_android.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_app_errors_record.xml b/app/src/main/res/layout/activity_app_errors_record.xml index 283c61b..2d6dba8 100644 --- a/app/src/main/res/layout/activity_app_errors_record.xml +++ b/app/src/main/res/layout/activity_app_errors_record.xml @@ -47,7 +47,8 @@ android:layout_marginEnd="15dp" android:src="@drawable/ic_clear" android:tint="@color/colorTextGray" - android:tooltipText="@string/clear_all" /> + android:tooltipText="@string/clear_all" + android:visibility="gone" /> + android:tooltipText="@string/export_all" + android:visibility="gone" />