feat: add ability to share debug logs

This commit is contained in:
Ax333l 2024-07-03 13:54:37 +02:00
parent d8248cc915
commit 8d3d500b7b
No known key found for this signature in database
GPG key ID: D2B4D85271127D23
3 changed files with 63 additions and 1 deletions

View file

@ -2,6 +2,8 @@ package app.revanced.manager.ui.screen.settings
import android.app.ActivityManager import android.app.ActivityManager
import android.os.Build import android.os.Build
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -86,6 +88,15 @@ fun AdvancedSettingsScreen(
} }
) )
val exportDebugLogsLauncher =
rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) {
it?.let(vm::exportDebugLogs)
}
SettingsListItem(
headlineContent = stringResource(R.string.debug_logs_export),
modifier = Modifier.clickable { exportDebugLogsLauncher.launch(vm.debugLogFileName) }
)
GroupHeader(stringResource(R.string.patcher)) GroupHeader(stringResource(R.string.patcher))
BooleanItem( BooleanItem(
preference = vm.prefs.useProcessRuntime, preference = vm.prefs.useProcessRuntime,

View file

@ -1,21 +1,41 @@
package app.revanced.manager.ui.viewmodel package app.revanced.manager.ui.viewmodel
import android.app.Application import android.app.Application
import android.net.Uri
import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import app.revanced.manager.R import app.revanced.manager.R
import app.revanced.manager.domain.bundles.RemotePatchBundle
import app.revanced.manager.domain.manager.PreferencesManager import app.revanced.manager.domain.manager.PreferencesManager
import app.revanced.manager.domain.repository.PatchBundleRepository import app.revanced.manager.domain.repository.PatchBundleRepository
import app.revanced.manager.domain.bundles.RemotePatchBundle import app.revanced.manager.util.tag
import app.revanced.manager.util.toast
import app.revanced.manager.util.uiSafe import app.revanced.manager.util.uiSafe
import com.github.pgreze.process.Redirect
import com.github.pgreze.process.process
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
class AdvancedSettingsViewModel( class AdvancedSettingsViewModel(
val prefs: PreferencesManager, val prefs: PreferencesManager,
private val app: Application, private val app: Application,
private val patchBundleRepository: PatchBundleRepository private val patchBundleRepository: PatchBundleRepository
) : ViewModel() { ) : ViewModel() {
val debugLogFileName: String
get() {
val time = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now())
return "revanced-manager_logcat_$time"
}
fun setApiUrl(value: String) = viewModelScope.launch(Dispatchers.Default) { fun setApiUrl(value: String) = viewModelScope.launch(Dispatchers.Default) {
if (value == prefs.api.get()) return@launch if (value == prefs.api.get()) return@launch
@ -32,4 +52,31 @@ class AdvancedSettingsViewModel(
fun resetBundles() = viewModelScope.launch { fun resetBundles() = viewModelScope.launch {
patchBundleRepository.reset() patchBundleRepository.reset()
} }
fun exportDebugLogs(target: Uri) = viewModelScope.launch {
val exitCode = try {
withContext(Dispatchers.IO) {
app.contentResolver.openOutputStream(target)!!.bufferedWriter().use { writer ->
val consumer = Redirect.Consume { flow ->
flow.onEach {
writer.write(it)
}.flowOn(Dispatchers.IO).collect()
}
process("logcat", "-d", stdout = consumer).resultCode
}
}
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
Log.e(tag, "Got exception while exporting logs", e)
app.toast(app.getString(R.string.debug_logs_export_failed))
return@launch
}
if (exitCode == 0)
app.toast(app.getString(R.string.debug_logs_export_success))
else
app.toast(app.getString(R.string.debug_logs_export_read_failed, exitCode))
}
} }

View file

@ -137,6 +137,10 @@
<string name="process_runtime_description">This is faster and allows Patcher to use more memory.</string> <string name="process_runtime_description">This is faster and allows Patcher to use more memory.</string>
<string name="process_runtime_memory_limit">Patcher process memory limit</string> <string name="process_runtime_memory_limit">Patcher process memory limit</string>
<string name="process_runtime_memory_limit_description">The max amount of memory that the Patcher process can use (in megabytes)</string> <string name="process_runtime_memory_limit_description">The max amount of memory that the Patcher process can use (in megabytes)</string>
<string name="debug_logs_export">Export debug logs</string>
<string name="debug_logs_export_read_failed">Failed to read logs (exit code %d)</string>
<string name="debug_logs_export_failed">Failed to export logs</string>
<string name="debug_logs_export_success">Exported logs</string>
<string name="api_url">API URL</string> <string name="api_url">API URL</string>
<string name="api_url_dialog_title">Set custom API URL</string> <string name="api_url_dialog_title">Set custom API URL</string>
<string name="api_url_dialog_description">You may have issues with features when using a custom API URL.</string> <string name="api_url_dialog_description">You may have issues with features when using a custom API URL.</string>