Added Apps Configs Template function

This commit is contained in:
2022-06-08 18:59:18 +08:00
parent 3c623365f3
commit 62c9982e2e
23 changed files with 741 additions and 54 deletions

View File

@@ -52,11 +52,9 @@ Added more features to app's crash dialog, fixed custom rom deleted dialog, the
## Future
此项目依然在开发中,现在未解决的问题和包含的问题如下
此项目依然在开发中,正在开发的功能如下
- 应用配置模板功能
- 更多功能 (计划内)
- 应用异常统计信息功能
## License

View File

@@ -54,6 +54,11 @@
</intent-filter>
</activity-alias>
<activity
android:name=".ui.activity.main.ConfigureActivity"
android:exported="false"
android:screenOrientation="behind" />
<activity
android:name=".ui.activity.errors.AppErrorsRecordActivity"
android:exported="true"

View File

@@ -0,0 +1,31 @@
/*
* 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/4.
*/
package com.fankes.apperrorstracking.bean
import java.io.Serializable
/**
* 应用过滤条件 bean
* @param name 名称或包名
* @param isContainsSystem 是否包含系统应用
*/
data class AppFiltersBean(var name: String = "", var isContainsSystem: Boolean = false) : Serializable

View File

@@ -0,0 +1,33 @@
/*
* 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.
*/
package com.fankes.apperrorstracking.bean
import android.graphics.drawable.Drawable
import java.io.Serializable
/**
* 应用信息 bean
* @param icon 图标
* @param name APP 名称
* @param packageName APP 包名
*/
data class AppInfoBean(var icon: Drawable? = null, var name: String, var packageName: String) : Serializable

View File

@@ -28,4 +28,5 @@ object DataConst {
val ENABLE_HIDE_ICON = PrefsData("_hide_icon", false)
val ENABLE_ONLY_SHOW_ERRORS_IN_FRONT = PrefsData("_enable_only_show_errors_in_front", false)
val ENABLE_ONLY_SHOW_ERRORS_IN_MAIN = PrefsData("_enable_only_show_errors_in_main", false)
val ENABLE_APP_CONFIG_TEMPLATE = PrefsData("_enable_app_config_template", false)
}

View File

@@ -26,12 +26,16 @@ package com.fankes.apperrorstracking.hook.entity
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.os.Message
import com.fankes.apperrorstracking.BuildConfig
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.DataConst
import com.fankes.apperrorstracking.hook.factory.isAppShowErrorsToast
import com.fankes.apperrorstracking.hook.factory.isAppShowNothing
import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsDisplayActivity
import com.fankes.apperrorstracking.utils.factory.appName
@@ -107,6 +111,21 @@ object FrameworkHooker : YukiBaseHooker() {
mutedErrorsIfUnlockApps.clear()
mutedErrorsIfRestartApps.clear()
}
onPushAppListData { filters ->
arrayListOf<AppInfoBean>().apply {
appContext.packageManager.getInstalledPackages(PackageManager.GET_CONFIGURATIONS).also { info ->
(if (filters.name.isNotBlank())
info.filter { it.packageName.contains(filters.name) || appContext.appName(it.packageName).contains(filters.name) }
else info).let { result ->
if (filters.isContainsSystem.not()) result.filter { (it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) == 0 }
else result
}.sortedByDescending { it.lastUpdateTime }
.forEach { add(AppInfoBean(name = appContext.appName(it.packageName), packageName = it.packageName)) }
/** 移除模块自身 */
removeIf { it.packageName == BuildConfig.APPLICATION_ID }
}
}
}
}
}
@@ -187,6 +206,9 @@ object FrameworkHooker : YukiBaseHooker() {
/** 是否短时内重复错误 */
val isRepeating = AppErrorDialog_DataClass.clazz.field { name = "repeating" }.get(errData).boolean()
/** 崩溃标题 */
val errorTitle = if (isRepeating) LocaleString.aerrRepeatedTitle(appName) else LocaleString.aerrTitle(appName)
/** 打印错误日志 */
if (isApp) loggerE(
msg = "App \"$packageName\"${if (packageName != processName) " --process \"$processName\"" else ""}" +
@@ -205,13 +227,21 @@ object FrameworkHooker : YukiBaseHooker() {
) return@afterHook
/** 判断是否为主进程 */
if (isMainProcess.not() && prefs.get(DataConst.ENABLE_ONLY_SHOW_ERRORS_IN_MAIN)) return@afterHook
/** 判断配置模块启用状态 */
if (prefs.get(DataConst.ENABLE_APP_CONFIG_TEMPLATE)) {
if (isAppShowNothing(packageName)) return@afterHook
if (isAppShowErrorsToast(packageName)) {
context.toast(errorTitle)
return@afterHook
}
}
/** 启动错误对话框显示窗口 */
AppErrorsDisplayActivity.start(
context, AppErrorsDisplayBean(
packageName = packageName,
processName = processName,
appName = appName,
title = if (isRepeating) LocaleString.aerrRepeatedTitle(appName) else LocaleString.aerrTitle(appName),
title = errorTitle,
isShowAppInfoButton = isApp,
isShowReopenButton = isApp && isRepeating.not() && context.isAppCanOpened(packageName) && isMainProcess,
isShowCloseAppButton = isApp

View File

@@ -0,0 +1,85 @@
/*
* 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.hook.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 是否配置显示错误 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 是否配置显示错误 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 是否配置显示错误 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

@@ -346,4 +346,46 @@ object LocaleString {
/** @string Automatic generated */
fun areYouSureUnmuteAll(vararg objArrs: Any) = R.string.are_you_sure_unmute_all.bind(*objArrs)
/** @string Automatic generated */
val filterByCondition get() = filterByCondition()
/** @string Automatic generated */
fun filterByCondition(vararg objArrs: Any) = R.string.filter_by_condition.bind(*objArrs)
/** @string Automatic generated */
val clearFilters get() = clearFilters()
/** @string Automatic generated */
fun clearFilters(vararg objArrs: Any) = R.string.clear_filters.bind(*objArrs)
/** @string Automatic generated */
val resultCount get() = resultCount()
/** @string Automatic generated */
fun resultCount(vararg objArrs: Any) = R.string.result_count.bind(*objArrs)
/** @string Automatic generated */
val loading get() = loading()
/** @string Automatic generated */
fun loading(vararg objArrs: Any) = R.string.loading.bind(*objArrs)
/** @string Automatic generated */
val showErrorsDialog get() = showErrorsDialog()
/** @string Automatic generated */
fun showErrorsDialog(vararg objArrs: Any) = R.string.show_errors_dialog.bind(*objArrs)
/** @string Automatic generated */
val showErrorsToast get() = showErrorsToast()
/** @string Automatic generated */
fun showErrorsToast(vararg objArrs: Any) = R.string.show_errors_toast.bind(*objArrs)
/** @string Automatic generated */
val showNothing get() = showNothing()
/** @string Automatic generated */
fun showNothing(vararg objArrs: Any) = R.string.show_nothing.bind(*objArrs)
}

View File

@@ -0,0 +1,142 @@
/*
* 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/4.
*/
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.databinding.ActivityConfigBinding
import com.fankes.apperrorstracking.databinding.AdapterAppInfoBinding
import com.fankes.apperrorstracking.databinding.DiaAppConfigBinding
import com.fankes.apperrorstracking.databinding.DiaAppsFilterBinding
import com.fankes.apperrorstracking.hook.factory.*
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.bindAdapter
import com.fankes.apperrorstracking.utils.factory.showDialog
import com.fankes.apperrorstracking.utils.tool.FrameworkTool
class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
/** 过滤条件 */
private var appFilters = AppFiltersBean()
/** 回调适配器改变 */
private var onChanged: (() -> Unit)? = null
/** 全部的 APP 信息 */
private val listData = ArrayList<AppInfoBean>()
override fun onCreate() {
binding.titleBackIcon.setOnClickListener { onBackPressed() }
binding.filterIcon.setOnClickListener {
showDialog<DiaAppsFilterBinding> {
title = LocaleString.filterByCondition
binding.containsSystemSwitch.isChecked = appFilters.isContainsSystem
binding.appFiltersEdit.apply {
requestFocus()
invalidate()
if (appFilters.name.isNotBlank()) {
setText(appFilters.name)
setSelection(appFilters.name.length)
}
}
confirmButton {
appFilters.isContainsSystem = binding.containsSystemSwitch.isChecked
appFilters.name = binding.appFiltersEdit.text.toString().trim()
refreshData()
}
cancelButton()
if (appFilters.name.isNotBlank())
neutralButton(LocaleString.clearFilters) {
appFilters.isContainsSystem = binding.containsSystemSwitch.isChecked
appFilters.name = ""
refreshData()
}
}
}
binding.listView.apply {
bindAdapter {
onBindDatas { listData }
onBindViews<AdapterAppInfoBinding> { binding, position ->
listData[position].also { bean ->
binding.appIcon.setImageDrawable(bean.icon)
binding.appNameText.text = bean.name
binding.configTypeText.text = when {
isAppShowErrorsDialog(bean.packageName) -> LocaleString.showErrorsDialog
isAppShowErrorsToast(bean.packageName) -> LocaleString.showErrorsToast
isAppShowNothing(bean.packageName) -> LocaleString.showNothing
else -> "Unknown type"
}
}
}
}.apply { onChanged = { notifyDataSetChanged() } }
setOnItemClickListener { _, _, p, _ ->
listData[p].also { bean ->
showDialog<DiaAppConfigBinding> {
title = bean.name
binding.configRadio1.isChecked = isAppShowErrorsDialog(bean.packageName)
binding.configRadio2.isChecked = isAppShowErrorsToast(bean.packageName)
binding.configRadio3.isChecked = isAppShowNothing(bean.packageName)
confirmButton {
putAppShowErrorsDialog(bean.packageName, binding.configRadio1.isChecked)
putAppShowErrorsToast(bean.packageName, binding.configRadio2.isChecked)
putAppShowNothing(bean.packageName, binding.configRadio3.isChecked)
onChanged?.invoke()
}
cancelButton()
}
}
}
}
/** 开始刷新数据 */
refreshData()
}
/** 刷新列表数据 */
private fun refreshData() {
binding.listProgressView.isVisible = true
binding.filterIcon.isVisible = false
binding.listView.isVisible = false
binding.listNoDataView.isVisible = false
binding.titleCountText.text = LocaleString.loading
FrameworkTool.fetchAppListData(context = this, appFilters) {
listData.clear()
Thread {
it.takeIf { e -> e.isNotEmpty() }?.forEach { e ->
listData.add(e)
e.icon = appIcon(e.packageName)
}
runOnUiThread {
onChanged?.invoke()
binding.listView.post { binding.listView.setSelection(0) }
binding.listProgressView.isVisible = false
binding.filterIcon.isVisible = true
binding.listView.isVisible = listData.isNotEmpty()
binding.listNoDataView.isVisible = listData.isEmpty()
binding.titleCountText.text = LocaleString.resultCount(listData.size)
}
}.start()
}
}
}

View File

@@ -53,7 +53,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
LocaleString.systemVersion("${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT}) ${Build.DISPLAY}")
binding.onlyShowErrorsInFrontSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_ONLY_SHOW_ERRORS_IN_FRONT)
binding.onlyShowErrorsInMainProcessSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_ONLY_SHOW_ERRORS_IN_MAIN)
binding.enableAppsConfigsTemplateSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_APP_CONFIG_TEMPLATE)
binding.hideIconInLauncherSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_HIDE_ICON)
binding.mgrAppsConfigsTemplateButton.isVisible = modulePrefs.get(DataConst.ENABLE_APP_CONFIG_TEMPLATE)
binding.hideIconInLauncherSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_HIDE_ICON, b)
@@ -72,14 +74,15 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
modulePrefs.put(DataConst.ENABLE_ONLY_SHOW_ERRORS_IN_MAIN, b)
}
binding.enableAppsConfigsTemplateSwitch.setOnCheckedChangeListener { btn, b ->
if (b) btn.isChecked = false
toastComingSoon()
if (btn.isPressed.not()) return@setOnCheckedChangeListener
binding.mgrAppsConfigsTemplateButton.isVisible = b
modulePrefs.put(DataConst.ENABLE_APP_CONFIG_TEMPLATE, b)
}
/** 管理应用配置模板按钮点击事件 */
binding.mgrAppsConfigsTemplateButton.setOnClickListener { toastComingSoon() }
binding.mgrAppsConfigsTemplateButton.setOnClickListener { whenActivated { navigate<ConfigureActivity>() } }
/** 功能管理按钮点击事件 */
binding.viewErrorsRecordButton.setOnClickListener { navigate<AppErrorsRecordActivity>() }
binding.viewMutedErrorsAppsButton.setOnClickListener { navigate<AppErrorsMutedActivity>() }
binding.viewErrorsRecordButton.setOnClickListener { whenActivated { navigate<AppErrorsRecordActivity>() } }
binding.viewMutedErrorsAppsButton.setOnClickListener { whenActivated { navigate<AppErrorsMutedActivity>() } }
/** 重启按钮点击事件 */
binding.titleRestartIcon.setOnClickListener { FrameworkTool.restartSystem(context = this) }
/** 项目地址按钮点击事件 */
@@ -111,8 +114,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.mainTextApiWay.text = "Activated by ${YukiHookAPI.Status.executorName} API ${YukiHookAPI.Status.executorVersion}"
}
/** 敬请期待 */
private fun toastComingSoon() = toast(msg = "Coming soon")
/**
* 当模块激活后才能执行相应功能
* @param callback 激活后回调
*/
private inline fun whenActivated(callback: () -> Unit) {
if (YukiHookAPI.Status.isXposedModuleActive) callback() else toast(LocaleString.moduleNotActivated)
}
override fun onResume() {
super.onResume()

View File

@@ -25,6 +25,8 @@ package com.fankes.apperrorstracking.utils.tool
import android.content.Context
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
import com.fankes.apperrorstracking.bean.AppFiltersBean
import com.fankes.apperrorstracking.bean.AppInfoBean
import com.fankes.apperrorstracking.bean.MutedErrorsAppBean
import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.utils.factory.execShell
@@ -55,7 +57,9 @@ object FrameworkTool {
private const val CALL_UNMUTE_ALL_ERRORS_APPS_DATA_RESULT = "call_unmute_all_errors_apps_data_result"
private val CALL_OPEN_SPECIFY_APP = ChannelData<String>("call_open_specify_app")
private val CALL_APP_LIST_DATA_GET = ChannelData<AppFiltersBean>("call_app_info_list_data_get")
private val CALL_APP_ERRORS_DATA_REMOVE = ChannelData<AppErrorsInfoBean>("call_app_errors_data_remove")
private val CALL_APP_LIST_DATA_GET_RESULT = ChannelData<ArrayList<AppInfoBean>>("call_app_info_list_data_get_result")
private val CALL_APP_ERRORS_DATA_GET_RESULT = ChannelData<ArrayList<AppErrorsInfoBean>>("call_app_errors_data_get_result")
private val CALL_MUTED_ERRORS_APP_DATA_GET_RESULT = ChannelData<ArrayList<MutedErrorsAppBean>>("call_muted_app_errors_data_get_result")
private val CALL_UNMUTE_ERRORS_APP_DATA = ChannelData<MutedErrorsAppBean>("call_unmute_errors_app_data")
@@ -177,6 +181,14 @@ object FrameworkTool {
}
}
}
/**
* 监听发送已安装 APP 列表数组
* @param result 回调数据
*/
fun onPushAppListData(result: (AppFiltersBean) -> ArrayList<AppInfoBean>) {
instance?.dataChannel?.with { wait(CALL_APP_LIST_DATA_GET) { put(CALL_APP_LIST_DATA_GET_RESULT, result(it)) } }
}
}
/**
@@ -314,4 +326,17 @@ object FrameworkTool {
put(CALL_UNMUTE_ALL_ERRORS_APPS_DATA)
}
}
/**
* 获取已安装 APP 列表数组
* @param context 实例
* @param appFilters 过滤条件
* @param result 回调数据
*/
fun fetchAppListData(context: Context, appFilters: AppFiltersBean, result: (ArrayList<AppInfoBean>) -> Unit) {
context.dataChannel(SYSTEM_FRAMEWORK_NAME).with {
wait(CALL_APP_LIST_DATA_GET_RESULT) { result(it) }
put(CALL_APP_LIST_DATA_GET, appFilters)
}
}
}

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="184.6dp"
android:height="150dp"
android:viewportWidth="1260"
android:viewportHeight="1024">
<path
android:fillColor="#ffffff"
android:pathData="M419.2,548.3L17,108.9C-23.6,64.4 13,0 79.7,0h846.5c66.6,0 103.3,64.4 62.8,108.9l-402.2,439.3v472.7c0,1.6 -1.3,2.9 -2.8,2.9a8.3,8.3 0,0 1,-5.2 -1.8l-154.3,-120a13.7,13.7 0,0 1,-5.3 -10.8L419.2,548.3zM838.2,511.9L1257.3,511.9L1257.3,597.2h-419.1L838.2,511.9zM838.2,682.5L1257.3,682.5v85.3h-419.1L838.2,682.5zM838.2,853.2L1257.3,853.2v85.3h-419.1v-85.3z" />
</vector>

View File

@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorThemeBackground"
android:orientation="vertical"
tools:context=".ui.activity.main.ConfigureActivity"
tools:ignore="ContentDescription,UseCompoundDrawables">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="0dp"
android:gravity="center|start"
android:paddingLeft="15dp"
android:paddingTop="13dp"
android:paddingRight="15dp"
android:paddingBottom="5dp">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/title_back_icon"
style="?android:attr/selectableItemBackgroundBorderless"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="20dp"
android:src="@mipmap/ic_back"
android:tint="@color/colorTextGray"
android:tooltipText="@string/back" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="2.5dp"
android:layout_weight="1"
android:gravity="center|start"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:singleLine="true"
android:text="@string/apps_config_template"
android:textColor="@color/colorTextGray"
android:textSize="19sp"
android:textStyle="bold" />
<TextView
android:id="@+id/title_count_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="@string/loading"
android:textColor="@color/colorTextDark"
android:textSize="11.5sp" />
</LinearLayout>
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/filter_icon"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_marginEnd="10dp"
android:src="@drawable/ic_filter"
android:tint="@color/colorTextGray"
android:tooltipText="@string/filter_by_condition"
android:visibility="gone" />
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:animateLayoutChanges="true">
<ProgressBar
android:id="@+id/list_progress_view"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center" />
<TextView
android:id="@+id/list_no_data_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:lineSpacingExtra="6dp"
android:text="@string/no_list_result"
android:textColor="@color/colorTextDark"
android:textSize="17sp"
android:visibility="gone" />
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/trans"
android:dividerHeight="15dp"
android:fadingEdgeLength="10dp"
android:listSelector="@color/trans"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingBottom="15dp"
android:requiresFadingEdge="vertical"
android:scrollbars="none"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>

View File

@@ -155,6 +155,7 @@
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:fadingEdgeLength="10dp"
android:fillViewport="true"
@@ -170,37 +171,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:layout_marginRight="15dp"
android:background="@drawable/bg_permotion_round"
android:elevation="0dp"
android:gravity="center"
android:orientation="horizontal"
android:padding="15dp">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginEnd="10dp"
android:alpha="0.85"
android:src="@mipmap/ic_about"
android:tint="@color/colorTextDark" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.6"
android:lineSpacingExtra="5dp"
android:text="@string/after_some_settings_need_restart"
android:textColor="@color/colorTextGray"
android:textSize="11sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:layout_marginRight="15dp"
android:animateLayoutChanges="true"
android:background="@drawable/bg_permotion_round"

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_permotion_ripple"
android:gravity="center|start"
android:orientation="horizontal"
android:padding="10dp"
tools:ignore="ContentDescription,UseCompoundDrawables,SmallSp">
<androidx.cardview.widget.CardView
android:layout_width="45dp"
android:layout_height="45dp"
app:cardBackgroundColor="@color/trans"
app:cardCornerRadius="10dp"
app:cardElevation="0dp">
<ImageView
android:id="@+id/app_icon"
android:layout_width="45dp"
android:layout_height="45dp" />
</androidx.cardview.widget.CardView>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_weight="1"
android:gravity="center|start"
android:orientation="vertical">
<TextView
android:id="@+id/app_name_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_marginBottom="4dp"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
android:id="@+id/config_type_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/colorTextDark"
android:textSize="11sp" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="15dp"
android:paddingTop="15dp"
android:paddingRight="15dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8.5dp"
android:layout_marginRight="8.5dp"
android:layout_marginBottom="10dp"
android:lineSpacingExtra="6dp"
android:text="@string/when_errors_how_to_show_tip"
android:textSize="14sp" />
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content">
<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_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"
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_nothing"
app:buttonTint="@color/colorPrimaryAccent" />
</RadioGroup>
</LinearLayout>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="15dp"
android:paddingTop="15dp"
android:paddingRight="15dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/app_filters_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:hint="@string/typo_app_name_pkg_name"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/contains_system_switch"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:text="@string/result_contains_system_apps"
app:buttonTint="@color/colorPrimaryAccent" />
</LinearLayout>

View File

@@ -52,7 +52,6 @@
<string name="module_version">モジュールバージョン: %1$s</string>
<string name="system_version">システムバージョン: %1$s</string>
<string name="module_is_activated">モジュールが有効化でした</string>
<string name="after_some_settings_need_restart">一部の設定を変更した後、リスタートシステムして有効にするには、右上隅をクリックする必要がある場合があります。</string>
<string name="display_settings">表示設定</string>
<string name="hide_app_icon_on_launcher">デスクトップ上のアプリアイコンを非表示</string>
<string name="hide_app_icon_on_launcher_tip">モジュールアイコンを非表示にすると、インターフェイスが閉じてデスクトップに表示されなくなります。モジュール設定は、EdXposedまたはLSPosedで検索して開くことができます。</string>
@@ -88,4 +87,16 @@
<string name="unmute">無視を解除</string>
<string name="unmute_all">無視を全部解除</string>
<string name="are_you_sure_unmute_all">エラーを無視したすべてのアプリを解除してもよろしいですか</string>
<string name="apps_config_template">アプリ設定テンプレート</string>
<string name="filter_by_condition">条件でフィルタリング</string>
<string name="no_list_result">表示結果はありません</string>
<string name="typo_app_name_pkg_name">アプリ名とパッケージ名を入力できます</string>
<string name="result_contains_system_apps">結果にはシステムアプリが含まれます</string>
<string name="clear_filters">条件をクリア</string>
<string name="result_count">%1$s の合計結果</string>
<string name="loading">ロード中</string>
<string name="when_errors_how_to_show_tip">エラーが現在適用されているときにシステムがエラーを表示する方法を構成できます。</string>
<string name="show_errors_dialog">エラーダイアログを表示</string>
<string name="show_errors_toast">エラー Toast を表示</string>
<string name="show_nothing">何も表示されません</string>
</resources>

View File

@@ -52,7 +52,6 @@
<string name="module_version">模块版本:%1$s</string>
<string name="system_version">系统版本:%1$s</string>
<string name="module_is_activated">模块已激活</string>
<string name="after_some_settings_need_restart">部分设置修改后可能需要点击右上角重启系统才能生效。</string>
<string name="display_settings">显示设置</string>
<string name="hide_app_icon_on_launcher">在桌面隐藏模块图标</string>
<string name="hide_app_icon_on_launcher_tip">隐藏模块图标后界面可能会被关闭,将不会再在桌面显示,你可以在 EdXposed、LSPosed 中找到模块设置并打开。</string>
@@ -73,19 +72,31 @@
<string name="share_error_stack">分享异常堆栈</string>
<string name="preference_settings">偏好设置</string>
<string name="function_mgr">功能管理</string>
<string name="only_show_errors_in_front">仅对前台应用示错误对话框</string>
<string name="only_show_errors_in_main_process">仅对应用主进程示错误对话框</string>
<string name="only_show_errors_in_front">仅对前台应用示错误对话框</string>
<string name="only_show_errors_in_main_process">仅对应用主进程示错误对话框</string>
<string name="enable_apps_config_template">启用应用配置模板</string>
<string name="mgr_apps_config_template">管理应用配置模板</string>
<string name="view_errors_record">查看异常历史记录</string>
<string name="view_muted_errors_apps">查看已忽略异常的应用</string>
<string name="only_show_errors_in_front_tip">启用后,只有发生异常的应用处于前台(正在使用中)时才会示错误对话框,发生异常的后台应用虽然不会示错误对话框,但是它们都会被记录到异常历史记录中。</string>
<string name="only_show_errors_in_main_process_tip">启用后,只有应用发生的异常位于主进程(第一个 Application 实例对象)时才会示错误对话框。</string>
<string name="apps_config_template_tip">你可以在这里对每个应用发生异常时,单独配置其在发生异常时是否示错误对话框。</string>
<string name="only_show_errors_in_front_tip">启用后,只有发生异常的应用处于前台(正在使用中)时才会示错误对话框,发生异常的后台应用虽然不会示错误对话框,但是它们都会被记录到异常历史记录中。</string>
<string name="only_show_errors_in_main_process_tip">启用后,只有应用发生的异常位于主进程(第一个 Application 实例对象)时才会示错误对话框。</string>
<string name="apps_config_template_tip">你可以在这里对每个应用发生异常时,单独配置其在发生异常时是否示错误对话框。</string>
<string name="view_errors_record_tip">在这里,你可以找到从系统开机以来到现在为止的全部应用异常记录,异常历史记录在重新启动后会自动清空,你可以对记录进行查看、导出和分享以及清空。</string>
<string name="view_muted_errors_apps_tip">在这里,你可以找到已被你以不同形式手动忽略异常的应用,这个列表将会在重新启动后自动清空,你可以对这些已忽略的应用进行管理以及从忽略列表中移除它们。</string>
<string name="muted_errors_apps">已忽略异常的应用</string>
<string name="unmute">取消忽略</string>
<string name="unmute_all">取消全部忽略</string>
<string name="are_you_sure_unmute_all">你确定要取消全部已忽略异常的应用吗?</string>
<string name="apps_config_template">应用配置模板</string>
<string name="filter_by_condition">按条件过滤</string>
<string name="no_list_result">没有结果可以显示</string>
<string name="typo_app_name_pkg_name">可输入 APP 名称、包名</string>
<string name="result_contains_system_apps">结果包含系统应用</string>
<string name="clear_filters">清除条件</string>
<string name="result_count">共 %1$s 个结果</string>
<string name="loading">加载中</string>
<string name="when_errors_how_to_show_tip">你可以配置当前应用崩溃时系统将如何向你显示错误提示信息。</string>
<string name="show_errors_dialog">显示错误对话框</string>
<string name="show_errors_toast">显示错误 Toast 提示</string>
<string name="show_nothing">不显示任何提示</string>
</resources>

View File

@@ -52,7 +52,6 @@
<string name="module_version">模組版本:%1$s</string>
<string name="system_version">系統版本:%1$s</string>
<string name="module_is_activated">模組已激活</string>
<string name="after_some_settings_need_restart">部分設置修改後可能需要點擊右上角重啟系統才能生效。</string>
<string name="display_settings">顯示設置</string>
<string name="hide_app_icon_on_launcher">在桌面隱藏模組圖標</string>
<string name="hide_app_icon_on_launcher_tip">隱藏模組圖標後界面可能會被關閉,將不會再在桌面顯示,你可以在 EdXposed、LSPosed 中找到模組設置並打開。</string>
@@ -88,4 +87,16 @@
<string name="unmute">取消忽略</string>
<string name="unmute_all">取消全部忽略</string>
<string name="are_you_sure_unmute_all">你確認要取消全部已忽略異常的程式嗎?</string>
<string name="apps_config_template">程式配置模板</string>
<string name="filter_by_condition">按條件過濾</string>
<string name="no_list_result">沒有結果可以展示</string>
<string name="typo_app_name_pkg_name">可輸入 APP 名稱、包名</string>
<string name="result_contains_system_apps">結果包含系統程式</string>
<string name="clear_filters">清除條件</string>
<string name="result_count">共 %1$s 個結果</string>
<string name="loading">加載中</string>
<string name="when_errors_how_to_show_tip">你可以配置當前程式崩潰時系統將如何向你展示錯誤提醒副案。</string>
<string name="show_errors_dialog">顯示錯誤對話框</string>
<string name="show_errors_toast">顯示錯誤 Toast 提示</string>
<string name="show_nothing">不顯示任何提示</string>
</resources>

View File

@@ -52,7 +52,6 @@
<string name="module_version">模組版本:%1$s</string>
<string name="system_version">系統版本:%1$s</string>
<string name="module_is_activated">模組已激活</string>
<string name="after_some_settings_need_restart">部分設置修改後可能需要點擊右上角重啟系統才能生效。</string>
<string name="display_settings">顯示設置</string>
<string name="hide_app_icon_on_launcher">在桌面隱藏模組圖標</string>
<string name="hide_app_icon_on_launcher_tip">隱藏模組圖標後界面可能會被關閉,將不會再在桌面顯示,你可以在 EdXposed、LSPosed 中找到模組設置並打開。</string>
@@ -88,4 +87,16 @@
<string name="unmute">取消忽略</string>
<string name="unmute_all">取消全部忽略</string>
<string name="are_you_sure_unmute_all">你確認要取消全部已忽略異常的程式嗎?</string>
<string name="apps_config_template">程式配置模板</string>
<string name="filter_by_condition">按條件過濾</string>
<string name="no_list_result">沒有結果可以展示</string>
<string name="typo_app_name_pkg_name">可輸入 APP 名稱、包名</string>
<string name="result_contains_system_apps">結果包含系統程式</string>
<string name="clear_filters">清除條件</string>
<string name="result_count">共 %1$s 個結果</string>
<string name="loading">加載中</string>
<string name="when_errors_how_to_show_tip">你可以配置當前程式崩潰時系統將如何向你展示錯誤提醒副案。</string>
<string name="show_errors_dialog">顯示錯誤對話框</string>
<string name="show_errors_toast">顯示錯誤 Toast 提示</string>
<string name="show_nothing">不顯示任何提示</string>
</resources>

View File

@@ -52,7 +52,6 @@
<string name="module_version">模組版本:%1$s</string>
<string name="system_version">系統版本:%1$s</string>
<string name="module_is_activated">模組已激活</string>
<string name="after_some_settings_need_restart">部分設置修改後可能需要點擊右上角重啟系統才能生效。</string>
<string name="display_settings">顯示設置</string>
<string name="hide_app_icon_on_launcher">在桌面隱藏模組圖標</string>
<string name="hide_app_icon_on_launcher_tip">隱藏模組圖標後界面可能會被關閉,將不會再在桌面顯示,你可以在 EdXposed、LSPosed 中找到模組設置並打開。</string>
@@ -88,4 +87,16 @@
<string name="unmute">取消忽略</string>
<string name="unmute_all">取消全部忽略</string>
<string name="are_you_sure_unmute_all">你確認要取消全部已忽略異常的程式嗎?</string>
<string name="apps_config_template">程式配置模板</string>
<string name="filter_by_condition">按條件過濾</string>
<string name="no_list_result">沒有結果可以展示</string>
<string name="typo_app_name_pkg_name">可輸入 APP 名稱、包名</string>
<string name="result_contains_system_apps">結果包含系統程式</string>
<string name="clear_filters">清除條件</string>
<string name="result_count">共 %1$s 個結果</string>
<string name="loading">加載中</string>
<string name="when_errors_how_to_show_tip">你可以配置當前程式崩潰時系統將如何向你展示錯誤提醒副案。</string>
<string name="show_errors_dialog">顯示錯誤對話框</string>
<string name="show_errors_toast">顯示錯誤 Toast 提示</string>
<string name="show_nothing">不顯示任何提示</string>
</resources>

View File

@@ -52,7 +52,6 @@
<string name="module_version">Module version: %1$s</string>
<string name="system_version">System version: %1$s</string>
<string name="module_is_activated">Module is activated</string>
<string name="after_some_settings_need_restart">After some settings are modified, you may need to click the upper right corner to restart the system to take effect.</string>
<string name="display_settings">Display settings</string>
<string name="hide_app_icon_on_launcher">Hide app icons on launcher</string>
<string name="hide_app_icon_on_launcher_tip">After hiding the app icon, the interface may be closed and will no longer be displayed on the launcher. You can find and open the module settings in EdXposed or LSPosed.</string>
@@ -88,4 +87,16 @@
<string name="unmute">Unmute</string>
<string name="unmute_all">Unmute all</string>
<string name="are_you_sure_unmute_all">Are you sure you want to unmute all apps?</string>
<string name="apps_config_template">Apps Config Template</string>
<string name="filter_by_condition">Filter by condition</string>
<string name="no_list_result">No result to display</string>
<string name="typo_app_name_pkg_name">Typo apps name or package name</string>
<string name="result_contains_system_apps">Result contains system apps</string>
<string name="clear_filters">Clear filters</string>
<string name="result_count">%1$s results found</string>
<string name="loading">Loading</string>
<string name="when_errors_how_to_show_tip">You can configure how the system will show you errors when the current app crashes.</string>
<string name="show_errors_dialog">Show errors dialog</string>
<string name="show_errors_toast">Show errors Toast</string>
<string name="show_nothing">Don\'t show anything</string>
</resources>