Skip to content

Commit

Permalink
revamp Terminal nuttons, all in one button supportInfoLogShare
Browse files Browse the repository at this point in the history
  • Loading branch information
hg42 committed Jan 5, 2023
1 parent babd8e4 commit 8f891b7
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 110 deletions.
67 changes: 50 additions & 17 deletions app/src/main/java/com/machiav3lli/backup/handler/LogsHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.machiav3lli.backup.handler

import android.content.Context
import android.content.Intent
import android.os.Process
import com.machiav3lli.backup.BACKUP_DATE_TIME_FORMATTER
import com.machiav3lli.backup.BuildConfig
Expand All @@ -34,6 +35,8 @@ import com.machiav3lli.backup.pref_useLogCatForUncaught
import com.machiav3lli.backup.utils.FileUtils.BackupLocationInAccessibleException
import com.machiav3lli.backup.utils.StorageLocationNotConfiguredException
import com.machiav3lli.backup.utils.getBackupRoot
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.BufferedOutputStream
import java.io.IOException
Expand All @@ -44,25 +47,55 @@ class LogsHandler {

companion object {

suspend fun share(log: Log, asFile: Boolean = true) {
withContext(Dispatchers.IO) {
try {
getLogFile(log.logDate)?.let { log ->
val text = if (!asFile) log.readText() else ""
if (!asFile and text.isEmpty())
throw Exception("${log.name} is empty or cannot be read")
val sendIntent = Intent().apply {
action = Intent.ACTION_SEND
type = "text/json"
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
putExtra(Intent.EXTRA_SUBJECT, "[NeoBackup] ${log.name}")
if (asFile)
putExtra(Intent.EXTRA_STREAM, log.uri) // send as file
else
putExtra(Intent.EXTRA_TEXT, text) // send as text
}
val shareIntent = Intent.createChooser(sendIntent, log.name)
OABX.activity?.startActivity(shareIntent)
}
} catch (e: Throwable) {
unhandledException(e)
}
}
}

@Throws(IOException::class)
fun writeToLogFile(logText: String) {
val backupRoot = OABX.context.getBackupRoot()
val logsDirectory = backupRoot.ensureDirectory(LOGS_FOLDER_NAME)
val date = LocalDateTime.now()
val logItem = Log(logText, date)
val logFileName = String.format(
LOG_INSTANCE,
BACKUP_DATE_TIME_FORMATTER.format(date)
)
logsDirectory.createFile(logFileName).let { logFile ->
BufferedOutputStream(logFile.outputStream()).use { logOut ->
logOut.write(
logItem.toJSON().toByteArray(StandardCharsets.UTF_8)
)
//traceDebug { "Wrote $logFile file for $logItem" }
fun writeToLogFile(logText: String) : StorageFile? {
runCatching {
val backupRoot = OABX.context.getBackupRoot()
val logsDirectory = backupRoot.ensureDirectory(LOGS_FOLDER_NAME)
val date = LocalDateTime.now()
val logItem = Log(logText, date)
val logFileName = String.format(
LOG_INSTANCE,
BACKUP_DATE_TIME_FORMATTER.format(date)
)
logsDirectory.createFile(logFileName).let { logFile ->
BufferedOutputStream(logFile.outputStream()).use { logOut ->
logOut.write(
logItem.toJSON().toByteArray(StandardCharsets.UTF_8)
)
//traceDebug { "Wrote $logFile file for $logItem" }
}
housekeepingLogs()
return logFile
}
}
housekeepingLogs()
return null
}

@Throws(IOException::class)
Expand All @@ -75,7 +108,7 @@ class LogsHandler {
if (logsDir.isDirectory) {
logsDir.listFiles().forEach {
if (it.isFile) try {
logs.add(Log(it))
logs.add(Log(it)) //TODO hg42 don't throw, but create a dummy log entry, so it can be deleted
} catch (e: Throwable) {
val message =
"(catchall) Incomplete log or wrong structure found in $it."
Expand Down
190 changes: 125 additions & 65 deletions app/src/main/java/com/machiav3lli/backup/preferences/TerminalPage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,15 @@ import com.machiav3lli.backup.OABX
import com.machiav3lli.backup.OABX.Companion.beginBusy
import com.machiav3lli.backup.OABX.Companion.endBusy
import com.machiav3lli.backup.handler.LogsHandler
import com.machiav3lli.backup.handler.LogsHandler.Companion.share
import com.machiav3lli.backup.handler.ShellHandler.Companion.runAsRoot
import com.machiav3lli.backup.handler.ShellHandler.Companion.utilBox
import com.machiav3lli.backup.handler.ShellHandler.FileInfo.Companion.utilBoxInfo
import com.machiav3lli.backup.pref_maxLogLines
import com.machiav3lli.backup.items.Log
import com.machiav3lli.backup.ui.compose.SelectionContainerX
import com.machiav3lli.backup.ui.compose.ifThen
import com.machiav3lli.backup.ui.compose.item.RoundButton
import com.machiav3lli.backup.utils.SystemUtils.getApplicationIssuer
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

Expand All @@ -96,8 +98,12 @@ fun info(): List<String> {
return listOf(
"",
"--- > info",
"${BuildConfig.APPLICATION_ID} ${BuildConfig.VERSION_NAME}"
) + utilBoxInfo()
BuildConfig.APPLICATION_ID,
BuildConfig.VERSION_NAME,
OABX.context.getApplicationIssuer()?.let { "signed by $it" } ?: "",
"",
"--- shell utility box"
).filterNotNull() + utilBoxInfo()
}

fun shell(command: String): List<String> {
Expand Down Expand Up @@ -153,22 +159,106 @@ fun TerminalPage() {
val scope = rememberCoroutineScope()
val focusManager = LocalFocusManager.current

fun add(lines: List<String>) {
fun launch(todo: () -> Unit) {
scope.launch {
try {
focusManager.clearFocus()
} catch (_: Throwable) {
}
output.addAll(lines)
todo()
}
}

fun busy(todo: () -> Unit) {
beginBusy()
todo()
endBusy()
}

fun add(lines: List<String>) {
runCatching {
focusManager.clearFocus()
}
output.addAll(lines)
}

fun run(command: String) {
scope.launch {
beginBusy()
add(shell(command))
endBusy()
add(shell(command))
}

fun envInfo() {
add(info())
run("su --help")
run("echo ${utilBox.name}")
run("${utilBox.name} --version")
run("${utilBox.name} --help")
}

fun logInt() {
add(listOf("--- > last internal log messages"))
add(OABX.lastLogMessages)
}

val maxLogcatLines = 1000

fun logApp() {
run("logcat -d -t ${maxLogcatLines} --pid=${Process.myPid()}")
}

fun logSys() {
run("logcat -d -t ${maxLogcatLines}")
}

fun dumpAlarms() {
run("dumpsys alarm | sed -n '/Alarm.*machiav3lli[.]backup/,/PendingIntent/{p}'")
}

fun accessTest() {
run("echo \"\$(ls /data/user/0/ | wc -l) packages (apk)\"")
run("echo \"$(ls /data/user/0/ | wc -l) packages (data)\"")
run("echo \"\$(ls -l /data/misc/ | wc -l) misc data\"")
}

fun lastErrorPkg() {
val pkg = OABX.lastErrorPackage
if (pkg.isNotEmpty()) {
add(listOf("--- last error package: $pkg"))
run("ls -l /data/user/0/$pkg")
run("ls -l /data/user_de/0/$pkg")
run("ls -l /sdcard/Android/*/$pkg")
} else {
add(listOf("--- ? no last error package"))
}
}

fun lastErrorCommand() {
val cmd = OABX.lastErrorCommand
if (cmd.isNotEmpty())
add(listOf(
"--- last error command",
cmd
))
}

fun textLogShare() {
LogsHandler.writeToLogFile(output.joinToString("\n"))?.let { file ->
output.clear()
Log(file).let { log ->
scope.launch {
share(log, asFile = true)
}
}
}
}

fun supportInfoLogShare() {
busy {
add(listOf("=== support log", ""))
envInfo()
dumpAlarms()
accessTest()
lastErrorPkg()
lastErrorCommand()
logInt()
logApp()
}
textLogShare()
}

Column(verticalArrangement = Arrangement.Top) {
Expand Down Expand Up @@ -205,50 +295,20 @@ fun TerminalPage() {
.fillMaxWidth()
.padding(padding)
) {
TerminalButton("->Log", important = true) {
LogsHandler.writeToLogFile(output.joinToString("\n"))
output.clear()
}
Spacer(Modifier.width(5.dp))
TerminalButton("Clear", important = true) {
output.clear()
}
Spacer(Modifier.width(5.dp))
TerminalButton("info") {
add(info())
run("su --help")
run("echo ${utilBox.name}")
run("${utilBox.name} --version")
run("${utilBox.name} --help")
}
TerminalButton("log/int") {
add(listOf("--- > last internal log messages"))
add(OABX.lastLogMessages)
}
TerminalButton("log/app") {
run("logcat -d -t ${pref_maxLogLines.value} --pid=${Process.myPid()}")
}
TerminalButton("log/all") {
run("logcat -d -t ${pref_maxLogLines.value}")
}
TerminalButton("access") {
run("echo \"\$(ls /data/user/0/ | wc -l) packages (apk)\"")
run("echo \"$(ls /data/user/0/ | wc -l) packages (data)\"")
run("echo \"\$(ls -l /data/misc/ | wc -l) misc data\"")
}
TerminalButton("epkg") {
val pkg = OABX.lastErrorPackage
if (pkg != "") {
run("ls -l /data/user/0/$pkg")
run("ls -l /data/user/0/$pkg")
run("ls -l /sdcard/Android/*/$pkg")
} else {
add(listOf("--- ? no last error package"))
}
}
TerminalButton("ecmd") {
command = OABX.lastErrorCommand
}
TerminalButton("support->share", important = true) { launch { supportInfoLogShare() } }
Spacer(Modifier.width(4.dp))
TerminalButton("share", important = true) { launch { textLogShare() } }
Spacer(Modifier.width(8.dp))
TerminalButton("clear", important = true) { output.clear() }
Spacer(Modifier.width(8.dp))
TerminalButton("info") { launch { envInfo() } }
TerminalButton("log/int") { launch { logInt() } }
TerminalButton("log/app") { launch { logApp() } }
TerminalButton("log/all") { launch { logSys() } }
TerminalButton("alarms") { launch { dumpAlarms() } }
TerminalButton("access") { launch { accessTest() } }
TerminalButton("errInfo") { launch { lastErrorPkg() ; lastErrorCommand() } }
TerminalButton("err->cmd") { command = OABX.lastErrorCommand }
if (BuildConfig.DEBUG) {
}
}
Expand Down Expand Up @@ -323,16 +383,16 @@ fun TerminalText(text: List<String>, limitLines: Int = 0, scrollOnAdd: Boolean =
if (it.contains(search, ignoreCase = true)) {
val color =
when {
it.contains("error", ignoreCase = true) -> Color(1f, 0f, 0f)
it.contains("error", ignoreCase = true) -> Color(1f, 0f, 0f)
it.contains("warning", ignoreCase = true) -> Color(1f, 0.5f, 0f)
it.contains("***") -> Color(0f, 1f, 1f)
it.startsWith("===") -> Color(1f, 1f, 0f)
it.startsWith("---") -> Color(
it.contains("***") -> Color(0f, 1f, 1f)
it.startsWith("===") -> Color(1f, 1f, 0f)
it.startsWith("---") -> Color(
0.8f,
0.8f,
0f
)
else -> Color.White
else -> Color.White
}
Text(
if (it == "") " " else it, //TODO hg42 workaround
Expand Down Expand Up @@ -369,8 +429,7 @@ fun TerminalText(text: List<String>, limitLines: Int = 0, scrollOnAdd: Boolean =
//val focusManager = LocalFocusManager.current

TextField(modifier = Modifier
.padding(0.dp)
, //.weight(1f),
.padding(0.dp), //.weight(1f),
value = search,
singleLine = true,
//placeholder = { Text(text = "search", color = Color.Gray) },
Expand All @@ -380,7 +439,8 @@ fun TerminalText(text: List<String>, limitLines: Int = 0, scrollOnAdd: Boolean =
unfocusedLeadingIconColor = overlayColor,
focusedLeadingIconColor = if (search.length > 0) Color.Transparent else overlayColor
),
textStyle = TextStyle(fontSize = fontSize*searchFontFactor, lineHeight = lineHeightSp*searchFontFactor),
textStyle = TextStyle(fontSize = fontSize * searchFontFactor,
lineHeight = lineHeightSp * searchFontFactor),
leadingIcon = {
Icon(
imageVector = Icons.Rounded.Search,
Expand Down
Loading

0 comments on commit 8f891b7

Please sign in to comment.