Skip to content

Commit

Permalink
move some settings logic out of screen
Browse files Browse the repository at this point in the history
  • Loading branch information
Arian04 committed Jun 21, 2024
1 parent 389eb69 commit 159497d
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 93 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package me.arianb.usb_hid_client.settings

import android.content.Context
import android.net.Uri
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.HorizontalDivider
Expand All @@ -14,6 +16,10 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import com.topjohnwu.superuser.Shell
import me.arianb.usb_hid_client.BuildConfig
import timber.log.Timber
import java.io.IOException


@Composable
Expand Down Expand Up @@ -78,3 +84,67 @@ fun OnClickPreference(
modifier = Modifier.clickable { onClick() }
)
}

fun saveLogFile(context: Context, uri: Uri) {
try {
val stringBuilder = StringBuilder()
var command: String
if (Shell.getShell().isRoot) {
command = String.format(
"logcat -e '%s' -t 1000",
BuildConfig.APPLICATION_ID
)
stringBuilder.append(
getCommandInLogFormatString(
command,
"Logcat"
)
)
command = "ls -lAhZ /config/usb_gadget"
stringBuilder.append(
getCommandInLogFormatString(
command,
"Gadgets Directory"
)
)
command =
"echo KERNEL_VERSION=$(uname -r |cut -d '-' -f1 ) && (gunzip -c /proc/config.gz | grep -i configfs | sed 's/# //; s/ is not set/=NOT_SET/')"
stringBuilder.append(
getCommandInLogFormatString(
command,
"Kernel Config"
)
)
} else {
stringBuilder.append("Could not create root shell. Was the app given root permissions?")
.append("\n")
}
Timber.d(stringBuilder.toString())

// Write out file
context.contentResolver.openOutputStream(uri).use { outputStream ->
if (outputStream == null) {
Timber.e("Failed to open output stream for writing log file.")
return
}
outputStream.write(stringBuilder.toString().toByteArray())
}
Timber.d("Successfully exported logs")
} catch (e: IOException) {
Timber.e(e)
Timber.e("Error occurred while exporting logs")
}
}

fun getCommandInLogFormatString(command: String, title: String): String {
val logStringBuilder = StringBuilder()
val halfDivider = "------------------------------"
val divider = halfDivider + halfDivider
val commandResult = Shell.cmd(command).exec()
val commandResultMultiline = java.lang.String.join("\n", commandResult.out)

logStringBuilder.append(String.format("%s %s %s", halfDivider, title, halfDivider)).append("\n")
logStringBuilder.append(commandResultMultiline).append("\n")
logStringBuilder.append(divider + "\n")
return logStringBuilder.toString()
}
122 changes: 29 additions & 93 deletions app/src/main/java/me/arianb/usb_hid_client/settings/SettingsScreen.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package me.arianb.usb_hid_client.settings

import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Arrangement
Expand All @@ -15,15 +13,13 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.Navigator
import com.topjohnwu.superuser.Shell
import me.arianb.usb_hid_client.BuildConfig
import me.arianb.usb_hid_client.R
import me.arianb.usb_hid_client.ui.theme.BasicPage
import me.arianb.usb_hid_client.ui.theme.DarkLightModePreviews
import me.arianb.usb_hid_client.ui.theme.PaddingNormal
import me.arianb.usb_hid_client.ui.theme.SimpleNavTopBar
import timber.log.Timber
import java.io.IOException

// TODO: make this scrollable

Expand All @@ -38,15 +34,6 @@ class SettingsScreen : Screen {
fun SettingsPage() {
val padding = PaddingNormal

val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
// If the user doesn't choose a location to save the file, don't continue
val uri = result.data?.data ?: return@rememberLauncherForActivityResult

Timber.d("selected file URI: %s", uri)
saveLogFile(context, uri)
}

BasicPage(
topBar = { SettingsTopBar() },
// paddingAll = padding,
Expand Down Expand Up @@ -77,97 +64,46 @@ fun SettingsPage() {
summary = stringResource(R.string.debug_mode_summary),
key = DEBUG_MODE_KEY
)
OnClickPreference(
title = stringResource(R.string.export_debug_logs_btn_title),
summary = stringResource(R.string.export_debug_logs_btn_summary),
onClick = {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "text/plain"

val unixTime = System.currentTimeMillis() / 1000
val filename = "debug_log_${BuildConfig.APPLICATION_ID}_${unixTime}.txt"
putExtra(Intent.EXTRA_TITLE, filename)
}

launcher.launch(intent)
}
)
ExportLogsPreferenceButton()
}

}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SettingsTopBar() {
SimpleNavTopBar(
title = stringResource(R.string.settings)
)
}
fun ExportLogsPreferenceButton() {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
// If the user doesn't choose a location to save the file, don't continue
val uri = result.data?.data ?: return@rememberLauncherForActivityResult

fun saveLogFile(context: Context, uri: Uri) {
try {
val stringBuilder = StringBuilder()
var command: String
if (Shell.getShell().isRoot) {
command = String.format(
"logcat -e '%s' -t 1000",
BuildConfig.APPLICATION_ID
)
stringBuilder.append(
getCommandInLogFormatString(
command,
"Logcat"
)
)
command = "ls -lAhZ /config/usb_gadget"
stringBuilder.append(
getCommandInLogFormatString(
command,
"Gadgets Directory"
)
)
command =
"echo KERNEL_VERSION=$(uname -r |cut -d '-' -f1 ) && (gunzip -c /proc/config.gz | grep -i configfs | sed 's/# //; s/ is not set/=NOT_SET/')"
stringBuilder.append(
getCommandInLogFormatString(
command,
"Kernel Config"
)
)
} else {
stringBuilder.append("Could not create root shell. Was the app given root permissions?")
.append("\n")
}
Timber.d(stringBuilder.toString())
Timber.d("selected file URI: %s", uri)
saveLogFile(context, uri)
}

// Write out file
context.contentResolver.openOutputStream(uri).use { outputStream ->
if (outputStream == null) {
Timber.e("Failed to open output stream for writing log file.")
return
OnClickPreference(
title = stringResource(R.string.export_debug_logs_btn_title),
summary = stringResource(R.string.export_debug_logs_btn_summary),
onClick = {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "text/plain"

val unixTime = System.currentTimeMillis() / 1000
val filename = "debug_log_${BuildConfig.APPLICATION_ID}_${unixTime}.txt"
putExtra(Intent.EXTRA_TITLE, filename)
}
outputStream.write(stringBuilder.toString().toByteArray())

launcher.launch(intent)
}
Timber.d("Successfully exported logs")
} catch (e: IOException) {
Timber.e(e)
Timber.e("Error occurred while exporting logs")
}
)
}

fun getCommandInLogFormatString(command: String, title: String): String {
val logStringBuilder = StringBuilder()
val halfDivider = "------------------------------"
val divider = halfDivider + halfDivider
val commandResult = Shell.cmd(command).exec()
val commandResultMultiline = java.lang.String.join("\n", commandResult.out)

logStringBuilder.append(String.format("%s %s %s", halfDivider, title, halfDivider)).append("\n")
logStringBuilder.append(commandResultMultiline).append("\n")
logStringBuilder.append(divider + "\n")
return logStringBuilder.toString()
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SettingsTopBar() {
SimpleNavTopBar(
title = stringResource(R.string.settings)
)
}

@DarkLightModePreviews
Expand Down

0 comments on commit 159497d

Please sign in to comment.