From 8d3d500b7b2dee95fbb02aab49404a8d41eb2dd3 Mon Sep 17 00:00:00 2001 From: Ax333l Date: Wed, 3 Jul 2024 13:54:37 +0200 Subject: [PATCH] feat: add ability to share debug logs --- .../screen/settings/AdvancedSettingsScreen.kt | 11 +++++ .../ui/viewmodel/AdvancedSettingsViewModel.kt | 49 ++++++++++++++++++- app/src/main/res/values/strings.xml | 4 ++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt index f46849c8..3817bd12 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt @@ -2,6 +2,8 @@ package app.revanced.manager.ui.screen.settings import android.app.ActivityManager import android.os.Build +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement 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)) BooleanItem( preference = vm.prefs.useProcessRuntime, diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/AdvancedSettingsViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/AdvancedSettingsViewModel.kt index 9efed1dd..5db843c0 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/AdvancedSettingsViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/AdvancedSettingsViewModel.kt @@ -1,21 +1,41 @@ package app.revanced.manager.ui.viewmodel import android.app.Application +import android.net.Uri +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.revanced.manager.R +import app.revanced.manager.domain.bundles.RemotePatchBundle import app.revanced.manager.domain.manager.PreferencesManager 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 com.github.pgreze.process.Redirect +import com.github.pgreze.process.process +import kotlinx.coroutines.CancellationException 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.withContext +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter class AdvancedSettingsViewModel( val prefs: PreferencesManager, private val app: Application, private val patchBundleRepository: PatchBundleRepository ) : 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) { if (value == prefs.api.get()) return@launch @@ -32,4 +52,31 @@ class AdvancedSettingsViewModel( fun resetBundles() = viewModelScope.launch { 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)) + } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6d3dc16f..5b833f6a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -137,6 +137,10 @@ This is faster and allows Patcher to use more memory. Patcher process memory limit The max amount of memory that the Patcher process can use (in megabytes) + Export debug logs + Failed to read logs (exit code %d) + Failed to export logs + Exported logs API URL Set custom API URL You may have issues with features when using a custom API URL.