Merge pull request #8975 from JosJuice/android-new-config

Android: Hook up the new config system
This commit is contained in:
JosJuice 2020-09-16 09:49:16 +02:00 committed by GitHub
commit a7b9e6857b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 2062 additions and 914 deletions

View File

@ -335,6 +335,8 @@ public final class NativeLibrary
public static native int DefaultCPUCore();
public static native String GetDefaultGraphicsBackendName();
public static native int GetMaxLogLevel();
public static native void ReloadConfig();

View File

@ -34,6 +34,8 @@ import androidx.fragment.app.FragmentManager;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import org.dolphinemu.dolphinemu.fragments.EmulationFragment;
import org.dolphinemu.dolphinemu.fragments.MenuFragment;
@ -101,7 +103,8 @@ public final class EmulationActivity extends AppCompatActivity
MENU_ACTION_LOAD_SLOT6, MENU_ACTION_EXIT, MENU_ACTION_CHANGE_DISC,
MENU_ACTION_RESET_OVERLAY, MENU_SET_IR_SENSITIVITY, MENU_ACTION_CHOOSE_DOUBLETAP,
MENU_ACTION_SCREEN_ORIENTATION, MENU_ACTION_MOTION_CONTROLS, MENU_ACTION_PAUSE_EMULATION,
MENU_ACTION_UNPAUSE_EMULATION, MENU_ACTION_OVERLAY_CONTROLS})
MENU_ACTION_UNPAUSE_EMULATION, MENU_ACTION_OVERLAY_CONTROLS, MENU_ACTION_SETTINGS_CORE,
MENU_ACTION_SETTINGS_GRAPHICS})
public @interface MenuAction
{
}
@ -140,6 +143,8 @@ public final class EmulationActivity extends AppCompatActivity
public static final int MENU_ACTION_PAUSE_EMULATION = 31;
public static final int MENU_ACTION_UNPAUSE_EMULATION = 32;
public static final int MENU_ACTION_OVERLAY_CONTROLS = 33;
public static final int MENU_ACTION_SETTINGS_CORE = 34;
public static final int MENU_ACTION_SETTINGS_GRAPHICS = 35;
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
@ -363,6 +368,13 @@ public final class EmulationActivity extends AppCompatActivity
super.onStop();
}
@Override
protected void onDestroy()
{
super.onDestroy();
mSettings.close();
}
@Override
public void onBackPressed()
{
@ -641,6 +653,14 @@ public final class EmulationActivity extends AppCompatActivity
showMotionControlsOptions();
return;
case MENU_ACTION_SETTINGS_CORE:
SettingsActivity.launch(this, MenuTag.CONFIG);
return;
case MENU_ACTION_SETTINGS_GRAPHICS:
SettingsActivity.launch(this, MenuTag.GRAPHICS);
return;
case MENU_ACTION_EXIT:
mEmulationFragment.stopEmulation();
finish();
@ -855,7 +875,7 @@ public final class EmulationActivity extends AppCompatActivity
{
editor.putInt("wiiController", indexSelected);
File wiimoteNewFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_WIIMOTE);
File wiimoteNewFile = SettingsFile.getSettingsFile(Settings.FILE_WIIMOTE);
IniFile wiimoteNewIni = new IniFile(wiimoteNewFile);
wiimoteNewIni.setString("Wiimote1", "Extension",
getResources().getStringArray(R.array.controllersValues)[indexSelected]);
@ -889,7 +909,7 @@ public final class EmulationActivity extends AppCompatActivity
else
mMotionListener.disable();
File wiimoteNewFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_WIIMOTE);
File wiimoteNewFile = SettingsFile.getSettingsFile(Settings.FILE_WIIMOTE);
IniFile wiimoteNewIni = new IniFile(wiimoteNewFile);
wiimoteNewIni.setBoolean("Wiimote1", "IMUIR/Enabled", indexSelected != 1);
wiimoteNewIni.save(wiimoteNewFile);

View File

@ -156,11 +156,12 @@ public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> impl
return true;
}
GamePropertiesDialog fragment =
GamePropertiesDialog
.newInstance(holder.gameFile.getPath(), gameId, holder.gameFile.getPlatform());
GamePropertiesDialog fragment = GamePropertiesDialog.newInstance(holder.gameFile.getPath(),
gameId, holder.gameFile.getRevision(), holder.gameFile.getPlatform());
((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction()
.add(fragment, GamePropertiesDialog.TAG).commit();
return true;
}

View File

@ -100,9 +100,9 @@ public final class GameRowPresenter extends Presenter
return true;
}
GamePropertiesDialog fragment =
GamePropertiesDialog.newInstance(holder.gameFile.getPath(), gameId,
holder.gameFile.getPlatform());
GamePropertiesDialog fragment = GamePropertiesDialog.newInstance(holder.gameFile.getPath(),
gameId, holder.gameFile.getRevision(), holder.gameFile.getPlatform());
((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction()
.add(fragment, GamePropertiesDialog.TAG).commit();

View File

@ -8,15 +8,13 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
import org.dolphinemu.dolphinemu.utils.IniFile;
import org.dolphinemu.dolphinemu.utils.Log;
import java.io.File;
@ -26,15 +24,18 @@ public class GamePropertiesDialog extends DialogFragment
public static final String TAG = "GamePropertiesDialog";
public static final String ARG_PATH = "path";
public static final String ARG_GAMEID = "game_id";
public static final String ARG_REVISION = "revision";
public static final String ARG_PLATFORM = "platform";
public static GamePropertiesDialog newInstance(String path, String gameId, int platform)
public static GamePropertiesDialog newInstance(String path, String gameId, int revision,
int platform)
{
GamePropertiesDialog fragment = new GamePropertiesDialog();
Bundle arguments = new Bundle();
arguments.putString(ARG_PATH, path);
arguments.putString(ARG_GAMEID, gameId);
arguments.putInt(ARG_REVISION, revision);
arguments.putInt(ARG_PLATFORM, platform);
fragment.setArguments(arguments);
@ -50,6 +51,7 @@ public class GamePropertiesDialog extends DialogFragment
String path = requireArguments().getString(ARG_PATH);
String gameId = requireArguments().getString(ARG_GAMEID);
int revision = requireArguments().getInt(ARG_REVISION);
int platform = requireArguments().getInt(ARG_PLATFORM);
builder.setTitle(requireContext()
@ -65,30 +67,28 @@ public class GamePropertiesDialog extends DialogFragment
.getSupportFragmentManager(), "game_details");
break;
case 1:
File dolphinFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_DOLPHIN);
IniFile dolphinIni = new IniFile(dolphinFile);
dolphinIni.setString(Settings.SECTION_INI_CORE, SettingsFile.KEY_DEFAULT_ISO,
path);
dolphinIni.save(dolphinFile);
NativeLibrary.ReloadConfig();
Toast.makeText(getContext(), "Default ISO set", Toast.LENGTH_SHORT).show();
try (Settings settings = new Settings())
{
settings.loadSettings(null);
StringSetting.MAIN_DEFAULT_ISO.setString(settings, path);
settings.saveSettings(null, getContext());
}
break;
case 2:
SettingsActivity.launch(getContext(), MenuTag.CONFIG, gameId);
SettingsActivity.launch(getContext(), MenuTag.CONFIG, gameId, revision);
break;
case 3:
SettingsActivity.launch(getContext(), MenuTag.GRAPHICS, gameId);
SettingsActivity.launch(getContext(), MenuTag.GRAPHICS, gameId, revision);
break;
case 4:
SettingsActivity.launch(getContext(), MenuTag.GCPAD_TYPE, gameId);
SettingsActivity.launch(getContext(), MenuTag.GCPAD_TYPE, gameId, revision);
break;
case 5:
// Clear option for GC, Wii controls for else
if (platform == Platform.GAMECUBE.toInt())
clearGameSettings(gameId);
else
SettingsActivity.launch(getActivity(), MenuTag.WIIMOTE, gameId);
SettingsActivity.launch(getActivity(), MenuTag.WIIMOTE, gameId, revision);
break;
case 6:
clearGameSettings(gameId);

View File

@ -0,0 +1,8 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public interface AbstractBooleanSetting extends AbstractSetting
{
boolean getBoolean(Settings settings);
void setBoolean(Settings settings, boolean newValue);
}

View File

@ -0,0 +1,8 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public interface AbstractFloatSetting extends AbstractSetting
{
float getFloat(Settings settings);
void setFloat(Settings settings, float newValue);
}

View File

@ -0,0 +1,8 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public interface AbstractIntSetting extends AbstractSetting
{
int getInt(Settings settings);
void setInt(Settings settings, int newValue);
}

View File

@ -0,0 +1,33 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public class AbstractLegacySetting implements AbstractSetting
{
protected final String mFile;
protected final String mSection;
protected final String mKey;
public AbstractLegacySetting(String file, String section, String key)
{
mFile = file;
mSection = section;
mKey = key;
}
@Override
public boolean isOverridden(Settings settings)
{
return settings.isGameSpecific() && settings.getSection(mFile, mSection).exists(mKey);
}
@Override
public boolean isRuntimeEditable()
{
return false;
}
@Override
public boolean delete(Settings settings)
{
return settings.getSection(mFile, mSection).delete(mKey);
}
}

View File

@ -0,0 +1,10 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public interface AbstractSetting
{
boolean isOverridden(Settings settings);
boolean isRuntimeEditable();
boolean delete(Settings settings);
}

View File

@ -0,0 +1,8 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public interface AbstractStringSetting extends AbstractSetting
{
String getString(Settings settings);
void setString(Settings settings, String newValue);
}

View File

@ -0,0 +1,52 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public class AdHocBooleanSetting implements AbstractBooleanSetting
{
private final String mFile;
private final String mSection;
private final String mKey;
private final boolean mDefaultValue;
public AdHocBooleanSetting(String file, String section, String key, boolean defaultValue)
{
mFile = file;
mSection = section;
mKey = key;
mDefaultValue = defaultValue;
if (!NativeConfig.isSettingSaveable(file, section, key))
{
throw new IllegalArgumentException("File/section/key is unknown or legacy");
}
}
@Override
public boolean isOverridden(Settings settings)
{
return NativeConfig.isOverridden(mFile, mSection, mKey);
}
@Override
public boolean isRuntimeEditable()
{
return true;
}
@Override
public boolean delete(Settings settings)
{
return NativeConfig.deleteKey(settings.getActiveLayer(), mFile, mSection, mKey);
}
@Override
public boolean getBoolean(Settings settings)
{
return NativeConfig.getBoolean(settings.getActiveLayer(), mFile, mSection, mKey, mDefaultValue);
}
@Override
public void setBoolean(Settings settings, boolean newValue)
{
NativeConfig.setBoolean(settings.getActiveLayer(), mFile, mSection, mKey, newValue);
}
}

View File

@ -0,0 +1,185 @@
package org.dolphinemu.dolphinemu.features.settings.model;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public enum BooleanSetting implements AbstractBooleanSetting
{
// These entries have the same names and order as in C++, just for consistency.
MAIN_DSP_HLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "DSPHLE", true),
MAIN_CPU_THREAD(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "CPUThread", true),
MAIN_OVERRIDE_REGION_SETTINGS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE,
"OverrideRegionSettings", false),
MAIN_AUDIO_STRETCH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AudioStretch", false),
MAIN_WII_SD_CARD(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "WiiSDCard", true),
MAIN_WIIMOTE_CONTINUOUS_SCANNING(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE,
"WiimoteContinuousScanning", false),
MAIN_WIIMOTE_ENABLE_SPEAKER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE,
"WiimoteEnableSpeaker", false),
MAIN_OVERCLOCK_ENABLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "OverclockEnable", false),
MAIN_AUTO_DISC_CHANGE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AutoDiscChange", false),
MAIN_ALLOW_SD_WRITES(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "WiiSDCardAllowWrites",
true),
MAIN_ENABLE_SAVESTATES(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EnableSaveStates",
false),
MAIN_DSP_JIT(Settings.FILE_DOLPHIN, Settings.SECTION_INI_DSP, "EnableJIT", true),
MAIN_USE_PANIC_HANDLERS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_INTERFACE,
"UsePanicHandlers", true),
MAIN_OSD_MESSAGES(Settings.FILE_DOLPHIN, Settings.SECTION_INI_INTERFACE,
"OnScreenDisplayMessages", true),
MAIN_ANALYTICS_ENABLED(Settings.FILE_DOLPHIN, Settings.SECTION_ANALYTICS, "Enabled", false),
MAIN_ANALYTICS_PERMISSION_ASKED(Settings.FILE_DOLPHIN, Settings.SECTION_ANALYTICS,
"PermissionAsked", false),
MAIN_RECURSIVE_ISO_PATHS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL,
"RecursiveISOPaths", false),
GFX_WIDESCREEN_HACK(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "wideScreenHack", false),
GFX_SHOW_FPS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowFPS", false),
GFX_ENABLE_GPU_TEXTURE_DECODING(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"EnableGPUTextureDecoding", false),
GFX_ENABLE_PIXEL_LIGHTING(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"EnablePixelLighting", false),
GFX_FAST_DEPTH_CALC(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "FastDepthCalc", true),
GFX_DISABLE_FOG(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DisableFog", false),
GFX_BACKEND_MULTITHREADING(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"BackendMultithreading", false),
GFX_WAIT_FOR_SHADERS_BEFORE_STARTING(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"WaitForShadersBeforeStarting", false),
GFX_ENHANCE_FORCE_FILTERING(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS,
"ForceFiltering", false),
GFX_ENHANCE_FORCE_TRUE_COLOR(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS,
"ForceTrueColor", true),
GFX_ENHANCE_DISABLE_COPY_FILTER(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS,
"DisableCopyFilter", true),
GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS,
"ArbitraryMipmapDetection", true),
GFX_STEREO_SWAP_EYES(Settings.FILE_GFX, Settings.SECTION_STEREOSCOPY, "StereoSwapEyes", false),
GFX_HACK_EFB_ACCESS_ENABLE(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "EFBAccessEnable",
true),
GFX_HACK_SKIP_EFB_COPY_TO_RAM(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS,
"EFBToTextureEnable", true),
GFX_HACK_SKIP_XFB_COPY_TO_RAM(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS,
"XFBToTextureEnable", true),
GFX_HACK_DEFER_EFB_COPIES(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "DeferEFBCopies", true),
GFX_HACK_IMMEDIATE_XFB(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "ImmediateXFBEnable",
false),
GFX_HACK_SKIP_DUPLICATE_XFBS(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "SkipDuplicateXFBs",
true),
GFX_HACK_COPY_EFB_SCALED(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "EFBScaledCopy", true),
GFX_HACK_EFB_EMULATE_FORMAT_CHANGES(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS,
"EFBEmulateFormatChanges", false),
LOGGER_WRITE_TO_FILE(Settings.FILE_LOGGER, Settings.SECTION_LOGGER_OPTIONS, "WriteToFile", false),
// These settings are not yet in the new config system in C++ - please move them once they are
MAIN_JIT_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitOff", false),
MAIN_JIT_LOAD_STORE_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitLoadStoreOff", false),
MAIN_JIT_LOAD_STORE_FLOATING_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG,
"JitLoadStoreFloatingOff", false),
MAIN_JIT_LOAD_STORE_PAIRED_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG,
"JitLoadStorePairedOff", false),
MAIN_JIT_FLOATING_POINT_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitFloatingPointOff",
false),
MAIN_JIT_INTEGER_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitIntegerOff", false),
MAIN_JIT_PAIRED_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitPairedOff", false),
MAIN_JIT_SYSTEM_REGISTERS_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG,
"JitSystemRegistersOff", false),
MAIN_JIT_BRANCH_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitBranchOff", false),
MAIN_JIT_REGISTER_CACHE_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitRegisterCacheOff",
false);
private static final BooleanSetting[] NOT_RUNTIME_EDITABLE_ARRAY = new BooleanSetting[]{
MAIN_DSP_HLE,
MAIN_CPU_THREAD,
MAIN_OVERRIDE_REGION_SETTINGS,
MAIN_WII_SD_CARD, // Can actually be changed, but specific code is required
MAIN_DSP_JIT
};
private static final Set<BooleanSetting> NOT_RUNTIME_EDITABLE =
new HashSet<>(Arrays.asList(NOT_RUNTIME_EDITABLE_ARRAY));
private final String mFile;
private final String mSection;
private final String mKey;
private final boolean mDefaultValue;
BooleanSetting(String file, String section, String key, boolean defaultValue)
{
mFile = file;
mSection = section;
mKey = key;
mDefaultValue = defaultValue;
}
@Override
public boolean isOverridden(Settings settings)
{
if (settings.isGameSpecific() && !NativeConfig.isSettingSaveable(mFile, mSection, mKey))
return settings.getSection(mFile, mSection).exists(mKey);
else
return NativeConfig.isOverridden(mFile, mSection, mKey);
}
@Override
public boolean isRuntimeEditable()
{
for (BooleanSetting setting : NOT_RUNTIME_EDITABLE)
{
if (setting == this)
return false;
}
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
}
@Override
public boolean delete(Settings settings)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
return NativeConfig.deleteKey(settings.getActiveLayer(), mFile, mSection, mKey);
}
else
{
return settings.getSection(mFile, mSection).delete(mKey);
}
}
@Override
public boolean getBoolean(Settings settings)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
return NativeConfig.getBoolean(settings.getActiveLayer(), mFile, mSection, mKey,
mDefaultValue);
}
else
{
return settings.getSection(mFile, mSection).getBoolean(mKey, mDefaultValue);
}
}
@Override
public void setBoolean(Settings settings, boolean newValue)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
NativeConfig.setBoolean(settings.getActiveLayer(), mFile, mSection, mKey, newValue);
}
else
{
settings.getSection(mFile, mSection).setBoolean(mKey, newValue);
}
}
}

View File

@ -0,0 +1,76 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public enum FloatSetting implements AbstractFloatSetting
{
// These entries have the same names and order as in C++, just for consistency.
MAIN_EMULATION_SPEED(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EmulationSpeed", 1.0f),
MAIN_OVERCLOCK(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "Overclock", 1.0f);
private final String mFile;
private final String mSection;
private final String mKey;
private final float mDefaultValue;
FloatSetting(String file, String section, String key, float defaultValue)
{
mFile = file;
mSection = section;
mKey = key;
mDefaultValue = defaultValue;
}
@Override
public boolean isOverridden(Settings settings)
{
if (settings.isGameSpecific() && !NativeConfig.isSettingSaveable(mFile, mSection, mKey))
return settings.getSection(mFile, mSection).exists(mKey);
else
return NativeConfig.isOverridden(mFile, mSection, mKey);
}
@Override
public boolean isRuntimeEditable()
{
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
}
@Override
public boolean delete(Settings settings)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
return NativeConfig.deleteKey(settings.getActiveLayer(), mFile, mSection, mKey);
}
else
{
return settings.getSection(mFile, mSection).delete(mKey);
}
}
@Override
public float getFloat(Settings settings)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
return NativeConfig.getFloat(settings.getActiveLayer(), mFile, mSection, mKey, mDefaultValue);
}
else
{
return settings.getSection(mFile, mSection).getFloat(mKey, mDefaultValue);
}
}
@Override
public void setFloat(Settings settings, float newValue)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
NativeConfig.setFloat(settings.getActiveLayer(), mFile, mSection, mKey, newValue);
}
else
{
settings.getSection(mFile, mSection).setFloat(mKey, newValue);
}
}
}

View File

@ -0,0 +1,123 @@
package org.dolphinemu.dolphinemu.features.settings.model;
import org.dolphinemu.dolphinemu.NativeLibrary;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public enum IntSetting implements AbstractIntSetting
{
// These entries have the same names and order as in C++, just for consistency.
MAIN_CPU_CORE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "CPUCore",
NativeLibrary.DefaultCPUCore()),
MAIN_GC_LANGUAGE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SelectedLanguage", 0),
MAIN_SLOT_A(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SlotA", 8),
MAIN_SLOT_B(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SlotB", 255),
MAIN_AUDIO_VOLUME(Settings.FILE_DOLPHIN, Settings.SECTION_INI_DSP, "Volume", 100),
MAIN_LAST_PLATFORM_TAB(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "LastPlatformTab", 0),
GFX_ASPECT_RATIO(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "AspectRatio", 0),
GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"SafeTextureCacheColorSamples", 128),
GFX_MSAA(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "MSAA", 1),
GFX_EFB_SCALE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "InternalResolution", 1),
GFX_SHADER_COMPILATION_MODE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"ShaderCompilationMode", 0),
GFX_ENHANCE_MAX_ANISOTROPY(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS, "MaxAnisotropy",
0),
GFX_STEREO_MODE(Settings.FILE_GFX, Settings.SECTION_STEREOSCOPY, "StereoMode", 0),
GFX_STEREO_DEPTH(Settings.FILE_GFX, Settings.SECTION_STEREOSCOPY, "StereoDepth", 20),
GFX_STEREO_CONVERGENCE_PERCENTAGE(Settings.FILE_GFX, Settings.SECTION_STEREOSCOPY,
"StereoConvergencePercentage", 100),
LOGGER_VERBOSITY(Settings.FILE_LOGGER, Settings.SECTION_LOGGER_OPTIONS, "Verbosity", 1);
private static final IntSetting[] NOT_RUNTIME_EDITABLE_ARRAY = new IntSetting[]{
MAIN_CPU_CORE,
MAIN_GC_LANGUAGE,
MAIN_SLOT_A, // Can actually be changed, but specific code is required
MAIN_SLOT_B, // Can actually be changed, but specific code is required
};
private static final Set<IntSetting> NOT_RUNTIME_EDITABLE =
new HashSet<>(Arrays.asList(NOT_RUNTIME_EDITABLE_ARRAY));
private final String mFile;
private final String mSection;
private final String mKey;
private final int mDefaultValue;
IntSetting(String file, String section, String key, int defaultValue)
{
mFile = file;
mSection = section;
mKey = key;
mDefaultValue = defaultValue;
}
@Override
public boolean isOverridden(Settings settings)
{
if (settings.isGameSpecific() && !NativeConfig.isSettingSaveable(mFile, mSection, mKey))
return settings.getSection(mFile, mSection).exists(mKey);
else
return NativeConfig.isOverridden(mFile, mSection, mKey);
}
@Override
public boolean isRuntimeEditable()
{
for (IntSetting setting : NOT_RUNTIME_EDITABLE)
{
if (setting == this)
return false;
}
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
}
@Override
public boolean delete(Settings settings)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
return NativeConfig.deleteKey(settings.getActiveLayer(), mFile, mSection, mKey);
}
else
{
return settings.getSection(mFile, mSection).delete(mKey);
}
}
@Override
public int getInt(Settings settings)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
return NativeConfig.getInt(settings.getActiveLayer(), mFile, mSection, mKey, mDefaultValue);
}
else
{
return settings.getSection(mFile, mSection).getInt(mKey, mDefaultValue);
}
}
@Override
public void setInt(Settings settings, int newValue)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
NativeConfig.setInt(settings.getActiveLayer(), mFile, mSection, mKey, newValue);
}
else
{
settings.getSection(mFile, mSection).setInt(mKey, newValue);
}
}
}

View File

@ -0,0 +1,24 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public class LegacyBooleanSetting extends AbstractLegacySetting implements AbstractBooleanSetting
{
private final boolean mDefaultValue;
public LegacyBooleanSetting(String file, String section, String key, boolean defaultValue)
{
super(file, section, key);
mDefaultValue = defaultValue;
}
@Override
public boolean getBoolean(Settings settings)
{
return settings.getSection(mFile, mSection).getBoolean(mKey, mDefaultValue);
}
@Override
public void setBoolean(Settings settings, boolean newValue)
{
settings.getSection(mFile, mSection).setBoolean(mKey, newValue);
}
}

View File

@ -0,0 +1,24 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public class LegacyFloatSetting extends AbstractLegacySetting implements AbstractFloatSetting
{
private final float mDefaultValue;
public LegacyFloatSetting(String file, String section, String key, float defaultValue)
{
super(file, section, key);
mDefaultValue = defaultValue;
}
@Override
public float getFloat(Settings settings)
{
return settings.getSection(mFile, mSection).getFloat(mKey, mDefaultValue);
}
@Override
public void setFloat(Settings settings, float newValue)
{
settings.getSection(mFile, mSection).setFloat(mKey, newValue);
}
}

View File

@ -0,0 +1,24 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public class LegacyIntSetting extends AbstractLegacySetting implements AbstractIntSetting
{
private final int mDefaultValue;
public LegacyIntSetting(String file, String section, String key, int defaultValue)
{
super(file, section, key);
mDefaultValue = defaultValue;
}
@Override
public int getInt(Settings settings)
{
return settings.getSection(mFile, mSection).getInt(mKey, mDefaultValue);
}
@Override
public void setInt(Settings settings, int newValue)
{
settings.getSection(mFile, mSection).setInt(mKey, newValue);
}
}

View File

@ -0,0 +1,24 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public class LegacyStringSetting extends AbstractLegacySetting implements AbstractStringSetting
{
private final String mDefaultValue;
public LegacyStringSetting(String file, String section, String key, String defaultValue)
{
super(file, section, key);
mDefaultValue = defaultValue;
}
@Override
public String getString(Settings settings)
{
return settings.getSection(mFile, mSection).getString(mKey, mDefaultValue);
}
@Override
public void setString(Settings settings, String newValue)
{
settings.getSection(mFile, mSection).setString(mKey, newValue);
}
}

View File

@ -0,0 +1,42 @@
package org.dolphinemu.dolphinemu.features.settings.model;
public class NativeConfig
{
public static final int LAYER_BASE_OR_CURRENT = 0;
public static final int LAYER_LOCAL_GAME = 1;
public static native boolean isSettingSaveable(String file, String section, String key);
public static native void loadGameInis(String gameId, int revision);
public static native void unloadGameInis();
public static native void save(int layer);
public static native boolean isOverridden(String file, String section, String key);
public static native boolean deleteKey(int layer, String file, String section, String key);
public static native String getString(int layer, String file, String section, String key,
String defaultValue);
public static native boolean getBoolean(int layer, String file, String section, String key,
boolean defaultValue);
public static native int getInt(int layer, String file, String section, String key,
int defaultValue);
public static native float getFloat(int layer, String file, String section, String key,
float defaultValue);
public static native void setString(int layer, String file, String section, String key,
String value);
public static native void setBoolean(int layer, String file, String section, String key,
boolean value);
public static native void setInt(int layer, String file, String section, String key, int value);
public static native void setFloat(int layer, String file, String section, String key,
float value);
}

View File

@ -2,6 +2,7 @@ package org.dolphinemu.dolphinemu.features.settings.model;
import android.content.Context;
import android.text.TextUtils;
import android.widget.Toast;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivityView;
@ -9,13 +10,18 @@ import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
import org.dolphinemu.dolphinemu.utils.IniFile;
import java.io.File;
import java.io.Closeable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Settings
public class Settings implements Closeable
{
public static final String FILE_DOLPHIN = "Dolphin";
public static final String FILE_GFX = "GFX";
public static final String FILE_LOGGER = "Logger";
public static final String FILE_GCPAD = "GCPadNew";
public static final String FILE_WIIMOTE = "WiimoteNew";
public static final String SECTION_INI_ANDROID = "Android";
public static final String SECTION_INI_GENERAL = "General";
public static final String SECTION_INI_CORE = "Core";
@ -39,25 +45,23 @@ public class Settings
public static final String SECTION_CONTROLS = "Controls";
public static final String SECTION_PROFILE = "Profile";
private static final int DSP_HLE = 0;
private static final int DSP_LLE_RECOMPILER = 1;
private static final int DSP_LLE_INTERPRETER = 2;
public static final String SECTION_ANALYTICS = "Analytics";
public static final String GAME_SETTINGS_PLACEHOLDER_FILE_NAME = "";
private String gameId;
private String mGameId;
private int mRevision;
private static final String[] configFiles = new String[]{SettingsFile.FILE_NAME_DOLPHIN,
SettingsFile.FILE_NAME_GFX, SettingsFile.FILE_NAME_LOGGER,
SettingsFile.FILE_NAME_WIIMOTE};
private static final String[] configFiles = new String[]{FILE_DOLPHIN, FILE_GFX, FILE_LOGGER,
FILE_WIIMOTE};
private HashMap<String, IniFile> mIniFiles = new HashMap<>();
private boolean mLoadedRecursiveIsoPathsValue = false;
private IniFile getGameSpecificFile()
{
if (TextUtils.isEmpty(gameId) || mIniFiles.size() != 1)
if (!isGameSpecific() || mIniFiles.size() != 1)
throw new IllegalStateException();
return mIniFiles.get(GAME_SETTINGS_PLACEHOLDER_FILE_NAME);
@ -65,7 +69,7 @@ public class Settings
public IniFile.Section getSection(String fileName, String sectionName)
{
if (TextUtils.isEmpty(gameId))
if (!isGameSpecific())
{
return mIniFiles.get(fileName).getOrCreateSection(sectionName);
}
@ -76,6 +80,16 @@ public class Settings
}
}
public boolean isGameSpecific()
{
return !TextUtils.isEmpty(mGameId);
}
public int getActiveLayer()
{
return isGameSpecific() ? NativeConfig.LAYER_LOCAL_GAME : NativeConfig.LAYER_BASE_OR_CURRENT;
}
public boolean isEmpty()
{
return mIniFiles.isEmpty();
@ -85,14 +99,21 @@ public class Settings
{
mIniFiles = new HashMap<>();
if (TextUtils.isEmpty(gameId))
if (!isGameSpecific())
{
loadDolphinSettings(view);
}
else
{
loadCustomGameSettings(gameId, view);
// Loading game INIs while the core is running will mess with the game INIs loaded by the core
if (NativeLibrary.IsRunning())
throw new IllegalStateException("Attempted to load game INI while emulating");
NativeConfig.loadGameInis(mGameId, mRevision);
loadCustomGameSettings(mGameId, view);
}
mLoadedRecursiveIsoPathsValue = BooleanSetting.MAIN_RECURSIVE_ISO_PATHS.getBoolean(this);
}
private void loadDolphinSettings(SettingsActivityView view)
@ -117,69 +138,54 @@ public class Settings
SettingsFile.readWiimoteProfile(gameId, getGameSpecificFile(), padId);
}
public void loadSettings(String gameId, SettingsActivityView view)
public void loadSettings(String gameId, int revision, SettingsActivityView view)
{
this.gameId = gameId;
mGameId = gameId;
mRevision = revision;
loadSettings(view);
}
public void saveSettings(SettingsActivityView view, Context context, Set<String> modifiedSettings)
public void saveSettings(SettingsActivityView view, Context context)
{
if (TextUtils.isEmpty(gameId))
if (!isGameSpecific())
{
view.showToastMessage("Saved settings to INI files");
if (context != null)
Toast.makeText(context, "Saved settings to INI files", Toast.LENGTH_SHORT).show();
for (Map.Entry<String, IniFile> entry : mIniFiles.entrySet())
{
SettingsFile.saveFile(entry.getKey(), entry.getValue(), view);
}
if (modifiedSettings.contains(SettingsFile.KEY_DSP_ENGINE))
NativeConfig.save(NativeConfig.LAYER_BASE_OR_CURRENT);
if (!NativeLibrary.IsRunning())
{
File dolphinFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_DOLPHIN);
IniFile dolphinIni = new IniFile(dolphinFile);
switch (dolphinIni.getInt(Settings.SECTION_INI_ANDROID, SettingsFile.KEY_DSP_ENGINE,
DSP_HLE))
{
case DSP_HLE:
dolphinIni.setBoolean(Settings.SECTION_INI_CORE, SettingsFile.KEY_DSP_HLE, true);
dolphinIni.setBoolean(Settings.SECTION_INI_DSP, SettingsFile.KEY_DSP_ENABLE_JIT, true);
break;
case DSP_LLE_RECOMPILER:
dolphinIni.setBoolean(Settings.SECTION_INI_CORE, SettingsFile.KEY_DSP_HLE, false);
dolphinIni.setBoolean(Settings.SECTION_INI_DSP, SettingsFile.KEY_DSP_ENABLE_JIT, true);
break;
case DSP_LLE_INTERPRETER:
dolphinIni.setBoolean(Settings.SECTION_INI_CORE, SettingsFile.KEY_DSP_HLE, false);
dolphinIni.setBoolean(Settings.SECTION_INI_DSP, SettingsFile.KEY_DSP_ENABLE_JIT, false);
break;
}
dolphinIni.save(dolphinFile);
// Notify the native code of the changes to legacy settings
NativeLibrary.ReloadConfig();
NativeLibrary.ReloadWiimoteConfig();
}
// Notify the native code of the changes
NativeLibrary.ReloadConfig();
NativeLibrary.ReloadWiimoteConfig();
// LogManager does use the new config system, but doesn't pick up on changes automatically
NativeLibrary.ReloadLoggerConfig();
NativeLibrary.UpdateGCAdapterScanThread();
if (modifiedSettings.contains(SettingsFile.KEY_RECURSIVE_ISO_PATHS))
if (mLoadedRecursiveIsoPathsValue != BooleanSetting.MAIN_RECURSIVE_ISO_PATHS.getBoolean(this))
{
// Refresh game library
GameFileCacheService.startRescan(context);
}
modifiedSettings.clear();
}
else
{
// custom game settings
view.showToastMessage("Saved settings for " + gameId);
SettingsFile.saveCustomGameSettings(gameId, getGameSpecificFile());
if (context != null)
Toast.makeText(context, "Saved settings for " + mGameId, Toast.LENGTH_SHORT).show();
SettingsFile.saveCustomGameSettings(mGameId, getGameSpecificFile());
NativeConfig.save(NativeConfig.LAYER_LOCAL_GAME);
}
}
@ -211,9 +217,18 @@ public class Settings
// possible to know which lines were added intentionally by the user and which lines were added
// unintentionally, which is why we have to delete the whole file in order to fix everything.
if (TextUtils.isEmpty(gameId))
if (!isGameSpecific())
return false;
return getSection(SettingsFile.FILE_NAME_DOLPHIN, SECTION_INI_INTERFACE).exists("ThemeName");
return getSection(Settings.FILE_DOLPHIN, SECTION_INI_INTERFACE).exists("ThemeName");
}
@Override
public void close()
{
if (isGameSpecific())
{
NativeConfig.unloadGameInis();
}
}
}

View File

@ -0,0 +1,107 @@
package org.dolphinemu.dolphinemu.features.settings.model;
import org.dolphinemu.dolphinemu.NativeLibrary;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public enum StringSetting implements AbstractStringSetting
{
// These entries have the same names and order as in C++, just for consistency.
MAIN_DEFAULT_ISO(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "DefaultISO", ""),
MAIN_GFX_BACKEND(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "GFXBackend",
NativeLibrary.GetDefaultGraphicsBackendName()),
MAIN_DUMP_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "DumpPath", ""),
MAIN_LOAD_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "LoadPath", ""),
MAIN_RESOURCEPACK_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "ResourcePackPath",
""),
MAIN_FS_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "NANDRootPath", ""),
MAIN_SD_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "WiiSDCardPath", ""),
GFX_ENHANCE_POST_SHADER(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS,
"PostProcessingShader", "");
private static final StringSetting[] NOT_RUNTIME_EDITABLE_ARRAY = new StringSetting[]{
MAIN_GFX_BACKEND,
};
private static final Set<StringSetting> NOT_RUNTIME_EDITABLE =
new HashSet<>(Arrays.asList(NOT_RUNTIME_EDITABLE_ARRAY));
private final String mFile;
private final String mSection;
private final String mKey;
private final String mDefaultValue;
StringSetting(String file, String section, String key, String defaultValue)
{
mFile = file;
mSection = section;
mKey = key;
mDefaultValue = defaultValue;
}
@Override
public boolean isOverridden(Settings settings)
{
if (settings.isGameSpecific() && !NativeConfig.isSettingSaveable(mFile, mSection, mKey))
return settings.getSection(mFile, mSection).exists(mKey);
else
return NativeConfig.isOverridden(mFile, mSection, mKey);
}
@Override
public boolean isRuntimeEditable()
{
for (StringSetting setting : NOT_RUNTIME_EDITABLE)
{
if (setting == this)
return false;
}
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
}
@Override
public boolean delete(Settings settings)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
return NativeConfig.deleteKey(settings.getActiveLayer(), mFile, mSection, mKey);
}
else
{
return settings.getSection(mFile, mSection).delete(mKey);
}
}
@Override
public String getString(Settings settings)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
return NativeConfig.getString(settings.getActiveLayer(), mFile, mSection, mKey,
mDefaultValue);
}
else
{
return settings.getSection(mFile, mSection).getString(mKey, mDefaultValue);
}
}
@Override
public void setString(Settings settings, String newValue)
{
if (NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
NativeConfig.setString(settings.getActiveLayer(), mFile, mSection, mKey, newValue);
}
else
{
settings.getSection(mFile, mSection).setString(mKey, newValue);
}
}
}

View File

@ -1,26 +1,27 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public class CheckBoxSetting extends SettingsItem
{
protected boolean mDefaultValue;
protected AbstractBooleanSetting mSetting;
public CheckBoxSetting(String file, String section, String key, int titleId, int descriptionId,
boolean defaultValue)
public CheckBoxSetting(AbstractBooleanSetting setting, int titleId, int descriptionId)
{
super(file, section, key, titleId, descriptionId);
mDefaultValue = defaultValue;
super(titleId, descriptionId);
mSetting = setting;
}
public boolean isChecked(Settings settings)
{
return settings.getSection(getFile(), getSection()).getBoolean(getKey(), mDefaultValue);
return mSetting.getBoolean(settings);
}
public void setChecked(Settings settings, boolean checked)
{
settings.getSection(getFile(), getSection()).setBoolean(getKey(), checked);
mSetting.setBoolean(settings, checked);
}
@Override
@ -28,4 +29,10 @@ public class CheckBoxSetting extends SettingsItem
{
return TYPE_CHECKBOX;
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -1,5 +1,7 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
public final class ConfirmRunnable extends SettingsItem
{
private int mAlertText;
@ -9,7 +11,7 @@ public final class ConfirmRunnable extends SettingsItem
public ConfirmRunnable(int titleId, int descriptionId, int alertText, int confirmationText,
Runnable runnable)
{
super(null, null, null, titleId, descriptionId);
super(titleId, descriptionId);
mAlertText = alertText;
mConfirmationText = confirmationText;
mRunnable = runnable;
@ -35,4 +37,10 @@ public final class ConfirmRunnable extends SettingsItem
{
return TYPE_CONFIRM_RUNNABLE;
}
@Override
public AbstractSetting getSetting()
{
return null;
}
}

View File

@ -1,28 +1,34 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import androidx.annotation.Nullable;
public final class FilePicker extends SettingsItem
{
private String mDefaultValue;
private AbstractStringSetting mSetting;
private int mRequestType;
private String mDefaultPathRelativeToUserDirectory;
public FilePicker(String file, String section, String key, int titleId, int descriptionId,
String defaultVault, int requestType)
public FilePicker(AbstractStringSetting setting, int titleId, int descriptionId, int requestType,
@Nullable String defaultPathRelativeToUserDirectory)
{
super(file, section, key, titleId, descriptionId);
mDefaultValue = defaultVault;
super(titleId, descriptionId);
mSetting = setting;
mRequestType = requestType;
mDefaultPathRelativeToUserDirectory = defaultPathRelativeToUserDirectory;
}
public String getSelectedValue(Settings settings)
{
return settings.getSection(getFile(), getSection()).getString(getKey(), mDefaultValue);
return mSetting.getString(settings);
}
public void setSelectedValue(Settings settings, String selection)
{
settings.getSection(getFile(), getSection()).setString(getKey(), selection);
mSetting.setString(settings, selection);
}
public int getRequestType()
@ -30,9 +36,21 @@ public final class FilePicker extends SettingsItem
return mRequestType;
}
@Nullable
public String getDefaultPathRelativeToUserDirectory()
{
return mDefaultPathRelativeToUserDirectory;
}
@Override
public int getType()
{
return TYPE_FILE_PICKER;
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -1,26 +1,33 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractFloatSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public class FloatSliderSetting extends SliderSetting
{
protected float mDefaultValue;
protected AbstractFloatSetting mSetting;
public FloatSliderSetting(String file, String section, String key, int titleId, int descriptionId,
int max, String units, float defaultValue)
public FloatSliderSetting(AbstractFloatSetting setting, int titleId, int descriptionId, int max,
String units)
{
super(file, section, key, titleId, descriptionId, max, units);
mDefaultValue = defaultValue;
super(titleId, descriptionId, max, units);
mSetting = setting;
}
public int getSelectedValue(Settings settings)
{
float value = settings.getSection(getFile(), getSection()).getFloat(getKey(), mDefaultValue);
return Math.round(value);
return Math.round(mSetting.getFloat(settings));
}
public void setSelectedValue(Settings settings, float selection)
{
settings.getSection(getFile(), getSection()).setFloat(getKey(), selection);
mSetting.setFloat(settings, selection);
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -1,10 +1,12 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
public final class HeaderSetting extends SettingsItem
{
public HeaderSetting(String key, int titleId, int descriptionId)
public HeaderSetting(int titleId, int descriptionId)
{
super(null, null, key, titleId, descriptionId);
super(titleId, descriptionId);
}
@Override
@ -12,4 +14,10 @@ public final class HeaderSetting extends SettingsItem
{
return SettingsItem.TYPE_HEADER;
}
@Override
public AbstractSetting getSetting()
{
return null;
}
}

View File

@ -6,21 +6,34 @@ import android.view.InputDevice;
import android.view.KeyEvent;
import org.dolphinemu.dolphinemu.DolphinApplication;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public class InputBindingSetting extends SettingsItem
{
private String gameId;
private String mFile;
private String mSection;
private String mKey;
private String mGameId;
public InputBindingSetting(String file, String section, String key, int titleId, String gameId)
{
super(file, section, key, titleId, 0);
this.gameId = gameId;
super(titleId, 0);
mFile = file;
mSection = section;
mKey = key;
mGameId = gameId;
}
public String getKey()
{
return mKey;
}
public String getValue(Settings settings)
{
return settings.getSection(getFile(), getSection()).getString(getKey(), "");
return settings.getSection(mFile, mSection).getString(mKey, "");
}
/**
@ -60,10 +73,10 @@ public class InputBindingSetting extends SettingsItem
preferences =
PreferenceManager.getDefaultSharedPreferences(DolphinApplication.getAppContext());
SharedPreferences.Editor editor = preferences.edit();
editor.putString(getKey() + gameId, ui);
editor.putString(mKey + mGameId, ui);
editor.apply();
settings.getSection(getFile(), getSection()).setString(getKey(), bind);
settings.getSection(mFile, mSection).setString(mKey, bind);
}
public void clearValue(Settings settings)
@ -79,6 +92,12 @@ public class InputBindingSetting extends SettingsItem
public String getGameId()
{
return gameId;
return mGameId;
}
@Override
public AbstractSetting getSetting()
{
return null;
}
}

View File

@ -1,25 +1,33 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public final class IntSliderSetting extends SliderSetting
{
private int mDefaultValue;
private AbstractIntSetting mSetting;
public IntSliderSetting(String file, String section, String key, int titleId, int descriptionId,
int max, String units, int defaultValue)
public IntSliderSetting(AbstractIntSetting setting, int titleId, int descriptionId, int max,
String units)
{
super(file, section, key, titleId, descriptionId, max, units);
mDefaultValue = defaultValue;
super(titleId, descriptionId, max, units);
mSetting = setting;
}
public int getSelectedValue(Settings settings)
{
return settings.getSection(getFile(), getSection()).getInt(getKey(), mDefaultValue);
return mSetting.getInt(settings);
}
public void setSelectedValue(Settings settings, int selection)
{
settings.getSection(getFile(), getSection()).setInt(getKey(), selection);
mSetting.setInt(settings, selection);
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -1,24 +1,32 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public final class InvertedCheckBoxSetting extends CheckBoxSetting
{
public InvertedCheckBoxSetting(String file, String section, String key, int titleId,
int descriptionId, boolean defaultValue)
public InvertedCheckBoxSetting(AbstractBooleanSetting setting, int titleId,
int descriptionId)
{
super(file, section, key, titleId, descriptionId, !defaultValue);
super(setting, titleId, descriptionId);
}
@Override
public boolean isChecked(Settings settings)
{
return !settings.getSection(getFile(), getSection()).getBoolean(getKey(), mDefaultValue);
return !mSetting.getBoolean(settings);
}
@Override
public void setChecked(Settings settings, boolean checked)
{
settings.getSection(getFile(), getSection()).setBoolean(getKey(), !checked);
mSetting.setBoolean(settings, !checked);
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -0,0 +1,21 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AdHocBooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public class LogCheckBoxSetting extends CheckBoxSetting
{
String mKey;
public LogCheckBoxSetting(String key, int titleId, int descriptionId)
{
super(new AdHocBooleanSetting(Settings.FILE_LOGGER, Settings.SECTION_LOGGER_LOGS, key, false),
titleId, descriptionId);
mKey = key;
}
public String getKey()
{
return mKey;
}
}

View File

@ -1,25 +1,32 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractFloatSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public final class PercentSliderSetting extends FloatSliderSetting
{
public PercentSliderSetting(String file, String section, String key, int titleId,
int descriptionId, int max, String units, float defaultValue)
public PercentSliderSetting(AbstractFloatSetting setting, int titleId, int descriptionId, int max,
String units)
{
super(file, section, key, titleId, descriptionId, max, units, defaultValue / 100);
super(setting, titleId, descriptionId, max, units);
}
@Override
public int getSelectedValue(Settings settings)
{
float value = settings.getSection(getFile(), getSection()).getFloat(getKey(), mDefaultValue);
return Math.round(value * 100);
return Math.round(mSetting.getFloat(settings) * 100);
}
@Override
public void setSelectedValue(Settings settings, float selection)
{
settings.getSection(getFile(), getSection()).setFloat(getKey(), selection / 100);
mSetting.setFloat(settings, selection / 100);
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -6,6 +6,7 @@ import android.view.KeyEvent;
import org.dolphinemu.dolphinemu.DolphinApplication;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.utils.Rumble;
@ -55,4 +56,10 @@ public class RumbleBindingSetting extends InputBindingSetting
{
return TYPE_RUMBLE_BINDING;
}
@Override
public AbstractSetting getSetting()
{
return null;
}
}

View File

@ -1,5 +1,8 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
/**
@ -21,56 +24,22 @@ public abstract class SettingsItem
public static final int TYPE_FILE_PICKER = 9;
public static final int TYPE_CONFIRM_RUNNABLE = 10;
private String mFile;
private String mSection;
private String mKey;
private int mNameId;
private int mDescriptionId;
/**
* Base constructor.
*
* @param file File to which the Setting belongs.
* @param section Section to which the Setting belongs.
* @param key Identifier for the Setting represented by this Item.
* @param nameId Resource ID for a text string to be displayed as this setting's name.
* @param descriptionId Resource ID for a text string to be displayed as this setting's description.
*/
public SettingsItem(String file, String section, String key, int nameId, int descriptionId)
public SettingsItem(int nameId, int descriptionId)
{
mFile = file;
mSection = section;
mKey = key;
mNameId = nameId;
mDescriptionId = descriptionId;
}
/**
* @return The file in which the backing setting belongs.
*/
public String getFile()
{
return mFile;
}
/**
* @return The header under which the backing setting belongs.
*/
public String getSection()
{
return mSection;
}
/**
* @return The identifier for the backing setting.
*/
public String getKey()
{
return mKey;
}
/**
* @return A resource ID for a text string representing this setting's name.
*/
@ -91,4 +60,21 @@ public abstract class SettingsItem
* @return An integer (ideally, one of the constants defined in this file)
*/
public abstract int getType();
protected abstract AbstractSetting getSetting();
public boolean isOverridden(Settings settings)
{
AbstractSetting setting = getSetting();
return setting != null && setting.isOverridden(settings);
}
public boolean isEditable()
{
if (!NativeLibrary.IsRunning())
return true;
AbstractSetting setting = getSetting();
return setting != null && setting.isRuntimeEditable();
}
}

View File

@ -1,30 +1,32 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public final class SingleChoiceSetting extends SettingsItem
{
private int mDefaultValue;
private AbstractIntSetting mSetting;
private int mChoicesId;
private int mValuesId;
private MenuTag menuTag;
public SingleChoiceSetting(String file, String section, String key, int titleId,
int descriptionId, int choicesId, int valuesId, int defaultValue, MenuTag menuTag)
public SingleChoiceSetting(AbstractIntSetting setting, int titleId, int descriptionId,
int choicesId, int valuesId, MenuTag menuTag)
{
super(file, section, key, titleId, descriptionId);
super(titleId, descriptionId);
mSetting = setting;
mValuesId = valuesId;
mChoicesId = choicesId;
mDefaultValue = defaultValue;
this.menuTag = menuTag;
}
public SingleChoiceSetting(String file, String section, String key, int titleId,
int descriptionId, int choicesId, int valuesId, int defaultValue)
public SingleChoiceSetting(AbstractIntSetting setting, int titleId, int descriptionId,
int choicesId, int valuesId)
{
this(file, section, key, titleId, descriptionId, choicesId, valuesId, defaultValue, null);
this(setting, titleId, descriptionId, choicesId, valuesId, null);
}
public int getChoicesId()
@ -39,7 +41,7 @@ public final class SingleChoiceSetting extends SettingsItem
public int getSelectedValue(Settings settings)
{
return settings.getSection(getFile(), getSection()).getInt(getKey(), mDefaultValue);
return mSetting.getInt(settings);
}
public MenuTag getMenuTag()
@ -49,7 +51,7 @@ public final class SingleChoiceSetting extends SettingsItem
public void setSelectedValue(Settings settings, int selection)
{
settings.getSection(getFile(), getSection()).setInt(getKey(), selection);
mSetting.setInt(settings, selection);
}
@Override
@ -57,4 +59,10 @@ public final class SingleChoiceSetting extends SettingsItem
{
return TYPE_SINGLE_CHOICE;
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -1,11 +1,13 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public final class SingleChoiceSettingDynamicDescriptions extends SettingsItem
{
private int mDefaultValue;
private AbstractIntSetting mSetting;
private int mChoicesId;
private int mValuesId;
@ -13,25 +15,25 @@ public final class SingleChoiceSettingDynamicDescriptions extends SettingsItem
private int mDescriptionValuesId;
private MenuTag menuTag;
public SingleChoiceSettingDynamicDescriptions(String file, String section, String key,
int titleId, int descriptionId, int choicesId, int valuesId, int descriptionChoicesId,
int descriptionValuesId, int defaultValue, MenuTag menuTag)
public SingleChoiceSettingDynamicDescriptions(AbstractIntSetting setting, int titleId,
int descriptionId, int choicesId, int valuesId, int descriptionChoicesId,
int descriptionValuesId, MenuTag menuTag)
{
super(file, section, key, titleId, descriptionId);
super(titleId, descriptionId);
mSetting = setting;
mValuesId = valuesId;
mChoicesId = choicesId;
mDescriptionChoicesId = descriptionChoicesId;
mDescriptionValuesId = descriptionValuesId;
mDefaultValue = defaultValue;
this.menuTag = menuTag;
}
public SingleChoiceSettingDynamicDescriptions(String file, String section, String key,
int titleId, int descriptionId, int choicesId, int valuesId, int descriptionChoicesId,
int descriptionValuesId, int defaultValue)
public SingleChoiceSettingDynamicDescriptions(AbstractIntSetting setting, int titleId,
int descriptionId, int choicesId, int valuesId, int descriptionChoicesId,
int descriptionValuesId)
{
this(file, section, key, titleId, descriptionId, choicesId, valuesId, descriptionChoicesId,
descriptionValuesId, defaultValue, null);
this(setting, titleId, descriptionId, choicesId, valuesId, descriptionChoicesId,
descriptionValuesId, null);
}
public int getChoicesId()
@ -56,7 +58,7 @@ public final class SingleChoiceSettingDynamicDescriptions extends SettingsItem
public int getSelectedValue(Settings settings)
{
return settings.getSection(getFile(), getSection()).getInt(getKey(), mDefaultValue);
return mSetting.getInt(settings);
}
public MenuTag getMenuTag()
@ -66,7 +68,7 @@ public final class SingleChoiceSettingDynamicDescriptions extends SettingsItem
public void setSelectedValue(Settings settings, int selection)
{
settings.getSection(getFile(), getSection()).setInt(getKey(), selection);
mSetting.setInt(settings, selection);
}
@Override
@ -74,4 +76,10 @@ public final class SingleChoiceSettingDynamicDescriptions extends SettingsItem
{
return TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS;
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -7,10 +7,9 @@ public abstract class SliderSetting extends SettingsItem
private int mMax;
private String mUnits;
public SliderSetting(String file, String section, String key, int nameId, int descriptionId,
int max, String units)
public SliderSetting(int nameId, int descriptionId, int max, String units)
{
super(file, section, key, nameId, descriptionId);
super(nameId, descriptionId);
mMax = max;
mUnits = units;
}

View File

@ -1,48 +1,49 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.DolphinApplication;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public class StringSingleChoiceSetting extends SettingsItem
{
private String mDefaultValue;
private AbstractStringSetting mSetting;
private String[] mChoicesId;
private String[] mValuesId;
private MenuTag mMenuTag;
public StringSingleChoiceSetting(String file, String section, String key, int titleId,
int descriptionId, String[] choicesId, String[] valuesId, String defaultValue,
MenuTag menuTag)
public StringSingleChoiceSetting(AbstractStringSetting setting, int titleId,
int descriptionId, String[] choicesId, String[] valuesId, MenuTag menuTag)
{
super(file, section, key, titleId, descriptionId);
super(titleId, descriptionId);
mSetting = setting;
mChoicesId = choicesId;
mValuesId = valuesId;
mDefaultValue = defaultValue;
mMenuTag = menuTag;
}
public StringSingleChoiceSetting(String file, String section, String key, int titleId,
int descriptionId, String[] choicesId, String[] valuesId, String defaultValue)
public StringSingleChoiceSetting(AbstractStringSetting setting, int titleId,
int descriptionId, String[] choicesId, String[] valuesId)
{
this(file, section, key, titleId, descriptionId, choicesId, valuesId, defaultValue, null);
this(setting, titleId, descriptionId, choicesId, valuesId, null);
}
public StringSingleChoiceSetting(String file, String section, String key, int titleId,
int descriptionId, int choicesId, int valuesId, String defaultValue, MenuTag menuTag)
public StringSingleChoiceSetting(AbstractStringSetting setting, int titleId,
int descriptionId, int choicesId, int valuesId, MenuTag menuTag)
{
super(file, section, key, titleId, descriptionId);
super(titleId, descriptionId);
mSetting = setting;
mChoicesId = DolphinApplication.getAppContext().getResources().getStringArray(choicesId);
mValuesId = DolphinApplication.getAppContext().getResources().getStringArray(valuesId);
mDefaultValue = defaultValue;
mMenuTag = menuTag;
}
public StringSingleChoiceSetting(String file, String section, String key, int titleId,
int descriptionId, int choicesId, int valuesId, String defaultValue)
public StringSingleChoiceSetting(AbstractStringSetting setting, int titleId,
int descriptionId, int choicesId, int valuesId)
{
this(file, section, key, titleId, descriptionId, choicesId, valuesId, defaultValue, null);
this(setting, titleId, descriptionId, choicesId, valuesId, null);
}
public String[] getChoicesId()
@ -70,7 +71,7 @@ public class StringSingleChoiceSetting extends SettingsItem
public String getSelectedValue(Settings settings)
{
return settings.getSection(getFile(), getSection()).getString(getKey(), mDefaultValue);
return mSetting.getString(settings);
}
public int getSelectValueIndex(Settings settings)
@ -94,7 +95,7 @@ public class StringSingleChoiceSetting extends SettingsItem
public void setSelectedValue(Settings settings, String selection)
{
settings.getSection(getFile(), getSection()).setString(getKey(), selection);
mSetting.setString(settings, selection);
}
@Override
@ -102,6 +103,12 @@ public class StringSingleChoiceSetting extends SettingsItem
{
return TYPE_STRING_SINGLE_CHOICE;
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -1,14 +1,15 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public final class SubmenuSetting extends SettingsItem
{
private MenuTag mMenuKey;
public SubmenuSetting(String key, int titleId, MenuTag menuKey)
public SubmenuSetting(int titleId, MenuTag menuKey)
{
super(null, null, key, titleId, 0);
super(titleId, 0);
mMenuKey = menuKey;
}
@ -22,4 +23,10 @@ public final class SubmenuSetting extends SettingsItem
{
return TYPE_SUBMENU;
}
@Override
public AbstractSetting getSetting()
{
return null;
}
}

View File

@ -26,16 +26,27 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
{
private static final String ARG_MENU_TAG = "menu_tag";
private static final String ARG_GAME_ID = "game_id";
private static final String ARG_REVISION = "revision";
private static final String FRAGMENT_TAG = "settings";
private SettingsActivityPresenter mPresenter;
private ProgressDialog dialog;
public static void launch(Context context, MenuTag menuTag, String gameId)
public static void launch(Context context, MenuTag menuTag, String gameId, int revision)
{
Intent settings = new Intent(context, SettingsActivity.class);
settings.putExtra(ARG_MENU_TAG, menuTag);
settings.putExtra(ARG_GAME_ID, gameId);
settings.putExtra(ARG_REVISION, revision);
context.startActivity(settings);
}
public static void launch(Context context, MenuTag menuTag)
{
Intent settings = new Intent(context, SettingsActivity.class);
settings.putExtra(ARG_MENU_TAG, menuTag);
settings.putExtra(ARG_GAME_ID, "");
settings.putExtra(ARG_REVISION, 0);
context.startActivity(settings);
}
@ -57,10 +68,11 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
Intent launcher = getIntent();
String gameID = launcher.getStringExtra(ARG_GAME_ID);
int revision = launcher.getIntExtra(ARG_REVISION, 0);
MenuTag menuTag = (MenuTag) launcher.getSerializableExtra(ARG_MENU_TAG);
mPresenter = new SettingsActivityPresenter(this, getSettings());
mPresenter.onCreate(savedInstanceState, menuTag, gameID, getApplicationContext());
mPresenter.onCreate(savedInstanceState, menuTag, gameID, revision, getApplicationContext());
}
@Override
@ -95,17 +107,22 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
/**
* If this is called, the user has left the settings screen (potentially through the
* home button) and will expect their changes to be persisted. So we kick off an
* IntentService which will do so on a background thread.
* home button) and will expect their changes to be persisted.
*/
@Override
protected void onStop()
{
super.onStop();
mPresenter.onStop(isFinishing());
}
@Override
protected void onDestroy()
{
super.onDestroy();
mPresenter.onDestroy();
}
@Override
public void showSettingsFragment(MenuTag menuTag, Bundle extras, boolean addToStack,
String gameID)
@ -224,9 +241,9 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
}
@Override
public void onSettingChanged(String key)
public void onSettingChanged()
{
mPresenter.onSettingChanged(key);
mPresenter.onSettingChanged();
}
@Override

View File

@ -10,9 +10,6 @@ import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
import org.dolphinemu.dolphinemu.utils.Log;
import java.util.HashSet;
import java.util.Set;
public final class SettingsActivityPresenter
{
private static final String KEY_SHOULD_SAVE = "should_save";
@ -27,25 +24,35 @@ public final class SettingsActivityPresenter
private MenuTag menuTag;
private String gameId;
private int revision;
private Context context;
private final Set<String> modifiedSettings = new HashSet<>();
SettingsActivityPresenter(SettingsActivityView view, Settings settings)
{
mView = view;
mSettings = settings;
}
public void onCreate(Bundle savedInstanceState, MenuTag menuTag, String gameId, Context context)
public void onCreate(Bundle savedInstanceState, MenuTag menuTag, String gameId, int revision,
Context context)
{
this.menuTag = menuTag;
this.gameId = gameId;
this.revision = revision;
this.context = context;
mShouldSave = savedInstanceState != null && savedInstanceState.getBoolean(KEY_SHOULD_SAVE);
}
public void onDestroy()
{
if (mSettings != null)
{
mSettings.close();
mSettings = null;
}
}
public void onStart()
{
prepareDolphinDirectoriesIfNeeded();
@ -57,7 +64,7 @@ public final class SettingsActivityPresenter
{
if (!TextUtils.isEmpty(gameId))
{
mSettings.loadSettings(gameId, mView);
mSettings.loadSettings(gameId, revision, mView);
if (mSettings.gameIniContainsJunk())
{
@ -98,7 +105,7 @@ public final class SettingsActivityPresenter
public void clearSettings()
{
mSettings.clearSettings();
onSettingChanged(null);
onSettingChanged();
}
public void onStop(boolean finishing)
@ -112,7 +119,7 @@ public final class SettingsActivityPresenter
if (mSettings != null && finishing && mShouldSave)
{
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
mSettings.saveSettings(mView, context, modifiedSettings);
mSettings.saveSettings(mView, context);
}
}
@ -127,13 +134,8 @@ public final class SettingsActivityPresenter
return false;
}
public void onSettingChanged(String key)
public void onSettingChanged()
{
if (key != null)
{
modifiedSettings.add(key);
}
mShouldSave = true;
}

View File

@ -53,10 +53,8 @@ public interface SettingsActivityView
/**
* Called by a containing Fragment to tell the Activity that a setting was changed;
* unless this has been called, the Activity will not save to disk.
*
* @param key Key of the modified setting.
*/
void onSettingChanged(String key);
void onSettingChanged();
/**
* Called by a containing Fragment to tell the containing Activity that a GCPad's setting

View File

@ -13,7 +13,9 @@ import androidx.recyclerview.widget.RecyclerView;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.dialogs.MotionAlertDialog;
import org.dolphinemu.dolphinemu.features.settings.model.AdHocBooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker;
import org.dolphinemu.dolphinemu.features.settings.model.view.FloatSliderSetting;
@ -36,10 +38,8 @@ import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SettingViewHold
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SingleChoiceViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SliderViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SubmenuViewHolder;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
import org.dolphinemu.dolphinemu.utils.IniFile;
import java.security.InvalidParameterException;
import java.util.ArrayList;
@ -164,7 +164,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
item.setChecked(getSettings(), checked);
notifyItemChanged(position);
mView.onSettingChanged(item.getKey());
mView.onSettingChanged();
}
public void onSingleChoiceClick(SingleChoiceSetting item, int position)
@ -265,7 +265,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
dialog.setOnDismissListener(dialog1 ->
{
notifyItemChanged(position);
mView.onSettingChanged(item.getKey());
mView.onSettingChanged();
});
dialog.setCanceledOnTouchOutside(false);
dialog.show();
@ -308,7 +308,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
FilePicker filePicker = (FilePicker) mClickedItem;
if (!filePicker.getSelectedValue(mView.getSettings()).equals(selectedFile))
mView.onSettingChanged(filePicker.getKey());
mView.onSettingChanged();
filePicker.setSelectedValue(mView.getSettings(), selectedFile);
@ -317,32 +317,29 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
public void resetPaths()
{
IniFile.Section coreSection = mView.getSettings().getSection(SettingsFile.FILE_NAME_DOLPHIN,
Settings.SECTION_INI_CORE);
IniFile.Section generalSection = mView.getSettings().getSection(SettingsFile.FILE_NAME_DOLPHIN,
Settings.SECTION_INI_GENERAL);
Settings settings = mView.getSettings();
coreSection.delete(SettingsFile.KEY_DEFAULT_ISO);
generalSection.delete(SettingsFile.KEY_NAND_ROOT_PATH);
generalSection.delete(SettingsFile.KEY_DUMP_PATH);
generalSection.delete(SettingsFile.KEY_LOAD_PATH);
generalSection.delete(SettingsFile.KEY_RESOURCE_PACK_PATH);
generalSection.delete(SettingsFile.KEY_WII_SD_CARD_PATH);
StringSetting.MAIN_DEFAULT_ISO.delete(settings);
StringSetting.MAIN_FS_PATH.delete(settings);
StringSetting.MAIN_DUMP_PATH.delete(settings);
StringSetting.MAIN_LOAD_PATH.delete(settings);
StringSetting.MAIN_RESOURCEPACK_PATH.delete(settings);
StringSetting.MAIN_SD_PATH.delete(settings);
mView.onSettingChanged(null);
mView.onSettingChanged();
}
public void setAllLogTypes(boolean value)
{
IniFile.Section section = mView.getSettings().getSection(SettingsFile.FILE_NAME_LOGGER,
Settings.SECTION_LOGGER_LOGS);
Settings settings = mView.getSettings();
for (Map.Entry<String, String> entry : SettingsFragmentPresenter.LOG_TYPE_NAMES.entrySet())
{
section.setBoolean(entry.getKey(), value);
new AdHocBooleanSetting(Settings.FILE_LOGGER, Settings.SECTION_LOGGER_LOGS, entry.getKey(),
false).setBoolean(settings, value);
}
mView.onSettingChanged(null);
mView.onSettingChanged();
}
private void handleMenuTag(MenuTag menuTag, int value)
@ -375,7 +372,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
int value = getValueForSingleChoiceSelection(scSetting, which);
if (scSetting.getSelectedValue(getSettings()) != value)
mView.onSettingChanged(mClickedItem.getKey());
mView.onSettingChanged();
handleMenuTag(scSetting.getMenuTag(), value);
@ -390,7 +387,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
int value = getValueForSingleChoiceDynamicDescriptionsSelection(scSetting, which);
if (scSetting.getSelectedValue(getSettings()) != value)
mView.onSettingChanged(mClickedItem.getKey());
mView.onSettingChanged();
scSetting.setSelectedValue(getSettings(), value);
@ -401,7 +398,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
StringSingleChoiceSetting scSetting = (StringSingleChoiceSetting) mClickedItem;
String value = scSetting.getValueAt(which);
if (!scSetting.getSelectedValue(getSettings()).equals(value))
mView.onSettingChanged(mClickedItem.getKey());
mView.onSettingChanged();
handleMenuTag(scSetting.getMenuTag(), which);
@ -413,7 +410,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
{
IntSliderSetting sliderSetting = (IntSliderSetting) mClickedItem;
if (sliderSetting.getSelectedValue(getSettings()) != mSeekbarProgress)
mView.onSettingChanged(mClickedItem.getKey());
mView.onSettingChanged();
sliderSetting.setSelectedValue(getSettings(), mSeekbarProgress);
@ -423,7 +420,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
{
FloatSliderSetting sliderSetting = (FloatSliderSetting) mClickedItem;
if (sliderSetting.getSelectedValue(getSettings()) != mSeekbarProgress)
mView.onSettingChanged(mClickedItem.getKey());
mView.onSettingChanged();
sliderSetting.setSelectedValue(getSettings(), mSeekbarProgress);

View File

@ -193,9 +193,9 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
}
@Override
public void onSettingChanged(String key)
public void onSettingChanged()
{
mActivity.onSettingChanged(key);
mActivity.onSettingChanged();
}
@Override

View File

@ -66,10 +66,8 @@ public interface SettingsFragmentView
/**
* Have the fragment tell the containing Activity that a setting was modified.
*
* @param key Key of the modified setting, potentially null for multiple settings.
*/
void onSettingChanged(String key);
void onSettingChanged();
/**
* Have the fragment tell the containing Activity that a GCPad's setting was modified.

View File

@ -5,8 +5,8 @@ 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.LogCheckBoxSetting;
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;
@ -39,9 +39,10 @@ public final class CheckBoxSettingViewHolder extends SettingViewHolder
mItem = (CheckBoxSetting) item;
// Special case for LogTypes retrieved via JNI since those aren't string references.
if (item.getNameId() == 0 && item.getSection().equals(Settings.SECTION_LOGGER_LOGS))
if (item.getNameId() == 0 && item instanceof LogCheckBoxSetting)
{
mTextSettingName.setText(SettingsFragmentPresenter.LOG_TYPE_NAMES.get(item.getKey()));
String key = ((LogCheckBoxSetting) item).getKey();
mTextSettingName.setText(SettingsFragmentPresenter.LOG_TYPE_NAMES.get(key));
}
else
{
@ -58,13 +59,23 @@ public final class CheckBoxSettingViewHolder extends SettingViewHolder
}
mCheckbox.setChecked(mItem.isChecked(getAdapter().getSettings()));
setStyle(mTextSettingName, mItem);
}
@Override
public void onClick(View clicked)
{
if (!mItem.isEditable())
{
showNotRuntimeEditableError();
return;
}
mCheckbox.toggle();
getAdapter().onBooleanClick(mItem, getAdapterPosition(), mCheckbox.isChecked());
setStyle(mTextSettingName, mItem);
}
}

View File

@ -1,5 +1,6 @@
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
@ -8,6 +9,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
public final class FilePickerViewHolder extends SettingViewHolder
{
@ -43,13 +45,32 @@ public final class FilePickerViewHolder extends SettingViewHolder
}
else
{
mTextSettingDescription.setText(mFilePicker.getSelectedValue(getAdapter().getSettings()));
String path = mFilePicker.getSelectedValue(getAdapter().getSettings());
if (TextUtils.isEmpty(path))
{
String defaultPathRelative = mFilePicker.getDefaultPathRelativeToUserDirectory();
if (defaultPathRelative != null)
{
path = DirectoryInitialization.getUserDirectory() + defaultPathRelative;
}
}
mTextSettingDescription.setText(path);
}
setStyle(mTextSettingName, mItem);
}
@Override
public void onClick(View clicked)
{
if (!mItem.isEditable())
{
showNotRuntimeEditableError();
return;
}
if (mFilePicker.getRequestType() == MainPresenter.REQUEST_DIRECTORY)
{
getAdapter().onFilePickerDirectoryClick(mItem);
@ -58,5 +79,7 @@ public final class FilePickerViewHolder extends SettingViewHolder
{
getAdapter().onFilePickerFileClick(mItem);
}
setStyle(mTextSettingName, mItem);
}
}

View File

@ -44,11 +44,21 @@ public final class InputBindingSettingViewHolder extends SettingViewHolder
mTextSettingName.setText(mItem.getNameId());
mTextSettingDescription
.setText(sharedPreferences.getString(mItem.getKey() + mItem.getGameId(), ""));
setStyle(mTextSettingName, mItem);
}
@Override
public void onClick(View clicked)
{
if (!mItem.isEditable())
{
showNotRuntimeEditableError();
return;
}
getAdapter().onInputBindingClick(mItem, getAdapterPosition());
setStyle(mTextSettingName, mItem);
}
}

View File

@ -44,11 +44,21 @@ public class RumbleBindingViewHolder extends SettingViewHolder
mTextSettingName.setText(item.getNameId());
mTextSettingDescription
.setText(sharedPreferences.getString(mItem.getKey() + mItem.getGameId(), ""));
setStyle(mTextSettingName, mItem);
}
@Override
public void onClick(View clicked)
{
if (!mItem.isEditable())
{
showNotRuntimeEditableError();
return;
}
getAdapter().onInputBindingClick(mItem, getAdapterPosition());
setStyle(mTextSettingName, mItem);
}
}

View File

@ -1,9 +1,16 @@
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import androidx.recyclerview.widget.RecyclerView;
import org.dolphinemu.dolphinemu.DolphinApplication;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
@ -28,6 +35,21 @@ public abstract class SettingViewHolder extends RecyclerView.ViewHolder
return mAdapter;
}
protected void setStyle(TextView textView, SettingsItem settingsItem)
{
boolean overridden = settingsItem.isOverridden(mAdapter.getSettings());
textView.setTypeface(null, overridden ? Typeface.BOLD : Typeface.NORMAL);
if (!settingsItem.isEditable())
textView.setPaintFlags(textView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
protected static void showNotRuntimeEditableError()
{
Toast.makeText(DolphinApplication.getAppContext(), R.string.setting_not_runtime_editable,
Toast.LENGTH_SHORT).show();
}
/**
* Gets handles to all this ViewHolder's child views using their XML-defined identifiers.
*

View File

@ -80,11 +80,19 @@ public final class SingleChoiceViewHolder extends SettingViewHolder
}
}
}
setStyle(mTextSettingName, mItem);
}
@Override
public void onClick(View clicked)
{
if (!mItem.isEditable())
{
showNotRuntimeEditableError();
return;
}
int position = getAdapterPosition();
if (mItem instanceof SingleChoiceSetting)
{
@ -99,5 +107,7 @@ public final class SingleChoiceViewHolder extends SettingViewHolder
getAdapter().onSingleChoiceDynamicDescriptionsClick(
(SingleChoiceSettingDynamicDescriptions) mItem, position);
}
setStyle(mTextSettingName, mItem);
}
}

View File

@ -49,12 +49,22 @@ public final class SliderViewHolder extends SettingViewHolder
.getString(R.string.slider_setting_value,
mItem.getSelectedValue(getAdapter().getSettings()), mItem.getUnits()));
}
setStyle(mTextSettingName, mItem);
}
@Override
public void onClick(View clicked)
{
if (!mItem.isEditable())
{
showNotRuntimeEditableError();
return;
}
getAdapter().onSliderClick(mItem, getAdapterPosition());
setStyle(mTextSettingName, mItem);
}
}

View File

@ -16,92 +16,6 @@ import java.io.File;
*/
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";
public static final String KEY_DSP_ENGINE = "DSPEngine";
public static final String KEY_LAST_PLATFORM_TAB = "LastPlatformTab";
public static final String KEY_CPU_CORE = "CPUCore";
public static final String KEY_DUAL_CORE = "CPUThread";
public static final String KEY_OVERCLOCK_ENABLE = "OverclockEnable";
public static final String KEY_OVERCLOCK_PERCENT = "Overclock";
public static final String KEY_SPEED_LIMIT = "EmulationSpeed";
public static final String KEY_VIDEO_BACKEND = "GFXBackend";
public static final String KEY_DSP_HLE = "DSPHLE";
public static final String KEY_DSP_ENABLE_JIT = "EnableJIT";
public static final String KEY_AUDIO_STRETCH = "AudioStretch";
public static final String KEY_AUDIO_VOLUME = "Volume";
public static final String KEY_AUTO_DISC_CHANGE = "AutoDiscChange";
public static final String KEY_GAME_CUBE_LANGUAGE = "SelectedLanguage";
public static final String KEY_OVERRIDE_REGION_SETTINGS = "OverrideRegionSettings";
public static final String KEY_SLOT_A_DEVICE = "SlotA";
public static final String KEY_SLOT_B_DEVICE = "SlotB";
public static final String KEY_ENABLE_SAVE_STATES = "EnableSaveStates";
public static final String KEY_RECURSIVE_ISO_PATHS = "RecursiveISOPaths";
public static final String KEY_DEFAULT_ISO = "DefaultISO";
public static final String KEY_NAND_ROOT_PATH = "NANDRootPath";
public static final String KEY_DUMP_PATH = "DumpPath";
public static final String KEY_LOAD_PATH = "LoadPath";
public static final String KEY_RESOURCE_PACK_PATH = "ResourcePackPath";
public static final String KEY_WII_SD_CARD_PATH = "WiiSDCardPath";
public static final String KEY_ANALYTICS_ENABLED = "Enabled";
public static final String KEY_ANALYTICS_PERMISSION_ASKED = "PermissionAsked";
public static final String KEY_USE_PANIC_HANDLERS = "UsePanicHandlers";
public static final String KEY_OSD_MESSAGES = "OnScreenDisplayMessages";
public static final String KEY_SHOW_FPS = "ShowFPS";
public static final String KEY_INTERNAL_RES = "InternalResolution";
public static final String KEY_FSAA = "MSAA";
public static final String KEY_ANISOTROPY = "MaxAnisotropy";
public static final String KEY_POST_SHADER = "PostProcessingShader";
public static final String KEY_SCALED_EFB = "EFBScaledCopy";
public static final String KEY_PER_PIXEL = "EnablePixelLighting";
public static final String KEY_FORCE_FILTERING = "ForceFiltering";
public static final String KEY_DISABLE_FOG = "DisableFog";
public static final String KEY_DISABLE_COPY_FILTER = "DisableCopyFilter";
public static final String KEY_ARBITRARY_MIPMAP_DETECTION = "ArbitraryMipmapDetection";
public static final String KEY_WIDE_SCREEN_HACK = "wideScreenHack";
public static final String KEY_FORCE_24_BIT_COLOR = "ForceTrueColor";
public static final String KEY_BACKEND_MULTITHREADING = "BackendMultithreading";
public static final String KEY_STEREO_MODE = "StereoMode";
public static final String KEY_STEREO_DEPTH = "StereoDepth";
public static final String KEY_STEREO_CONV = "StereoConvergencePercentage";
public static final String KEY_STEREO_SWAP = "StereoSwapEyes";
public static final String KEY_SKIP_EFB = "EFBAccessEnable";
public static final String KEY_IGNORE_FORMAT = "EFBEmulateFormatChanges";
public static final String KEY_EFB_TEXTURE = "EFBToTextureEnable";
public static final String KEY_DEFER_EFB_COPIES = "DeferEFBCopies";
public static final String KEY_TEXCACHE_ACCURACY = "SafeTextureCacheColorSamples";
public static final String KEY_GPU_TEXTURE_DECODING = "EnableGPUTextureDecoding";
public static final String KEY_XFB_TEXTURE = "XFBToTextureEnable";
public static final String KEY_IMMEDIATE_XFB = "ImmediateXFBEnable";
public static final String KEY_SKIP_DUPLICATE_XFBS = "SkipDuplicateXFBs";
public static final String KEY_FAST_DEPTH = "FastDepthCalc";
public static final String KEY_ASPECT_RATIO = "AspectRatio";
public static final String KEY_SHADER_COMPILATION_MODE = "ShaderCompilationMode";
public static final String KEY_WAIT_FOR_SHADERS = "WaitForShadersBeforeStarting";
public static final String KEY_DEBUG_JITOFF = "JitOff";
public static final String KEY_DEBUG_JITLOADSTOREOFF = "JitLoadStoreOff";
public static final String KEY_DEBUG_JITLOADSTOREFLOATINGPOINTOFF = "JitLoadStoreFloatingOff";
public static final String KEY_DEBUG_JITLOADSTOREPAIREDOFF = "JitLoadStorePairedOff";
public static final String KEY_DEBUG_JITFLOATINGPOINTOFF = "JitFloatingPointOff";
public static final String KEY_DEBUG_JITINTEGEROFF = "JitIntegerOff";
public static final String KEY_DEBUG_JITPAIREDOFF = "JitPairedOff";
public static final String KEY_DEBUG_JITSYSTEMREGISTEROFF = "JitSystemRegistersOff";
public static final String KEY_DEBUG_JITBRANCHOFF = "JitBranchOff";
public static final String KEY_DEBUG_JITREGISTERCACHEOFF = "JitRegisterCacheOff";
public static final String KEY_GCPAD_TYPE = "SIDevice";
public static final String KEY_GCPAD_PLAYER_1 = "SIDevice0";
public static final String KEY_GCPAD_G_TYPE = "PadType";
@ -264,14 +178,6 @@ public final class SettingsFile
public static final String KEY_WIIBIND_TURNTABLE_CROSSFADE_LEFT = "TurntableCrossLeft_";
public static final String KEY_WIIBIND_TURNTABLE_CROSSFADE_RIGHT = "TurntableCrossRight_";
public static final String KEY_WII_SD_CARD = "WiiSDCard";
public static final String KEY_WII_SD_CARD_ALLOW_WRITES = "WiiSDCardAllowWrites";
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<String, String> sectionsMap = new BiMap<>();
static
@ -310,7 +216,7 @@ public final class SettingsFile
{
readFile(getSettingsFile(fileName), ini, view);
if (fileName.equals(SettingsFile.FILE_NAME_DOLPHIN))
if (fileName.equals(Settings.FILE_DOLPHIN))
{
addGcPadSettingsIfTheyDontExist(ini);
}
@ -505,15 +411,4 @@ public final class SettingsFile
}
}
}
public static void firstAnalyticsAdd(boolean enabled)
{
IniFile dolphinIni = new IniFile();
readFile(SettingsFile.FILE_NAME_DOLPHIN, dolphinIni, null);
dolphinIni.setBoolean(Settings.SECTION_ANALYTICS, KEY_ANALYTICS_ENABLED, enabled);
dolphinIni.setBoolean(Settings.SECTION_ANALYTICS, KEY_ANALYTICS_PERMISSION_ASKED, true);
saveFile(SettingsFile.FILE_NAME_DOLPHIN, dolphinIni, null);
}
}

View File

@ -16,8 +16,8 @@ import androidx.fragment.app.Fragment;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
public final class MenuFragment extends Fragment implements View.OnClickListener
{
@ -50,6 +50,9 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
.append(R.id.menu_screen_orientation, EmulationActivity.MENU_ACTION_SCREEN_ORIENTATION);
buttonsActionsMap.append(R.id.menu_change_disc, EmulationActivity.MENU_ACTION_CHANGE_DISC);
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
buttonsActionsMap.append(R.id.menu_settings_core, EmulationActivity.MENU_ACTION_SETTINGS_CORE);
buttonsActionsMap.append(R.id.menu_settings_graphics,
EmulationActivity.MENU_ACTION_SETTINGS_GRAPHICS);
}
public static MenuFragment newInstance(String title)
@ -83,18 +86,6 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
updatePauseUnpauseVisibility();
boolean enableSaveStates = ((EmulationActivity) getActivity()).getSettings()
.getSection(SettingsFile.FILE_NAME_DOLPHIN, Settings.SECTION_INI_CORE)
.getBoolean(SettingsFile.KEY_ENABLE_SAVE_STATES, false);
if (enableSaveStates)
{
options.findViewById(R.id.menu_quicksave).setVisibility(View.VISIBLE);
options.findViewById(R.id.menu_quickload).setVisibility(View.VISIBLE);
options.findViewById(R.id.menu_emulation_save_root).setVisibility(View.VISIBLE);
options.findViewById(R.id.menu_emulation_load_root).setVisibility(View.VISIBLE);
}
PackageManager packageManager = requireActivity().getPackageManager();
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN))
@ -149,6 +140,22 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
return rootView;
}
@Override
public void onResume()
{
super.onResume();
LinearLayout options = requireView().findViewById(R.id.layout_options);
Settings settings = ((EmulationActivity) requireActivity()).getSettings();
boolean savestatesEnabled = BooleanSetting.MAIN_ENABLE_SAVESTATES.getBoolean(settings);
int savestateVisibility = savestatesEnabled ? View.VISIBLE : View.GONE;
options.findViewById(R.id.menu_quicksave).setVisibility(savestateVisibility);
options.findViewById(R.id.menu_quickload).setVisibility(savestateVisibility);
options.findViewById(R.id.menu_emulation_save_root).setVisibility(savestateVisibility);
options.findViewById(R.id.menu_emulation_load_root).setVisibility(savestateVisibility);
}
private void updatePauseUnpauseVisibility()
{
boolean paused = EmulationActivity.getHasUserPausedEmulation();

View File

@ -4,9 +4,8 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import org.dolphinemu.dolphinemu.utils.IniFile;
import java.io.File;
import java.util.HashSet;
@ -82,10 +81,12 @@ public class GameFileCache
*/
public boolean scanLibrary(Context context)
{
IniFile dolphinIni =
new IniFile(SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_DOLPHIN));
boolean recursiveScan = dolphinIni.getBoolean(Settings.SECTION_INI_GENERAL,
SettingsFile.KEY_RECURSIVE_ISO_PATHS, false);
boolean recursiveScan;
try (Settings settings = new Settings())
{
settings.loadSettings(null);
recursiveScan = BooleanSetting.MAIN_RECURSIVE_ISO_PATHS.getBoolean(settings);
}
removeNonExistentGameFolders(context);

View File

@ -716,8 +716,7 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
// Add all the enabled overlay items back to the HashSet.
if (EmulationActivity.isGameCubeGame())
{
IniFile dolphinIni =
new IniFile(SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_DOLPHIN));
IniFile dolphinIni = new IniFile(SettingsFile.getSettingsFile(Settings.FILE_DOLPHIN));
switch (dolphinIni.getInt(Settings.SECTION_INI_CORE, SettingsFile.KEY_GCPAD_PLAYER_1,
EMULATED_GAMECUBE_CONTROLLER))

View File

@ -20,22 +20,19 @@ import com.google.android.material.tabs.TabLayout;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter;
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView;
import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
import org.dolphinemu.dolphinemu.utils.IniFile;
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
import org.dolphinemu.dolphinemu.utils.StartupHandler;
import java.io.File;
/**
* The main Activity of the Lollipop style UI. Manages several PlatformGamesFragments, which
* individually display a grid of available games for each Fragment, in a tabbed layout.
@ -155,7 +152,7 @@ public final class MainActivity extends AppCompatActivity implements MainView
@Override
public void launchSettingsActivity(MenuTag menuTag)
{
SettingsActivity.launch(this, menuTag, "");
SettingsActivity.launch(this, menuTag);
}
@Override
@ -282,18 +279,23 @@ public final class MainActivity extends AppCompatActivity implements MainView
{
super.onTabSelected(tab);
File dolphinFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_DOLPHIN);
IniFile dolphinIni = new IniFile(dolphinFile);
dolphinIni.setInt(Settings.SECTION_INI_ANDROID, SettingsFile.KEY_LAST_PLATFORM_TAB,
tab.getPosition());
dolphinIni.save(dolphinFile);
try (Settings settings = new Settings())
{
settings.loadSettings(null);
IntSetting.MAIN_LAST_PLATFORM_TAB.setInt(settings, tab.getPosition());
// Context is set to null to avoid toasts
settings.saveSettings(null, null);
}
}
});
IniFile dolphinIni =
new IniFile(SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_DOLPHIN));
mViewPager.setCurrentItem(dolphinIni.getInt(Settings.SECTION_INI_ANDROID,
SettingsFile.KEY_LAST_PLATFORM_TAB, 0));
try (Settings settings = new Settings())
{
settings.loadSettings(null);
mViewPager.setCurrentItem(IntSetting.MAIN_LAST_PLATFORM_TAB.getInt(settings));
}
showGames();
GameFileCacheService.startLoad(this);

View File

@ -153,7 +153,7 @@ public final class TvMainActivity extends FragmentActivity implements MainView
@Override
public void launchSettingsActivity(MenuTag menuTag)
{
SettingsActivity.launch(this, menuTag, "");
SettingsActivity.launch(this, menuTag);
}
@Override

View File

@ -1,9 +1,7 @@
package org.dolphinemu.dolphinemu.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.PreferenceManager;
import androidx.appcompat.app.AlertDialog;
@ -12,16 +10,11 @@ import com.android.volley.toolbox.StringRequest;
import org.dolphinemu.dolphinemu.DolphinApplication;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
public class Analytics
{
private static final String analyticsAsked =
Settings.SECTION_ANALYTICS + "_" + SettingsFile.KEY_ANALYTICS_PERMISSION_ASKED;
private static final String analyticsEnabled =
Settings.SECTION_ANALYTICS + "_" + SettingsFile.KEY_ANALYTICS_ENABLED;
private static final String DEVICE_MANUFACTURER = "DEVICE_MANUFACTURER";
private static final String DEVICE_OS = "DEVICE_OS";
private static final String DEVICE_MODEL = "DEVICE_MODEL";
@ -29,39 +22,48 @@ public class Analytics
public static void checkAnalyticsInit(Context context)
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
if (!preferences.getBoolean(analyticsAsked, false))
new AfterDirectoryInitializationRunner().run(context, false, () ->
{
new AfterDirectoryInitializationRunner().run(context, false,
() -> showMessage(context, preferences));
}
Settings settings = new Settings();
settings.loadSettings(null);
if (!BooleanSetting.MAIN_ANALYTICS_PERMISSION_ASKED.getBoolean(settings))
{
showMessage(context, settings);
}
else
{
settings.close();
}
});
}
private static void showMessage(Context context, SharedPreferences preferences)
private static void showMessage(Context context, Settings settings)
{
// We asked, set to true regardless of answer
SharedPreferences.Editor sPrefsEditor = preferences.edit();
sPrefsEditor.putBoolean(analyticsAsked, true);
sPrefsEditor.apply();
new AlertDialog.Builder(context, R.style.DolphinDialogBase)
.setTitle(context.getString(R.string.analytics))
.setMessage(context.getString(R.string.analytics_desc))
.setPositiveButton(R.string.yes, (dialogInterface, i) ->
{
sPrefsEditor.putBoolean(analyticsEnabled, true);
sPrefsEditor.apply();
SettingsFile.firstAnalyticsAdd(true);
firstAnalyticsAdd(settings, true);
})
.setNegativeButton(R.string.no, (dialogInterface, i) ->
{
sPrefsEditor.putBoolean(analyticsEnabled, false);
sPrefsEditor.apply();
SettingsFile.firstAnalyticsAdd(false);
firstAnalyticsAdd(settings, false);
})
.show();
}
private static void firstAnalyticsAdd(Settings settings, boolean enabled)
{
BooleanSetting.MAIN_ANALYTICS_ENABLED.setBoolean(settings, enabled);
BooleanSetting.MAIN_ANALYTICS_PERMISSION_ASKED.setBoolean(settings, true);
// Context is set to null to avoid toasts
settings.saveSettings(null, null);
settings.close();
}
public static void sendReport(String endpoint, byte[] data)
{
StringRequest request = new StringRequest(Request.Method.POST, endpoint,

View File

@ -29,7 +29,7 @@ public class Rumble
for (int i = 0; i < 8; i++)
{
String deviceName = activity.getSettings()
.getSection(SettingsFile.FILE_NAME_DOLPHIN, Settings.SECTION_BINDINGS)
.getSection(Settings.FILE_DOLPHIN, Settings.SECTION_BINDINGS)
.getString(SettingsFile.KEY_EMU_RUMBLE + i, "");
if (!deviceName.isEmpty())

View File

@ -30,6 +30,16 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="@+id/menu_settings_core"
android:text="@string/grid_menu_config"
style="@style/InGameMenuOption"/>
<Button
android:id="@+id/menu_settings_graphics"
android:text="@string/grid_menu_graphics_settings"
style="@style/InGameMenuOption"/>
<Button
android:id="@+id/menu_pause_emulation"
android:text="@string/pause_emulation"

View File

@ -287,7 +287,7 @@
<string name="debug_jitfloatingpointoff">Jit Floating Point Disabled</string>
<string name="debug_jitintegeroff">Jit Integer Disabled</string>
<string name="debug_jitpairedoff">Jit Paired Disabled</string>
<string name="debug_jitsystemregistersoffr">Jit System Registers Disabled</string>
<string name="debug_jitsystemregistersoff">Jit System Registers Disabled</string>
<string name="debug_jitbranchoff">Jit Branch Disabled</string>
<string name="debug_jitregistercacheoff">Jit Register Cache Disabled</string>
@ -378,6 +378,7 @@
<string name="write_permission_needed">You need to allow write access to external storage for the emulator to work</string>
<string name="load_settings">Loading Settings...</string>
<string name="setting_not_runtime_editable">This setting can\'t be changed while a game is running.</string>
<string name="emulation_change_disc">Change Disc</string>
<string name="external_storage_not_mounted">The external storage needs to be available in order to use Dolphin</string>

View File

@ -5,6 +5,7 @@ add_library(main SHARED
GameList/GameFileCache.cpp
IniFile.cpp
MainAndroid.cpp
NativeConfig.cpp
)
target_link_libraries(main

View File

@ -74,6 +74,7 @@ IniFile s_ini;
// sequentially for access.
std::mutex s_host_identity_lock;
Common::Event s_update_main_frame_event;
Common::Event s_emulation_end_event;
bool s_have_wm_user_stop = false;
} // Anonymous namespace
@ -241,6 +242,9 @@ 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 jstring JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDefaultGraphicsBackendName(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,
@ -279,9 +283,17 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulati
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv* env,
jobject obj)
{
std::lock_guard<std::mutex> guard(s_host_identity_lock);
Core::Stop();
s_update_main_frame_event.Set(); // Kick the waiting event
{
std::lock_guard<std::mutex> guard(s_host_identity_lock);
s_emulation_end_event.Reset();
Core::Stop();
// Kick the waiting event
s_update_main_frame_event.Set();
}
// Wait for shutdown, to avoid accessing the config at the same time as the shutdown code
s_emulation_end_event.Wait();
}
JNIEXPORT void JNICALL
@ -425,6 +437,12 @@ JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_DefaultCPUCo
return static_cast<jint>(PowerPC::DefaultCPUCore());
}
JNIEXPORT jstring JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_GetDefaultGraphicsBackendName(JNIEnv* env, jobject obj)
{
return ToJString(env, VideoBackendBase::GetDefaultBackendName());
}
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetMaxLogLevel(JNIEnv* env,
jobject obj)
{
@ -589,6 +607,8 @@ static void Run(JNIEnv* env, const std::vector<std::string>& paths,
ANativeWindow_release(s_surf);
s_surf = nullptr;
}
s_emulation_end_event.Set();
}
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2(

View File

@ -0,0 +1,193 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <memory>
#include <string>
#include <jni.h>
#include "Common/Assert.h"
#include "Common/Config/Config.h"
#include "Core/ConfigLoaders/GameConfigLoader.h"
#include "Core/ConfigLoaders/IsSettingSaveable.h"
#include "jni/AndroidCommon/AndroidCommon.h"
constexpr jint LAYER_BASE_OR_CURRENT = 0;
constexpr jint LAYER_LOCAL_GAME = 1;
static Config::Location GetLocation(JNIEnv* env, jstring file, jstring section, jstring key)
{
const std::string decoded_file = GetJString(env, file);
Config::System system;
if (decoded_file == "Dolphin")
{
system = Config::System::Main;
}
else if (decoded_file == "GFX")
{
system = Config::System::GFX;
}
else if (decoded_file == "Logger")
{
system = Config::System::Logger;
}
else
{
ASSERT(false);
return {};
}
return Config::Location{system, GetJString(env, section), GetJString(env, key)};
}
static std::shared_ptr<Config::Layer> GetLayer(jint layer, const Config::Location& location)
{
switch (layer)
{
case LAYER_BASE_OR_CURRENT:
if (GetActiveLayerForConfig(location) == Config::LayerType::Base)
return Config::GetLayer(Config::LayerType::Base);
else
return Config::GetLayer(Config::LayerType::CurrentRun);
case LAYER_LOCAL_GAME:
return Config::GetLayer(Config::LayerType::LocalGame);
default:
ASSERT(false);
return nullptr;
}
}
template <typename T>
static T Get(jint layer, const Config::Location& location, T default_value)
{
return GetLayer(layer, location)->Get<T>(location).value_or(default_value);
}
template <typename T>
static void Set(jint layer, const Config::Location& location, T value)
{
GetLayer(layer, location)->Set(location, value);
Config::InvokeConfigChangedCallbacks();
}
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_isSettingSaveable(
JNIEnv* env, jclass obj, jstring file, jstring section, jstring key)
{
const Config::Location location = GetLocation(env, file, section, key);
return static_cast<jboolean>(ConfigLoaders::IsSettingSaveable(location));
}
JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_loadGameInis(JNIEnv* env,
jclass obj,
jstring jGameId,
jint jRevision)
{
const std::string game_id = GetJString(env, jGameId);
const u16 revision = static_cast<u16>(jRevision);
Config::AddLayer(ConfigLoaders::GenerateGlobalGameConfigLoader(game_id, revision));
Config::AddLayer(ConfigLoaders::GenerateLocalGameConfigLoader(game_id, revision));
}
JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_unloadGameInis(JNIEnv* env,
jclass obj)
{
Config::RemoveLayer(Config::LayerType::GlobalGame);
Config::RemoveLayer(Config::LayerType::LocalGame);
}
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_save(
JNIEnv* env, jclass obj, jint layer)
{
return GetLayer(layer, {})->Save();
}
JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_isOverridden(
JNIEnv* env, jclass obj, jstring file, jstring section, jstring key)
{
const Config::Location location = GetLocation(env, file, section, key);
const bool result = Config::GetActiveLayerForConfig(location) != Config::LayerType::Base;
return static_cast<jboolean>(result);
}
JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_deleteKey(
JNIEnv* env, jclass obj, jint layer, jstring file, jstring section, jstring key)
{
const Config::Location location = GetLocation(env, file, section, key);
return static_cast<jboolean>(GetLayer(layer, location)->DeleteKey(location));
}
JNIEXPORT jstring JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_getString(
JNIEnv* env, jclass obj, jint layer, jstring file, jstring section, jstring key,
jstring default_value)
{
const Config::Location location = GetLocation(env, file, section, key);
return ToJString(env, Get(layer, location, GetJString(env, default_value)));
}
JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_getBoolean(
JNIEnv* env, jclass obj, jint layer, jstring file, jstring section, jstring key,
jboolean default_value)
{
const Config::Location location = GetLocation(env, file, section, key);
return static_cast<jboolean>(Get(layer, location, static_cast<bool>(default_value)));
}
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_getInt(
JNIEnv* env, jclass obj, jint layer, jstring file, jstring section, jstring key,
jint default_value)
{
return Get(layer, GetLocation(env, file, section, key), default_value);
}
JNIEXPORT jfloat JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_getFloat(
JNIEnv* env, jclass obj, jint layer, jstring file, jstring section, jstring key,
jfloat default_value)
{
return Get(layer, GetLocation(env, file, section, key), default_value);
}
JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_setString(
JNIEnv* env, jclass obj, jint layer, jstring file, jstring section, jstring key, jstring value)
{
return Set(layer, GetLocation(env, file, section, key), GetJString(env, value));
}
JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_setBoolean(
JNIEnv* env, jclass obj, jint layer, jstring file, jstring section, jstring key, jboolean value)
{
return Set(layer, GetLocation(env, file, section, key), static_cast<bool>(value));
}
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_setInt(
JNIEnv* env, jclass obj, jint layer, jstring file, jstring section, jstring key, jint value)
{
return Set(layer, GetLocation(env, file, section, key), value);
}
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_settings_model_NativeConfig_setFloat(
JNIEnv* env, jclass obj, jint layer, jstring file, jstring section, jstring key, jfloat value)
{
return Set(layer, GetLocation(env, file, section, key), value);
}
#ifdef __cplusplus
}
#endif