From 159497de15d082919b3bb5860f5b478145131df4 Mon Sep 17 00:00:00 2001 From: Arian Baishya Date: Fri, 21 Jun 2024 17:53:45 -0500 Subject: [PATCH] move some settings logic out of screen --- .../usb_hid_client/settings/SettingsHelper.kt | 70 ++++++++++ .../usb_hid_client/settings/SettingsScreen.kt | 122 +++++------------- 2 files changed, 99 insertions(+), 93 deletions(-) diff --git a/app/src/main/java/me/arianb/usb_hid_client/settings/SettingsHelper.kt b/app/src/main/java/me/arianb/usb_hid_client/settings/SettingsHelper.kt index c93e54e..e3c676f 100644 --- a/app/src/main/java/me/arianb/usb_hid_client/settings/SettingsHelper.kt +++ b/app/src/main/java/me/arianb/usb_hid_client/settings/SettingsHelper.kt @@ -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 @@ -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 @@ -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() +} diff --git a/app/src/main/java/me/arianb/usb_hid_client/settings/SettingsScreen.kt b/app/src/main/java/me/arianb/usb_hid_client/settings/SettingsScreen.kt index a0aefb1..e7889a8 100644 --- a/app/src/main/java/me/arianb/usb_hid_client/settings/SettingsScreen.kt +++ b/app/src/main/java/me/arianb/usb_hid_client/settings/SettingsScreen.kt @@ -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 @@ -15,7 +13,6 @@ 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 @@ -23,7 +20,6 @@ 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 @@ -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, @@ -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