mirror of
https://github.com/KitsunePie/AppErrorsTracking.git
synced 2025-09-04 02:05:16 +08:00
Added debug log viewing function
This commit is contained in:
@@ -63,6 +63,11 @@
|
|||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:screenOrientation="behind" />
|
android:screenOrientation="behind" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".ui.activity.debug.LoggerActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:screenOrientation="behind" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.activity.errors.AppErrorsRecordActivity"
|
android:name=".ui.activity.errors.AppErrorsRecordActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
@@ -33,7 +33,10 @@ import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
|
|||||||
class HookEntry : IYukiHookXposedInit {
|
class HookEntry : IYukiHookXposedInit {
|
||||||
|
|
||||||
override fun onInit() = configs {
|
override fun onInit() = configs {
|
||||||
debugLog { tag = "AppErrorsTracking" }
|
debugLog {
|
||||||
|
tag = "AppErrorsTracking"
|
||||||
|
isRecord = true
|
||||||
|
}
|
||||||
isDebug = false
|
isDebug = false
|
||||||
isEnableModulePrefsCache = false
|
isEnableModulePrefsCache = false
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* 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/10/4.
|
||||||
|
*/
|
||||||
|
@file:Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
|
||||||
|
|
||||||
|
package com.fankes.apperrorstracking.ui.activity.debug
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.view.ContextMenu
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.AdapterView
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.fankes.apperrorstracking.R
|
||||||
|
import com.fankes.apperrorstracking.databinding.ActivitiyLoggerBinding
|
||||||
|
import com.fankes.apperrorstracking.databinding.AdapterLoggerBinding
|
||||||
|
import com.fankes.apperrorstracking.databinding.DiaLoggerFilterBinding
|
||||||
|
import com.fankes.apperrorstracking.locale.LocaleString
|
||||||
|
import com.fankes.apperrorstracking.ui.activity.base.BaseActivity
|
||||||
|
import com.fankes.apperrorstracking.utils.factory.*
|
||||||
|
import com.fankes.apperrorstracking.utils.tool.FrameworkTool
|
||||||
|
import com.highcapable.yukihookapi.hook.factory.current
|
||||||
|
import com.highcapable.yukihookapi.hook.factory.dataChannel
|
||||||
|
import com.highcapable.yukihookapi.hook.log.YukiHookLogger
|
||||||
|
import com.highcapable.yukihookapi.hook.log.YukiLoggerData
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.PrintStream
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class LoggerActivity : BaseActivity<ActivitiyLoggerBinding>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/** 请求保存文件回调标识 */
|
||||||
|
private const val WRITE_REQUEST_CODE = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 回调适配器改变 */
|
||||||
|
private var onChanged: (() -> Unit)? = null
|
||||||
|
|
||||||
|
/** 过滤条件 */
|
||||||
|
private var filters = arrayListOf("D", "I", "W", "E")
|
||||||
|
|
||||||
|
/** 全部的调试日志数据 */
|
||||||
|
private val listData = ArrayList<YukiLoggerData>()
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
binding.titleBackIcon.setOnClickListener { finish() }
|
||||||
|
binding.refreshIcon.setOnClickListener { refreshData() }
|
||||||
|
binding.filterIcon.setOnClickListener {
|
||||||
|
showDialog<DiaLoggerFilterBinding> {
|
||||||
|
title = LocaleString.filterByCondition
|
||||||
|
binding.configCheck0.isChecked = filters.any { it == "D" }
|
||||||
|
binding.configCheck1.isChecked = filters.any { it == "I" }
|
||||||
|
binding.configCheck2.isChecked = filters.any { it == "W" }
|
||||||
|
binding.configCheck3.isChecked = filters.any { it == "E" }
|
||||||
|
confirmButton {
|
||||||
|
filters.clear()
|
||||||
|
if (binding.configCheck0.isChecked) filters.add("D")
|
||||||
|
if (binding.configCheck1.isChecked) filters.add("I")
|
||||||
|
if (binding.configCheck2.isChecked) filters.add("W")
|
||||||
|
if (binding.configCheck3.isChecked) filters.add("E")
|
||||||
|
refreshData()
|
||||||
|
}
|
||||||
|
cancelButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.exportAllIcon.setOnClickListener {
|
||||||
|
runCatching {
|
||||||
|
startActivityForResult(Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
|
||||||
|
addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
type = "*/application"
|
||||||
|
putExtra(Intent.EXTRA_TITLE, "app_errors_tracking_${System.currentTimeMillis().toUtcTime()}.log")
|
||||||
|
}, WRITE_REQUEST_CODE)
|
||||||
|
}.onFailure { toast(msg = "Start Android SAF failed") }
|
||||||
|
}
|
||||||
|
/** 设置列表元素和 Adapter */
|
||||||
|
binding.listView.apply {
|
||||||
|
bindAdapter {
|
||||||
|
onBindDatas { listData }
|
||||||
|
onBindViews<AdapterLoggerBinding> { binding, position ->
|
||||||
|
listData[position].also { bean ->
|
||||||
|
binding.priorityText.apply {
|
||||||
|
text = bean.priority
|
||||||
|
setBackgroundResource(
|
||||||
|
when (bean.priority) {
|
||||||
|
"D" -> R.drawable.bg_logger_d_round
|
||||||
|
"I" -> R.drawable.bg_logger_i_round
|
||||||
|
"W" -> R.drawable.bg_logger_w_round
|
||||||
|
"E" -> R.drawable.bg_logger_e_round
|
||||||
|
else -> R.drawable.bg_logger_d_round
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
binding.messageText.text = bean.msg.format()
|
||||||
|
binding.timeText.text = bean.timestamp.format()
|
||||||
|
binding.throwableText.isVisible = bean.throwable != null
|
||||||
|
binding.throwableText.text = bean.throwable?.toStackTrace() ?: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.apply { onChanged = { notifyDataSetChanged() } }
|
||||||
|
registerForContextMenu(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新列表数据 */
|
||||||
|
private fun refreshData() {
|
||||||
|
dataChannel(FrameworkTool.SYSTEM_FRAMEWORK_NAME).obtainLoggerInMemoryData {
|
||||||
|
listData.clear()
|
||||||
|
it.takeIf { e -> e.isNotEmpty() }?.reversed()?.filter { filters.any { e -> it.priority == e } }?.forEach { e -> listData.add(e) }
|
||||||
|
onChanged?.invoke()
|
||||||
|
binding.listView.post { binding.listView.setSelection(0) }
|
||||||
|
binding.exportAllIcon.isVisible = listData.isNotEmpty()
|
||||||
|
binding.listView.isVisible = listData.isNotEmpty()
|
||||||
|
binding.listNoDataView.isVisible = listData.isEmpty()
|
||||||
|
binding.listNoDataView.text = if (filters.size < 4) LocaleString.noListResult else LocaleString.noListData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前所有日志写出文件的格式
|
||||||
|
*
|
||||||
|
* 复制自 [YukiHookLogger.contents]
|
||||||
|
* @return [String]
|
||||||
|
*/
|
||||||
|
private val loggerContents: String
|
||||||
|
get() {
|
||||||
|
var content = ""
|
||||||
|
listData.takeIf { it.isNotEmpty() }?.forEach {
|
||||||
|
val head = "${it.time} ------ "
|
||||||
|
content += "$head$it\n"
|
||||||
|
it.throwable?.also { e ->
|
||||||
|
content += "${head}Dump stack trace for \"${e.current().name}\":\n"
|
||||||
|
content += e.toStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化为本地时间格式
|
||||||
|
* @return [String]
|
||||||
|
*/
|
||||||
|
private fun Long.format() = SimpleDateFormat.getDateTimeInstance().format(Date(this))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化消息字符串样式
|
||||||
|
* @return [String]
|
||||||
|
*/
|
||||||
|
private fun String.format() = replace(oldValue = "--", newValue = "\n--")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取完整的异常堆栈内容
|
||||||
|
* @return [String]
|
||||||
|
*/
|
||||||
|
private fun Throwable.toStackTrace() = ByteArrayOutputStream().also { printStackTrace(PrintStream(it)) }.toString().trim()
|
||||||
|
|
||||||
|
override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) {
|
||||||
|
menuInflater.inflate(R.menu.menu_logger_action, menu)
|
||||||
|
super.onCreateContextMenu(menu, v, menuInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onContextItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (item.menuInfo is AdapterView.AdapterContextMenuInfo)
|
||||||
|
(item.menuInfo as? AdapterView.AdapterContextMenuInfo?)?.also {
|
||||||
|
if (item.itemId == R.id.logger_copy)
|
||||||
|
copyToClipboard(listData[it.position].let { e -> e.toString() + (e.throwable?.toStackTrace()?.let { t -> "\n$t" } ?: "") })
|
||||||
|
}
|
||||||
|
return super.onContextItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
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(loggerContents.toByteArray()) }?.close()
|
||||||
|
toast(LocaleString.exportAllLogsSuccess)
|
||||||
|
} ?: toast(LocaleString.exportAllLogsFail)
|
||||||
|
}.onFailure { toast(LocaleString.exportAllLogsFail) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
/** 执行更新 */
|
||||||
|
refreshData()
|
||||||
|
}
|
||||||
|
}
|
@@ -32,6 +32,7 @@ import com.fankes.apperrorstracking.data.ConfigData.bind
|
|||||||
import com.fankes.apperrorstracking.databinding.ActivityMainBinding
|
import com.fankes.apperrorstracking.databinding.ActivityMainBinding
|
||||||
import com.fankes.apperrorstracking.locale.LocaleString
|
import com.fankes.apperrorstracking.locale.LocaleString
|
||||||
import com.fankes.apperrorstracking.ui.activity.base.BaseActivity
|
import com.fankes.apperrorstracking.ui.activity.base.BaseActivity
|
||||||
|
import com.fankes.apperrorstracking.ui.activity.debug.LoggerActivity
|
||||||
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsMutedActivity
|
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsMutedActivity
|
||||||
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsRecordActivity
|
import com.fankes.apperrorstracking.ui.activity.errors.AppErrorsRecordActivity
|
||||||
import com.fankes.apperrorstracking.utils.factory.*
|
import com.fankes.apperrorstracking.utils.factory.*
|
||||||
@@ -78,6 +79,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
|||||||
/** 功能管理按钮点击事件 */
|
/** 功能管理按钮点击事件 */
|
||||||
binding.viewErrorsRecordButton.setOnClickListener { whenActivated { navigate<AppErrorsRecordActivity>() } }
|
binding.viewErrorsRecordButton.setOnClickListener { whenActivated { navigate<AppErrorsRecordActivity>() } }
|
||||||
binding.viewMutedErrorsAppsButton.setOnClickListener { whenActivated { navigate<AppErrorsMutedActivity>() } }
|
binding.viewMutedErrorsAppsButton.setOnClickListener { whenActivated { navigate<AppErrorsMutedActivity>() } }
|
||||||
|
/** 调试日志按钮点击事件 */
|
||||||
|
binding.titleLoggerIcon.setOnClickListener { navigate<LoggerActivity>() }
|
||||||
/** 重启按钮点击事件 */
|
/** 重启按钮点击事件 */
|
||||||
binding.titleRestartIcon.setOnClickListener { FrameworkTool.restartSystem(context = this) }
|
binding.titleRestartIcon.setOnClickListener { FrameworkTool.restartSystem(context = this) }
|
||||||
/** 项目地址按钮点击事件 */
|
/** 项目地址按钮点击事件 */
|
||||||
|
@@ -43,7 +43,7 @@ import com.highcapable.yukihookapi.hook.xposed.channel.data.ChannelData
|
|||||||
object FrameworkTool {
|
object FrameworkTool {
|
||||||
|
|
||||||
/** 系统框架包名 */
|
/** 系统框架包名 */
|
||||||
private const val SYSTEM_FRAMEWORK_NAME = "android"
|
const val SYSTEM_FRAMEWORK_NAME = "android"
|
||||||
|
|
||||||
private const val CALL_APP_ERRORS_DATA_GET = "call_app_errors_data_get"
|
private const val CALL_APP_ERRORS_DATA_GET = "call_app_errors_data_get"
|
||||||
private const val CALL_MUTED_ERRORS_APP_DATA_GET = "call_muted_app_errors_data_get"
|
private const val CALL_MUTED_ERRORS_APP_DATA_GET = "call_muted_app_errors_data_get"
|
||||||
|
8
app/src/main/res/drawable/bg_logger_d_round.xml
Normal file
8
app/src/main/res/drawable/bg_logger_d_round.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="#565656" />
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="10dp"
|
||||||
|
android:topLeftRadius="10dp" />
|
||||||
|
</shape>
|
8
app/src/main/res/drawable/bg_logger_e_round.xml
Normal file
8
app/src/main/res/drawable/bg_logger_e_round.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="#E53935" />
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="10dp"
|
||||||
|
android:topLeftRadius="10dp" />
|
||||||
|
</shape>
|
8
app/src/main/res/drawable/bg_logger_i_round.xml
Normal file
8
app/src/main/res/drawable/bg_logger_i_round.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="#3974CB" />
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="10dp"
|
||||||
|
android:topLeftRadius="10dp" />
|
||||||
|
</shape>
|
8
app/src/main/res/drawable/bg_logger_w_round.xml
Normal file
8
app/src/main/res/drawable/bg_logger_w_round.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="#FB8C00" />
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="10dp"
|
||||||
|
android:topLeftRadius="10dp" />
|
||||||
|
</shape>
|
9
app/src/main/res/drawable/ic_refresh.xml
Normal file
9
app/src/main/res/drawable/ic_refresh.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:pathData="M712.9,295.1c-120.7,-110.7 -308.3,-102.6 -419,18.1 -87.4,95.3 -103,236.3 -38.5,348.4 82,141.7 263.2,190.3 405,108.4 66.8,-38.6 116,-101.7 137,-176 8.9,-31.5 41.7,-49.8 73.2,-40.9 31.5,8.9 49.8,41.7 40.9,73.2C849.1,846.8 619.8,975 399.2,912.6 178.7,850.2 50.5,620.9 112.9,400.3S404.6,51.6 625.2,114c64.2,18.2 123.1,51.5 171.6,97.3l79.7,-79.7c11.6,-11.6 30.3,-11.6 41.9,-0.1 5.6,5.6 8.7,13.1 8.7,21V407c0,16.4 -13.3,29.6 -29.6,29.6H642.9c-16.4,0 -29.6,-13.3 -29.6,-29.7 0,-7.8 3.1,-15.3 8.6,-20.9l91,-90.9z"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
</vector>
|
129
app/src/main/res/layout/activitiy_logger.xml
Normal file
129
app/src/main/res/layout/activitiy_logger.xml
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<?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.debug.LoggerActivity"
|
||||||
|
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="@drawable/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/debug_log"
|
||||||
|
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:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/this_contents_clear_when_restarts_tip"
|
||||||
|
android:textColor="@color/colorTextDark"
|
||||||
|
android:textSize="11.5sp"
|
||||||
|
android:tooltipText="@string/this_contents_clear_when_restarts_tip" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
|
android:gravity="center|end"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
|
android:id="@+id/refresh_icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:src="@drawable/ic_refresh"
|
||||||
|
android:tint="@color/colorTextGray"
|
||||||
|
android:tooltipText="@string/refresh" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
|
android:id="@+id/filter_icon"
|
||||||
|
android:layout_width="22dp"
|
||||||
|
android:layout_height="22dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:src="@drawable/ic_filter"
|
||||||
|
android:tint="@color/colorTextGray"
|
||||||
|
android:tooltipText="@string/filter_by_condition" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
|
android:id="@+id/export_all_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_all" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
|
||||||
|
<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_data"
|
||||||
|
android:textColor="@color/colorTextDark"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/list_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:divider="@color/trans"
|
||||||
|
android:dividerHeight="5dp"
|
||||||
|
android:fadingEdgeLength="10dp"
|
||||||
|
android:listSelector="@color/trans"
|
||||||
|
android:paddingLeft="15dp"
|
||||||
|
android:paddingRight="15dp"
|
||||||
|
android:paddingBottom="5dp"
|
||||||
|
android:requiresFadingEdge="vertical"
|
||||||
|
android:scrollbars="none"
|
||||||
|
android:visibility="gone" />
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
@@ -29,6 +29,18 @@
|
|||||||
android:textSize="25sp"
|
android:textSize="25sp"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
|
android:id="@+id/title_logger_icon"
|
||||||
|
style="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:layout_width="25dp"
|
||||||
|
android:layout_height="25dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:alpha="0.85"
|
||||||
|
android:padding="0.5dp"
|
||||||
|
android:src="@drawable/ic_debug"
|
||||||
|
android:tint="@color/colorTextGray"
|
||||||
|
android:tooltipText="@string/debug_log" />
|
||||||
|
|
||||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
android:id="@+id/title_restart_icon"
|
android:id="@+id/title_restart_icon"
|
||||||
style="?android:attr/selectableItemBackgroundBorderless"
|
style="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
53
app/src/main/res/layout/adapter_logger.xml
Normal file
53
app/src/main/res/layout/adapter_logger.xml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_permotion_round"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/priority_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:typeface="monospace" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center|start"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/message_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:lineSpacingExtra="3dp"
|
||||||
|
android:textColor="@color/colorTextGray"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/time_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="@color/colorTextDark"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/throwable_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:lineSpacingExtra="3dp"
|
||||||
|
android:textColor="#EF5350"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
54
app/src/main/res/layout/dia_logger_filter.xml
Normal file
54
app/src/main/res/layout/dia_logger_filter.xml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?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="HardcodedText">
|
||||||
|
|
||||||
|
<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_logger_how_to_show_tip"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/config_check_0"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="DEBUG"
|
||||||
|
app:buttonTint="@color/colorPrimaryAccent" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/config_check_1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="INFO"
|
||||||
|
app:buttonTint="@color/colorPrimaryAccent" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/config_check_2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="WARN"
|
||||||
|
app:buttonTint="@color/colorPrimaryAccent" />
|
||||||
|
|
||||||
|
<com.google.android.material.checkbox.MaterialCheckBox
|
||||||
|
android:id="@+id/config_check_3"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="ERROR"
|
||||||
|
app:buttonTint="@color/colorPrimaryAccent" />
|
||||||
|
</LinearLayout>
|
6
app/src/main/res/menu/menu_logger_action.xml
Normal file
6
app/src/main/res/menu/menu_logger_action.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:id="@+id/logger_copy"
|
||||||
|
android:title="@string/copy" />
|
||||||
|
</menu>
|
Reference in New Issue
Block a user