diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index ff4521ffdb..85f632878f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -15,6 +15,7 @@ import org.dolphinemu.dolphinemu.utils.Log; import org.dolphinemu.dolphinemu.utils.Rumble; import java.lang.ref.WeakReference; +import java.util.LinkedHashMap; /** * Class which contains methods that interact @@ -370,6 +371,8 @@ public final class NativeLibrary public static native int DefaultCPUCore(); + public static native int GetMaxLogLevel(); + public static native void ReloadConfig(); /** @@ -452,6 +455,10 @@ public final class NativeLibrary public static native void ReloadWiimoteConfig(); + public static native LinkedHashMap GetLogTypeNames(); + + public static native void ReloadLoggerConfig(); + public static native boolean InstallWAD(String file); public static native String FormatSize(long bytes, int decimals); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Setting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Setting.java index df24648ab3..6dcc49478c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Setting.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Setting.java @@ -39,7 +39,6 @@ public abstract class Setting return mSection; } - /** * @return A representation of this Setting's backing value converted to a String (e.g. for serialization). */ diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java index 36e38dd203..b07a3d2917 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java @@ -23,6 +23,9 @@ public class Settings public static final String SECTION_INI_INTERFACE = "Interface"; public static final String SECTION_INI_DSP = "DSP"; + public static final String SECTION_LOGGER_LOGS = "Logs"; + public static final String SECTION_LOGGER_OPTIONS = "Options"; + public static final String SECTION_GFX_SETTINGS = "Settings"; public static final String SECTION_GFX_ENHANCEMENTS = "Enhancements"; public static final String SECTION_GFX_HACKS = "Hacks"; @@ -57,6 +60,8 @@ public class Settings configFileSectionsMap.put(SettingsFile.FILE_NAME_GFX, Arrays.asList(SECTION_GFX_SETTINGS, SECTION_GFX_ENHANCEMENTS, SECTION_GFX_HACKS, SECTION_STEREOSCOPY)); + configFileSectionsMap.put(SettingsFile.FILE_NAME_LOGGER, + Arrays.asList(SECTION_LOGGER_LOGS, SECTION_LOGGER_OPTIONS)); configFileSectionsMap.put(SettingsFile.FILE_NAME_WIIMOTE, Arrays.asList(SECTION_WIIMOTE + 1, SECTION_WIIMOTE + 2, SECTION_WIIMOTE + 3, SECTION_WIIMOTE + 4)); @@ -226,6 +231,7 @@ public class Settings // Notify the native code of the changes NativeLibrary.ReloadConfig(); NativeLibrary.ReloadWiimoteConfig(); + NativeLibrary.ReloadLoggerConfig(); if (modifiedSettings.contains(SettingsFile.KEY_RECURSIVE_ISO_PATHS)) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java index f96bdbb33b..aa6f9a48f4 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java @@ -10,6 +10,7 @@ public enum MenuTag CONFIG_GAME_CUBE("config_gamecube"), CONFIG_WII("config_wii"), CONFIG_ADVANCED("config_advanced"), + CONFIG_LOG("config_log"), WIIMOTE("wiimote"), WIIMOTE_EXTENSION("wiimote_extension"), GCPAD_TYPE("gc_pad_type"), diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java index 7f38ed9162..e2b387a049 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java @@ -50,6 +50,7 @@ import org.dolphinemu.dolphinemu.utils.Log; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.HashSet; +import java.util.Map; public final class SettingsAdapter extends RecyclerView.Adapter implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener @@ -369,6 +370,15 @@ public final class SettingsAdapter extends RecyclerView.Adapter entry : SettingsFragmentPresenter.LOG_TYPE_NAMES.entrySet()) + { + sView.putSetting(new StringSetting(entry.getKey(), Settings.SECTION_LOGGER_LOGS, value)); + } + sView.onSettingChanged(null); + } + private void handleMenuTag(MenuTag menuTag, int value) { if (menuTag != null) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java index 8292058add..3c1767b45e 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java @@ -48,6 +48,7 @@ public final class SettingsFragment extends Fragment implements SettingsFragment titles.put(MenuTag.GCPAD_TYPE, R.string.grid_menu_gcpad_settings); titles.put(MenuTag.GRAPHICS, R.string.grid_menu_graphics_settings); titles.put(MenuTag.HACKS, R.string.hacks_submenu); + titles.put(MenuTag.CONFIG_LOG, R.string.log_submenu); titles.put(MenuTag.DEBUG, R.string.debug_submenu); titles.put(MenuTag.ENHANCEMENTS, R.string.enhancements_submenu); titles.put(MenuTag.STEREOSCOPY, R.string.stereoscopy_submenu); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java index 80718eb7b4..fd3d943def 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java @@ -31,11 +31,16 @@ import org.dolphinemu.dolphinemu.utils.Log; import java.io.File; import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Map; public final class SettingsFragmentPresenter { private SettingsFragmentView mView; + public static final LinkedHashMap LOG_TYPE_NAMES = + NativeLibrary.GetLogTypeNames(); + public static final String ARG_CONTROLLER_TYPE = "controller_type"; private MenuTag mMenuTag; private String mGameID; @@ -176,6 +181,10 @@ public final class SettingsFragmentPresenter addHackSettings(sl); break; + case CONFIG_LOG: + addLogConfigurationSettings(sl); + break; + case DEBUG: addDebugSettings(sl); break; @@ -223,6 +232,7 @@ public final class SettingsFragmentPresenter sl.add(new SubmenuSetting(null, null, R.string.gamecube_submenu, MenuTag.CONFIG_GAME_CUBE)); sl.add(new SubmenuSetting(null, null, R.string.wii_submenu, MenuTag.CONFIG_WII)); sl.add(new SubmenuSetting(null, null, R.string.advanced_submenu, MenuTag.CONFIG_ADVANCED)); + sl.add(new SubmenuSetting(null, null, R.string.log_submenu, MenuTag.CONFIG_LOG)); sl.add(new SubmenuSetting(null, null, R.string.debug_submenu, MenuTag.DEBUG)); sl.add(new HeaderSetting(null, null, R.string.gametdb_thanks, 0)); } @@ -729,6 +739,36 @@ public final class SettingsFragmentPresenter fastDepth)); } + private void addLogConfigurationSettings(ArrayList sl) + { + SettingSection logsSection = mSettings.getSection(Settings.SECTION_LOGGER_LOGS); + SettingSection optionsSection = mSettings.getSection(Settings.SECTION_LOGGER_OPTIONS); + Setting enableLogging = optionsSection.getSetting(SettingsFile.KEY_ENABLE_LOGGING); + Setting logVerbosity = optionsSection.getSetting(SettingsFile.KEY_LOG_VERBOSITY); + + sl.add(new CheckBoxSetting(SettingsFile.KEY_ENABLE_LOGGING, Settings.SECTION_LOGGER_OPTIONS, + R.string.enable_logging, R.string.enable_logging_description, false, enableLogging)); + sl.add(new SingleChoiceSetting(SettingsFile.KEY_LOG_VERBOSITY, Settings.SECTION_LOGGER_OPTIONS, + R.string.log_verbosity, 0, getLogVerbosityEntries(), getLogVerbosityValues(), 1, + logVerbosity)); + sl.add(new ConfirmRunnable(R.string.log_enable_all, 0, R.string.log_enable_all_confirmation, 0, + () -> SettingsAdapter.setAllLogTypes("True"))); + sl.add( + new ConfirmRunnable(R.string.log_disable_all, 0, R.string.log_disable_all_confirmation, + 0, + () -> SettingsAdapter.setAllLogTypes("False"))); + + sl.add(new HeaderSetting(null, null, R.string.log_types, 0)); + for (Map.Entry entry : LOG_TYPE_NAMES.entrySet()) + { + Setting setting = logsSection.getSetting(entry.getKey()); + // TitleID is handled by special case in CheckBoxSettingViewHolder. + sl.add( + new CheckBoxSetting(entry.getKey(), Settings.SECTION_LOGGER_LOGS, 0, 0, false, + setting)); + } + } + private void addDebugSettings(ArrayList sl) { SettingSection debugSection = mSettings.getSection(Settings.SECTION_DEBUG); @@ -1599,4 +1639,30 @@ public final class SettingsFragmentPresenter { return DirectoryInitialization.getUserDirectory() + "/Wii/sd.raw"; } + + private static int getLogVerbosityEntries() + { + // Value obtained from LOG_LEVELS in Common/Logging/Log.h + if (NativeLibrary.GetMaxLogLevel() == 5) + { + return R.array.logVerbosityEntriesMaxLevelDebug; + } + else + { + return R.array.logVerbosityEntriesMaxLevelInfo; + } + } + + private static int getLogVerbosityValues() + { + // Value obtained from LOG_LEVELS in Common/Logging/Log.h + if (NativeLibrary.GetMaxLogLevel() == 5) + { + return R.array.logVerbosityValuesMaxLevelDebug; + } + else + { + return R.array.logVerbosityValuesMaxLevelInfo; + } + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/CheckBoxSettingViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/CheckBoxSettingViewHolder.java index e2b5c2e42d..1e5ed6cf15 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/CheckBoxSettingViewHolder.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/CheckBoxSettingViewHolder.java @@ -5,9 +5,11 @@ import android.widget.CheckBox; import android.widget.TextView; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; +import org.dolphinemu.dolphinemu.features.settings.ui.SettingsFragmentPresenter; public final class CheckBoxSettingViewHolder extends SettingViewHolder { @@ -36,7 +38,15 @@ public final class CheckBoxSettingViewHolder extends SettingViewHolder { mItem = (CheckBoxSetting) item; - mTextSettingName.setText(item.getNameId()); + // Special case for LogTypes retrieved via JNI since those aren't string references. + if (item.getNameId() == 0 && item.getSection().equals(Settings.SECTION_LOGGER_LOGS)) + { + mTextSettingName.setText(SettingsFragmentPresenter.LOG_TYPE_NAMES.get(item.getKey())); + } + else + { + mTextSettingName.setText(item.getNameId()); + } if (item.getDescriptionId() > 0) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java index e4bc8b9bd9..8f1d1ea468 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java @@ -36,6 +36,7 @@ public final class SettingsFile { public static final String FILE_NAME_DOLPHIN = "Dolphin"; public static final String FILE_NAME_GFX = "GFX"; + public static final String FILE_NAME_LOGGER = "Logger"; public static final String FILE_NAME_GCPAD = "GCPadNew"; public static final String FILE_NAME_WIIMOTE = "WiimoteNew"; @@ -286,6 +287,9 @@ public final class SettingsFile public static final String KEY_WIIMOTE_SCAN = "WiimoteContinuousScanning"; public static final String KEY_WIIMOTE_SPEAKER = "WiimoteEnableSpeaker"; + public static final String KEY_ENABLE_LOGGING = "WriteToFile"; + public static final String KEY_LOG_VERBOSITY = "Verbosity"; + private static BiMap sectionsMap = new BiMap<>(); static diff --git a/Source/Android/app/src/main/res/values/arrays.xml b/Source/Android/app/src/main/res/values/arrays.xml index 881701b9b9..5adc40229d 100644 --- a/Source/Android/app/src/main/res/values/arrays.xml +++ b/Source/Android/app/src/main/res/values/arrays.xml @@ -71,7 +71,7 @@ 5 - + Nothing Dummy @@ -85,6 +85,34 @@ 8 + + + Notice + Error + Warning + Info + + + 1 + 2 + 3 + 4 + + + Notice + Error + Warning + Info + Debug + + + 1 + 2 + 3 + 4 + 5 + + OpenGL diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index 2ffc5320e4..e72828590a 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -265,6 +265,17 @@ Emulated CPU Clock Speed Adjusts the emulated CPU\'s clock rate if \"Override Emulated CPU Clock Speed\" is enabled. + + Log + Enable Logging + Log messages from enabled log types to dolphin-emu/Logs/. Will decrease performance. + Verbosity + Enable all Log Types + Are you sure you want to enable all log types? + Disable all Log Types + Are you sure you want to disable all log types? + Log Types + Debug Warning: These settings will slow emulation diff --git a/Source/Android/jni/AndroidCommon/IDCache.cpp b/Source/Android/jni/AndroidCommon/IDCache.cpp index 01f76f344a..32160edaee 100644 --- a/Source/Android/jni/AndroidCommon/IDCache.cpp +++ b/Source/Android/jni/AndroidCommon/IDCache.cpp @@ -12,6 +12,7 @@ static JavaVM* s_java_vm; static jclass s_native_library_class; static jmethodID s_display_alert_msg; +static jmethodID s_do_rumble; static jmethodID s_get_update_touch_pointer; static jclass s_game_file_class; @@ -25,7 +26,9 @@ static jclass s_analytics_class; static jmethodID s_send_analytics_report; static jmethodID s_get_analytics_value; -static jmethodID s_do_rumble; +static jclass s_linked_hash_map_class; +static jmethodID s_linked_hash_map_init; +static jmethodID s_linked_hash_map_put; namespace IDCache { @@ -62,6 +65,11 @@ jmethodID GetDisplayAlertMsg() return s_display_alert_msg; } +jmethodID GetDoRumble() +{ + return s_do_rumble; +} + jmethodID GetUpdateTouchPointer() { return s_get_update_touch_pointer; @@ -106,9 +114,19 @@ jfieldID GetGameFileCachePointer() return s_game_file_cache_pointer; } -jmethodID GetDoRumble() +jclass GetLinkedHashMapClass() { - return s_do_rumble; + return s_linked_hash_map_class; +} + +jmethodID GetLinkedHashMapInit() +{ + return s_linked_hash_map_init; +} + +jmethodID GetLinkedHashMapPut() +{ + return s_linked_hash_map_put; } } // namespace IDCache @@ -150,6 +168,12 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) s_get_analytics_value = env->GetStaticMethodID(s_analytics_class, "getValue", "(Ljava/lang/String;)Ljava/lang/String;"); + const jclass map_class = env->FindClass("java/util/LinkedHashMap"); + s_linked_hash_map_class = reinterpret_cast(env->NewGlobalRef(map_class)); + s_linked_hash_map_init = env->GetMethodID(s_linked_hash_map_class, "", "(I)V"); + s_linked_hash_map_put = env->GetMethodID( + s_linked_hash_map_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + return JNI_VERSION; } @@ -163,6 +187,7 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) env->DeleteGlobalRef(s_game_file_class); env->DeleteGlobalRef(s_game_file_cache_class); env->DeleteGlobalRef(s_analytics_class); + env->DeleteGlobalRef(s_linked_hash_map_class); } #ifdef __cplusplus diff --git a/Source/Android/jni/AndroidCommon/IDCache.h b/Source/Android/jni/AndroidCommon/IDCache.h index 68cfdb80af..286009239f 100644 --- a/Source/Android/jni/AndroidCommon/IDCache.h +++ b/Source/Android/jni/AndroidCommon/IDCache.h @@ -28,4 +28,8 @@ jmethodID GetGameFileConstructor(); jclass GetGameFileCacheClass(); jfieldID GetGameFileCachePointer(); +jclass GetLinkedHashMapClass(); +jmethodID GetLinkedHashMapInit(); +jmethodID GetLinkedHashMapPut(); + } // namespace IDCache diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index f39f27a503..03fb660e1d 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -244,6 +244,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetCacheDire JNIEnv* env, jobject obj, jstring jDirectory); JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_DefaultCPUCore(JNIEnv* env, jobject obj); +JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetMaxLogLevel(JNIEnv* env, + jobject obj); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv* env, jobject obj, jboolean enable); @@ -549,6 +551,12 @@ JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_DefaultCPUCo return static_cast(PowerPC::DefaultCPUCore()); } +JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetMaxLogLevel(JNIEnv* env, + jobject obj) +{ + return static_cast(MAX_LOGLEVEL); +} + JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv* env, jobject obj, jboolean enable) @@ -753,6 +761,28 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ChangeDisc(J Core::RunAsCPUThread([&path] { DVDInterface::ChangeDisc(path); }); } +JNIEXPORT jobject JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetLogTypeNames(JNIEnv* env, + jobject obj) +{ + std::map map = Common::Log::LogManager::GetInstance()->GetLogTypes(); + + auto map_size = static_cast(map.size()); + jobject linked_hash_map = + env->NewObject(IDCache::GetLinkedHashMapClass(), IDCache::GetLinkedHashMapInit(), map_size); + for (const auto& entry : map) + { + env->CallObjectMethod(linked_hash_map, IDCache::GetLinkedHashMapPut(), + ToJString(env, entry.first), ToJString(env, entry.second)); + } + return linked_hash_map; +} + +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ReloadLoggerConfig(JNIEnv* env, + jobject obj) +{ + Common::Log::LogManager::Init(); +} + JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_InstallWAD(JNIEnv* env, jobject obj, jstring jFile) diff --git a/Source/Core/Common/Logging/LogManager.cpp b/Source/Core/Common/Logging/LogManager.cpp index ba6e33e78d..99ddf83d67 100644 --- a/Source/Core/Common/Logging/LogManager.cpp +++ b/Source/Core/Common/Logging/LogManager.cpp @@ -239,6 +239,17 @@ bool LogManager::IsEnabled(LOG_TYPE type, LOG_LEVELS level) const return m_log[type].m_enable && GetLogLevel() >= level; } +std::map LogManager::GetLogTypes() +{ + std::map log_types; + + for (const auto& container : m_log) + { + log_types.emplace(container.m_short_name, container.m_full_name); + } + return log_types; +} + const char* LogManager::GetShortName(LOG_TYPE type) const { return m_log[type].m_short_name; diff --git a/Source/Core/Common/Logging/LogManager.h b/Source/Core/Common/Logging/LogManager.h index 3fb99da7ec..69a5fe9132 100644 --- a/Source/Core/Common/Logging/LogManager.h +++ b/Source/Core/Common/Logging/LogManager.h @@ -6,6 +6,7 @@ #include #include +#include #include "Common/BitSet.h" #include "Common/Logging/Log.h" @@ -47,6 +48,8 @@ public: void SetEnable(LOG_TYPE type, bool enable); bool IsEnabled(LOG_TYPE type, LOG_LEVELS level = LNOTICE) const; + std::map GetLogTypes(); + const char* GetShortName(LOG_TYPE type) const; const char* GetFullName(LOG_TYPE type) const;