Commit 56813ad4 authored by Ricki Hirner's avatar Ricki Hirner

Logging: Use FileProvider instead of external file

parent 036fc405
Pipeline #41938832 passed with stages
in 10 minutes and 25 seconds
...@@ -8,45 +8,52 @@ ...@@ -8,45 +8,52 @@
package at.bitfire.davdroid.log package at.bitfire.davdroid.log
import android.annotation.SuppressLint
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Process
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.util.Log import android.util.Log
import android.widget.Toast
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.FileProvider
import at.bitfire.davdroid.R import at.bitfire.davdroid.R
import at.bitfire.davdroid.ui.AppSettingsActivity import at.bitfire.davdroid.ui.AppSettingsActivity
import at.bitfire.davdroid.ui.NotificationUtils import at.bitfire.davdroid.ui.NotificationUtils
import org.apache.commons.lang3.time.DateFormatUtils
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.util.logging.FileHandler import java.util.logging.FileHandler
import java.util.logging.Level import java.util.logging.Level
object Logger { @SuppressLint("StaticFieldLeak") // we'll only keep an app context
object Logger : SharedPreferences.OnSharedPreferenceChangeListener {
const val LOG_TO_EXTERNAL_STORAGE = "log_to_external_storage" private const val LOG_TO_FILE = "log_to_file"
val log = java.util.logging.Logger.getLogger("davdroid")!! val log = java.util.logging.Logger.getLogger("davdroid")!!
private lateinit var context: Context
private lateinit var preferences: SharedPreferences private lateinit var preferences: SharedPreferences
fun initialize(appContext: Context) { fun initialize(someContext: Context) {
preferences = PreferenceManager.getDefaultSharedPreferences(appContext) context = someContext.applicationContext
preferences.registerOnSharedPreferenceChangeListener { _, s -> preferences = PreferenceManager.getDefaultSharedPreferences(context)
if (s == LOG_TO_EXTERNAL_STORAGE) preferences.registerOnSharedPreferenceChangeListener(this)
reinitialize(appContext.applicationContext)
} reinitialize()
}
reinitialize(appContext) override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
if (key == LOG_TO_FILE) {
log.info("Logging settings changed; re-initializing logger")
reinitialize()
}
} }
private fun reinitialize(context: Context) { private fun reinitialize() {
val logToFile = preferences.getBoolean(LOG_TO_EXTERNAL_STORAGE, false) val logToFile = preferences.getBoolean(LOG_TO_FILE, false)
val logVerbose = logToFile || Log.isLoggable(log.name, Log.DEBUG) val logVerbose = logToFile || Log.isLoggable(log.name, Log.DEBUG)
log.info("Verbose logging: $logVerbose; to file: $logToFile") log.info("Verbose logging: $logVerbose; to file: $logToFile")
...@@ -65,42 +72,64 @@ object Logger { ...@@ -65,42 +72,64 @@ object Logger {
if (logToFile) { if (logToFile) {
val builder = NotificationUtils.newBuilder(context, NotificationUtils.CHANNEL_DEBUG) val builder = NotificationUtils.newBuilder(context, NotificationUtils.CHANNEL_DEBUG)
builder .setSmallIcon(R.drawable.ic_sd_storage_notification) builder .setSmallIcon(R.drawable.ic_sd_storage_notification)
.setContentTitle(context.getString(R.string.logging_davx5_file_logging)) .setContentTitle(context.getString(R.string.logging_notification_title))
.setLocalOnly(true)
val logDir = debugDir(context) ?: return
val dir = context.getExternalFilesDir(null) val logFile = File(logDir, "davx5-log.txt")
if (dir != null)
try { try {
val fileName = File(dir, "davdroid-${Process.myPid()}-${DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd-HHmmss")}.txt").toString() val fileHandler = FileHandler(logFile.toString(), true)
log.info("Logging to $fileName") fileHandler.formatter = PlainTextFormatter.DEFAULT
rootLogger.addHandler(fileHandler)
val fileHandler = FileHandler(fileName)
fileHandler.formatter = PlainTextFormatter.DEFAULT val prefIntent = Intent(context, AppSettingsActivity::class.java)
rootLogger.addHandler(fileHandler) prefIntent.putExtra(AppSettingsActivity.EXTRA_SCROLL_TO, LOG_TO_FILE)
val prefIntent = Intent(context, AppSettingsActivity::class.java) builder .setContentText(logDir.path)
prefIntent.putExtra(AppSettingsActivity.EXTRA_SCROLL_TO, LOG_TO_EXTERNAL_STORAGE) .setCategory(NotificationCompat.CATEGORY_STATUS)
.setPriority(NotificationCompat.PRIORITY_HIGH)
builder .setContentText(dir.path) .setContentText(context.getString(R.string.logging_notification_text))
.setCategory(NotificationCompat.CATEGORY_STATUS) .setContentIntent(PendingIntent.getActivity(context, 0, prefIntent, PendingIntent.FLAG_UPDATE_CURRENT))
.setPriority(NotificationCompat.PRIORITY_HIGH) .setOngoing(true)
.setContentIntent(PendingIntent.getActivity(context, 0, prefIntent, PendingIntent.FLAG_UPDATE_CURRENT))
.setStyle(NotificationCompat.BigTextStyle().bigText(context.getString(R.string.logging_to_external_storage, dir.path))) // add "Share" action
.setOngoing(true) val logFileUri = FileProvider.getUriForFile(context, context.getString(R.string.authority_log_provider), logFile)
log.fine("Now logging to file: $logFile -> $logFileUri")
} catch(e: IOException) {
log.log(Level.SEVERE, "Couldn't create external log file", e) val shareIntent = Intent(Intent.ACTION_SEND)
val message = context.getString(R.string.logging_couldnt_create_file, e.localizedMessage) shareIntent.setDataAndType(logFileUri, "text/plain")
builder .setContentText(message) shareIntent.putExtra(Intent.EXTRA_SUBJECT, "DAVx⁵ logs")
.setStyle(NotificationCompat.BigTextStyle().bigText(message)) shareIntent.putExtra(Intent.EXTRA_STREAM, logFileUri)
.setCategory(NotificationCompat.CATEGORY_ERROR) shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
} val shareAction = NotificationCompat.Action.Builder(R.drawable.ic_share_action,
else context.getString(R.string.logging_notification_share_log),
builder.setContentText(context.getString(R.string.logging_no_external_storage)) PendingIntent.getActivity(context, 0, shareIntent, PendingIntent.FLAG_UPDATE_CURRENT))
builder.addAction(shareAction.build())
} catch(e: IOException) {
log.log(Level.SEVERE, "Couldn't create log file", e)
Toast.makeText(context, context.getString(R.string.logging_couldnt_create_file), Toast.LENGTH_LONG).show()
}
nm.notify(NotificationUtils.NOTIFY_EXTERNAL_FILE_LOGGING, builder.build()) nm.notify(NotificationUtils.NOTIFY_EXTERNAL_FILE_LOGGING, builder.build())
} else } else {
nm.cancel(NotificationUtils.NOTIFY_EXTERNAL_FILE_LOGGING) nm.cancel(NotificationUtils.NOTIFY_EXTERNAL_FILE_LOGGING)
// delete old logs
debugDir(context)?.deleteRecursively()
}
}
private fun debugDir(context: Context): File? {
val dir = File(context.filesDir, "debug")
if (dir.exists() && dir.isDirectory)
return dir
if (dir.mkdir())
return dir
Toast.makeText(context, context.getString(R.string.logging_couldnt_create_file), Toast.LENGTH_LONG).show()
return null
} }
} }
\ No newline at end of file
...@@ -120,12 +120,6 @@ class AppSettingsActivity: AppCompatActivity() { ...@@ -120,12 +120,6 @@ class AppSettingsActivity: AppCompatActivity() {
// security settings // security settings
val prefDistrustSystemCerts = findPreference(Settings.DISTRUST_SYSTEM_CERTIFICATES) as SwitchPreferenceCompat val prefDistrustSystemCerts = findPreference(Settings.DISTRUST_SYSTEM_CERTIFICATES) as SwitchPreferenceCompat
prefDistrustSystemCerts.isChecked = settings.getBoolean(Settings.DISTRUST_SYSTEM_CERTIFICATES) ?: Settings.DISTRUST_SYSTEM_CERTIFICATES_DEFAULT prefDistrustSystemCerts.isChecked = settings.getBoolean(Settings.DISTRUST_SYSTEM_CERTIFICATES) ?: Settings.DISTRUST_SYSTEM_CERTIFICATES_DEFAULT
// debugging settings
val prefLogToExternalStorage = findPreference(Logger.LOG_TO_EXTERNAL_STORAGE) as SwitchPreferenceCompat
prefLogToExternalStorage.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
true
}
} }
override fun onSettingsChanged() { override fun onSettingsChanged() {
......
...@@ -57,10 +57,10 @@ ...@@ -57,10 +57,10 @@
<string name="about_license_info_no_warranty">This program comes with ABSOLUTELY NO WARRANTY. It is free software, and you are welcome to redistribute it under certain conditions.</string> <string name="about_license_info_no_warranty">This program comes with ABSOLUTELY NO WARRANTY. It is free software, and you are welcome to redistribute it under certain conditions.</string>
<!-- global settings --> <!-- global settings -->
<string name="logging_davx5_file_logging">DAVx⁵ file logging</string> <string name="logging_couldnt_create_file">Couldn\'t create log file</string>
<string name="logging_to_external_storage">Logging to external storage: %s</string> <string name="logging_notification_title">DAVx⁵ logging</string>
<string name="logging_couldnt_create_file">Couldn\'t create external log file: %s</string> <string name="logging_notification_text">Now logging all DAVx⁵ activities</string>
<string name="logging_no_external_storage">External storage not found</string> <string name="logging_notification_share_log">Share log</string>
<!-- AccountsActivity --> <!-- AccountsActivity -->
<string name="navigation_drawer_open">Open navigation drawer</string> <string name="navigation_drawer_open">Open navigation drawer</string>
...@@ -87,10 +87,12 @@ ...@@ -87,10 +87,12 @@
<!-- AppSettingsActivity --> <!-- AppSettingsActivity -->
<string name="app_settings">Settings</string> <string name="app_settings">Settings</string>
<string name="app_settings_user_interface">User interface</string> <string name="app_settings_debug">Debugging</string>
<string name="app_settings_reset_hints">Reset hints</string> <string name="app_settings_show_debug_info">Show debug info</string>
<string name="app_settings_reset_hints_summary">Re-enables hints which have been dismissed previously</string> <string name="app_settings_show_debug_info_details">View/share software and configuration details</string>
<string name="app_settings_reset_hints_success">All hints will be shown again</string> <string name="app_settings_logging">Verbose logging</string>
<string name="app_settings_logging_on">Logging is active</string>
<string name="app_settings_logging_off">Logging is disabled</string>
<string name="app_settings_connection">Connection</string> <string name="app_settings_connection">Connection</string>
<string name="app_settings_override_proxy">Override proxy settings</string> <string name="app_settings_override_proxy">Override proxy settings</string>
<string name="app_settings_override_proxy_on">Use custom proxy settings</string> <string name="app_settings_override_proxy_on">Use custom proxy settings</string>
...@@ -104,12 +106,10 @@ ...@@ -104,12 +106,10 @@
<string name="app_settings_reset_certificates">Reset (un)trusted certificates</string> <string name="app_settings_reset_certificates">Reset (un)trusted certificates</string>
<string name="app_settings_reset_certificates_summary">Resets trust of all custom certificates</string> <string name="app_settings_reset_certificates_summary">Resets trust of all custom certificates</string>
<string name="app_settings_reset_certificates_success">All custom certificates have been cleared</string> <string name="app_settings_reset_certificates_success">All custom certificates have been cleared</string>
<string name="app_settings_debug">Debugging</string> <string name="app_settings_user_interface">User interface</string>
<string name="app_settings_log_to_external_storage">Log to external file</string> <string name="app_settings_reset_hints">Reset hints</string>
<string name="app_settings_log_to_external_storage_on">Logging to external storage (if available)</string> <string name="app_settings_reset_hints_summary">Re-enables hints which have been dismissed previously</string>
<string name="app_settings_log_to_external_storage_off">External file logging is disabled</string> <string name="app_settings_reset_hints_success">All hints will be shown again</string>
<string name="app_settings_show_debug_info">Show debug info</string>
<string name="app_settings_show_debug_info_details">View/share software and configuration details</string>
<!-- AccountActivity --> <!-- AccountActivity -->
<string name="account_synchronize_now">Synchronize now</string> <string name="account_synchronize_now">Synchronize now</string>
......
...@@ -8,6 +8,5 @@ ...@@ -8,6 +8,5 @@
--> -->
<paths> <paths>
<!-- debug info can be deleted after it has been used, so let's use a cache dir --> <files-path name="debug" path="debug/"/>
<cache-path name="debug-info" path="debug-info/"/>
</paths> </paths>
\ No newline at end of file
...@@ -11,13 +11,6 @@ ...@@ -11,13 +11,6 @@
<PreferenceCategory android:title="@string/app_settings_debug"> <PreferenceCategory android:title="@string/app_settings_debug">
<SwitchPreferenceCompat
android:key="log_to_external_storage"
android:title="@string/app_settings_log_to_external_storage"
android:icon="@drawable/ic_adb_dark"
android:summaryOn="@string/app_settings_log_to_external_storage_on"
android:summaryOff="@string/app_settings_log_to_external_storage_off"/>
<Preference <Preference
android:title="@string/app_settings_show_debug_info" android:title="@string/app_settings_show_debug_info"
android:summary="@string/app_settings_show_debug_info_details" android:summary="@string/app_settings_show_debug_info_details"
...@@ -27,6 +20,13 @@ ...@@ -27,6 +20,13 @@
android:targetClass="at.bitfire.davdroid.ui.DebugInfoActivity"/> android:targetClass="at.bitfire.davdroid.ui.DebugInfoActivity"/>
</Preference> </Preference>
<SwitchPreferenceCompat
android:key="log_to_file"
android:title="@string/app_settings_logging"
android:icon="@drawable/ic_adb_dark"
android:summaryOn="@string/app_settings_logging_on"
android:summaryOff="@string/app_settings_logging_off"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/app_settings_connection"> <PreferenceCategory android:title="@string/app_settings_connection">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment