diff --git a/application/vlc-android/src/org/videolan/vlc/DebugLogService.kt b/application/vlc-android/src/org/videolan/vlc/DebugLogService.kt index dd6bfc651..681a268a7 100644 --- a/application/vlc-android/src/org/videolan/vlc/DebugLogService.kt +++ b/application/vlc-android/src/org/videolan/vlc/DebugLogService.kt @@ -29,6 +29,7 @@ import android.content.Intent import android.content.ServiceConnection import android.os.* import android.text.format.DateFormat +import android.util.Log import androidx.core.app.NotificationCompat import org.videolan.libvlc.util.AndroidUtil import org.videolan.resources.AndroidDevices @@ -39,6 +40,7 @@ import org.videolan.tools.Logcat import org.videolan.tools.getContextWithLocale import org.videolan.vlc.gui.DebugLogActivity import org.videolan.vlc.gui.helpers.NotificationHelper +import org.videolan.vlc.gui.preferences.search.PreferenceParser import java.io.* import java.util.* @@ -176,7 +178,17 @@ class DebugLogService : Service(), Logcat.Callback, Runnable { output = OutputStreamWriter(fos) bw = BufferedWriter(output) synchronized(this) { + bw.write("____________________________\r\n") + bw.write("Useful info\r\n") + bw.write("____________________________\r\n") bw.write("App version: ${BuildConfig.VLC_VERSION_CODE} / ${BuildConfig.VLC_VERSION_NAME}\r\n") + try { + bw.write("Changed settings:\r\n${PreferenceParser.getChangedPrefsString(this)}\r\n") + } catch (e: Exception) { + bw.write("Cannot retrieve changed settings\r\n") + bw.write(Log.getStackTraceString(e)) + } + bw.write("____________________________\r\n") for (line in logList) { bw.write(line) bw.newLine() diff --git a/application/vlc-android/src/org/videolan/vlc/gui/preferences/search/PreferenceParser.kt b/application/vlc-android/src/org/videolan/vlc/gui/preferences/search/PreferenceParser.kt index 3bc575c3b..58c95ccfd 100644 --- a/application/vlc-android/src/org/videolan/vlc/gui/preferences/search/PreferenceParser.kt +++ b/application/vlc-android/src/org/videolan/vlc/gui/preferences/search/PreferenceParser.kt @@ -26,17 +26,23 @@ package org.videolan.vlc.gui.preferences.search import android.content.Context import android.content.ContextWrapper +import android.content.SharedPreferences import android.content.res.XmlResourceParser import android.os.Parcelable -import android.util.Log +import androidx.annotation.XmlRes import kotlinx.android.parcel.Parcelize import org.videolan.tools.Settings import org.videolan.tools.wrap -import org.videolan.vlc.BuildConfig import org.videolan.vlc.R object PreferenceParser { + /** + * Parses all the preferences available in the app. + * @param context the context to be used to retrieve the preferences + * + * @return a list of [PreferenceItem] + */ fun parsePreferences(context: Context): ArrayList { val result = ArrayList() arrayOf(R.xml.preferences, R.xml.preferences_adv, R.xml.preferences_audio, R.xml.preferences_casting, R.xml.preferences_perf, R.xml.preferences_subtitles, R.xml.preferences_ui, R.xml.preferences_video).forEach { @@ -45,7 +51,59 @@ object PreferenceParser { return result } - private fun parsePreferences(context: Context, id: Int): ArrayList { + /** + * Compares the preference list with the set settings to get the list of the changed settings by the user + * @param context the context to be used to retrieve the preferences + * + * @return a list of changed settings in the form a of pair of the key and the value + */ + private fun getAllChangedPrefs(context: Context): ArrayList> { + val allPrefs = parsePreferences(context) + val allSettings = Settings.getInstance(context).all + val changedSettings = ArrayList>() + allPrefs.forEach { pref -> + allSettings.forEach { setting -> + if (pref.key == setting.key) { + setting.value?.let { + if (!isSame(it, pref.defaultValue)) changedSettings.add(Pair(pref.key, it)) + } + } + } + } + return changedSettings + } + + /** + * Compares a [SharedPreferences] item value to a retrieved String from the preference parsing + * @param settingValue the found preference value + * @param defaultValue the defaultValue [String] found by parsing the pref xml + * + * @return true if values are considered to be the same + */ + private fun isSame(settingValue: Any, defaultValue: String?) = when { + defaultValue == null -> false + settingValue is Boolean -> settingValue.toString() == defaultValue + else -> settingValue == defaultValue + } + + /** + * Get a string describing the preferences changed by the user + * @param context the context to be used to retrieve the preferences + * + * @return a string of all the changed preferences + */ + fun getChangedPrefsString(context: Context) = buildString { + getAllChangedPrefs(context).forEach { append("\t* ${it.first} -> ${it.second}\r\n") } + } + + /** + * Parse a preference xml resource to get a list of [PreferenceItem] + * @param context the context to be used to retrieve the preferences + * @param id the xml resource id to parse + * + * @return all the parsed items in the form of a [PreferenceItem] list + */ + private fun parsePreferences(context: Context, @XmlRes id: Int): ArrayList { var category = "" var categoryEng = "" val result = ArrayList() @@ -69,10 +127,10 @@ object PreferenceParser { val titleEng = getValue(englishContext, parser, namespace, "title") var summary = getValue(context, parser, namespace, "summary") var summaryEng = getValue(englishContext, parser, namespace, "summary") + val defaultValue = getValue(context, parser, namespace, "defaultValue") if (summary.contains("%s") && element == "ListPreference") { //get the current value for the string substitution try { - val defaultValue = getValue(context, parser, namespace, "defaultValue") val rawValue = Settings.getInstance(context).getString(key, defaultValue) ?: "" val entriesId = parser.getAttributeResourceValue(namespace, "entries", -1) val entryValuesId = parser.getAttributeResourceValue(namespace, "entryValues", -1) @@ -82,7 +140,7 @@ object PreferenceParser { } catch (e: Exception) { } } - if (key.isNotBlank()) result.add(PreferenceItem(key, id, title, summary, titleEng, summaryEng, category, categoryEng)) + if (key.isNotBlank()) result.add(PreferenceItem(key, id, title, summary, titleEng, summaryEng, category, categoryEng, defaultValue)) } } eventType = parser.next() @@ -90,6 +148,15 @@ object PreferenceParser { return result } + /** + * Get the value of an xml node + * @param context the context to be used to retrieve the value. This context can be localized in English to retrieve the strings + * @param parser the [XmlResourceParser] to use to parse the attributes + * @param namespace the namespace to use to parse the attributes + * @param node the node to be parsed + * + * @return the parsed value + */ private fun getValue(context: Context, parser: XmlResourceParser, namespace: String, node: String): String { try { val titleResId = parser.getAttributeResourceValue(namespace, node, -1) @@ -102,17 +169,10 @@ object PreferenceParser { } return "" } - - private fun getSummary (context: Context, parser: XmlResourceParser, namespace: String, node: String, defaultValue:String, key:String):String { - - val value = getValue(context, parser, namespace, node) - if (value.contains("%s")) if (BuildConfig.DEBUG) Log.d(this::class.java.simpleName, "Found string replacement for $key") - return if (value.contains("%s")) - value.replace("%s", Settings.getInstance(context).getString(key, defaultValue) ?: "") - else value - - } } +/** + * Object describing a [androidx.preference.Preference] with useful values to search / display them + */ @Parcelize -data class PreferenceItem(val key: String, val parentScreen: Int, val title: String, val summary: String, val titleEng:String, val summaryEng: String, val category: String, val categoryEng: String) : Parcelable \ No newline at end of file +data class PreferenceItem(val key: String, val parentScreen: Int, val title: String, val summary: String, val titleEng:String, val summaryEng: String, val category: String, val categoryEng: String, val defaultValue:String?) : Parcelable \ No newline at end of file