mirror of
https://github.com/KitsunePie/AppErrorsTracking.git
synced 2025-09-01 16:55:18 +08:00
Added App errors statistics function
This commit is contained in:
@@ -46,6 +46,8 @@ Added more features to app's crash dialog, fixed custom rom deleted dialog, the
|
||||
|
||||
- 异常历史记录功能,可通过通知栏磁贴“异常历史记录”进入和模块主界面进入
|
||||
|
||||
- 应用异常统计功能
|
||||
|
||||
- 多进程 APP 的异常将会显示异常的进程名
|
||||
|
||||
- 支持 Android 10 及以上系统的深色模式
|
||||
@@ -54,7 +56,7 @@ Added more features to app's crash dialog, fixed custom rom deleted dialog, the
|
||||
|
||||
此项目依然在开发中,正在开发的功能如下
|
||||
|
||||
- 应用异常统计信息功能
|
||||
- 是否始终允许错误对话框显示“重新打开”按钮 (计划中)
|
||||
|
||||
## License
|
||||
|
||||
|
@@ -388,4 +388,28 @@ object LocaleString {
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun showNothing(vararg objArrs: Any) = R.string.show_nothing.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val appErrorsStatistics get() = appErrorsStatistics()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun appErrorsStatistics(vararg objArrs: Any) = R.string.app_errors_statistics.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val totalErrorsUnit get() = totalErrorsUnit()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun totalErrorsUnit(vararg objArrs: Any) = R.string.total_errors_unit.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val totalAppsUnit get() = totalAppsUnit()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun totalAppsUnit(vararg objArrs: Any) = R.string.total_apps_unit.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val generatingStatistics get() = generatingStatistics()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun generatingStatistics(vararg objArrs: Any) = R.string.generating_statistics.bind(*objArrs)
|
||||
}
|
@@ -19,7 +19,7 @@
|
||||
*
|
||||
* This file is Created by fankes on 2022/5/11.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
|
||||
@file:Suppress("DEPRECATION", "OVERRIDE_DEPRECATION", "SetTextI18n")
|
||||
|
||||
package com.fankes.apperrorstracking.ui.activity.errors
|
||||
|
||||
@@ -32,8 +32,10 @@ import android.widget.AdapterView.AdapterContextMenuInfo
|
||||
import androidx.core.view.isVisible
|
||||
import com.fankes.apperrorstracking.R
|
||||
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
|
||||
import com.fankes.apperrorstracking.bean.AppFiltersBean
|
||||
import com.fankes.apperrorstracking.databinding.ActivityAppErrorsRecordBinding
|
||||
import com.fankes.apperrorstracking.databinding.AdapterAppErrorsRecordBinding
|
||||
import com.fankes.apperrorstracking.databinding.DiaAppErrorsStatisticsBinding
|
||||
import com.fankes.apperrorstracking.locale.LocaleString
|
||||
import com.fankes.apperrorstracking.ui.activity.base.BaseActivity
|
||||
import com.fankes.apperrorstracking.utils.factory.*
|
||||
@@ -61,6 +63,40 @@ class AppErrorsRecordActivity : BaseActivity<ActivityAppErrorsRecordBinding>() {
|
||||
|
||||
override fun onCreate() {
|
||||
binding.titleBackIcon.setOnClickListener { onBackPressed() }
|
||||
binding.appErrorSisIcon.setOnClickListener {
|
||||
showDialog {
|
||||
title = LocaleString.notice
|
||||
progressContent = LocaleString.generatingStatistics
|
||||
noCancelable()
|
||||
FrameworkTool.fetchAppListData(context, AppFiltersBean(isContainsSystem = true)) {
|
||||
Thread {
|
||||
val errorsApps = listData.groupBy { it.packageName }
|
||||
.map { it.key to it.value.size }
|
||||
.sortedByDescending { it.second }
|
||||
.takeIf { it.isNotEmpty() }
|
||||
val mostAppPackageName = errorsApps?.get(0)?.first ?: ""
|
||||
val mostErrorsType = listData.groupBy { it.exceptionClassName }
|
||||
.map { it.key to it.value.size }
|
||||
.sortedByDescending { it.second }
|
||||
.takeIf { it.isNotEmpty() }?.get(0)?.first?.simpleThwName() ?: ""
|
||||
val pptCount = (((errorsApps?.size?.toFloat() ?: 0f) * 100f) / it.size.toFloat()).decimal()
|
||||
runOnUiThread {
|
||||
cancel()
|
||||
showDialog<DiaAppErrorsStatisticsBinding> {
|
||||
title = LocaleString.appErrorsStatistics
|
||||
binding.totalErrorsUnitText.text = LocaleString.totalErrorsUnit(listData.size)
|
||||
binding.totalAppsUnitText.text = LocaleString.totalAppsUnit(it.size)
|
||||
binding.mostErrorsAppIcon.setImageDrawable(appIcon(mostAppPackageName))
|
||||
binding.mostErrorsAppText.text = appName(mostAppPackageName)
|
||||
binding.mostErrorsTypeText.text = mostErrorsType
|
||||
binding.totalPptOfErrorsText.text = "$pptCount%"
|
||||
confirmButton(LocaleString.gotIt)
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.clearAllIcon.setOnClickListener {
|
||||
showDialog {
|
||||
title = LocaleString.notice
|
||||
@@ -92,9 +128,7 @@ class AppErrorsRecordActivity : BaseActivity<ActivityAppErrorsRecordBinding>() {
|
||||
binding.appNameText.text = appName(bean.packageName)
|
||||
binding.errorsTimeText.text = bean.crossTime
|
||||
binding.errorTypeIcon.setImageResource(if (bean.isNativeCrash) R.drawable.ic_cpp else R.drawable.ic_java)
|
||||
binding.errorTypeText.text = if (bean.isNativeCrash) "Native crash" else bean.exceptionClassName.let { text ->
|
||||
if (text.contains(other = ".")) text.split(".").let { e -> e[e.lastIndex] } else text
|
||||
}
|
||||
binding.errorTypeText.text = if (bean.isNativeCrash) "Native crash" else bean.exceptionClassName.simpleThwName()
|
||||
binding.errorMsgText.text = bean.exceptionMessage
|
||||
}
|
||||
}
|
||||
@@ -110,6 +144,7 @@ class AppErrorsRecordActivity : BaseActivity<ActivityAppErrorsRecordBinding>() {
|
||||
listData.clear()
|
||||
it.takeIf { e -> e.isNotEmpty() }?.forEach { e -> listData.add(e) }
|
||||
onChanged?.invoke()
|
||||
binding.appErrorSisIcon.isVisible = listData.isNotEmpty()
|
||||
binding.clearAllIcon.isVisible = listData.isNotEmpty()
|
||||
binding.exportAllIcon.isVisible = listData.isNotEmpty()
|
||||
binding.listView.isVisible = listData.isNotEmpty()
|
||||
@@ -143,6 +178,13 @@ class AppErrorsRecordActivity : BaseActivity<ActivityAppErrorsRecordBinding>() {
|
||||
cacheDir.mkdirs()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取异常的精简名称
|
||||
* @return [String]
|
||||
*/
|
||||
private fun String.simpleThwName() =
|
||||
let { text -> if (text.contains(other = ".")) text.split(".").let { e -> e[e.lastIndex] } else text }
|
||||
|
||||
override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) {
|
||||
menuInflater.inflate(R.menu.menu_list_detail_action, menu)
|
||||
super.onCreateContextMenu(menu, v, menuInfo)
|
||||
|
@@ -41,6 +41,8 @@ import com.google.android.material.snackbar.Snackbar
|
||||
import com.highcapable.yukihookapi.hook.factory.field
|
||||
import com.highcapable.yukihookapi.hook.type.android.ApplicationInfoClass
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import java.math.RoundingMode
|
||||
import java.text.DecimalFormat
|
||||
|
||||
/**
|
||||
* 系统深色模式是否开启
|
||||
@@ -139,6 +141,27 @@ fun Long.difference(now: String, second: String, minute: String, hour: String, d
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保留小数
|
||||
* @param count 要保留的位数 - 默认 2 位 - 最多 7 位
|
||||
* @return [String] 得到的字符串数字 - 格式化失败返回原始数字的字符串
|
||||
*/
|
||||
fun Number.decimal(count: Int = 2) = runCatching {
|
||||
DecimalFormat(
|
||||
when (count) {
|
||||
0 -> "0"
|
||||
1 -> "0.0"
|
||||
2 -> "0.00"
|
||||
3 -> "0.000"
|
||||
4 -> "0.0000"
|
||||
5 -> "0.00000"
|
||||
6 -> "0.000000"
|
||||
7 -> "0.0000000"
|
||||
else -> "0.0"
|
||||
}
|
||||
).apply { roundingMode = RoundingMode.HALF_UP }.format(this) ?: toString()
|
||||
}.getOrNull() ?: this
|
||||
|
||||
/**
|
||||
* 弹出 [Toast]
|
||||
* @param msg 提示内容
|
||||
|
9
app/src/main/res/drawable/ic_statistics.xml
Normal file
9
app/src/main/res/drawable/ic_statistics.xml
Normal 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:fillColor="#ffffff"
|
||||
android:pathData="M446.2,566.7h369.3c-2.9,103.8 -39.4,190.7 -109.4,260.7s-156.6,106.4 -259.9,109.4c-103.8,-2.9 -190.7,-39.4 -260.7,-109.4s-106.4,-156.9 -109.4,-260.7c2.9,-103.2 39.4,-189.9 109.4,-259.9S342.4,200.4 446.2,197.5v369.2zM829.5,183.5c70,70 106.4,156.9 109.4,260.7L568.7,444.2L568.7,74.1c103.9,2.9 190.8,39.4 260.8,109.4z" />
|
||||
</vector>
|
@@ -40,6 +40,16 @@
|
||||
android:textSize="19sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/app_error_sis_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:src="@drawable/ic_statistics"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="@string/app_errors_statistics"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/clear_all_icon"
|
||||
android:layout_width="26dp"
|
||||
|
169
app/src/main/res/layout/dia_app_errors_statistics.xml
Normal file
169
app/src/main/res/layout/dia_app_errors_statistics.xml
Normal file
@@ -0,0 +1,169 @@
|
||||
<?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:orientation="vertical"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="15dp"
|
||||
tools:ignore="ContentDescription,SmallSp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8.5dp"
|
||||
android:layout_marginRight="8.5dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:gravity="center|start">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/total_errors"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/total_errors_unit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/total_errors_unit"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8.5dp"
|
||||
android:layout_marginRight="8.5dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:gravity="center|start">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/total_apps"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/total_apps_unit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/total_apps_unit"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8.5dp"
|
||||
android:layout_marginRight="8.5dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:gravity="center|start">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/most_errors_app"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
app:cardBackgroundColor="@color/trans"
|
||||
app:cardCornerRadius="3.5dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/most_errors_app_icon"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:src="@drawable/ic_android" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/most_errors_app_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8.5dp"
|
||||
android:layout_marginRight="8.5dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:gravity="center|start">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/most_errors_type"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/most_errors_type_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="@drawable/bg_red_round"
|
||||
android:ellipsize="end"
|
||||
android:paddingLeft="3dp"
|
||||
android:paddingTop="0.5dp"
|
||||
android:paddingRight="3dp"
|
||||
android:paddingBottom="0.5dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="10sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8.5dp"
|
||||
android:layout_marginRight="8.5dp"
|
||||
android:gravity="center|start">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/total_proportion_of_errors"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/total_ppt_of_errors_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
@@ -99,4 +99,13 @@
|
||||
<string name="show_errors_dialog">エラーダイアログを表示</string>
|
||||
<string name="show_errors_toast">エラー Toast を表示</string>
|
||||
<string name="show_nothing">何も表示されません</string>
|
||||
<string name="app_errors_statistics">アプリのエラー統計</string>
|
||||
<string name="total_errors">エラーの総数</string>
|
||||
<string name="total_apps">アプリの総数</string>
|
||||
<string name="most_errors_app">エラーが最も多いアプリ</string>
|
||||
<string name="most_errors_type">エラーが最も多いタイプ</string>
|
||||
<string name="total_proportion_of_errors">エラーの合計割合</string>
|
||||
<string name="total_errors_unit">%1$s 個</string>
|
||||
<string name="total_apps_unit">%1$s 個 (システムアプリを含む)</string>
|
||||
<string name="generating_statistics">統計が生成されています</string>
|
||||
</resources>
|
@@ -99,4 +99,13 @@
|
||||
<string name="show_errors_dialog">显示错误对话框</string>
|
||||
<string name="show_errors_toast">显示错误 Toast 提示</string>
|
||||
<string name="show_nothing">不显示任何提示</string>
|
||||
<string name="app_errors_statistics">应用异常统计</string>
|
||||
<string name="total_errors">异常总数</string>
|
||||
<string name="total_apps">应用总数</string>
|
||||
<string name="most_errors_app">最多异常的应用</string>
|
||||
<string name="most_errors_type">最多异常的类型</string>
|
||||
<string name="total_proportion_of_errors">异常总占比</string>
|
||||
<string name="total_errors_unit">%1$s 条</string>
|
||||
<string name="total_apps_unit">%1$s 个 (含系统应用)</string>
|
||||
<string name="generating_statistics">正在生成统计数据</string>
|
||||
</resources>
|
@@ -99,4 +99,13 @@
|
||||
<string name="show_errors_dialog">顯示錯誤對話框</string>
|
||||
<string name="show_errors_toast">顯示錯誤 Toast 提示</string>
|
||||
<string name="show_nothing">不顯示任何提示</string>
|
||||
<string name="app_errors_statistics">程式異常統計</string>
|
||||
<string name="total_errors">異常總數</string>
|
||||
<string name="total_apps">程式總數</string>
|
||||
<string name="most_errors_app">最多異常的程式</string>
|
||||
<string name="most_errors_type">最多異常的類型</string>
|
||||
<string name="total_proportion_of_errors">異常總佔比</string>
|
||||
<string name="total_errors_unit">%1$s 條</string>
|
||||
<string name="total_apps_unit">%1$s 個 (含系統程式)</string>
|
||||
<string name="generating_statistics">統計數據生成中</string>
|
||||
</resources>
|
@@ -99,4 +99,13 @@
|
||||
<string name="show_errors_dialog">顯示錯誤對話框</string>
|
||||
<string name="show_errors_toast">顯示錯誤 Toast 提示</string>
|
||||
<string name="show_nothing">不顯示任何提示</string>
|
||||
<string name="app_errors_statistics">程式異常統計</string>
|
||||
<string name="total_errors">異常總數</string>
|
||||
<string name="total_apps">程式總數</string>
|
||||
<string name="most_errors_app">最多異常的程式</string>
|
||||
<string name="most_errors_type">最多異常的類型</string>
|
||||
<string name="total_proportion_of_errors">異常總佔比</string>
|
||||
<string name="total_errors_unit">%1$s 條</string>
|
||||
<string name="total_apps_unit">%1$s 個 (含系統程式)</string>
|
||||
<string name="generating_statistics">統計數據生成中</string>
|
||||
</resources>
|
@@ -99,4 +99,13 @@
|
||||
<string name="show_errors_dialog">顯示錯誤對話框</string>
|
||||
<string name="show_errors_toast">顯示錯誤 Toast 提示</string>
|
||||
<string name="show_nothing">不顯示任何提示</string>
|
||||
<string name="app_errors_statistics">程式異常統計</string>
|
||||
<string name="total_errors">異常總數</string>
|
||||
<string name="total_apps">程式總數</string>
|
||||
<string name="most_errors_app">最多異常的程式</string>
|
||||
<string name="most_errors_type">最多異常的類型</string>
|
||||
<string name="total_proportion_of_errors">異常總佔比</string>
|
||||
<string name="total_errors_unit">%1$s 條</string>
|
||||
<string name="total_apps_unit">%1$s 個 (含系統程式)</string>
|
||||
<string name="generating_statistics">統計數據生成中</string>
|
||||
</resources>
|
@@ -99,4 +99,13 @@
|
||||
<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>
|
||||
<string name="app_errors_statistics">App errors statistics</string>
|
||||
<string name="total_errors">Total errors</string>
|
||||
<string name="total_apps">Total apps</string>
|
||||
<string name="most_errors_app">The most errors app</string>
|
||||
<string name="most_errors_type">The most errors type</string>
|
||||
<string name="total_proportion_of_errors">Total proportion of errors</string>
|
||||
<string name="total_errors_unit">%1$s</string>
|
||||
<string name="total_apps_unit">%1$s (including system apps)</string>
|
||||
<string name="generating_statistics">Generating statistics</string>
|
||||
</resources>
|
Reference in New Issue
Block a user