Added global app config template function and remove old implementations

This commit is contained in:
2023-01-20 03:09:25 +08:00
parent 72e99bd4f2
commit c349ee5dc7
10 changed files with 381 additions and 155 deletions

View File

@@ -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)
}
}

View File

@@ -67,6 +67,55 @@ object ConfigData {
is Context, is PackageParam -> this.instance = instance
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")
}
}
/**

View File

@@ -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
}

View File

@@ -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)

View File

@@ -28,6 +28,7 @@ import android.content.Intent
import android.content.pm.ApplicationInfo
import android.os.Build
import android.os.Message
import android.os.SystemClock
import android.util.ArrayMap
import androidx.core.graphics.drawable.IconCompat
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.AppInfoBean
import com.fankes.apperrorstracking.bean.MutedErrorsAppBean
import com.fankes.apperrorstracking.data.AppErrorsConfigData
import com.fankes.apperrorstracking.data.AppErrorsRecordData
import com.fankes.apperrorstracking.data.ConfigData
import com.fankes.apperrorstracking.data.factory.isAppShowErrorsDialog
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.data.enum.AppErrorsConfigType
import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsDisplayActivity
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsRecordActivity
@@ -178,6 +177,13 @@ object FrameworkHooker : YukiBaseHooker() {
onCreate { AppErrorsRecordData.init(context = 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 {
appContext?.openApp(it.first, it.second)
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")
}
ConfigData.isEnableAppConfigTemplate -> when {
isAppShowNothing(packageName) -> {}
isAppShowErrorsNotify(packageName) -> showAppErrorsWithNotify()
isAppShowErrorsToast(packageName) -> showAppErrorsWithToast()
isAppShowErrorsDialog(packageName) -> showAppErrorsWithDialog()
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.GLOBAL, packageName) -> when {
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.DIALOG) -> showAppErrorsWithDialog()
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.NOTIFY) -> showAppErrorsWithNotify()
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()
}

View File

@@ -24,7 +24,8 @@ package com.fankes.apperrorstracking.ui.activity.main
import androidx.core.view.isVisible
import com.fankes.apperrorstracking.bean.AppFiltersBean
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.AdapterAppInfoBinding
import com.fankes.apperrorstracking.databinding.DiaAppConfigBinding
@@ -50,30 +51,23 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
override fun onCreate() {
binding.titleBackIcon.setOnClickListener { finish() }
binding.globalIcon.setOnClickListener {
showAppConfigDialog(LocaleString.globalConfig, isShowGlobalConfig = false) { type ->
AppErrorsConfigData.putAppShowingType(type)
onChanged?.invoke()
}
}
binding.batchIcon.setOnClickListener {
showDialog<DiaAppConfigBinding> {
title = LocaleString.batchOperations
confirmButton {
val config0 = binding.configRadio0.isChecked
val config1 = binding.configRadio1.isChecked
val config2 = binding.configRadio2.isChecked
val config3 = binding.configRadio3.isChecked
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()
showAppConfigDialog(LocaleString.batchOperationsNumber(listData.size), isNotSetDefaultValue = true) { type ->
showDialog {
title = LocaleString.notice
msg = LocaleString.areYouSureApplySiteApps(listData.size)
confirmButton {
listData.takeIf { it.isNotEmpty() }?.forEach { AppErrorsConfigData.putAppShowingType(type, it.packageName) }
onChanged?.invoke()
}
cancelButton()
}
cancelButton()
}
}
binding.filterIcon.setOnClickListener {
@@ -110,10 +104,11 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
binding.appIcon.setImageDrawable(bean.icon)
binding.appNameText.text = bean.name
binding.configTypeText.text = when {
isAppShowErrorsDialog(bean.packageName) -> LocaleString.showErrorsDialog
isAppShowErrorsNotify(bean.packageName) -> LocaleString.showErrorsNotify
isAppShowErrorsToast(bean.packageName) -> LocaleString.showErrorsToast
isAppShowNothing(bean.packageName) -> LocaleString.showNothing
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.GLOBAL, bean.packageName) -> LocaleString.followGlobalConfig
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.DIALOG, bean.packageName) -> LocaleString.showErrorsDialog
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.NOTIFY, bean.packageName) -> LocaleString.showErrorsNotify
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.TOAST, bean.packageName) -> LocaleString.showErrorsToast
AppErrorsConfigData.isAppShowingType(AppErrorsConfigType.NOTHING, bean.packageName) -> LocaleString.showNothing
else -> "Unknown type"
}
}
@@ -121,20 +116,9 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
}.apply { onChanged = { notifyDataSetChanged() } }
setOnItemClickListener { _, _, p, _ ->
listData[p].also { bean ->
showDialog<DiaAppConfigBinding> {
title = bean.name
binding.configRadio0.isChecked = isAppShowErrorsDialog(bean.packageName)
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()
showAppConfigDialog(bean.name, bean.packageName) { type ->
AppErrorsConfigData.putAppShowingType(type, bean.packageName)
onChanged?.invoke()
}
}
}
@@ -152,9 +136,53 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
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() {
binding.listProgressView.isVisible = true
binding.globalIcon.isVisible = false
binding.batchIcon.isVisible = false
binding.filterIcon.isVisible = false
binding.listView.isVisible = false
@@ -176,6 +204,7 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
onChanged?.invoke()
binding.listView.post { binding.listView.setSelection(0) }
binding.listProgressView.isVisible = false
binding.globalIcon.isVisible = true
binding.batchIcon.isVisible = listData.isNotEmpty()
binding.filterIcon.isVisible = true
binding.listView.isVisible = listData.isNotEmpty()

View File

@@ -44,6 +44,7 @@ object FrameworkTool {
/** 系统框架包名 */
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_MUTED_ERRORS_APP_DATA_GET = "call_muted_app_errors_data_get"
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)
/**
* 通知系统框架刷新存储的数据
* @param callback 回调
*/
fun onRefreshFrameworkPrefsData(callback: () -> Unit) = instance?.dataChannel?.wait(CALL_REFRESH_HOST_PREFS_DATA) { callback() }
/**
* 监听使用系统框架打开 APP
* @param result 回调包名和用户 ID
@@ -244,6 +251,12 @@ object FrameworkTool {
fun checkingActivated(context: Context, result: (Boolean) -> Unit) =
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]
* @param context 实例

View 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>

View File

@@ -57,6 +57,16 @@
android:textSize="11.5sp" />
</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
android:id="@+id/batch_icon"
android:layout_width="25dp"

View File

@@ -27,27 +27,34 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/show_errors_dialog"
android:text="@string/follow_global_config"
app:buttonTint="@color/colorPrimaryAccent" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/config_radio_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/show_errors_notify"
android:text="@string/show_errors_dialog"
app:buttonTint="@color/colorPrimaryAccent" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/config_radio_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/show_errors_toast"
android:text="@string/show_errors_notify"
app:buttonTint="@color/colorPrimaryAccent" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/config_radio_3"
android:layout_width="match_parent"
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"
app:buttonTint="@color/colorPrimaryAccent" />
</RadioGroup>