Added ability to save and view logs
This commit is contained in:
parent
b2b9caa4d3
commit
e14273642d
|
|
@ -2,6 +2,7 @@ apply from: "../android-configs/lib-config.gradle"
|
|||
|
||||
dependencies {
|
||||
implementation "androidx.recyclerview:recyclerview"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout"
|
||||
implementation "androidx.fragment:fragment-ktx"
|
||||
implementation project(path: ':logging')
|
||||
|
||||
|
|
@ -12,6 +13,12 @@ dependencies {
|
|||
}
|
||||
}
|
||||
|
||||
implementation("androidx.coordinatorlayout:coordinatorlayout") {
|
||||
version {
|
||||
require '1.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
implementation("androidx.fragment:fragment-ktx") {
|
||||
version {
|
||||
require '1.2.1'
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ apply from: "../android-configs/lib-config.gradle"
|
|||
|
||||
dependencies {
|
||||
implementation "androidx.annotation:annotation"
|
||||
|
||||
implementation "com.google.firebase:firebase-crashlytics"
|
||||
|
||||
implementation "androidx.recyclerview:recyclerview"
|
||||
implementation "androidx.constraintlayout:constraintlayout"
|
||||
|
||||
constraints {
|
||||
implementation("androidx.annotation:annotation") {
|
||||
version {
|
||||
|
|
@ -17,5 +19,17 @@ dependencies {
|
|||
require '17.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
implementation("androidx.recyclerview:recyclerview") {
|
||||
version {
|
||||
require '1.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
implementation("androidx.constraintlayout:constraintlayout"){
|
||||
version {
|
||||
require '2.2.0-alpha03'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,15 @@
|
|||
<manifest package="ru.touchin.roboswag.core.log" />
|
||||
<manifest
|
||||
package="ru.touchin.roboswag.core.log"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application>
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="ru.touchin.roboswag.core.log.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
package ru.touchin.roboswag.core.log_file
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import ru.touchin.roboswag.core.log.BuildConfig
|
||||
import ru.touchin.roboswag.core.log.R
|
||||
import ru.touchin.roboswag.core.log.databinding.DialogFragmentDebugLogsBinding
|
||||
import ru.touchin.roboswag.core.log_file.LogFileManager.Companion.getLogDirectory
|
||||
import java.io.File
|
||||
|
||||
class DebugLogsDialogFragment : DialogFragment() {
|
||||
|
||||
private val logItemsList: MutableList<String> = mutableListOf()
|
||||
private lateinit var binding: DialogFragmentDebugLogsBinding
|
||||
|
||||
override fun getTheme(): Int = R.style.DialogFullscreenTheme
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
binding = DialogFragmentDebugLogsBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
initSpinner()
|
||||
|
||||
binding.logsRecycler.layoutManager = LinearLayoutManager(requireContext())
|
||||
binding.logsRecycler.adapter = LogItemAdapter(requireContext(), logItemsList)
|
||||
|
||||
binding.shareBtn.setOnClickListener {
|
||||
val files = getLogDirectory(requireContext()).listFiles()
|
||||
|
||||
if (!files.isNullOrEmpty()) {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
requireContext(),
|
||||
BuildConfig.LIBRARY_PACKAGE_NAME + LogFileManager.fileProviderName,
|
||||
files.first()
|
||||
)
|
||||
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.setType("*/*")
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri)
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initSpinner() {
|
||||
val priorityTitle = LogFileManager.Priority.values().map { it.title }
|
||||
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, priorityTitle)
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line)
|
||||
|
||||
binding.priorityFilter.adapter = adapter;
|
||||
binding.priorityFilter.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
||||
val priority = LogFileManager.Priority.values()[position]
|
||||
LogFileManager.saveLogcatToFile(requireContext(), priority.tag)
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>) {}
|
||||
}
|
||||
binding.updateBtn.setOnClickListener { updateRecycler() }
|
||||
}
|
||||
|
||||
private fun updateRecycler() {
|
||||
logItemsList.clear()
|
||||
val files = getLogDirectory(requireContext()).listFiles()
|
||||
if (!files.isNullOrEmpty()) {
|
||||
File(files.firstOrNull()?.getAbsolutePath() ?: "")
|
||||
.useLines { lines -> lines.forEach { logItemsList.add(it) } }
|
||||
}
|
||||
binding.logsRecycler.adapter?.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package ru.touchin.roboswag.core.log_file
|
||||
|
||||
import android.content.Context
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class LogFileManager {
|
||||
|
||||
enum class Priority(val title: String, val tag: String) {
|
||||
VERBOSE("VERBOSE", "*:V"),
|
||||
DEBUG("DEBUG", "*:D"),
|
||||
INFO("INFO", "*:I"),
|
||||
WARNING("WARNING", "*:W"),
|
||||
ERROR("ERROR", "*:E"),
|
||||
ASSERT("ASSERT", "*:A")
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val logDirecroryName = "log"
|
||||
const val fileProviderName = ".fileprovider"
|
||||
|
||||
fun getLogDirectory(context: Context) : File{
|
||||
val appDirectory = context.getExternalFilesDir(null)
|
||||
return File(appDirectory.toString() + "/$logDirecroryName")
|
||||
}
|
||||
|
||||
fun saveLogcatToFile(context: Context, priorityTag: String) {
|
||||
val logDirectory = initLogDirectory(context)
|
||||
|
||||
val sdf = SimpleDateFormat("yyyy-MM-dd'T'HH_mm_ss_SSS", Locale.getDefault())
|
||||
val logFile = File(logDirectory, "logcat_${sdf.format(Date())}.txt")
|
||||
|
||||
try {
|
||||
Runtime.getRuntime().exec("logcat ${priorityTag} -f $logFile")
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initLogDirectory(context: Context): File {
|
||||
val appDirectory = context.getExternalFilesDir(null)
|
||||
if (!appDirectory!!.exists()) {
|
||||
appDirectory.mkdir()
|
||||
}
|
||||
|
||||
val logDirectory = File(appDirectory.toString() + "/$logDirecroryName")
|
||||
if (!logDirectory.exists()) {
|
||||
logDirectory.mkdir()
|
||||
}
|
||||
|
||||
for (file in logDirectory.listFiles()) {
|
||||
file.delete()
|
||||
}
|
||||
return logDirectory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package ru.touchin.roboswag.core.log_file
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ru.touchin.roboswag.core.log.databinding.LogItemBinding
|
||||
|
||||
class LogItemAdapter(private val context: Context, private val logItemList:MutableList<String>)
|
||||
: RecyclerView.Adapter<LogItemAdapter.LogItemViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LogItemViewHolder {
|
||||
val binding = LogItemBinding.inflate(LayoutInflater.from(context),parent,false)
|
||||
return LogItemViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: LogItemViewHolder, position: Int) {
|
||||
val foodItem = logItemList[position]
|
||||
holder.bind(foodItem)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return logItemList.size
|
||||
}
|
||||
|
||||
class LogItemViewHolder(logItemLayoutBinding: LogItemBinding)
|
||||
: RecyclerView.ViewHolder(logItemLayoutBinding.root){
|
||||
|
||||
private val binding = logItemLayoutBinding
|
||||
|
||||
fun bind(logItem: String){
|
||||
binding.logDescription.text = logItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:paddingVertical="10dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/priority_filter"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/update_btn"/>
|
||||
|
||||
<Button
|
||||
android:id = "@+id/update_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="update"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/logs_recycler"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/logs_recycler"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:scrollbarAlwaysDrawVerticalTrack="true"
|
||||
android:scrollbars="vertical"
|
||||
android:layout_marginBottom="20dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/priority_filter"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
tools:listitem="@layout/log_item"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<Button
|
||||
android:id = "@+id/share_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="share"
|
||||
app:layout_constraintTop_toBottomOf="@id/logs_recycler"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?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="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/log_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:fontFamily="sans-serif"
|
||||
android:textIsSelectable="false"
|
||||
android:maxLines="30"
|
||||
android:textSize="17sp"
|
||||
tools:maxLines="5"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:background="@android:color/black" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="DialogFullscreenTheme">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths>
|
||||
<external-path
|
||||
name="external_files"
|
||||
path="." />
|
||||
</paths>
|
||||
Loading…
Reference in New Issue