Added AppErrorsDetailActivity function and more function

This commit is contained in:
2022-05-11 02:41:54 +08:00
parent cac96e188e
commit e2b6fe8a81
31 changed files with 1058 additions and 11 deletions

View File

@@ -22,27 +22,33 @@ Added more features to app's crash dialog, fixed custom rom deleted dialog, the
## Feature ## Feature
- 重新定制应用错误对话框 - 重新定制应用异常错误对话框
- 记录每个应用的异常记录,直到重新启动前 - 记录每个应用的异常,直到重新启动前持续保留
- “错误详情”按钮功能,可查看具体的异常堆栈
- “应用信息”按钮功能(原生功能),点击可打开当前出错的应用详情页面 - “应用信息”按钮功能(原生功能),点击可打开当前出错的应用详情页面
- “重新打开”按钮功能(原生功能),在首次崩溃可点击按钮重新打开应用 - “重新打开”按钮功能(原生功能),在首次错误可点击按钮重新打开应用
- “屡次停止运行”显示(原生功能) - “屡次停止运行”显示(原生功能)
- “忽略(直到设备重新解锁/重新启动)”显示(原生功能) - “忽略(直到设备重新解锁/重新启动)”显示(原生功能)
- 对话框支持 Android 10 及以上系统的深色模式 - “错误详情”按钮功能,可查看具体的异常堆栈
- 导出异常堆栈到文件功能
- 复制异常堆栈功能
- 打印异常堆栈到控制台功能
- 支持 Android 10 及以上系统的深色模式
## Future ## Future
此项目依然在开发中,现在未解决的问题和包含的问题如下 此项目依然在开发中,现在未解决的问题和包含的问题如下
- “错误详情”按钮现在是无效的,还在开发 - 异常历史记录和排除列表正在开发
- 后台进程可能依然会弹出崩溃对话框且开发者选项里的设置无效,还在排查 - 后台进程可能依然会弹出崩溃对话框且开发者选项里的设置无效,还在排查

View File

@@ -1,7 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<application <application
android:name=".application.AppErrorsApplication"
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
@@ -21,5 +27,10 @@
<meta-data <meta-data
android:name="xposedscope" android:name="xposedscope"
android:resource="@array/module_scope" /> android:resource="@array/module_scope" />
<activity
android:name=".ui.activity.AppErrorsDetailActivity"
android:exported="true"
android:screenOrientation="behind" />
</application> </application>
</manifest> </manifest>

View File

@@ -0,0 +1,34 @@
/*
* 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/5/10.
*/
package com.fankes.apperrorstracking.application
import androidx.appcompat.app.AppCompatDelegate
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
class AppErrorsApplication : ModuleApplication() {
override fun onCreate() {
super.onCreate()
/** 跟随系统夜间模式 */
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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/5/10.
*/
package com.fankes.apperrorstracking.bean
import java.io.Serializable
/**
* 应用异常信息 bean
* @param packageName 包名
* @param isNativeCrash 是否为原生层异常
* @param exceptionClassName 异常类名
* @param exceptionMessage 异常信息
* @param throwClassName 抛出异常的类名
* @param throwFileName 抛出异常的文件名
* @param throwMethodName 抛出异常的方法名
* @param throwLineNumber 抛出异常的行号
* @param stackTrace 异常堆栈
* @param timestamp 记录时间戳
*/
data class AppErrorsInfoBean(
var packageName: String,
var isNativeCrash: Boolean,
var exceptionClassName: String,
var exceptionMessage: String,
var throwFileName: String,
var throwClassName: String,
var throwMethodName: String,
var throwLineNumber: Int,
var stackTrace: String,
var timestamp: Long,
) : Serializable

View File

@@ -24,6 +24,7 @@
package com.fankes.apperrorstracking.hook.entity package com.fankes.apperrorstracking.hook.entity
import android.app.AlertDialog import android.app.AlertDialog
import android.app.ApplicationErrorReport
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -40,6 +41,8 @@ import android.widget.ImageView
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import com.fankes.apperrorstracking.R import com.fankes.apperrorstracking.R
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
import com.fankes.apperrorstracking.ui.activity.AppErrorsDetailActivity
import com.fankes.apperrorstracking.utils.drawable.drawabletoolbox.DrawableBuilder import com.fankes.apperrorstracking.utils.drawable.drawabletoolbox.DrawableBuilder
import com.fankes.apperrorstracking.utils.factory.* import com.fankes.apperrorstracking.utils.factory.*
import com.highcapable.yukihookapi.hook.bean.VariousClass import com.highcapable.yukihookapi.hook.bean.VariousClass
@@ -52,6 +55,8 @@ import com.highcapable.yukihookapi.hook.type.android.MessageClass
object FrameworkHooker : YukiBaseHooker() { object FrameworkHooker : YukiBaseHooker() {
const val APP_ERRORS_INFO = "app_errors_info"
private const val AppErrorsClass = "com.android.server.am.AppErrors" private const val AppErrorsClass = "com.android.server.am.AppErrors"
private const val AppErrorResultClass = "com.android.server.am.AppErrorResult" private const val AppErrorResultClass = "com.android.server.am.AppErrorResult"
@@ -79,6 +84,9 @@ object FrameworkHooker : YukiBaseHooker() {
/** 已忽略错误的 APP 数组 - 直到重新启动 */ /** 已忽略错误的 APP 数组 - 直到重新启动 */
private var ignoredErrorsIfRestartApps = HashSet<String>() private var ignoredErrorsIfRestartApps = HashSet<String>()
/** 已记录的 APP 异常信息数组 - 直到重新启动 */
private val appErrorsRecords = arrayListOf<AppErrorsInfoBean>()
/** 是否已经注册广播 */ /** 是否已经注册广播 */
private var isRegisterReceiver = false private var isRegisterReceiver = false
@@ -113,6 +121,14 @@ object FrameworkHooker : YukiBaseHooker() {
isRegisterReceiver = true isRegisterReceiver = true
} }
/**
* 获取最新的 APP 错误信息
* @param packageName 包名
* @return [AppErrorsInfoBean] or null
*/
private fun lastAppErrorsInfo(packageName: String) =
appErrorsRecords.takeIf { it.isNotEmpty() }?.filter { it.packageName == packageName }?.get(0)
/** /**
* 获取 I18n 字符串 * 获取 I18n 字符串
* @param resId 模块资源 Id * @param resId 模块资源 Id
@@ -203,7 +219,7 @@ object FrameworkHooker : YukiBaseHooker() {
val packageName = appInfo?.packageName ?: processName val packageName = appInfo?.packageName ?: processName
/** 当前 APP 名称 */ /** 当前 APP 名称 */
val appName = appInfo?.let { context.packageManager.getApplicationLabel(it) } ?: packageName val appName = appInfo?.let { context.appName(it.packageName) } ?: packageName
/** 是否为 APP */ /** 是否为 APP */
val isApp = (PackageListClass.clazz.method { val isApp = (PackageListClass.clazz.method {
@@ -260,7 +276,9 @@ object FrameworkHooker : YukiBaseHooker() {
/** 错误详情按钮 */ /** 错误详情按钮 */
val errorDetailButton = val errorDetailButton =
createButtonItem(context, R.drawable.ic_baseline_bug_report, string(R.string.error_detail)) { createButtonItem(context, R.drawable.ic_baseline_bug_report, string(R.string.error_detail)) {
// TODO 待开发 cancel()
lastAppErrorsInfo(packageName)?.let { AppErrorsDetailActivity.start(context, it) }
?: context.toast(msg = "Invalid AppErrorsInfo")
} }
/** 忽略按钮 - 直到解锁 */ /** 忽略按钮 - 直到解锁 */
@@ -300,6 +318,34 @@ object FrameworkHooker : YukiBaseHooker() {
}.show() }.show()
} }
} }
injectMember {
method {
name = "crashApplication"
paramCount = 2
}
afterHook {
/** 当前 APP 信息 */
val appInfo = ProcessRecordClass.clazz.field { name = "info" }.get(args().first().any()).cast<ApplicationInfo>()
/** 当前异常信息 */
args().last().cast<ApplicationErrorReport.CrashInfo>()?.also { crashInfo ->
/** 添加到第一位 */
appErrorsRecords.add(
0, AppErrorsInfoBean(
packageName = appInfo?.packageName ?: "",
isNativeCrash = crashInfo.exceptionClassName.lowercase() == "native crash",
exceptionClassName = crashInfo.exceptionClassName ?: "",
exceptionMessage = crashInfo.exceptionMessage ?: "",
throwFileName = crashInfo.throwFileName ?: "",
throwClassName = crashInfo.throwClassName ?: "",
throwMethodName = crashInfo.throwMethodName ?: "",
throwLineNumber = crashInfo.throwLineNumber,
stackTrace = crashInfo.stackTrace?.trim() ?: "",
timestamp = System.currentTimeMillis()
)
)
}
}
}
} }
} }
} }

View File

@@ -0,0 +1,126 @@
/*
* 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/5/7.
*/
@file:Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
package com.fankes.apperrorstracking.ui.activity
import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import androidx.core.view.isGone
import com.fankes.apperrorstracking.BuildConfig
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.ui.activity.base.BaseActivity
import com.fankes.apperrorstracking.utils.factory.*
import com.highcapable.yukihookapi.hook.log.loggerE
import java.text.SimpleDateFormat
import java.util.*
class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
companion object {
/** 请求保存文件回调标识 */
private const val WRITE_REQUEST_CODE = 0
/**
* 启动 [AppErrorsDetailActivity]
* @param context 实例
* @param appErrorsInfo 应用异常信息
*/
fun start(context: Context, appErrorsInfo: AppErrorsInfoBean) {
runCatching {
context.startActivity(Intent().apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
component = ComponentName(BuildConfig.APPLICATION_ID, AppErrorsDetailActivity::class.java.name)
putExtra(FrameworkHooker.APP_ERRORS_INFO, appErrorsInfo)
})
}.onFailure { context.toast(msg = "Start AppErrorsDetailActivity failed") }
}
}
/** 预导出的异常堆栈 */
private var stackTrace = ""
override fun onCreate() {
val appErrorsInfo =
intent?.getSerializableExtra(FrameworkHooker.APP_ERRORS_INFO) as? AppErrorsInfoBean ?: return toastAndFinish()
/** 创建异常堆栈模板 */
fun createStack() =
"package name: ${appErrorsInfo.packageName} timestamp: ${appErrorsInfo.timestamp}\n${appErrorsInfo.stackTrace}"
binding.titleBackIcon.setOnClickListener { onBackPressed() }
binding.printIcon.setOnClickListener {
loggerE(msg = createStack())
toast(getString(R.string.print_to_logcat_success))
}
binding.copyIcon.setOnClickListener { copyToClipboard(appErrorsInfo.stackTrace) }
binding.exportIcon.setOnClickListener {
stackTrace = createStack()
runCatching {
startActivityForResult(Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "text/plain"
putExtra(Intent.EXTRA_TITLE, "${appErrorsInfo.packageName}_${appErrorsInfo.timestamp}.log")
}, WRITE_REQUEST_CODE)
}.onFailure { toast(msg = "Start Android SAF failed") }
}
binding.appIcon.setImageDrawable(appIcon(appErrorsInfo.packageName))
binding.appName.text = appName(appErrorsInfo.packageName)
binding.appVersion.text = appVersion(appErrorsInfo.packageName)
binding.jvmErrorPanel.isGone = appErrorsInfo.isNativeCrash
binding.errorTypeIcon.setImageResource(if (appErrorsInfo.isNativeCrash) R.drawable.ic_cpp else R.drawable.ic_java)
binding.errorInfoText.text = appErrorsInfo.exceptionMessage
binding.errorTypeText.text = appErrorsInfo.exceptionClassName
binding.errorFileNameText.text = appErrorsInfo.throwFileName
binding.errorThrowClassText.text = appErrorsInfo.throwClassName
binding.errorThrowMethodText.text = appErrorsInfo.throwMethodName
binding.errorLineNumberText.text = appErrorsInfo.throwLineNumber.toString()
binding.errorRecordTimeText.text = SimpleDateFormat.getDateTimeInstance().format(Date(appErrorsInfo.timestamp))
binding.errorStackText.text = appErrorsInfo.stackTrace
}
/** 弹出提示并退出 */
private fun toastAndFinish() {
toast(msg = "Invalid AppErrorsInfo, exit")
finish()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
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)) }
}
override fun onBackPressed() {
intent?.removeExtra(FrameworkHooker.APP_ERRORS_INFO)
finish()
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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/5/7.
*/
@file:Suppress("UNCHECKED_CAST")
package com.fankes.apperrorstracking.ui.activity.base
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.viewbinding.ViewBinding
import com.fankes.apperrorstracking.R
import com.fankes.apperrorstracking.utils.factory.isNotSystemInDarkMode
import com.gyf.immersionbar.ktx.immersionBar
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
import java.lang.reflect.ParameterizedType
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
/** 获取绑定布局对象 */
lateinit var binding: VB
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
javaClass.genericSuperclass.also { type ->
if (type is ParameterizedType) {
binding = (type.actualTypeArguments[0] as Class<VB>).method {
name = "inflate"
param(LayoutInflaterClass)
}.get().invoke<VB>(layoutInflater) ?: error("binding failed")
setContentView(binding.root)
} else error("binding but got wrong type")
}
/** 隐藏系统的标题栏 */
supportActionBar?.hide()
/** 初始化沉浸状态栏 */
immersionBar {
statusBarColor(R.color.colorThemeBackground)
autoDarkModeEnable(true)
statusBarDarkFont(isNotSystemInDarkMode)
navigationBarColor(R.color.colorThemeBackground)
navigationBarDarkIcon(isNotSystemInDarkMode)
fitsSystemWindows(true)
}
/** 装载子类 */
onCreate()
}
/** 回调 [onCreate] 方法 */
abstract fun onCreate()
}

View File

@@ -23,12 +23,19 @@
package com.fankes.apperrorstracking.utils.factory package com.fankes.apperrorstracking.utils.factory
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.provider.Settings import android.provider.Settings
import android.widget.Toast import android.widget.Toast
import com.fankes.apperrorstracking.R
/** /**
* 系统深色模式是否开启 * 系统深色模式是否开启
@@ -56,12 +63,57 @@ fun Number.dp(context: Context) = dpFloat(context).toInt()
*/ */
fun Number.dpFloat(context: Context) = toFloat() * context.resources.displayMetrics.density fun Number.dpFloat(context: Context) = toFloat() * context.resources.displayMetrics.density
/**
* 获取 APP 名称
* @param packageName 包名
* @return [String]
*/
fun Context.appName(packageName: String) =
runCatching {
packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA)
.applicationInfo.loadLabel(packageManager).toString()
}.getOrNull() ?: packageName
/**
* 获取 APP 完整版本
* @param packageName 包名
* @return [String]
*/
fun Context.appVersion(packageName: String) =
runCatching {
packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA)?.let { "${it.versionName} (${it.versionCode})" }
}.getOrNull() ?: "unknown"
/**
* 获取 APP 图标
* @param packageName 包名
* @return [Drawable]
*/
fun Context.appIcon(packageName: String) =
runCatching {
packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA)
.applicationInfo.loadIcon(packageManager)
}.getOrNull() ?: ColorDrawable(Color.WHITE)
/** /**
* 弹出 [Toast] * 弹出 [Toast]
* @param msg 提示内容 * @param msg 提示内容
*/ */
fun Context.toast(msg: String) = Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() fun Context.toast(msg: String) = Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
/**
* 复制到剪贴板
* @param content 要复制的文本
*/
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))
}
}
}
/** /**
* 跳转 APP 自身设置界面 * 跳转 APP 自身设置界面
* @param packageName 包名 * @param packageName 包名

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#666E6E6E" />
<corners android:radius="15dp" />
</shape>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#777777">
<item>
<shape android:shape="rectangle">
<solid android:color="#66DAD9D9" />
<corners android:radius="15dp" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#66E4E4E4" />
<corners android:radius="15dp" />
</shape>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FF14171F" />
<corners android:radius="15dp" />
</shape>

View File

@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="150dp"
android:height="150dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#ffffff"
android:pathData="M316.8,784h377.6v140.8c0,42.2 -34.6,76.8 -76.8,76.8h-518.4c-42.2,0 -76.8,-34.6 -76.8,-76.8v-518.4c0,-42.2 34.6,-76.8 76.8,-76.8h140.8v377.6c0,42.2 34.6,76.8 76.8,76.8z" />
<path
android:fillColor="#ffffff"
android:pathData="M1008,105.6v518.4c0,42.2 -34.6,76.8 -76.8,76.8h-518.4c-42.2,0 -76.8,-34.6 -76.8,-76.8v-518.4c0,-42.2 34.6,-76.8 76.8,-76.8h518.4c42.2,0 76.8,34.6 76.8,76.8z" />
</vector>

View File

@@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="250dp"
android:height="250dp"
android:viewportWidth="1024"
android:viewportHeight="1024"
tools:ignore="VectorRaster">
<path
android:fillColor="#1D88E5"
android:pathData="M403.5,880.6c-202.8,0 -368.6,-165.9 -368.6,-368.6s165.9,-368.6 368.6,-368.6c116.7,0 223.2,54.3 292.9,145.4L563.2,367.6c-41,-44 -98.3,-70.7 -158.7,-70.7 -117.8,0 -215,96.3 -215,215s96.3,215 215,215c60.4,0 117.8,-26.6 158.7,-70.7l134.1,78.8C628.7,826.4 520.2,880.6 403.5,880.6z" />
<path
android:fillColor="#1D88E5"
android:pathData="M772.1,542.7L711.7,542.7v61.4h-62.5v-61.4L588.8,542.7v-61.4h60.4v-61.4h62.5v61.4h60.4v61.4zM989.2,542.7L926.7,542.7v61.4h-60.4v-61.4L803.8,542.7v-61.4h62.5v-61.4h60.4v61.4h62.5v61.4z" />
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="250dp"
android:height="250dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M511,0a376.4,376.4 0,0 0,-265.1 106.8,365.1 365.1,0 0,0 -108,258.6v498.7h742L880,365.5a362.4,362.4 0,0 0,-108.9 -258.6A374.9,374.9 0,0 0,511 0zM480.3,744.6L469.5,502.9L286.9,502.9l239.9,-303.1 20.5,195.2 174.1,6.1 -243.2,343.3zM0.1,966.4a55.6,55.6 0,0 1,55.6 -56.2h910.6a57.6,57.6 0,0 1,39.3 16.3,58.7 58.7,0 0,1 16.4,39.9 55.7,55.7 0,0 1,-55.7 55.6L55.6,1022.1a55.6,55.6 0,0 1,-55.5 -55.6z"
android:fillColor="#ffffff"/>
</vector>

View File

@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="150dp"
android:height="150dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#ffffff"
android:pathData="M768,678.4v108.8H256v-108.8c0,-12.8 -6.4,-19.2 -19.2,-19.2H147.2c-12.8,0 -19.2,6.4 -19.2,19.2v172.8c0,38.4 25.6,64 64,64h640c38.4,0 64,-25.6 64,-64v-172.8c0,-12.8 -6.4,-19.2 -19.2,-19.2h-89.6c-12.8,0 -19.2,6.4 -19.2,19.2z" />
<path
android:fillColor="#ffffff"
android:pathData="M499.2,115.2L281.6,390.4c-12.8,12.8 0,32 12.8,32H448v268.8c0,6.4 6.4,12.8 19.2,12.8h89.6c12.8,0 19.2,-6.4 19.2,-19.2V416h153.6c19.2,0 25.6,-19.2 12.8,-32L524.8,115.2c-6.4,-6.4 -19.2,-6.4 -25.6,0z" />
</vector>

View File

@@ -0,0 +1,26 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="250dp"
android:height="250dp"
android:viewportWidth="1024"
android:viewportHeight="1024"
tools:ignore="VectorRaster">
<path
android:fillColor="#FF1515"
android:pathData="M747,175.6c-29.7,21 -58.4,38.9 -90.1,64.5 -24.1,19.5 -67.6,46.6 -69.6,82.4 -3.6,54.8 80.9,106 36.4,175.6 -16.9,26.6 -46.1,37.9 -82.4,54.3 -4.6,-8.2 9.7,-14.8 15.4,-23 56.3,-81.4 -58.4,-108.5 -44,-208.9 13.8,-97.8 128,-131.6 234.5,-144.9z" />
<path
android:fillColor="#2365C4"
android:pathData="M388.1,511c-26.6,12.3 -71.2,14.8 -90.1,41.5 19.5,14.8 48.1,14.3 74.8,15.4 109.1,5.1 245.2,-4.6 337.9,-20.5 3.1,6.7 -12.8,18.4 -23,25.6 -58.4,43 -240.6,54.8 -366.6,46.6 -42,-3.1 -138.2,-13.8 -139.3,-51.7 -1.5,-45.6 116.7,-50.7 164.9,-54.3 9.7,-1 27.6,-4.6 41.5,-2.6zM333.8,626.7c12.3,1.5 -8.7,8.7 -5.1,17.9 44.5,44 182.3,31.2 250.4,17.9 14.3,-3.1 28.2,-11.3 38.9,-10.2 25.6,2.6 42.5,32.3 64.5,36.4 -78.3,35.3 -229.9,52.2 -340.5,30.7 -28.7,-5.6 -78.3,-21 -79.9,-44 -2.6,-30.7 49.2,-43.5 71.7,-48.6zM367.6,732.7c8.2,2.6 -3.1,7.2 -2.6,10.2 23.6,41 139.8,26.1 198.7,12.8 11.8,-3.1 23.6,-11.3 33.8,-10.2 29.7,2 41.5,33.3 67.1,38.9 -82.4,50.2 -281.6,70.7 -364,7.7 -4.1,-46.1 32.8,-51.2 67.1,-59.4z" />
<path
android:fillColor="#2365C4"
android:pathData="M292.9,810c-24.6,6.1 -88.1,-2.6 -90.1,30.7 -1,12.8 21.5,28.2 36.4,33.8 84,31.7 252.9,36.9 392.2,20.5 64.5,-7.7 185.9,-29.2 170.5,-95.2 19.5,2.6 36.9,14.8 38.9,33.8 7.7,71.2 -155.6,101.4 -221.7,108.5 -143.9,15.9 -323.1,12.8 -433.7,-25.6 -35.8,-12.3 -79.4,-35.3 -77.3,-69.6 2,-58.4 141.3,-74.2 184.8,-36.9z" />
<path
android:fillColor="#2365C4"
android:pathData="M512,1024c-96.8,-10.8 -190,-24.6 -268.3,-59.4 205.3,49.2 504.3,45.6 647.7,-59.4 7.7,-5.6 14.8,-16.9 25.6,-15.4 -36.4,108.5 -175.1,115.7 -293.9,134.1H512z" />
<path
android:fillColor="#FF1515"
android:pathData="M579.1,0c17.9,16.9 30.7,48.6 30.7,82.4 0,99.8 -106,157.7 -157.2,224.3 -11.3,14.8 -26.1,37.9 -25.6,62 0.5,54.3 56.8,115.2 77.3,159.7 -36.4,-23.6 -79.9,-55.3 -111.1,-92.7 -30.7,-37.4 -62,-97.3 -33.8,-149.5 42.5,-78.3 169.5,-124.9 214,-208.9 11.3,-20.5 20,-51.7 5.6,-77.3z" />
<path
android:fillColor="#2365C4"
android:pathData="M731.1,536.6c53.2,-45.6 143.4,-27.6 146.9,49.2 4.6,89.6 -93.7,140.3 -165.4,144.4 32.8,-31.2 120.3,-81.9 103.4,-154.6 -6.7,-29.7 -43,-47.6 -85,-38.9z" />
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="150dp"
android:height="150dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M851.2,957.9L179.2,957.9c-61.9,0 -110.9,-49.1 -110.9,-110.9L68.3,454.4c0,-32 25.6,-55.5 55.5,-55.5h55.5v224c0,32 25.6,55.5 55.5,55.5h558.9c32,0 55.5,-25.6 55.5,-55.5L849.1,398.9h55.5c32,0 55.5,25.6 55.5,55.5v390.4c2.1,64 -46.9,113.1 -108.8,113.1zM738.1,622.9h-448c-32,0 -55.5,-25.6 -55.5,-55.5v-448C234.7,89.6 260.3,64 290.1,64h448c32,0 55.5,25.6 55.5,55.5v448c0,29.9 -23.5,55.5 -55.5,55.5zM657.1,232.5L377.6,232.5c-19.2,0 -32,19.2 -32,32s12.8,25.6 32,32h279.5c19.2,0 32,-12.8 32,-32s-19.2,-32 -32,-32zM657.1,398.9L377.6,398.9c-19.2,0 -32,12.8 -32,32 0,12.8 19.2,25.6 32,25.6h279.5c19.2,0 32,-12.8 32,-25.6 0,-19.2 -19.2,-32 -32,-32z"
android:fillColor="#ffffff"/>
</vector>

View File

@@ -0,0 +1,402 @@
<?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="match_parent"
android:background="@color/colorThemeBackground"
android:orientation="vertical"
tools:context=".ui.activity.AppErrorsDetailActivity"
tools:ignore="UnusedAttribute,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="15dp"
android:paddingRight="15dp"
android:paddingBottom="15dp">
<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" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="2.5dp"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/app_name"
android:textColor="@color/colorTextGray"
android:textSize="19sp"
android:textStyle="bold" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/print_icon"
android:layout_width="23dp"
android:layout_height="23dp"
android:layout_marginEnd="15dp"
android:src="@drawable/ic_print"
android:tint="@color/colorTextGray"
android:tooltipText="@string/print_to_logcat" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/copy_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="15dp"
android:src="@drawable/ic_copy"
android:tint="@color/colorTextGray"
android:tooltipText="@string/copy_error_stack" />
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/export_icon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginEnd="10dp"
android:src="@drawable/ic_export"
android:tint="@color/colorTextGray"
android:tooltipText="@string/export_to_file" />
</LinearLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="5dp"
android:layout_marginBottom="10dp"
android:fadingEdgeLength="10dp"
android:fillViewport="true"
android:requiresFadingEdge="vertical"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/bg_permotion_round"
android:gravity="center|start"
android:padding="10dp">
<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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:gravity="center|start"
android:orientation="horizontal">
<TextView
android:id="@+id/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<ImageView
android:layout_width="13dp"
android:layout_height="13dp"
android:src="@drawable/ic_exception"
app:tint="#FFEF5350" />
</LinearLayout>
<TextView
android:id="@+id/app_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:id="@+id/error_type_icon"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginEnd="10dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/bg_permotion_round"
android:gravity="center|start"
android:orientation="vertical"
android:padding="15dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:gravity="center|start|top"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/error_info"
android:textColor="@color/colorTextDark"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/error_info_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lineSpacingExtra="5dp"
android:textColor="@color/colorTextGray"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="@+id/jvm_error_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:gravity="center|start"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:gravity="center|start"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/error_type"
android:textColor="@color/colorTextDark"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/error_type_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#FFEF5350"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:gravity="center|start"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/error_file_name"
android:textColor="@color/colorTextDark"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/error_file_name_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:gravity="center|start"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/error_throw_class"
android:textColor="@color/colorTextDark"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/error_throw_class_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:gravity="center|start"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/error_throw_method"
android:textColor="@color/colorTextDark"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/error_throw_method_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center|start"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/error_line_number"
android:textColor="@color/colorTextDark"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/error_line_number_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center|start"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/error_record_time"
android:textColor="@color/colorTextDark"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/error_record_time_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="@color/colorTextGray"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/error_stack_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/bg_stack_round"
android:lineSpacingExtra="5dp"
android:padding="15dp"
android:textColor="#B65B57"
android:textIsSelectable="true"
android:textSize="12sp"
android:typeface="monospace" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -13,4 +13,19 @@
<string name="ignore_if_restart_tip">システイムが再起動するまで、「%1$s」のエラーを無視します</string> <string name="ignore_if_restart_tip">システイムが再起動するまで、「%1$s」のエラーを無視します</string>
<string name="ignore_if_unlock_tip">ロックが解除されるまで、「%1$s」のエラーを無視します</string> <string name="ignore_if_unlock_tip">ロックが解除されるまで、「%1$s」のエラーを無視します</string>
<string name="back">戻る</string> <string name="back">戻る</string>
<string name="copy_error_stack">例外スタックをコピーする</string>
<string name="export_to_file">ファイルにエクスポート</string>
<string name="error_info">例外情報</string>
<string name="error_type">例外タイプ</string>
<string name="error_file_name">ファイル名</string>
<string name="error_throw_class">投擲クラス</string>
<string name="error_throw_method">投擲メソッド</string>
<string name="error_line_number">行番号</string>
<string name="error_record_time">記録タイム</string>
<string name="copied">コピーしました</string>
<string name="copy_fail">コピーに失敗しました</string>
<string name="print_to_logcat">コンソールに印刷</string>
<string name="print_to_logcat_success">コンソールに印刷されていました</string>
<string name="output_stack_success">エクスポートされた例外スタックされていました</string>
<string name="output_stack_fail">例外スタックのエクスポートに失敗しました</string>
</resources> </resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorThemeBackground">#FF2D2D2D</color>
<color name="colorTextDark">#FFCFCFCF</color>
<color name="colorTextGray">#FFD3D3D3</color>
</resources>

View File

@@ -0,0 +1,16 @@
<resources>
<!-- Base application theme. -->
<style name="Theme.AppErrorsTracking" parent="Theme.Material3.DayNight">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -13,4 +13,19 @@
<string name="ignore_if_unlock_tip">忽略“%1$s”的错误直到设备重新解锁</string> <string name="ignore_if_unlock_tip">忽略“%1$s”的错误直到设备重新解锁</string>
<string name="ignore_if_restart_tip">忽略“%1$s”的错误直到设备重新启动</string> <string name="ignore_if_restart_tip">忽略“%1$s”的错误直到设备重新启动</string>
<string name="back">返回</string> <string name="back">返回</string>
<string name="copy_error_stack">复制异常堆栈</string>
<string name="export_to_file">导出到文件</string>
<string name="error_info">异常信息</string>
<string name="error_type">异常类型</string>
<string name="error_file_name">文件名</string>
<string name="error_throw_class">抛出类</string>
<string name="error_throw_method">抛出方法</string>
<string name="error_line_number">行号</string>
<string name="error_record_time">记录时间</string>
<string name="copied">已复制</string>
<string name="copy_fail">复制失败</string>
<string name="print_to_logcat">打印到控制台</string>
<string name="print_to_logcat_success">已打印到控制台</string>
<string name="output_stack_success">已导出异常堆栈</string>
<string name="output_stack_fail">导出异常堆栈失败</string>
</resources> </resources>

View File

@@ -13,4 +13,19 @@
<string name="ignore_if_unlock_tip">忽略“%1$s”的錯誤直到設備重新開屏</string> <string name="ignore_if_unlock_tip">忽略“%1$s”的錯誤直到設備重新開屏</string>
<string name="ignore_if_restart_tip">忽略“%1$s”的錯誤直到設備重新開機</string> <string name="ignore_if_restart_tip">忽略“%1$s”的錯誤直到設備重新開機</string>
<string name="back">回退</string> <string name="back">回退</string>
<string name="copy_error_stack">複製異常堆棧</string>
<string name="export_to_file">導出到副案</string>
<string name="error_info">異常訊息</string>
<string name="error_type">異常類型</string>
<string name="error_file_name">文件名</string>
<string name="error_throw_class">拋出 Class</string>
<string name="error_throw_method">抛出 Method</string>
<string name="error_line_number">行號</string>
<string name="error_record_time">記錄時間</string>
<string name="copied">已復制</string>
<string name="copy_fail">複製失敗</string>
<string name="print_to_logcat">打印到控制台</string>
<string name="print_to_logcat_success">已打印到控制台</string>
<string name="output_stack_success">已導出異常堆棧</string>
<string name="output_stack_fail">導出異常堆棧失敗</string>
</resources> </resources>

View File

@@ -13,4 +13,19 @@
<string name="ignore_if_unlock_tip">忽略“%1$s”的錯誤直到設備重新開屏</string> <string name="ignore_if_unlock_tip">忽略“%1$s”的錯誤直到設備重新開屏</string>
<string name="ignore_if_restart_tip">忽略“%1$s”的錯誤直到設備重新開機</string> <string name="ignore_if_restart_tip">忽略“%1$s”的錯誤直到設備重新開機</string>
<string name="back">回退</string> <string name="back">回退</string>
<string name="copy_error_stack">複製異常堆棧</string>
<string name="export_to_file">導出到副案</string>
<string name="error_info">異常訊息</string>
<string name="error_type">異常類型</string>
<string name="error_file_name">文件名</string>
<string name="error_throw_class">拋出 Class</string>
<string name="error_throw_method">抛出 Method</string>
<string name="error_line_number">行號</string>
<string name="error_record_time">記錄時間</string>
<string name="copied">已復制</string>
<string name="copy_fail">複製失敗</string>
<string name="print_to_logcat">打印到控制台</string>
<string name="print_to_logcat_success">已打印到控制台</string>
<string name="output_stack_success">已導出異常堆棧</string>
<string name="output_stack_fail">導出異常堆棧失敗</string>
</resources> </resources>

View File

@@ -13,4 +13,19 @@
<string name="ignore_if_unlock_tip">忽略“%1$s”的錯誤直到設備重新開屏</string> <string name="ignore_if_unlock_tip">忽略“%1$s”的錯誤直到設備重新開屏</string>
<string name="ignore_if_restart_tip">忽略“%1$s”的錯誤直到設備重新開機</string> <string name="ignore_if_restart_tip">忽略“%1$s”的錯誤直到設備重新開機</string>
<string name="back">回退</string> <string name="back">回退</string>
<string name="copy_error_stack">複製異常堆棧</string>
<string name="export_to_file">導出到副案</string>
<string name="error_info">異常訊息</string>
<string name="error_type">異常類型</string>
<string name="error_file_name">文件名</string>
<string name="error_throw_class">拋出 Class</string>
<string name="error_throw_method">抛出 Method</string>
<string name="error_line_number">行號</string>
<string name="error_record_time">記錄時間</string>
<string name="copied">已復制</string>
<string name="copy_fail">複製失敗</string>
<string name="print_to_logcat">打印到控制台</string>
<string name="print_to_logcat_success">已打印到控制台</string>
<string name="output_stack_success">已導出異常堆棧</string>
<string name="output_stack_fail">導出異常堆棧失敗</string>
</resources> </resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorThemeBackground">#FFFFFFFF</color>
<color name="colorTextDark">#FF777777</color>
<color name="colorTextGray">#FF323B42</color>
</resources>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#656565</color>
<color name="purple_500">#656565</color>
<color name="purple_700">#656565</color>
<color name="teal_200">#656565</color>
<color name="teal_700">#656565</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="trans">#00000000</color>
</resources>

View File

@@ -12,4 +12,19 @@
<string name="ignore_if_unlock_tip">Ignore errors for \'%1$s\' until device is re-unlocked</string> <string name="ignore_if_unlock_tip">Ignore errors for \'%1$s\' until device is re-unlocked</string>
<string name="ignore_if_restart_tip">Ignore errors for \'%1$s\' until device reboots</string> <string name="ignore_if_restart_tip">Ignore errors for \'%1$s\' until device reboots</string>
<string name="back">Back</string> <string name="back">Back</string>
<string name="copy_error_stack">Copy error stack</string>
<string name="export_to_file">Export to file</string>
<string name="error_info">Error Info</string>
<string name="error_type">Error Type</string>
<string name="error_file_name">File Name</string>
<string name="error_throw_class">Throw Class</string>
<string name="error_throw_method">Throw Method</string>
<string name="error_line_number">Line Number</string>
<string name="error_record_time">Record Time</string>
<string name="copied">Copied</string>
<string name="copy_fail">Copy failed</string>
<string name="print_to_logcat">Print to logcat</string>
<string name="print_to_logcat_success">Printed to logcat</string>
<string name="output_stack_success">Export exception stack succeeded</string>
<string name="output_stack_fail">Failed to export exception stack</string>
</resources> </resources>

View File

@@ -1,4 +1,16 @@
<resources> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.AppErrorsTracking" parent="android:Theme.DeviceDefault" /> <style name="Theme.AppErrorsTracking" parent="Theme.Material3.DayNight">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/teal_700</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources> </resources>