forked from geode-sdk/android-launcher
filter by crash buffer option
This commit is contained in:
4 files changed
+83
-25
No files matched your search
@@ -24,6 +24,7 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.Check
|
||||||
import androidx.compose.material.icons.filled.MoreVert
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
import androidx.compose.material.icons.filled.Share
|
import androidx.compose.material.icons.filled.Share
|
||||||
import androidx.compose.material3.Divider
|
import androidx.compose.material3.Divider
|
||||||
@@ -219,27 +220,25 @@ fun ApplicationLogsScreen(
|
|||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
IconButton(onClick = {
|
IconButton(onClick = {
|
||||||
if (!logLines.isEmpty()) {
|
coroutineScope.launch {
|
||||||
coroutineScope.launch {
|
val data = logViewModel.getLogData()
|
||||||
val data = logViewModel.getLogData()
|
|
||||||
|
|
||||||
val sendIntent = Intent(Intent.ACTION_SEND).apply {
|
val sendIntent = Intent(Intent.ACTION_SEND).apply {
|
||||||
putExtra(Intent.EXTRA_TEXT, data)
|
putExtra(Intent.EXTRA_TEXT, data)
|
||||||
type = "text/plain"
|
type = "text/plain"
|
||||||
}
|
|
||||||
|
|
||||||
val shareIntent = Intent.createChooser(sendIntent, null)
|
|
||||||
|
|
||||||
context.startActivity(shareIntent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val shareIntent = Intent.createChooser(sendIntent, null)
|
||||||
|
|
||||||
|
context.startActivity(shareIntent)
|
||||||
}
|
}
|
||||||
}) {
|
}, enabled = !logLines.isEmpty()) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Filled.Share,
|
Icons.Filled.Share,
|
||||||
contentDescription = stringResource(R.string.application_logs_share)
|
contentDescription = stringResource(R.string.application_logs_share)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
IconButton(onClick = { showMoreOptions = !showMoreOptions }) {
|
IconButton(onClick = { showMoreOptions = !showMoreOptions },) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Filled.MoreVert,
|
Icons.Filled.MoreVert,
|
||||||
contentDescription = stringResource(R.string.application_logs_more)
|
contentDescription = stringResource(R.string.application_logs_more)
|
||||||
@@ -253,32 +252,54 @@ fun ApplicationLogsScreen(
|
|||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
Icon(
|
Icon(
|
||||||
painterResource(R.drawable.icon_save),
|
painterResource(R.drawable.icon_filter_list),
|
||||||
contentDescription = stringResource(R.string.application_logs_export)
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
text = {
|
trailingIcon = {
|
||||||
Text(stringResource(R.string.application_logs_export))
|
if (logViewModel.filterCrashes) {
|
||||||
}, onClick = {
|
Icon(
|
||||||
if (!logLines.isEmpty()) {
|
Icons.Filled.Check,
|
||||||
saveLauncher.launch(context.getString(R.string.application_logs_default_filename))
|
contentDescription = stringResource(R.string.application_logs_crash_only_enabled_alt)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(stringResource(R.string.application_logs_crash_only))
|
||||||
|
}, onClick = {
|
||||||
|
logViewModel.toggleCrashBuffer()
|
||||||
showMoreOptions = false
|
showMoreOptions = false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
DropdownMenuItem(
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.icon_save),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(stringResource(R.string.application_logs_export))
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
saveLauncher.launch(context.getString(R.string.application_logs_default_filename))
|
||||||
|
showMoreOptions = false
|
||||||
|
},
|
||||||
|
enabled = !logLines.isEmpty()
|
||||||
|
)
|
||||||
|
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
Icon(
|
Icon(
|
||||||
painterResource(R.drawable.icon_delete),
|
painterResource(R.drawable.icon_delete),
|
||||||
contentDescription = stringResource(R.string.application_logs_delete)
|
contentDescription = null
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
text = {
|
text = {
|
||||||
Text(stringResource(R.string.application_logs_delete))
|
Text(stringResource(R.string.application_logs_delete))
|
||||||
}, onClick = {
|
}, onClick = {
|
||||||
logViewModel.clearLogs()
|
logViewModel.clearLogs()
|
||||||
onBackPressedDispatcher?.onBackPressed()
|
|
||||||
showMoreOptions = false
|
showMoreOptions = false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import androidx.compose.runtime.mutableStateListOf
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@@ -29,11 +30,26 @@ class LogViewModel: ViewModel() {
|
|||||||
private var _isLoading = MutableStateFlow(false)
|
private var _isLoading = MutableStateFlow(false)
|
||||||
var isLoading = _isLoading.asStateFlow()
|
var isLoading = _isLoading.asStateFlow()
|
||||||
|
|
||||||
|
var logJob: Job? = null
|
||||||
|
|
||||||
|
var filterCrashes = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun toggleCrashBuffer() {
|
||||||
|
filterCrashes = !filterCrashes
|
||||||
|
|
||||||
|
_lineState.clear()
|
||||||
|
loadLogs()
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun logOutput(): List<LogLine> {
|
private suspend fun logOutput(): List<LogLine> {
|
||||||
val logLines = LinkedList<LogLine>()
|
val logLines = LinkedList<LogLine>()
|
||||||
|
|
||||||
|
val logCommand = if (filterCrashes) "logcat -b crash -B -d"
|
||||||
|
else "logcat -B -d"
|
||||||
|
|
||||||
// -B = binary format, -d = dump logs
|
// -B = binary format, -d = dump logs
|
||||||
val logSource = Runtime.getRuntime().exec("logcat -B -d")
|
val logSource = Runtime.getRuntime().exec(logCommand)
|
||||||
.inputStream.source().buffer()
|
.inputStream.source().buffer()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -61,6 +77,8 @@ class LogViewModel: ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun clearLogs() {
|
fun clearLogs() {
|
||||||
|
logJob?.cancel()
|
||||||
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
// -c = clear
|
// -c = clear
|
||||||
Runtime.getRuntime().exec("logcat -c")
|
Runtime.getRuntime().exec("logcat -c")
|
||||||
@@ -74,13 +92,20 @@ class LogViewModel: ViewModel() {
|
|||||||
return _lineState.joinToString("\n") { it.asSimpleString }
|
return _lineState.joinToString("\n") { it.asSimpleString }
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
private fun loadLogs() {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
logJob?.cancel()
|
||||||
|
logJob = viewModelScope.launch(Dispatchers.IO) {
|
||||||
val lines = logOutput()
|
val lines = logOutput()
|
||||||
_lineState.addAll(lines)
|
_lineState.addAll(lines)
|
||||||
_isLoading.value = false
|
_isLoading.value = false
|
||||||
|
|
||||||
|
logJob = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
loadLogs()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M400,720L400,640L560,640L560,720L400,720ZM240,520L240,440L720,440L720,520L240,520ZM120,320L120,240L840,240L840,320L120,320Z"/>
|
||||||
|
</vector>
|
||||||
@@ -94,4 +94,6 @@
|
|||||||
<string name="application_logs_export">Save To</string>
|
<string name="application_logs_export">Save To</string>
|
||||||
<string name="application_logs_export_completed">Log export complete.</string>
|
<string name="application_logs_export_completed">Log export complete.</string>
|
||||||
<string name="application_logs_default_filename" translatable="false">launcher_logcat.txt</string>
|
<string name="application_logs_default_filename" translatable="false">launcher_logcat.txt</string>
|
||||||
|
<string name="application_logs_crash_only">Show Crash Buffer</string>
|
||||||
|
<string name="application_logs_crash_only_enabled_alt">Enabled</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in new issue
Block a user