Skip to content

Commit

Permalink
move all troubleshooting stuff into its own subpackage
Browse files Browse the repository at this point in the history
also move some stuff that SettingsScreen doesn't use out of SettingsHelper.kt
and into TroubleshootingHelper.kt
  • Loading branch information
Arian04 committed Jun 30, 2024
1 parent 808828d commit ee41072
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 117 deletions.
1 change: 1 addition & 0 deletions app/src/main/java/me/arianb/usb_hid_client/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import cafe.adriel.voyager.navigator.NavigatorDisposeBehavior
import cafe.adriel.voyager.transitions.SlideTransition
import com.topjohnwu.superuser.Shell
import me.arianb.usb_hid_client.settings.SettingsViewModel
import me.arianb.usb_hid_client.troubleshooting.ProductionTree
import timber.log.Timber

// TODO: move all misc strings used in snackbars and alerts throughout the app into strings.xml for translation purposes.
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/me/arianb/usb_hid_client/MainScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import me.arianb.usb_hid_client.input_views.ManualInput
import me.arianb.usb_hid_client.input_views.Touchpad
import me.arianb.usb_hid_client.settings.SettingsScreen
import me.arianb.usb_hid_client.shell_utils.RootStateHolder
import me.arianb.usb_hid_client.troubleshooting.TroubleshootingScreen
import me.arianb.usb_hid_client.ui.utils.BasicPage
import me.arianb.usb_hid_client.ui.utils.BasicTopBar
import me.arianb.usb_hid_client.ui.utils.DarkLightModePreviews
Expand Down
113 changes: 0 additions & 113 deletions app/src/main/java/me/arianb/usb_hid_client/settings/SettingsHelper.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
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.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
Expand All @@ -26,17 +21,10 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import me.arianb.usb_hid_client.BuildConfig
import me.arianb.usb_hid_client.LogBuffer
import me.arianb.usb_hid_client.R
import me.arianb.usb_hid_client.TroubleshootingInfo
import me.arianb.usb_hid_client.detectIssues
import me.arianb.usb_hid_client.ui.utils.LabeledCategory
import timber.log.Timber
import java.io.IOException


// This is basically just an alias now
Expand Down Expand Up @@ -209,104 +197,3 @@ fun OnClickPreference(
trailingContent = trailingContent
)
}

@Composable
fun ExportLogsPreferenceButton() {
val troubleshootingInfo = detectIssues()

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, troubleshootingInfo)
}

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)
}
)
}

private inline fun StringBuilder.appendDivider(): StringBuilder =
appendLine().appendLine("------------------------------")

private fun saveLogFile(context: Context, uri: Uri, troubleshootingInfo: TroubleshootingInfo) {
try {
val stringBuilder = buildString {
val rootPermissionInfo = troubleshootingInfo.rootPermissionInfo
val characterDevicesInfoList = troubleshootingInfo.characterDevicesInfoList
val kernelInfo = troubleshootingInfo.kernelInfo

appendLine("Do we have root permissions?: ${rootPermissionInfo.hasRootPermissions}")
appendLine("Root method: ${rootPermissionInfo.rootMethod.name}")

appendDivider()

if (characterDevicesInfoList != null) {
for (characterDevice in characterDevicesInfoList) {
appendLine("character device info for: ${characterDevice.path}")
appendLine("does it exist?: ${characterDevice.isPresent}")
appendLine("is it visible without root?: ${characterDevice.isVisibleWithoutRoot}")
appendLine("permissions: ")
appendLine(characterDevice.permissions)

appendLine()
}
} else {
appendLine("character device info list is null, that's bad.")
}

appendDivider()

if (kernelInfo != null) {
appendLine("relevant snippet of kernel config: ")
appendLine(kernelInfo.kernelConfigAnnotated.text)
appendLine("-")
appendLine("has ConfigFS support?: ${kernelInfo.hasConfigFsSupport}")
appendLine("has ConfigFS HID function support?: ${kernelInfo.hasConfigFsHidFunctionSupport}")

} else {
appendLine("kernel info is null, that's bad.")
}

appendDivider()

appendLine("Logs: ")

// Append all logs
for (entry in LogBuffer.getLogList()) {
appendLine(entry.toString())
}
}

Timber.d(stringBuilder)

// 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.toByteArray())
}

Timber.d("Successfully exported logs")
} catch (e: IOException) {
Timber.e(e)
Timber.e("IOException occurred while exporting logs")
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.arianb.usb_hid_client
package me.arianb.usb_hid_client.troubleshooting

import android.util.Log
import timber.log.Timber
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
package me.arianb.usb_hid_client
package me.arianb.usb_hid_client.troubleshooting

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.collection.mutableIntSetOf
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
import me.arianb.usb_hid_client.BuildConfig
import me.arianb.usb_hid_client.R
import me.arianb.usb_hid_client.hid_utils.CharacterDeviceManager
import me.arianb.usb_hid_client.settings.OnClickPreference
import me.arianb.usb_hid_client.shell_utils.RootMethod
import me.arianb.usb_hid_client.shell_utils.RootStateHolder
import timber.log.Timber
import java.io.File
import java.io.IOException

data class TroubleshootingInfo(
val rootPermissionInfo: RootPermissionInfo,
Expand Down Expand Up @@ -262,3 +274,104 @@ private fun getKernelConfig(): List<String> {
* Should only be called if you know you have root permissions
*/
annotation class RequiresRoot

@Composable
fun ExportLogsPreferenceButton() {
val troubleshootingInfo = detectIssues()

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, troubleshootingInfo)
}

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)
}
)
}

private inline fun StringBuilder.appendDivider(): StringBuilder =
appendLine().appendLine("------------------------------")

private fun saveLogFile(context: Context, uri: Uri, troubleshootingInfo: TroubleshootingInfo) {
try {
val stringBuilder = buildString {
val rootPermissionInfo = troubleshootingInfo.rootPermissionInfo
val characterDevicesInfoList = troubleshootingInfo.characterDevicesInfoList
val kernelInfo = troubleshootingInfo.kernelInfo

appendLine("Do we have root permissions?: ${rootPermissionInfo.hasRootPermissions}")
appendLine("Root method: ${rootPermissionInfo.rootMethod.name}")

appendDivider()

if (characterDevicesInfoList != null) {
for (characterDevice in characterDevicesInfoList) {
appendLine("character device info for: ${characterDevice.path}")
appendLine("does it exist?: ${characterDevice.isPresent}")
appendLine("is it visible without root?: ${characterDevice.isVisibleWithoutRoot}")
appendLine("permissions: ")
appendLine(characterDevice.permissions)

appendLine()
}
} else {
appendLine("character device info list is null, that's bad.")
}

appendDivider()

if (kernelInfo != null) {
appendLine("relevant snippet of kernel config: ")
appendLine(kernelInfo.kernelConfigAnnotated.text)
appendLine("-")
appendLine("has ConfigFS support?: ${kernelInfo.hasConfigFsSupport}")
appendLine("has ConfigFS HID function support?: ${kernelInfo.hasConfigFsHidFunctionSupport}")

} else {
appendLine("kernel info is null, that's bad.")
}

appendDivider()

appendLine("Logs: ")

// Append all logs
for (entry in LogBuffer.getLogList()) {
appendLine(entry.toString())
}
}

Timber.d(stringBuilder)

// 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.toByteArray())
}

Timber.d("Successfully exported logs")
} catch (e: IOException) {
Timber.e(e)
Timber.e("IOException occurred while exporting logs")
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.arianb.usb_hid_client
package me.arianb.usb_hid_client.troubleshooting

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
Expand Down Expand Up @@ -37,7 +37,8 @@ import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.Navigator
import me.arianb.usb_hid_client.settings.ExportLogsPreferenceButton
import me.arianb.usb_hid_client.MainViewModel
import me.arianb.usb_hid_client.R
import me.arianb.usb_hid_client.shell_utils.RootMethod
import me.arianb.usb_hid_client.ui.theme.codeLineHeightScaleFactor
import me.arianb.usb_hid_client.ui.theme.codeStyle
Expand Down

0 comments on commit ee41072

Please sign in to comment.