Refactor logcat handling to use LogcatViewModel
This commit is contained in:
1 parent
bb1f677d45
commit
41b0983582
3 files changed
+103
-85
No files matched your search
@@ -2,37 +2,34 @@ package com.v2ray.ang.ui
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
import com.v2ray.ang.AppConfig
|
|
||||||
import com.v2ray.ang.AppConfig.ANG_PACKAGE
|
|
||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.databinding.ActivityLogcatBinding
|
import com.v2ray.ang.databinding.ActivityLogcatBinding
|
||||||
|
import com.v2ray.ang.extension.toast
|
||||||
import com.v2ray.ang.extension.toastSuccess
|
import com.v2ray.ang.extension.toastSuccess
|
||||||
import com.v2ray.ang.util.Utils
|
import com.v2ray.ang.util.Utils
|
||||||
|
import com.v2ray.ang.viewmodel.LogcatViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
|
|
||||||
class LogcatActivity : BaseActivity(), SwipeRefreshLayout.OnRefreshListener {
|
class LogcatActivity : BaseActivity(), SwipeRefreshLayout.OnRefreshListener {
|
||||||
private val binding by lazy { ActivityLogcatBinding.inflate(layoutInflater) }
|
private val binding by lazy { ActivityLogcatBinding.inflate(layoutInflater) }
|
||||||
|
private val viewModel: LogcatViewModel by viewModels()
|
||||||
private var logsetsAll: MutableList<String> = mutableListOf()
|
private lateinit var adapter: LogcatRecyclerAdapter
|
||||||
var logsets: MutableList<String> = mutableListOf()
|
|
||||||
private val adapter by lazy { LogcatRecyclerAdapter(this) }
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
//setContentView(binding.root)
|
|
||||||
setContentViewWithToolbar(binding.root, showHomeAsUp = true, title = getString(R.string.title_logcat))
|
setContentViewWithToolbar(binding.root, showHomeAsUp = true, title = getString(R.string.title_logcat))
|
||||||
|
|
||||||
|
adapter = LogcatRecyclerAdapter(viewModel, ::onLogLongClick)
|
||||||
|
|
||||||
binding.recyclerView.setHasFixedSize(true)
|
binding.recyclerView.setHasFixedSize(true)
|
||||||
binding.recyclerView.layoutManager = LinearLayoutManager(this)
|
binding.recyclerView.layoutManager = LinearLayoutManager(this)
|
||||||
addCustomDividerToRecyclerView(binding.recyclerView, this, R.drawable.custom_divider)
|
addCustomDividerToRecyclerView(binding.recyclerView, this, R.drawable.custom_divider)
|
||||||
@@ -40,58 +37,12 @@ class LogcatActivity : BaseActivity(), SwipeRefreshLayout.OnRefreshListener {
|
|||||||
|
|
||||||
binding.refreshLayout.setOnRefreshListener(this)
|
binding.refreshLayout.setOnRefreshListener(this)
|
||||||
|
|
||||||
logsets.add(getString(R.string.pull_down_to_refresh))
|
toast(getString(R.string.pull_down_to_refresh))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLogcat() {
|
private fun onLogLongClick(log: String): Boolean {
|
||||||
|
Utils.setClipboard(this, log)
|
||||||
try {
|
return true
|
||||||
binding.refreshLayout.isRefreshing = true
|
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.Default) {
|
|
||||||
val lst = LinkedHashSet<String>()
|
|
||||||
lst.add("logcat")
|
|
||||||
lst.add("-d")
|
|
||||||
lst.add("-v")
|
|
||||||
lst.add("time")
|
|
||||||
lst.add("-s")
|
|
||||||
lst.add("GoLog,${ANG_PACKAGE},AndroidRuntime,System.err")
|
|
||||||
val process = withContext(Dispatchers.IO) {
|
|
||||||
Runtime.getRuntime().exec(lst.toTypedArray())
|
|
||||||
}
|
|
||||||
|
|
||||||
val allText = process.inputStream.bufferedReader().use { it.readLines() }.reversed()
|
|
||||||
launch(Dispatchers.Main) {
|
|
||||||
logsetsAll = allText.toMutableList()
|
|
||||||
logsets = allText.toMutableList()
|
|
||||||
refreshData()
|
|
||||||
binding.refreshLayout.isRefreshing = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.e(AppConfig.TAG, "Failed to get logcat", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearLogcat() {
|
|
||||||
try {
|
|
||||||
lifecycleScope.launch(Dispatchers.Default) {
|
|
||||||
val lst = LinkedHashSet<String>()
|
|
||||||
lst.add("logcat")
|
|
||||||
lst.add("-c")
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
val process = Runtime.getRuntime().exec(lst.toTypedArray())
|
|
||||||
process.waitFor()
|
|
||||||
}
|
|
||||||
launch(Dispatchers.Main) {
|
|
||||||
logsetsAll.clear()
|
|
||||||
logsets.clear()
|
|
||||||
refreshData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.e(AppConfig.TAG, "Failed to clear logcat", e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
@@ -104,12 +55,14 @@ class LogcatActivity : BaseActivity(), SwipeRefreshLayout.OnRefreshListener {
|
|||||||
override fun onQueryTextSubmit(query: String?): Boolean = false
|
override fun onQueryTextSubmit(query: String?): Boolean = false
|
||||||
|
|
||||||
override fun onQueryTextChange(newText: String?): Boolean {
|
override fun onQueryTextChange(newText: String?): Boolean {
|
||||||
filterLogs(newText)
|
viewModel.filter(newText)
|
||||||
|
refreshData()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
searchView.setOnCloseListener {
|
searchView.setOnCloseListener {
|
||||||
filterLogs("")
|
viewModel.filter("")
|
||||||
|
refreshData()
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,33 +72,33 @@ class LogcatActivity : BaseActivity(), SwipeRefreshLayout.OnRefreshListener {
|
|||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
|
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
|
||||||
R.id.copy_all -> {
|
R.id.copy_all -> {
|
||||||
Utils.setClipboard(this, logsets.joinToString("\n"))
|
val all = viewModel.getAll().joinToString("\n")
|
||||||
|
Utils.setClipboard(this, all)
|
||||||
toastSuccess(R.string.toast_success)
|
toastSuccess(R.string.toast_success)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.clear_all -> {
|
R.id.clear_all -> {
|
||||||
clearLogcat()
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
viewModel.clearLogcat()
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
refreshData()
|
||||||
|
}
|
||||||
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filterLogs(content: String?): Boolean {
|
|
||||||
val key = content?.trim()
|
|
||||||
logsets = if (key.isNullOrEmpty()) {
|
|
||||||
logsetsAll.toMutableList()
|
|
||||||
} else {
|
|
||||||
logsetsAll.filter { it.contains(key) }.toMutableList()
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshData()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRefresh() {
|
override fun onRefresh() {
|
||||||
getLogcat()
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
viewModel.loadLogcat()
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.refreshLayout.isRefreshing = false
|
||||||
|
refreshData()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
|||||||
@@ -6,17 +6,20 @@ import android.view.ViewGroup
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
import com.v2ray.ang.databinding.ItemRecyclerLogcatBinding
|
import com.v2ray.ang.databinding.ItemRecyclerLogcatBinding
|
||||||
import com.v2ray.ang.util.Utils
|
import com.v2ray.ang.viewmodel.LogcatViewModel
|
||||||
|
|
||||||
class LogcatRecyclerAdapter(val activity: LogcatActivity) : RecyclerView.Adapter<LogcatRecyclerAdapter.MainViewHolder>() {
|
class LogcatRecyclerAdapter(
|
||||||
private var mActivity: LogcatActivity = activity
|
private val viewModel: LogcatViewModel,
|
||||||
|
private val onLongClick: ((String) -> Boolean)? = null
|
||||||
|
) : RecyclerView.Adapter<LogcatRecyclerAdapter.MainViewHolder>() {
|
||||||
|
|
||||||
|
override fun getItemCount() = viewModel.getAll().size
|
||||||
override fun getItemCount() = mActivity.logsets.size
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
|
||||||
try {
|
try {
|
||||||
val log = mActivity.logsets[position]
|
val logs = viewModel.getAll()
|
||||||
|
val log = logs[position]
|
||||||
|
|
||||||
if (log.isEmpty()) {
|
if (log.isEmpty()) {
|
||||||
holder.itemSubSettingBinding.logTag.text = ""
|
holder.itemSubSettingBinding.logTag.text = ""
|
||||||
holder.itemSubSettingBinding.logContent.text = ""
|
holder.itemSubSettingBinding.logContent.text = ""
|
||||||
@@ -27,8 +30,7 @@ class LogcatRecyclerAdapter(val activity: LogcatActivity) : RecyclerView.Adapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
holder.itemView.setOnLongClickListener {
|
holder.itemView.setOnLongClickListener {
|
||||||
Utils.setClipboard(mActivity, log)
|
onLongClick?.invoke(log) ?: false
|
||||||
true
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(AppConfig.TAG, "Error binding log view data", e)
|
Log.e(AppConfig.TAG, "Error binding log view data", e)
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.v2ray.ang.viewmodel
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.v2ray.ang.AppConfig
|
||||||
|
import com.v2ray.ang.AppConfig.ANG_PACKAGE
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.LinkedHashSet
|
||||||
|
|
||||||
|
class LogcatViewModel : ViewModel() {
|
||||||
|
private val logsetsAll: MutableList<String> = mutableListOf()
|
||||||
|
private var filteredLogs: List<String> = emptyList()
|
||||||
|
private var currentFilter: String = ""
|
||||||
|
|
||||||
|
fun getAll(): List<String> = filteredLogs
|
||||||
|
|
||||||
|
fun loadLogcat() {
|
||||||
|
try {
|
||||||
|
val lst = LinkedHashSet<String>()
|
||||||
|
lst.add("logcat")
|
||||||
|
lst.add("-d")
|
||||||
|
lst.add("-v")
|
||||||
|
lst.add("time")
|
||||||
|
lst.add("-s")
|
||||||
|
lst.add("GoLog,${ANG_PACKAGE},AndroidRuntime,System.err")
|
||||||
|
val process = Runtime.getRuntime().exec(lst.toTypedArray())
|
||||||
|
val allText = process.inputStream.bufferedReader().use { it.readLines() }.reversed()
|
||||||
|
|
||||||
|
logsetsAll.clear()
|
||||||
|
logsetsAll.addAll(allText)
|
||||||
|
applyFilter()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
android.util.Log.e(AppConfig.TAG, "Failed to get logcat", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearLogcat() {
|
||||||
|
try {
|
||||||
|
val lst = LinkedHashSet<String>()
|
||||||
|
lst.add("logcat")
|
||||||
|
lst.add("-c")
|
||||||
|
val process = Runtime.getRuntime().exec(lst.toTypedArray())
|
||||||
|
process.waitFor()
|
||||||
|
|
||||||
|
logsetsAll.clear()
|
||||||
|
filteredLogs = emptyList()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
android.util.Log.e(AppConfig.TAG, "Failed to clear logcat", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun filter(content: String?) {
|
||||||
|
currentFilter = content?.trim() ?: ""
|
||||||
|
applyFilter()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun applyFilter() {
|
||||||
|
filteredLogs = if (currentFilter.isEmpty()) {
|
||||||
|
logsetsAll.toList()
|
||||||
|
} else {
|
||||||
|
logsetsAll.filter { it.contains(currentFilter) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user