diff --git a/app/src/main/java/com/fankes/apperrorstracking/application/AppErrorsApplication.kt b/app/src/main/java/com/fankes/apperrorstracking/application/AppErrorsApplication.kt
index 731b3fa..ab07144 100644
--- a/app/src/main/java/com/fankes/apperrorstracking/application/AppErrorsApplication.kt
+++ b/app/src/main/java/com/fankes/apperrorstracking/application/AppErrorsApplication.kt
@@ -22,6 +22,7 @@
package com.fankes.apperrorstracking.application
import androidx.appcompat.app.AppCompatDelegate
+import com.fankes.apperrorstracking.locale.LocaleString
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
class AppErrorsApplication : ModuleApplication() {
@@ -30,5 +31,7 @@ class AppErrorsApplication : ModuleApplication() {
super.onCreate()
/** 跟随系统夜间模式 */
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
+ /** 绑定 I18n */
+ LocaleString.bind(instance = this)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/apperrorstracking/hook/HookEntry.kt b/app/src/main/java/com/fankes/apperrorstracking/hook/HookEntry.kt
index 0d41f91..9b9483a 100644
--- a/app/src/main/java/com/fankes/apperrorstracking/hook/HookEntry.kt
+++ b/app/src/main/java/com/fankes/apperrorstracking/hook/HookEntry.kt
@@ -22,6 +22,7 @@
package com.fankes.apperrorstracking.hook
import com.fankes.apperrorstracking.hook.entity.FrameworkHooker
+import com.fankes.apperrorstracking.locale.LocaleString
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.factory.configs
import com.highcapable.yukihookapi.hook.factory.encase
@@ -35,5 +36,10 @@ class HookEntry : IYukiHookXposedInit {
isDebug = false
}
- override fun onHook() = encase { loadSystem(FrameworkHooker) }
+ override fun onHook() = encase {
+ loadSystem {
+ LocaleString.bind(instance = this)
+ loadHooker(FrameworkHooker)
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/apperrorstracking/hook/entity/FrameworkHooker.kt b/app/src/main/java/com/fankes/apperrorstracking/hook/entity/FrameworkHooker.kt
index fec1416..9e3b3d6 100644
--- a/app/src/main/java/com/fankes/apperrorstracking/hook/entity/FrameworkHooker.kt
+++ b/app/src/main/java/com/fankes/apperrorstracking/hook/entity/FrameworkHooker.kt
@@ -42,6 +42,7 @@ import android.widget.LinearLayout
import android.widget.TextView
import com.fankes.apperrorstracking.R
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
+import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.ui.activity.AppErrorsDetailActivity
import com.fankes.apperrorstracking.utils.drawable.drawabletoolbox.DrawableBuilder
import com.fankes.apperrorstracking.utils.factory.*
@@ -129,14 +130,6 @@ object FrameworkHooker : YukiBaseHooker() {
private fun lastAppErrorsInfo(packageName: String) =
appErrorsRecords.takeIf { it.isNotEmpty() }?.filter { it.packageName == packageName }?.get(0)
- /**
- * 获取 I18n 字符串
- * @param resId 模块资源 Id
- * @param objArrs 格式化数组
- * @return [String]
- */
- private fun string(resId: Int, vararg objArrs: Any) = moduleAppResources.getString(resId, *objArrs)
-
/**
* 创建对话框按钮
* @param context 实例
@@ -252,30 +245,30 @@ object FrameworkHooker : YukiBaseHooker() {
android.R.style.Theme_Material_Dialog
else android.R.style.Theme_Material_Light_Dialog
).create().apply {
- setTitle(string(if (isRepeating) R.string.aerr_repeated_title else R.string.aerr_title, appName))
+ setTitle(if (isRepeating) LocaleString.aerrRepeatedTitle(appName) else LocaleString.aerrTitle(appName))
setView(LinearLayout(context).apply {
orientation = LinearLayout.VERTICAL
/** 应用信息按钮 */
val appInfoButton =
- createButtonItem(context, R.drawable.ic_baseline_info, string(R.string.app_info)) {
+ createButtonItem(context, R.drawable.ic_baseline_info, LocaleString.appInfo) {
cancel()
context.openSelfSetting(packageName)
}
/** 关闭应用按钮 */
val closeAppButton =
- createButtonItem(context, R.drawable.ic_baseline_close, string(R.string.close_app)) { cancel() }
+ createButtonItem(context, R.drawable.ic_baseline_close, LocaleString.closeApp) { cancel() }
/** 重新打开按钮 */
val reOpenButton =
- createButtonItem(context, R.drawable.ic_baseline_refresh, string(R.string.reopen_app)) {
+ createButtonItem(context, R.drawable.ic_baseline_refresh, LocaleString.reopenApp) {
cancel()
context.openApp(packageName)
}
/** 错误详情按钮 */
val errorDetailButton =
- createButtonItem(context, R.drawable.ic_baseline_bug_report, string(R.string.error_detail)) {
+ createButtonItem(context, R.drawable.ic_baseline_bug_report, LocaleString.errorDetail) {
cancel()
lastAppErrorsInfo(packageName)?.let { AppErrorsDetailActivity.start(context, it, isOutSide = true) }
?: context.toast(msg = "Invalid AppErrorsInfo")
@@ -283,18 +276,18 @@ object FrameworkHooker : YukiBaseHooker() {
/** 忽略按钮 - 直到解锁 */
val ignoredUntilUnlockButton =
- createButtonItem(context, R.drawable.ic_baseline_eject, string(R.string.ignore_if_unlock)) {
+ createButtonItem(context, R.drawable.ic_baseline_eject, LocaleString.ignoreIfUnlock) {
cancel()
ignoredErrorsIfUnlockApps.add(packageName)
- context.toast(string(R.string.ignore_if_unlock_tip, appName))
+ context.toast(LocaleString.ignoreIfUnlockTip(appName))
}
/** 忽略按钮 - 直到重启 */
val ignoredUntilRestartButton =
- createButtonItem(context, R.drawable.ic_baseline_eject, string(R.string.ignore_if_restart)) {
+ createButtonItem(context, R.drawable.ic_baseline_eject, LocaleString.ignoreIfRestart) {
cancel()
ignoredErrorsIfRestartApps.add(packageName)
- context.toast(string(R.string.ignore_if_restart_tip, appName))
+ context.toast(LocaleString.ignoreIfRestartTip(appName))
}
/** 判断进程是否为 APP */
if (isApp) {
diff --git a/app/src/main/java/com/fankes/apperrorstracking/locale/LocaleString.kt b/app/src/main/java/com/fankes/apperrorstracking/locale/LocaleString.kt
new file mode 100644
index 0000000..ce870ee
--- /dev/null
+++ b/app/src/main/java/com/fankes/apperrorstracking/locale/LocaleString.kt
@@ -0,0 +1,163 @@
+/*
+ * AppErrorsTracking - Added more features to app's crash dialog, fixed custom rom deleted dialog, the best experience to Android developer.
+ * Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
+ * https://github.com/KitsunePie/AppErrorsTracking
+ *
+ * This software is non-free but opensource software: you can redistribute it
+ * and/or modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * and eula along with this software. If not, see
+ *
+ *
+ * This file is Created by fankes on 2022/5/11.
+ */
+@file:Suppress("MemberVisibilityCanBePrivate", "StaticFieldLeak", "unused")
+
+package com.fankes.apperrorstracking.locale
+
+import android.content.Context
+import android.content.res.Resources
+import com.fankes.apperrorstracking.R
+import com.highcapable.yukihookapi.hook.param.PackageParam
+
+/**
+ * I18n 字符串实例
+ */
+object LocaleString {
+
+ /** 当前的 [Context] */
+ private var baseContext: Context? = null
+
+ /** 当前的 [PackageParam] */
+ private var basePackageParam: PackageParam? = null
+
+ /** 当前的 [Resources] */
+ private var baseResources: Resources? = null
+
+ /**
+ * 当前的 [Resources]
+ * @return [Resources]
+ * @throws IllegalStateException 如果 [LocaleString] 没有被绑定
+ */
+ private val resources
+ get() = baseContext?.resources ?: basePackageParam?.moduleAppResources ?: baseResources
+ ?: error("LocaleString must bind an instance first")
+
+ /**
+ * 绑定并初始化
+ * @param instance 可以是 [Context]、[PackageParam]、[Resources]
+ */
+ fun bind(instance: Any) {
+ when (instance) {
+ is Context -> baseContext = instance
+ is PackageParam -> basePackageParam = instance
+ is Resources -> baseResources = instance
+ else -> error("LocaleString bind an unknown instance")
+ }
+ }
+
+ /**
+ * 根据资源 Id 获取字符串
+ * @param objArrs 格式化实例
+ * @return [String]
+ */
+ private fun Int.bind(vararg objArrs: Any) = resources.getString(this, *objArrs)
+
+ /** @string Automatic generated */
+ val copied get() = copied()
+
+ /** @string Automatic generated */
+ fun copied(vararg objArrs: Any) = R.string.copied.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val copyFail get() = copyFail()
+
+ /** @string Automatic generated */
+ fun copyFail(vararg objArrs: Any) = R.string.copy_fail.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val printToLogcatSuccess get() = printToLogcatSuccess()
+
+ /** @string Automatic generated */
+ fun printToLogcatSuccess(vararg objArrs: Any) = R.string.print_to_logcat_success.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val outputStackSuccess get() = outputStackSuccess()
+
+ /** @string Automatic generated */
+ fun outputStackSuccess(vararg objArrs: Any) = R.string.output_stack_success.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val outputStackFail get() = outputStackFail()
+
+ /** @string Automatic generated */
+ fun outputStackFail(vararg objArrs: Any) = R.string.output_stack_fail.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val aerrTitle get() = aerrTitle()
+
+ /** @string Automatic generated */
+ fun aerrTitle(vararg objArrs: Any) = R.string.aerr_title.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val aerrRepeatedTitle get() = aerrRepeatedTitle()
+
+ /** @string Automatic generated */
+ fun aerrRepeatedTitle(vararg objArrs: Any) = R.string.aerr_repeated_title.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val appInfo get() = appInfo()
+
+ /** @string Automatic generated */
+ fun appInfo(vararg objArrs: Any) = R.string.app_info.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val closeApp get() = closeApp()
+
+ /** @string Automatic generated */
+ fun closeApp(vararg objArrs: Any) = R.string.close_app.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val reopenApp get() = reopenApp()
+
+ /** @string Automatic generated */
+ fun reopenApp(vararg objArrs: Any) = R.string.reopen_app.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val errorDetail get() = errorDetail()
+
+ /** @string Automatic generated */
+ fun errorDetail(vararg objArrs: Any) = R.string.error_detail.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val ignoreIfUnlock get() = ignoreIfUnlock()
+
+ /** @string Automatic generated */
+ fun ignoreIfUnlock(vararg objArrs: Any) = R.string.ignore_if_unlock.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val ignoreIfRestart get() = ignoreIfRestart()
+
+ /** @string Automatic generated */
+ fun ignoreIfRestart(vararg objArrs: Any) = R.string.ignore_if_restart.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val ignoreIfUnlockTip get() = ignoreIfUnlockTip()
+
+ /** @string Automatic generated */
+ fun ignoreIfUnlockTip(vararg objArrs: Any) = R.string.ignore_if_unlock_tip.bind(*objArrs)
+
+ /** @string Automatic generated */
+ val ignoreIfRestartTip get() = ignoreIfRestartTip()
+
+ /** @string Automatic generated */
+ fun ignoreIfRestartTip(vararg objArrs: Any) = R.string.ignore_if_restart_tip.bind(*objArrs)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fankes/apperrorstracking/ui/activity/AppErrorsDetailActivity.kt b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/AppErrorsDetailActivity.kt
index 9b39ae6..41974ce 100644
--- a/app/src/main/java/com/fankes/apperrorstracking/ui/activity/AppErrorsDetailActivity.kt
+++ b/app/src/main/java/com/fankes/apperrorstracking/ui/activity/AppErrorsDetailActivity.kt
@@ -33,6 +33,7 @@ import com.fankes.apperrorstracking.R
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
import com.fankes.apperrorstracking.databinding.ActivityAppErrorsDetailBinding
import com.fankes.apperrorstracking.hook.entity.FrameworkHooker
+import com.fankes.apperrorstracking.locale.LocaleString
import com.fankes.apperrorstracking.ui.activity.base.BaseActivity
import com.fankes.apperrorstracking.utils.factory.*
import com.highcapable.yukihookapi.hook.log.loggerE
@@ -55,7 +56,8 @@ class AppErrorsDetailActivity : BaseActivity() {
fun start(context: Context, appErrorsInfo: AppErrorsInfoBean, isOutSide: Boolean = false) {
runCatching {
context.startActivity((if (isOutSide) Intent() else Intent(context, AppErrorsDetailActivity::class.java)).apply {
- if (context !is Activity) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ flags = if (context !is Activity) Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ else Intent.FLAG_ACTIVITY_NEW_TASK
if (isOutSide) component = ComponentName(BuildConfig.APPLICATION_ID, AppErrorsDetailActivity::class.java.name)
putExtra(FrameworkHooker.APP_ERRORS_INFO, appErrorsInfo)
})
@@ -76,7 +78,7 @@ class AppErrorsDetailActivity : BaseActivity() {
binding.titleBackIcon.setOnClickListener { onBackPressed() }
binding.printIcon.setOnClickListener {
loggerE(msg = createStack())
- toast(getString(R.string.print_to_logcat_success))
+ toast(LocaleString.printToLogcatSuccess)
}
binding.copyIcon.setOnClickListener { copyToClipboard(appErrorsInfo.stackTrace) }
binding.exportIcon.setOnClickListener {
@@ -115,9 +117,9 @@ class AppErrorsDetailActivity : BaseActivity() {
if (requestCode == WRITE_REQUEST_CODE && resultCode == Activity.RESULT_OK) runCatching {
data?.data?.let {
contentResolver?.openOutputStream(it)?.apply { write(stackTrace.toByteArray()) }?.close()
- toast(getString(R.string.output_stack_success))
- } ?: toast(getString(R.string.output_stack_fail))
- }.onFailure { toast(getString(R.string.output_stack_fail)) }
+ toast(LocaleString.outputStackSuccess)
+ } ?: toast(LocaleString.outputStackFail)
+ }.onFailure { toast(LocaleString.outputStackFail) }
}
override fun onBackPressed() {
diff --git a/app/src/main/java/com/fankes/apperrorstracking/utils/factory/FunctionFactory.kt b/app/src/main/java/com/fankes/apperrorstracking/utils/factory/FunctionFactory.kt
index 3c2ca58..d40195b 100644
--- a/app/src/main/java/com/fankes/apperrorstracking/utils/factory/FunctionFactory.kt
+++ b/app/src/main/java/com/fankes/apperrorstracking/utils/factory/FunctionFactory.kt
@@ -35,7 +35,7 @@ import android.graphics.drawable.Drawable
import android.net.Uri
import android.provider.Settings
import android.widget.Toast
-import com.fankes.apperrorstracking.R
+import com.fankes.apperrorstracking.locale.LocaleString
/**
* 系统深色模式是否开启
@@ -109,7 +109,7 @@ fun Context.copyToClipboard(content: String) = runCatching {
(getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).apply {
setPrimaryClip(ClipData.newPlainText(null, content))
(primaryClip?.getItemAt(0)?.text ?: "").also {
- if (it != content) toast(getString(R.string.copy_fail)) else toast(getString(R.string.copied))
+ if (it != content) toast(LocaleString.copyFail) else toast(LocaleString.copied)
}
}
}