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.