2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-08-22 01:51:47 +00:00

Allow exporting the logs form the app

This commit is contained in:
Albert Vaca Cintora 2025-04-06 10:24:28 +02:00
parent d4ab2ca6cf
commit 72e958a891
No known key found for this signature in database
3 changed files with 67 additions and 0 deletions

View File

@ -401,6 +401,9 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
<string name="settings_rename">Device name</string>
<string name="settings_dark_mode">Dark theme</string>
<string name="settings_export_logs">Export KDE Connect logs</string>
<string name="settings_export_logs_text">Generate a file with execution information that can help troubleshoot issues.</string>
<string name="settings_more_settings_title">More settings</string>
<string name="settings_more_settings_text">Per-device settings can be found under \'Plugin settings\' from within a device.</string>
<string name="setting_persistent_notification">Show persistent notification</string>

View File

@ -0,0 +1,27 @@
package org.kde.kdeconnect.Helpers
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.activity.result.contract.ActivityResultContract
data class CreateFileParams(
val fileMimeType: String,
val suggestedFileName: String,
)
class CreateFileResultContract : ActivityResultContract<CreateFileParams, Uri?>() {
override fun createIntent(context: Context, input: CreateFileParams): Intent =
Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
setTypeAndNormalize(input.fileMimeType)
putExtra(Intent.EXTRA_TITLE, input.suggestedFileName)
}
override fun parseResult(resultCode: Int, intent: Intent?): Uri? = when (resultCode) {
Activity.RESULT_OK -> intent?.data
else -> null
}
}

View File

@ -11,6 +11,7 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.InputFilter
@ -20,6 +21,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import androidx.activity.result.ActivityResultLauncher
import androidx.core.content.ContextCompat
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference
@ -27,14 +29,22 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.apache.commons.io.IOUtils
import org.kde.kdeconnect.BackgroundService
import org.kde.kdeconnect.Helpers.CreateFileParams
import org.kde.kdeconnect.Helpers.CreateFileResultContract
import org.kde.kdeconnect.Helpers.DeviceHelper
import org.kde.kdeconnect.Helpers.DeviceHelper.filterName
import org.kde.kdeconnect.Helpers.DeviceHelper.getDeviceName
import org.kde.kdeconnect.Helpers.NotificationHelper
import org.kde.kdeconnect.UserInterface.ThemeUtil.applyTheme
import org.kde.kdeconnect.extensions.setupBottomPadding
import org.kde.kdeconnect_tp.BuildConfig
import org.kde.kdeconnect_tp.R
import java.io.InputStreamReader
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
@ -56,6 +66,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
devicesByIpPref(context),
udpBroadcastPref(context),
bluetoothSupportPref(context),
exportLogsPref(context),
moreSettingsPref(context),
).forEach(screen::addPreference)
@ -217,6 +228,32 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
}
private fun exportLogsPref(context: Context) = Preference(context).apply {
isPersistent = false
setTitle(R.string.settings_export_logs)
setSummary(R.string.settings_export_logs_text)
onPreferenceClickListener = Preference.OnPreferenceClickListener {
exportLogs.launch(CreateFileParams("text/plain", "kdeconnect-log.txt"))
true
}
}
private val exportLogs: ActivityResultLauncher<CreateFileParams> = registerForActivityResult(
CreateFileResultContract()
) { uri: Uri? ->
val output = uri?.let { context?.contentResolver?.openOutputStream(uri) } ?: return@registerForActivityResult
CoroutineScope(Dispatchers.IO).launch {
val pid = android.os.Process.myPid()
val process = Runtime.getRuntime().exec(arrayOf("logcat", "-d", "--pid=$pid"))
val reader = InputStreamReader(process.inputStream)
output.use {
it.write("KDE Connect ${BuildConfig.VERSION_NAME}\n".toByteArray(Charsets.UTF_8))
it.write("Android ${Build.VERSION.RELEASE} (${Build.MANUFACTURER} ${Build.MODEL})\n".toByteArray(Charsets.UTF_8))
IOUtils.copy(reader, it, Charsets.UTF_8)
}
}
}
private fun moreSettingsPref(context: Context) = Preference(context).apply {
isPersistent = false
isSelectable = false