mirror of
https://github.com/KitsunePie/AppErrorsTracking.git
synced 2025-09-04 02:05:16 +08:00
Added global app config template function and remove old implementations
This commit is contained in:
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* <https://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
* This file is Created by fankes on 2023/1/20.
|
||||||
|
*/
|
||||||
|
package com.fankes.apperrorstracking.data
|
||||||
|
|
||||||
|
import com.fankes.apperrorstracking.data.enum.AppErrorsConfigType
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用配置模版存储控制类
|
||||||
|
*/
|
||||||
|
object AppErrorsConfigData {
|
||||||
|
|
||||||
|
/** 显示错误对话框键值名称 */
|
||||||
|
private const val SHOW_ERRORS_DIALOG_APPS = "_show_errors_dialog_apps"
|
||||||
|
|
||||||
|
/** 推送错误通知键值名称 */
|
||||||
|
private const val SHOW_ERRORS_NOTIFY_APPS = "_show_errors_notify_apps"
|
||||||
|
|
||||||
|
/** 显示错误 Toast 键值名称 */
|
||||||
|
private const val SHOW_ERRORS_TOAST_APPS = "_show_errors_toast_apps"
|
||||||
|
|
||||||
|
/** 什么也不显示键值名称 */
|
||||||
|
private const val SHOW_ERRORS_NOTHING_APPS = "_show_errors_nothing_apps"
|
||||||
|
|
||||||
|
/** 全局错误显示类型 */
|
||||||
|
private val GLOBAL_SHOW_ERRORS_TYPE = PrefsData("_global_show_errors_type", AppErrorsConfigType.DIALOG.ordinal)
|
||||||
|
|
||||||
|
/** 显示错误对话框的 APP 包名数组 */
|
||||||
|
private var showDialogApps = HashSet<String>()
|
||||||
|
|
||||||
|
/** 推送错误通知的 APP 包名数组 */
|
||||||
|
private var showNotifyApps = HashSet<String>()
|
||||||
|
|
||||||
|
/** 显示错误 Toast 的 APP 包名数组 */
|
||||||
|
private var showToastApps = HashSet<String>()
|
||||||
|
|
||||||
|
/** 什么也不显示的 APP 包名数组 */
|
||||||
|
private var showNothingApps = HashSet<String>()
|
||||||
|
|
||||||
|
/** 刷新存储控制类 */
|
||||||
|
fun refresh() {
|
||||||
|
showDialogApps = ConfigData.getStringSet(SHOW_ERRORS_DIALOG_APPS).toHashSet()
|
||||||
|
showNotifyApps = ConfigData.getStringSet(SHOW_ERRORS_NOTIFY_APPS).toHashSet()
|
||||||
|
showToastApps = ConfigData.getStringSet(SHOW_ERRORS_TOAST_APPS).toHashSet()
|
||||||
|
showNothingApps = ConfigData.getStringSet(SHOW_ERRORS_NOTHING_APPS).toHashSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前 APP 显示错误的类型是否为 [type]
|
||||||
|
* @param type 当前类型
|
||||||
|
* @param packageName 当前 APP 包名 - 不填为全局配置
|
||||||
|
* @return [Boolean]
|
||||||
|
*/
|
||||||
|
fun isAppShowingType(type: AppErrorsConfigType, packageName: String = "") =
|
||||||
|
if (packageName.isNotBlank()) when (type) {
|
||||||
|
AppErrorsConfigType.GLOBAL ->
|
||||||
|
showDialogApps.contains(packageName).not() &&
|
||||||
|
showNotifyApps.contains(packageName).not() &&
|
||||||
|
showToastApps.contains(packageName).not() &&
|
||||||
|
showNothingApps.contains(packageName).not()
|
||||||
|
AppErrorsConfigType.DIALOG -> showDialogApps.contains(packageName)
|
||||||
|
AppErrorsConfigType.NOTIFY -> showNotifyApps.contains(packageName)
|
||||||
|
AppErrorsConfigType.TOAST -> showToastApps.contains(packageName)
|
||||||
|
AppErrorsConfigType.NOTHING -> showNothingApps.contains(packageName)
|
||||||
|
} else ConfigData.getInt(GLOBAL_SHOW_ERRORS_TYPE) == type.ordinal
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入当前 APP 显示错误的类型
|
||||||
|
* @param type 当前类型
|
||||||
|
* @param packageName 当前 APP 包名 - 不填为全局配置
|
||||||
|
*/
|
||||||
|
fun putAppShowingType(type: AppErrorsConfigType, packageName: String = "") {
|
||||||
|
if (packageName.isBlank() && type == AppErrorsConfigType.GLOBAL)
|
||||||
|
error("You can't still specify the \"follow global config\" type when saving the global config")
|
||||||
|
fun saveAllData() {
|
||||||
|
ConfigData.putStringSet(SHOW_ERRORS_DIALOG_APPS, showDialogApps)
|
||||||
|
ConfigData.putStringSet(SHOW_ERRORS_NOTIFY_APPS, showNotifyApps)
|
||||||
|
ConfigData.putStringSet(SHOW_ERRORS_TOAST_APPS, showToastApps)
|
||||||
|
ConfigData.putStringSet(SHOW_ERRORS_NOTHING_APPS, showNothingApps)
|
||||||
|
}
|
||||||
|
if (packageName.isNotBlank()) when (type) {
|
||||||
|
AppErrorsConfigType.GLOBAL -> {
|
||||||
|
showDialogApps.remove(packageName)
|
||||||
|
showNotifyApps.remove(packageName)
|
||||||
|
showToastApps.remove(packageName)
|
||||||
|
showNothingApps.remove(packageName)
|
||||||
|
saveAllData()
|
||||||
|
}
|
||||||
|
AppErrorsConfigType.DIALOG -> {
|
||||||
|
showDialogApps.add(packageName)
|
||||||
|
showNotifyApps.remove(packageName)
|
||||||
|
showToastApps.remove(packageName)
|
||||||
|
showNothingApps.remove(packageName)
|
||||||
|
saveAllData()
|
||||||
|
}
|
||||||
|
AppErrorsConfigType.NOTIFY -> {
|
||||||
|
showDialogApps.remove(packageName)
|
||||||
|
showNotifyApps.add(packageName)
|
||||||
|
showToastApps.remove(packageName)
|
||||||
|
showNothingApps.remove(packageName)
|
||||||
|
saveAllData()
|
||||||
|
}
|
||||||
|
AppErrorsConfigType.TOAST -> {
|
||||||
|
showDialogApps.remove(packageName)
|
||||||
|
showNotifyApps.remove(packageName)
|
||||||
|
showToastApps.add(packageName)
|
||||||
|
showNothingApps.remove(packageName)
|
||||||
|
saveAllData()
|
||||||
|
}
|
||||||
|
AppErrorsConfigType.NOTHING -> {
|
||||||
|
showDialogApps.remove(packageName)
|
||||||
|
showNotifyApps.remove(packageName)
|
||||||
|
showToastApps.remove(packageName)
|
||||||
|
showNothingApps.add(packageName)
|
||||||
|
saveAllData()
|
||||||
|
}
|
||||||
|
} else ConfigData.putInt(GLOBAL_SHOW_ERRORS_TYPE, type.ordinal)
|
||||||
|
}
|
||||||
|
}
|
@@ -67,6 +67,55 @@ object ConfigData {
|
|||||||
is Context, is PackageParam -> this.instance = instance
|
is Context, is PackageParam -> this.instance = instance
|
||||||
else -> error("Unknown type for init ConfigData")
|
else -> error("Unknown type for init ConfigData")
|
||||||
}
|
}
|
||||||
|
AppErrorsConfigData.refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 [Set]<[String]> 数据
|
||||||
|
* @param key 键值名称
|
||||||
|
* @return [Set]<[String]>
|
||||||
|
*/
|
||||||
|
internal fun getStringSet(key: String) = when (instance) {
|
||||||
|
is Context -> (instance as Context).modulePrefs.getStringSet(key, setOf())
|
||||||
|
is PackageParam -> (instance as PackageParam).prefs.getStringSet(key, setOf())
|
||||||
|
else -> error("Unknown type for get prefs data")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存入 [Set]<[String]> 数据
|
||||||
|
* @param key 键值名称
|
||||||
|
* @param value 键值内容
|
||||||
|
*/
|
||||||
|
internal fun putStringSet(key: String, value: Set<String>) {
|
||||||
|
when (instance) {
|
||||||
|
is Context -> (instance as Context).modulePrefs.putStringSet(key, value)
|
||||||
|
is PackageParam -> loggerW(msg = "Not support for this method")
|
||||||
|
else -> error("Unknown type for put prefs data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 [Int] 数据
|
||||||
|
* @param data 键值数据模板
|
||||||
|
* @return [Int]
|
||||||
|
*/
|
||||||
|
internal fun getInt(data: PrefsData<Int>) = when (instance) {
|
||||||
|
is Context -> (instance as Context).modulePrefs.get(data)
|
||||||
|
is PackageParam -> (instance as PackageParam).prefs.get(data)
|
||||||
|
else -> error("Unknown type for get prefs data")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存入 [Int] 数据
|
||||||
|
* @param data 键值数据模板
|
||||||
|
* @param value 键值内容
|
||||||
|
*/
|
||||||
|
internal fun putInt(data: PrefsData<Int>, value: Int) {
|
||||||
|
when (instance) {
|
||||||
|
is Context -> (instance as Context).modulePrefs.put(data, value)
|
||||||
|
is PackageParam -> loggerW(msg = "Not support for this method")
|
||||||
|
else -> error("Unknown type for put prefs data")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -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
|
||||||
|
* <https://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
* This file is Created by fankes on 2023/1/20.
|
||||||
|
*/
|
||||||
|
package com.fankes.apperrorstracking.data.enum
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用配置模版类型定义类
|
||||||
|
*/
|
||||||
|
enum class AppErrorsConfigType {
|
||||||
|
/** 跟随全局配置 */
|
||||||
|
GLOBAL,
|
||||||
|
|
||||||
|
/** 对话框 */
|
||||||
|
DIALOG,
|
||||||
|
|
||||||
|
/** 通知 */
|
||||||
|
NOTIFY,
|
||||||
|
|
||||||
|
/** Toast */
|
||||||
|
TOAST,
|
||||||
|
|
||||||
|
/** 什么也不显示 */
|
||||||
|
NOTHING
|
||||||
|
}
|
@@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
* <https://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
* This file is Created by fankes on 2022/6/8.
|
|
||||||
*/
|
|
||||||
@file:Suppress("unused")
|
|
||||||
|
|
||||||
package com.fankes.apperrorstracking.data.factory
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
|
||||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取此 APP 是否配置显示错误对话框
|
|
||||||
* @param packageName APP 包名
|
|
||||||
*/
|
|
||||||
fun PackageParam.isAppShowErrorsDialog(packageName: String) = prefs.getBoolean("${packageName}_show_errors_dialog", true)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取此 APP 是否配置显示错误通知推送
|
|
||||||
* @param packageName APP 包名
|
|
||||||
*/
|
|
||||||
fun PackageParam.isAppShowErrorsNotify(packageName: String) = prefs.getBoolean("${packageName}_show_errors_notify", false)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取此 APP 是否配置显示错误 Toast 提示
|
|
||||||
* @param packageName APP 包名
|
|
||||||
*/
|
|
||||||
fun PackageParam.isAppShowErrorsToast(packageName: String) = prefs.getBoolean("${packageName}_show_errors_toast", false)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取此 APP 是否配置不显示任何提示
|
|
||||||
* @param packageName APP 包名
|
|
||||||
*/
|
|
||||||
fun PackageParam.isAppShowNothing(packageName: String) = prefs.getBoolean("${packageName}_show_nothing", false)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取此 APP 是否配置显示错误对话框
|
|
||||||
* @param packageName APP 包名
|
|
||||||
*/
|
|
||||||
fun Context.isAppShowErrorsDialog(packageName: String) = modulePrefs.getBoolean("${packageName}_show_errors_dialog", true)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取此 APP 是否配置显示错误通知推送
|
|
||||||
* @param packageName APP 包名
|
|
||||||
*/
|
|
||||||
fun Context.isAppShowErrorsNotify(packageName: String) = modulePrefs.getBoolean("${packageName}_show_errors_notify", false)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取此 APP 是否配置显示错误 Toast 提示
|
|
||||||
* @param packageName APP 包名
|
|
||||||
*/
|
|
||||||
fun Context.isAppShowErrorsToast(packageName: String) = modulePrefs.getBoolean("${packageName}_show_errors_toast", false)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取此 APP 是否配置不显示任何提示
|
|
||||||
* @param packageName APP 包名
|
|
||||||
*/
|
|
||||||
fun Context.isAppShowNothing(packageName: String) = modulePrefs.getBoolean("${packageName}_show_nothing", false)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置此 APP 是否配置显示错误对话框
|
|
||||||
* @param packageName APP 包名
|
|
||||||
* @param isApply 是否设置
|
|
||||||
*/
|
|
||||||
fun Context.putAppShowErrorsDialog(packageName: String, isApply: Boolean) = modulePrefs.putBoolean("${packageName}_show_errors_dialog", isApply)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置此 APP 是否配置显示错误通知推送
|
|
||||||
* @param packageName APP 包名
|
|
||||||
* @param isApply 是否设置
|
|
||||||
*/
|
|
||||||
fun Context.putAppShowErrorsNotify(packageName: String, isApply: Boolean) = modulePrefs.putBoolean("${packageName}_show_errors_notify", isApply)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置此 APP 是否配置显示错误 Toast 提示
|
|
||||||
* @param packageName APP 包名
|
|
||||||
* @param isApply 是否设置
|
|
||||||
*/
|
|
||||||
fun Context.putAppShowErrorsToast(packageName: String, isApply: Boolean) = modulePrefs.putBoolean("${packageName}_show_errors_toast", isApply)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置此 APP 是否配置不显示任何提示
|
|
||||||
* @param packageName APP 包名
|
|
||||||
* @param isApply 是否设置
|
|
||||||
*/
|
|
||||||
fun Context.putAppShowNothing(packageName: String, isApply: Boolean) = modulePrefs.putBoolean("${packageName}_show_nothing", isApply)
|
|
@@ -28,6 +28,7 @@ import android.content.Intent
|
|||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Message
|
import android.os.Message
|
||||||
|
import android.os.SystemClock
|
||||||
import android.util.ArrayMap
|
import android.util.ArrayMap
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
@@ -37,12 +38,10 @@ import com.fankes.apperrorstracking.bean.AppErrorsDisplayBean
|
|||||||
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
|
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
|
||||||
import com.fankes.apperrorstracking.bean.AppInfoBean
|
import com.fankes.apperrorstracking.bean.AppInfoBean
|
||||||
import com.fankes.apperrorstracking.bean.MutedErrorsAppBean
|
import com.fankes.apperrorstracking.bean.MutedErrorsAppBean
|
||||||
|
import com.fankes.apperrorstracking.data.AppErrorsConfigData
|
||||||
import com.fankes.apperrorstracking.data.AppErrorsRecordData
|
import com.fankes.apperrorstracking.data.AppErrorsRecordData
|
||||||
import com.fankes.apperrorstracking.data.ConfigData
|
import com.fankes.apperrorstracking.data.ConfigData
|
||||||
import com.fankes.apperrorstracking.data.factory.isAppShowErrorsDialog
|
import com.fankes.apperrorstracking.data.enum.AppErrorsConfigType
|
||||||
import com.fankes.apperrorstracking.data.factory.isAppShowErrorsNotify
|
|
||||||
import com.fankes.apperrorstracking.data.factory.isAppShowErrorsToast
|
|
||||||
import com.fankes.apperrorstracking.data.factory.isAppShowNothing
|
|
||||||
import com.fankes.apperrorstracking.locale.LocaleString
|
import com.fankes.apperrorstracking.locale.LocaleString
|
||||||
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsDisplayActivity
|
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsDisplayActivity
|
||||||
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsRecordActivity
|
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsRecordActivity
|
||||||
@@ -178,6 +177,13 @@ object FrameworkHooker : YukiBaseHooker() {
|
|||||||
onCreate { AppErrorsRecordData.init(context = this) }
|
onCreate { AppErrorsRecordData.init(context = this) }
|
||||||
}
|
}
|
||||||
FrameworkTool.Host.with(instance = this) {
|
FrameworkTool.Host.with(instance = this) {
|
||||||
|
onRefreshFrameworkPrefsData {
|
||||||
|
/** 必要的延迟防止 Sp 存储不刷新 */
|
||||||
|
SystemClock.sleep(100)
|
||||||
|
/** 刷新存储类 */
|
||||||
|
AppErrorsConfigData.refresh()
|
||||||
|
if (prefs.isPreferencesAvailable.not()) loggerW(msg = "Cannot refreshing app errors config data, preferences is not available")
|
||||||
|
}
|
||||||
onOpenAppUsedFramework {
|
onOpenAppUsedFramework {
|
||||||
appContext?.openApp(it.first, it.second)
|
appContext?.openApp(it.first, it.second)
|
||||||
loggerI(msg = "Opened \"${it.first}\"${it.second.takeIf { e -> e > 0 }?.let { e -> " --user $e" } ?: ""}")
|
loggerI(msg = "Opened \"${it.first}\"${it.second.takeIf { e -> e > 0 }?.let { e -> " --user $e" } ?: ""}")
|
||||||
@@ -310,10 +316,16 @@ object FrameworkHooker : YukiBaseHooker() {
|
|||||||
loggerE(msg = "AppErrorsTracking has crashed itself, please see the Android Runtime Exception in console")
|
loggerE(msg = "AppErrorsTracking has crashed itself, please see the Android Runtime Exception in console")
|
||||||
}
|
}
|
||||||
ConfigData.isEnableAppConfigTemplate -> when {
|
ConfigData.isEnableAppConfigTemplate -> when {
|
||||||
isAppShowNothing(packageName) -> {}
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.GLOBAL, packageName) -> when {
|
||||||
isAppShowErrorsNotify(packageName) -> showAppErrorsWithNotify()
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.DIALOG) -> showAppErrorsWithDialog()
|
||||||
isAppShowErrorsToast(packageName) -> showAppErrorsWithToast()
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.NOTIFY) -> showAppErrorsWithNotify()
|
||||||
isAppShowErrorsDialog(packageName) -> showAppErrorsWithDialog()
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.TOAST) -> showAppErrorsWithToast()
|
||||||
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.NOTHING) -> {}
|
||||||
|
}
|
||||||
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.DIALOG, packageName) -> showAppErrorsWithDialog()
|
||||||
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.NOTIFY, packageName) -> showAppErrorsWithNotify()
|
||||||
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.TOAST, packageName) -> showAppErrorsWithToast()
|
||||||
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.NOTHING, packageName) -> {}
|
||||||
}
|
}
|
||||||
else -> showAppErrorsWithDialog()
|
else -> showAppErrorsWithDialog()
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,8 @@ package com.fankes.apperrorstracking.ui.activity.main
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.fankes.apperrorstracking.bean.AppFiltersBean
|
import com.fankes.apperrorstracking.bean.AppFiltersBean
|
||||||
import com.fankes.apperrorstracking.bean.AppInfoBean
|
import com.fankes.apperrorstracking.bean.AppInfoBean
|
||||||
import com.fankes.apperrorstracking.data.factory.*
|
import com.fankes.apperrorstracking.data.AppErrorsConfigData
|
||||||
|
import com.fankes.apperrorstracking.data.enum.AppErrorsConfigType
|
||||||
import com.fankes.apperrorstracking.databinding.ActivityConfigBinding
|
import com.fankes.apperrorstracking.databinding.ActivityConfigBinding
|
||||||
import com.fankes.apperrorstracking.databinding.AdapterAppInfoBinding
|
import com.fankes.apperrorstracking.databinding.AdapterAppInfoBinding
|
||||||
import com.fankes.apperrorstracking.databinding.DiaAppConfigBinding
|
import com.fankes.apperrorstracking.databinding.DiaAppConfigBinding
|
||||||
@@ -50,30 +51,23 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
|||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
binding.titleBackIcon.setOnClickListener { finish() }
|
binding.titleBackIcon.setOnClickListener { finish() }
|
||||||
|
binding.globalIcon.setOnClickListener {
|
||||||
|
showAppConfigDialog(LocaleString.globalConfig, isShowGlobalConfig = false) { type ->
|
||||||
|
AppErrorsConfigData.putAppShowingType(type)
|
||||||
|
onChanged?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
binding.batchIcon.setOnClickListener {
|
binding.batchIcon.setOnClickListener {
|
||||||
showDialog<DiaAppConfigBinding> {
|
showAppConfigDialog(LocaleString.batchOperationsNumber(listData.size), isNotSetDefaultValue = true) { type ->
|
||||||
title = LocaleString.batchOperations
|
showDialog {
|
||||||
confirmButton {
|
title = LocaleString.notice
|
||||||
val config0 = binding.configRadio0.isChecked
|
msg = LocaleString.areYouSureApplySiteApps(listData.size)
|
||||||
val config1 = binding.configRadio1.isChecked
|
confirmButton {
|
||||||
val config2 = binding.configRadio2.isChecked
|
listData.takeIf { it.isNotEmpty() }?.forEach { AppErrorsConfigData.putAppShowingType(type, it.packageName) }
|
||||||
val config3 = binding.configRadio3.isChecked
|
onChanged?.invoke()
|
||||||
showDialog {
|
|
||||||
title = LocaleString.notice
|
|
||||||
msg = LocaleString.areYouSureApplySiteApps(listData.size)
|
|
||||||
confirmButton {
|
|
||||||
listData.takeIf { it.isNotEmpty() }?.forEach {
|
|
||||||
putAppShowErrorsDialog(it.packageName, config0)
|
|
||||||
putAppShowErrorsNotify(it.packageName, config1)
|
|
||||||
putAppShowErrorsToast(it.packageName, config2)
|
|
||||||
putAppShowNothing(it.packageName, config3)
|
|
||||||
}
|
|
||||||
onChanged?.invoke()
|
|
||||||
}
|
|
||||||
cancelButton()
|
|
||||||
}
|
}
|
||||||
|
cancelButton()
|
||||||
}
|
}
|
||||||
cancelButton()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.filterIcon.setOnClickListener {
|
binding.filterIcon.setOnClickListener {
|
||||||
@@ -110,10 +104,11 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
|||||||
binding.appIcon.setImageDrawable(bean.icon)
|
binding.appIcon.setImageDrawable(bean.icon)
|
||||||
binding.appNameText.text = bean.name
|
binding.appNameText.text = bean.name
|
||||||
binding.configTypeText.text = when {
|
binding.configTypeText.text = when {
|
||||||
isAppShowErrorsDialog(bean.packageName) -> LocaleString.showErrorsDialog
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.GLOBAL, bean.packageName) -> LocaleString.followGlobalConfig
|
||||||
isAppShowErrorsNotify(bean.packageName) -> LocaleString.showErrorsNotify
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.DIALOG, bean.packageName) -> LocaleString.showErrorsDialog
|
||||||
isAppShowErrorsToast(bean.packageName) -> LocaleString.showErrorsToast
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.NOTIFY, bean.packageName) -> LocaleString.showErrorsNotify
|
||||||
isAppShowNothing(bean.packageName) -> LocaleString.showNothing
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.TOAST, bean.packageName) -> LocaleString.showErrorsToast
|
||||||
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.NOTHING, bean.packageName) -> LocaleString.showNothing
|
||||||
else -> "Unknown type"
|
else -> "Unknown type"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,20 +116,9 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
|||||||
}.apply { onChanged = { notifyDataSetChanged() } }
|
}.apply { onChanged = { notifyDataSetChanged() } }
|
||||||
setOnItemClickListener { _, _, p, _ ->
|
setOnItemClickListener { _, _, p, _ ->
|
||||||
listData[p].also { bean ->
|
listData[p].also { bean ->
|
||||||
showDialog<DiaAppConfigBinding> {
|
showAppConfigDialog(bean.name, bean.packageName) { type ->
|
||||||
title = bean.name
|
AppErrorsConfigData.putAppShowingType(type, bean.packageName)
|
||||||
binding.configRadio0.isChecked = isAppShowErrorsDialog(bean.packageName)
|
onChanged?.invoke()
|
||||||
binding.configRadio1.isChecked = isAppShowErrorsNotify(bean.packageName)
|
|
||||||
binding.configRadio2.isChecked = isAppShowErrorsToast(bean.packageName)
|
|
||||||
binding.configRadio3.isChecked = isAppShowNothing(bean.packageName)
|
|
||||||
confirmButton {
|
|
||||||
putAppShowErrorsDialog(bean.packageName, binding.configRadio0.isChecked)
|
|
||||||
putAppShowErrorsNotify(bean.packageName, binding.configRadio1.isChecked)
|
|
||||||
putAppShowErrorsToast(bean.packageName, binding.configRadio2.isChecked)
|
|
||||||
putAppShowNothing(bean.packageName, binding.configRadio3.isChecked)
|
|
||||||
onChanged?.invoke()
|
|
||||||
}
|
|
||||||
cancelButton()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,9 +136,53 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
|||||||
refreshData()
|
refreshData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示应用配置对话框
|
||||||
|
* @param title 对话框标题
|
||||||
|
* @param packageName APP 包名 - 默认空 (空时使用全局配置的默认值)
|
||||||
|
* @param isNotSetDefaultValue 是否不设置选项的默认值 - 默认否
|
||||||
|
* @param isShowGlobalConfig 是否显示跟随全局配置选项 - 默认是
|
||||||
|
* @param result 回调类型结果
|
||||||
|
*/
|
||||||
|
private fun showAppConfigDialog(
|
||||||
|
title: String,
|
||||||
|
packageName: String = "",
|
||||||
|
isNotSetDefaultValue: Boolean = false,
|
||||||
|
isShowGlobalConfig: Boolean = true,
|
||||||
|
result: (AppErrorsConfigType) -> Unit
|
||||||
|
) {
|
||||||
|
showDialog<DiaAppConfigBinding> {
|
||||||
|
this.title = title
|
||||||
|
binding.configRadio0.isVisible = isShowGlobalConfig
|
||||||
|
if (isNotSetDefaultValue.not()) {
|
||||||
|
if (isShowGlobalConfig) binding.configRadio0.isChecked =
|
||||||
|
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.GLOBAL, packageName)
|
||||||
|
binding.configRadio1.isChecked = AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.DIALOG, packageName)
|
||||||
|
binding.configRadio2.isChecked = AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.NOTIFY, packageName)
|
||||||
|
binding.configRadio3.isChecked = AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.TOAST, packageName)
|
||||||
|
binding.configRadio4.isChecked = AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.NOTHING, packageName)
|
||||||
|
}
|
||||||
|
confirmButton {
|
||||||
|
result(
|
||||||
|
when {
|
||||||
|
binding.configRadio0.isChecked -> AppErrorsConfigType.GLOBAL
|
||||||
|
binding.configRadio1.isChecked -> AppErrorsConfigType.DIALOG
|
||||||
|
binding.configRadio2.isChecked -> AppErrorsConfigType.NOTIFY
|
||||||
|
binding.configRadio3.isChecked -> AppErrorsConfigType.TOAST
|
||||||
|
binding.configRadio4.isChecked -> AppErrorsConfigType.NOTHING
|
||||||
|
else -> error("Invalid config type")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
FrameworkTool.refreshFrameworkPrefsData(context)
|
||||||
|
}
|
||||||
|
cancelButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 刷新列表数据 */
|
/** 刷新列表数据 */
|
||||||
private fun refreshData() {
|
private fun refreshData() {
|
||||||
binding.listProgressView.isVisible = true
|
binding.listProgressView.isVisible = true
|
||||||
|
binding.globalIcon.isVisible = false
|
||||||
binding.batchIcon.isVisible = false
|
binding.batchIcon.isVisible = false
|
||||||
binding.filterIcon.isVisible = false
|
binding.filterIcon.isVisible = false
|
||||||
binding.listView.isVisible = false
|
binding.listView.isVisible = false
|
||||||
@@ -176,6 +204,7 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
|||||||
onChanged?.invoke()
|
onChanged?.invoke()
|
||||||
binding.listView.post { binding.listView.setSelection(0) }
|
binding.listView.post { binding.listView.setSelection(0) }
|
||||||
binding.listProgressView.isVisible = false
|
binding.listProgressView.isVisible = false
|
||||||
|
binding.globalIcon.isVisible = true
|
||||||
binding.batchIcon.isVisible = listData.isNotEmpty()
|
binding.batchIcon.isVisible = listData.isNotEmpty()
|
||||||
binding.filterIcon.isVisible = true
|
binding.filterIcon.isVisible = true
|
||||||
binding.listView.isVisible = listData.isNotEmpty()
|
binding.listView.isVisible = listData.isNotEmpty()
|
||||||
|
@@ -44,6 +44,7 @@ object FrameworkTool {
|
|||||||
/** 系统框架包名 */
|
/** 系统框架包名 */
|
||||||
const val SYSTEM_FRAMEWORK_NAME = "android"
|
const val SYSTEM_FRAMEWORK_NAME = "android"
|
||||||
|
|
||||||
|
private const val CALL_REFRESH_HOST_PREFS_DATA = "call_refresh_host_prefs_data"
|
||||||
private const val CALL_APP_ERRORS_DATA_GET = "call_app_errors_data_get"
|
private const val CALL_APP_ERRORS_DATA_GET = "call_app_errors_data_get"
|
||||||
private const val CALL_MUTED_ERRORS_APP_DATA_GET = "call_muted_app_errors_data_get"
|
private const val CALL_MUTED_ERRORS_APP_DATA_GET = "call_muted_app_errors_data_get"
|
||||||
private const val CALL_APP_ERRORS_DATA_CLEAR = "call_app_errors_data_clear"
|
private const val CALL_APP_ERRORS_DATA_CLEAR = "call_app_errors_data_clear"
|
||||||
@@ -83,6 +84,12 @@ object FrameworkTool {
|
|||||||
*/
|
*/
|
||||||
fun with(instance: PackageParam, initiate: Host.() -> Unit) = apply { this.instance = instance }.apply(initiate)
|
fun with(instance: PackageParam, initiate: Host.() -> Unit) = apply { this.instance = instance }.apply(initiate)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知系统框架刷新存储的数据
|
||||||
|
* @param callback 回调
|
||||||
|
*/
|
||||||
|
fun onRefreshFrameworkPrefsData(callback: () -> Unit) = instance?.dataChannel?.wait(CALL_REFRESH_HOST_PREFS_DATA) { callback() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听使用系统框架打开 APP
|
* 监听使用系统框架打开 APP
|
||||||
* @param result 回调包名和用户 ID
|
* @param result 回调包名和用户 ID
|
||||||
@@ -244,6 +251,12 @@ object FrameworkTool {
|
|||||||
fun checkingActivated(context: Context, result: (Boolean) -> Unit) =
|
fun checkingActivated(context: Context, result: (Boolean) -> Unit) =
|
||||||
context.dataChannel(SYSTEM_FRAMEWORK_NAME).checkingVersionEquals(result = result)
|
context.dataChannel(SYSTEM_FRAMEWORK_NAME).checkingVersionEquals(result = result)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知系统框架刷新存储的数据
|
||||||
|
* @param context 实例
|
||||||
|
*/
|
||||||
|
fun refreshFrameworkPrefsData(context: Context) = context.dataChannel(SYSTEM_FRAMEWORK_NAME).put(CALL_REFRESH_HOST_PREFS_DATA)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用系统框架打开 [packageName]
|
* 使用系统框架打开 [packageName]
|
||||||
* @param context 实例
|
* @param context 实例
|
||||||
|
30
app/src/main/res/drawable/ic_global.xml
Normal file
30
app/src/main/res/drawable/ic_global.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="48dp"
|
||||||
|
android:height="48dp"
|
||||||
|
android:viewportWidth="48"
|
||||||
|
android:viewportHeight="48">
|
||||||
|
<path
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:pathData="M18,6H8C6.895,6 6,6.895 6,8V18C6,19.105 6.895,20 8,20H18C19.105,20 20,19.105 20,18V8C20,6.895 19.105,6 18,6Z"
|
||||||
|
android:strokeWidth="4"
|
||||||
|
android:strokeColor="#ffffff"
|
||||||
|
android:strokeLineJoin="round" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:pathData="M18,28H8C6.895,28 6,28.895 6,30V40C6,41.105 6.895,42 8,42H18C19.105,42 20,41.105 20,40V30C20,28.895 19.105,28 18,28Z"
|
||||||
|
android:strokeWidth="4"
|
||||||
|
android:strokeColor="#ffffff"
|
||||||
|
android:strokeLineJoin="round" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:pathData="M40,6H30C28.895,6 28,6.895 28,8V18C28,19.105 28.895,20 30,20H40C41.105,20 42,19.105 42,18V8C42,6.895 41.105,6 40,6Z"
|
||||||
|
android:strokeWidth="4"
|
||||||
|
android:strokeColor="#ffffff"
|
||||||
|
android:strokeLineJoin="round" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:pathData="M40,28H30C28.895,28 28,28.895 28,30V40C28,41.105 28.895,42 30,42H40C41.105,42 42,41.105 42,40V30C42,28.895 41.105,28 40,28Z"
|
||||||
|
android:strokeWidth="4"
|
||||||
|
android:strokeColor="#ffffff"
|
||||||
|
android:strokeLineJoin="round" />
|
||||||
|
</vector>
|
@@ -57,6 +57,16 @@
|
|||||||
android:textSize="11.5sp" />
|
android:textSize="11.5sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
|
android:id="@+id/global_icon"
|
||||||
|
android:layout_width="23dp"
|
||||||
|
android:layout_height="23dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:src="@drawable/ic_global"
|
||||||
|
android:tint="@color/colorTextGray"
|
||||||
|
android:tooltipText="@string/global_config"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
android:id="@+id/batch_icon"
|
android:id="@+id/batch_icon"
|
||||||
android:layout_width="25dp"
|
android:layout_width="25dp"
|
||||||
|
@@ -27,27 +27,34 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:checked="true"
|
android:checked="true"
|
||||||
android:text="@string/show_errors_dialog"
|
android:text="@string/follow_global_config"
|
||||||
app:buttonTint="@color/colorPrimaryAccent" />
|
app:buttonTint="@color/colorPrimaryAccent" />
|
||||||
|
|
||||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
android:id="@+id/config_radio_1"
|
android:id="@+id/config_radio_1"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/show_errors_notify"
|
android:text="@string/show_errors_dialog"
|
||||||
app:buttonTint="@color/colorPrimaryAccent" />
|
app:buttonTint="@color/colorPrimaryAccent" />
|
||||||
|
|
||||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
android:id="@+id/config_radio_2"
|
android:id="@+id/config_radio_2"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/show_errors_toast"
|
android:text="@string/show_errors_notify"
|
||||||
app:buttonTint="@color/colorPrimaryAccent" />
|
app:buttonTint="@color/colorPrimaryAccent" />
|
||||||
|
|
||||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
android:id="@+id/config_radio_3"
|
android:id="@+id/config_radio_3"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/show_errors_toast"
|
||||||
|
app:buttonTint="@color/colorPrimaryAccent" />
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/config_radio_4"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/show_nothing"
|
android:text="@string/show_nothing"
|
||||||
app:buttonTint="@color/colorPrimaryAccent" />
|
app:buttonTint="@color/colorPrimaryAccent" />
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
Reference in New Issue
Block a user