Loading core/android/logging/src/main/kotlin/net/thunderbird/core/android/logging/LogFileWriter.kt +26 −11 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import android.content.ContentResolver import android.content.Context import android.net.Uri import android.provider.OpenableColumns import java.io.OutputStream import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext Loading Loading @@ -31,24 +32,38 @@ class MultiLogFileWriter( } val outputStream = contentResolver.openOutputStream(contentUri, "wt") ?: error("Error opening contentUri for writing") if (uriString.contains("thunderbird-sync-logs")) { if (uriString.contains(DEFAULT_SYNC_FILENAME)) { copyInternalFileToExternal(outputStream) clearInternalFile() } else { outputStream.use { try { context?.openFileInput("thunderbird-sync-logs.txt").use { inputStream -> processExecutor.exec("logcat -d").use { inputStream -> IOUtils.copy(inputStream, outputStream) } } catch (e: FileSystemException) { println(e) } } context?.openFileOutput("thunderbird-sync-logs.txt", Context.MODE_PRIVATE)?.bufferedWriter()?.write("") } else { } } private fun copyInternalFileToExternal(outputStream: OutputStream) { outputStream.use { processExecutor.exec("logcat -d").use { inputStream -> try { context?.openFileInput("${DEFAULT_SYNC_FILENAME}.txt").use { inputStream -> IOUtils.copy(inputStream, outputStream) } } catch (e: FileSystemException) { Timber.e(" Error while outputting into file: $e") } } } private fun clearInternalFile() { context?.openFileOutput( "${DEFAULT_SYNC_FILENAME}.txt", Context.MODE_PRIVATE, )?.bufferedWriter()?.write("") } companion object { const val DEFAULT_SYNC_FILENAME = "thunderbird-sync-logs" } } gradle/libs.versions.toml +1 −2 Original line number Diff line number Diff line Loading @@ -24,8 +24,7 @@ androidxAutofill = "1.3.0-rc01" androidxBiometric = "1.1.0" androidxCamera = "1.4.2" # https://developer.android.com/jetpack/compose/bom/bom-mapping androidxComposeBom = "2025.02.00" androidxComposeUi = "1.8.0-rc02" androidxComposeBom = "2025.04.01" androidxConstraintLayout = "2.2.1" androidxCoordinatorLayout = "1.3.0" androidxCore = "1.16.0" Loading legacy/core/src/main/java/com/fsck/k9/FileLoggerTree.kt +10 −10 Original line number Diff line number Diff line Loading @@ -6,7 +6,6 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicReference import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers Loading @@ -14,11 +13,13 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import timber.log.Timber class FileLoggerTree(private val context: Context) : Timber.Tree() { private val coroutineContext: CoroutineContext = Dispatchers.IO class FileLoggerTree( context: Context, coroutineContext: CoroutineContext = Dispatchers.IO, ) : Timber.Tree() { private val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob()) private val writeFile = AtomicReference<File>() private val writeFile = context.createFile(fileName = "$DEFAULT_SYNC_FILENAME.txt") private val accumulatedLogs = ConcurrentHashMap<String, String>() override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { Loading @@ -34,15 +35,14 @@ class FileLoggerTree(private val context: Context) : Timber.Tree() { private fun createLogFile() = coroutineScope.launch { writeFile.lazySet( context.createFile(fileName = "$DEFAULT_SYNC_FILENAME.txt"), ) writeToLogFile() } private suspend fun writeToLogFile() { private fun writeToLogFile() { val result = runCatching { writeFile.get().bufferedWriter().use { it.write(accumulatedLogs.toString()) } writeFile.bufferedWriter().use { it.write(accumulatedLogs.entries.joinToString("\n") { it2 -> it2.key + " " + it2.value }) } } if (result.isFailure) { result.exceptionOrNull()?.printStackTrace() Loading @@ -55,7 +55,7 @@ class FileLoggerTree(private val context: Context) : Timber.Tree() { return format.format(date) } companion object { private const val ANDROID_LOG_TIME_FORMAT = "MM-dd-yy kk:mm:ss.SSS" private const val ANDROID_LOG_TIME_FORMAT = "MM-dd-yy hh:mm:ss.SSS" const val DEFAULT_SYNC_FILENAME = "thunderbird-sync-logs" } Loading legacy/core/src/main/java/com/fsck/k9/K9.kt +4 −7 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ object K9 : KoinComponent { private val telemetryManager: TelemetryManager by inject() private val featureFlagProvider: FeatureFlagProvider by inject() private val logger: Logger by inject() private val context: Context by inject() /** * If this is `true`, various development settings will be enabled. Loading Loading @@ -294,9 +295,6 @@ object K9 : KoinComponent { var fundingReminderReferenceTimestamp: Long = 0 var fundingReminderShownTimestamp: Long = 0 var fundingActivityCounterInMillis: Long = 0 private var savedContext: Context? = null val isQuietTime: Boolean get() { if (!isQuietTimeEnabled) { Loading Loading @@ -334,7 +332,6 @@ object K9 : KoinComponent { com.fsck.k9.logging.Timber.logger = logger checkCachedDatabaseVersion(context) savedContext = context loadPrefs(generalSettingsManager.storage) } Loading Loading @@ -516,11 +513,11 @@ object K9 : KoinComponent { } private fun updateSyncLogging() { if (savedContext != null && Timber.forest().contains(FileLoggerTree(savedContext!!))) { savedContext?.let { Timber.uproot(FileLoggerTree(it)) } if (Timber.forest().contains(FileLoggerTree(context))) { Timber.uproot(FileLoggerTree(context)) } if (isSyncLoggingEnabled) { savedContext?.let { Timber.plant(FileLoggerTree(it)) } Timber.plant(FileLoggerTree(context)) } } Loading legacy/core/src/main/java/com/fsck/k9/preferences/GeneralSettingsDescriptions.java +1 −1 Original line number Diff line number Diff line Loading @@ -86,7 +86,7 @@ class GeneralSettingsDescriptions { new V(1, new BooleanSetting(false)) )); s.put("enableSyncDebugLogging", Settings.versions( new V(1, new BooleanSetting(false)) new V(103, new BooleanSetting(false)) )); s.put("enableSensitiveLogging", Settings.versions( new V(1, new BooleanSetting(false)) Loading Loading
core/android/logging/src/main/kotlin/net/thunderbird/core/android/logging/LogFileWriter.kt +26 −11 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import android.content.ContentResolver import android.content.Context import android.net.Uri import android.provider.OpenableColumns import java.io.OutputStream import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext Loading Loading @@ -31,24 +32,38 @@ class MultiLogFileWriter( } val outputStream = contentResolver.openOutputStream(contentUri, "wt") ?: error("Error opening contentUri for writing") if (uriString.contains("thunderbird-sync-logs")) { if (uriString.contains(DEFAULT_SYNC_FILENAME)) { copyInternalFileToExternal(outputStream) clearInternalFile() } else { outputStream.use { try { context?.openFileInput("thunderbird-sync-logs.txt").use { inputStream -> processExecutor.exec("logcat -d").use { inputStream -> IOUtils.copy(inputStream, outputStream) } } catch (e: FileSystemException) { println(e) } } context?.openFileOutput("thunderbird-sync-logs.txt", Context.MODE_PRIVATE)?.bufferedWriter()?.write("") } else { } } private fun copyInternalFileToExternal(outputStream: OutputStream) { outputStream.use { processExecutor.exec("logcat -d").use { inputStream -> try { context?.openFileInput("${DEFAULT_SYNC_FILENAME}.txt").use { inputStream -> IOUtils.copy(inputStream, outputStream) } } catch (e: FileSystemException) { Timber.e(" Error while outputting into file: $e") } } } private fun clearInternalFile() { context?.openFileOutput( "${DEFAULT_SYNC_FILENAME}.txt", Context.MODE_PRIVATE, )?.bufferedWriter()?.write("") } companion object { const val DEFAULT_SYNC_FILENAME = "thunderbird-sync-logs" } }
gradle/libs.versions.toml +1 −2 Original line number Diff line number Diff line Loading @@ -24,8 +24,7 @@ androidxAutofill = "1.3.0-rc01" androidxBiometric = "1.1.0" androidxCamera = "1.4.2" # https://developer.android.com/jetpack/compose/bom/bom-mapping androidxComposeBom = "2025.02.00" androidxComposeUi = "1.8.0-rc02" androidxComposeBom = "2025.04.01" androidxConstraintLayout = "2.2.1" androidxCoordinatorLayout = "1.3.0" androidxCore = "1.16.0" Loading
legacy/core/src/main/java/com/fsck/k9/FileLoggerTree.kt +10 −10 Original line number Diff line number Diff line Loading @@ -6,7 +6,6 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicReference import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers Loading @@ -14,11 +13,13 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import timber.log.Timber class FileLoggerTree(private val context: Context) : Timber.Tree() { private val coroutineContext: CoroutineContext = Dispatchers.IO class FileLoggerTree( context: Context, coroutineContext: CoroutineContext = Dispatchers.IO, ) : Timber.Tree() { private val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob()) private val writeFile = AtomicReference<File>() private val writeFile = context.createFile(fileName = "$DEFAULT_SYNC_FILENAME.txt") private val accumulatedLogs = ConcurrentHashMap<String, String>() override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { Loading @@ -34,15 +35,14 @@ class FileLoggerTree(private val context: Context) : Timber.Tree() { private fun createLogFile() = coroutineScope.launch { writeFile.lazySet( context.createFile(fileName = "$DEFAULT_SYNC_FILENAME.txt"), ) writeToLogFile() } private suspend fun writeToLogFile() { private fun writeToLogFile() { val result = runCatching { writeFile.get().bufferedWriter().use { it.write(accumulatedLogs.toString()) } writeFile.bufferedWriter().use { it.write(accumulatedLogs.entries.joinToString("\n") { it2 -> it2.key + " " + it2.value }) } } if (result.isFailure) { result.exceptionOrNull()?.printStackTrace() Loading @@ -55,7 +55,7 @@ class FileLoggerTree(private val context: Context) : Timber.Tree() { return format.format(date) } companion object { private const val ANDROID_LOG_TIME_FORMAT = "MM-dd-yy kk:mm:ss.SSS" private const val ANDROID_LOG_TIME_FORMAT = "MM-dd-yy hh:mm:ss.SSS" const val DEFAULT_SYNC_FILENAME = "thunderbird-sync-logs" } Loading
legacy/core/src/main/java/com/fsck/k9/K9.kt +4 −7 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ object K9 : KoinComponent { private val telemetryManager: TelemetryManager by inject() private val featureFlagProvider: FeatureFlagProvider by inject() private val logger: Logger by inject() private val context: Context by inject() /** * If this is `true`, various development settings will be enabled. Loading Loading @@ -294,9 +295,6 @@ object K9 : KoinComponent { var fundingReminderReferenceTimestamp: Long = 0 var fundingReminderShownTimestamp: Long = 0 var fundingActivityCounterInMillis: Long = 0 private var savedContext: Context? = null val isQuietTime: Boolean get() { if (!isQuietTimeEnabled) { Loading Loading @@ -334,7 +332,6 @@ object K9 : KoinComponent { com.fsck.k9.logging.Timber.logger = logger checkCachedDatabaseVersion(context) savedContext = context loadPrefs(generalSettingsManager.storage) } Loading Loading @@ -516,11 +513,11 @@ object K9 : KoinComponent { } private fun updateSyncLogging() { if (savedContext != null && Timber.forest().contains(FileLoggerTree(savedContext!!))) { savedContext?.let { Timber.uproot(FileLoggerTree(it)) } if (Timber.forest().contains(FileLoggerTree(context))) { Timber.uproot(FileLoggerTree(context)) } if (isSyncLoggingEnabled) { savedContext?.let { Timber.plant(FileLoggerTree(it)) } Timber.plant(FileLoggerTree(context)) } } Loading
legacy/core/src/main/java/com/fsck/k9/preferences/GeneralSettingsDescriptions.java +1 −1 Original line number Diff line number Diff line Loading @@ -86,7 +86,7 @@ class GeneralSettingsDescriptions { new V(1, new BooleanSetting(false)) )); s.put("enableSyncDebugLogging", Settings.versions( new V(1, new BooleanSetting(false)) new V(103, new BooleanSetting(false)) )); s.put("enableSensitiveLogging", Settings.versions( new V(1, new BooleanSetting(false)) Loading