Android: Expose a proper interface for C++ IniFile class

Replaces the inflexible INI functions in NativeLibrary.
This commit is contained in:
JosJuice
2020-07-06 16:57:49 +02:00
parent c8c4ec28ce
commit 74f197caed
17 changed files with 360 additions and 249 deletions

View File

@ -274,43 +274,6 @@ public final class NativeLibrary
// Angle is in radians and should be non-negative
public static native double GetInputRadiusAtAngle(int emu_pad_id, int stick, double angle);
public static native void NewGameIniFile();
public static native void LoadGameIniFile(String gameId);
public static native void SaveGameIniFile(String gameId);
public static native String GetUserSetting(String gameID, String Section, String Key);
public static native void SetUserSetting(String gameID, String Section, String Key, String Value);
public static native void SetProfileSetting(String profile, String Section, String Key,
String Value);
public static native void InitGameIni(String gameID);
/**
* Gets a value from a key in the given ini-based config file.
*
* @param configFile The ini-based config file to get the value from.
* @param Section The section key that the actual key is in.
* @param Key The key to get the value from.
* @param Default The value to return in the event the given key doesn't exist.
* @return the value stored at the key, or a default value if it doesn't exist.
*/
public static native String GetConfig(String configFile, String Section, String Key,
String Default);
/**
* Sets a value to a key in the given ini config file.
*
* @param configFile The ini-based config file to add the value to.
* @param Section The section key for the ini key
* @param Key The actual ini key to set.
* @param Value The string to set the ini key to.
*/
public static native void SetConfig(String configFile, String Section, String Key, String Value);
/**
* Gets the Dolphin version string.
*

View File

@ -47,10 +47,12 @@ import org.dolphinemu.dolphinemu.ui.main.TvMainActivity;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
import org.dolphinemu.dolphinemu.utils.ControllerMappingHelper;
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
import org.dolphinemu.dolphinemu.utils.IniFile;
import org.dolphinemu.dolphinemu.utils.MotionListener;
import org.dolphinemu.dolphinemu.utils.Rumble;
import org.dolphinemu.dolphinemu.utils.TvUtil;
import java.io.File;
import java.lang.annotation.Retention;
import java.util.List;
@ -962,10 +964,14 @@ public final class EmulationActivity extends AppCompatActivity
(dialog, indexSelected) ->
{
editor.putInt("wiiController", indexSelected);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Extension",
File wiimoteNewFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_WIIMOTE);
IniFile wiimoteNewIni = new IniFile(wiimoteNewFile);
wiimoteNewIni.setString("Wiimote1", "Extension",
getResources().getStringArray(R.array.controllersValues)[indexSelected]);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1",
"Options/Sideways Wiimote", indexSelected == 2 ? "True" : "False");
wiimoteNewIni.setBoolean("Wiimote1", "Options/Sideways Wiimote", indexSelected == 2);
wiimoteNewIni.save(wiimoteNewFile);
NativeLibrary.ReloadWiimoteConfig();
});
builder.setPositiveButton(getString(R.string.ok), (dialogInterface, i) ->
@ -994,8 +1000,11 @@ public final class EmulationActivity extends AppCompatActivity
else
mMotionListener.disable();
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "IMUIR/Enabled",
indexSelected != 1 ? "True" : "False");
File wiimoteNewFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_WIIMOTE);
IniFile wiimoteNewIni = new IniFile(wiimoteNewFile);
wiimoteNewIni.setBoolean("Wiimote1", "IMUIR/Enabled", indexSelected != 1);
wiimoteNewIni.save(wiimoteNewFile);
NativeLibrary.ReloadWiimoteConfig();
});
builder.setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> editor.apply());
@ -1137,15 +1146,15 @@ public final class EmulationActivity extends AppCompatActivity
builder.setView(view);
builder.setPositiveButton(R.string.ok, (dialogInterface, i) ->
{
NativeLibrary.LoadGameIniFile(mSelectedGameId);
NativeLibrary.SetUserSetting(mSelectedGameId, Settings.SECTION_CONTROLS,
SettingsFile.KEY_WIIBIND_IR_PITCH, text_slider_value_pitch.getText().toString());
NativeLibrary.SetUserSetting(mSelectedGameId, Settings.SECTION_CONTROLS,
SettingsFile.KEY_WIIBIND_IR_YAW, text_slider_value_yaw.getText().toString());
NativeLibrary.SetUserSetting(mSelectedGameId, Settings.SECTION_CONTROLS,
SettingsFile.KEY_WIIBIND_IR_VERTICAL_OFFSET,
File file = SettingsFile.getCustomGameSettingsFile(mSelectedGameId);
IniFile ini = new IniFile(file);
ini.setString(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_PITCH,
text_slider_value_pitch.getText().toString());
ini.setString(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_YAW,
text_slider_value_yaw.getText().toString());
ini.setString(Settings.SECTION_CONTROLS, SettingsFile.KEY_WIIBIND_IR_VERTICAL_OFFSET,
text_slider_value_vertical_offset.getText().toString());
NativeLibrary.SaveGameIniFile(mSelectedGameId);
ini.save(file);
NativeLibrary.ReloadWiimoteConfig();

View File

@ -16,6 +16,7 @@ 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.IniFile;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
import org.dolphinemu.dolphinemu.utils.Log;
@ -65,8 +66,12 @@ public class GamePropertiesDialog extends DialogFragment
.getSupportFragmentManager(), "game_details");
break;
case 1:
NativeLibrary.SetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini",
Settings.SECTION_INI_CORE, SettingsFile.KEY_DEFAULT_ISO, path);
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();
break;

View File

@ -7,7 +7,9 @@ import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivityView;
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.util.Arrays;
import java.util.HashMap;
import java.util.List;
@ -40,9 +42,9 @@ public class Settings
public static final String SECTION_CONTROLS = "Controls";
public static final String SECTION_PROFILE = "Profile";
private static final String DSP_HLE = "0";
private static final String DSP_LLE_RECOMPILER = "1";
private static final String DSP_LLE_INTERPRETER = "2";
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";
@ -195,37 +197,29 @@ public class Settings
if (modifiedSettings.contains(SettingsFile.KEY_DSP_ENGINE))
{
switch (NativeLibrary
.GetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", Settings.SECTION_INI_ANDROID,
SettingsFile.KEY_DSP_ENGINE, DSP_HLE))
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:
NativeLibrary
.SetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", Settings.SECTION_INI_CORE,
SettingsFile.KEY_DSP_HLE, "True");
NativeLibrary
.SetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", Settings.SECTION_INI_DSP,
SettingsFile.KEY_DSP_ENABLE_JIT, "True");
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:
NativeLibrary
.SetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", Settings.SECTION_INI_CORE,
SettingsFile.KEY_DSP_HLE, "False");
NativeLibrary
.SetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", Settings.SECTION_INI_DSP,
SettingsFile.KEY_DSP_ENABLE_JIT, "True");
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:
NativeLibrary
.SetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", Settings.SECTION_INI_CORE,
SettingsFile.KEY_DSP_HLE, "False");
NativeLibrary
.SetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", Settings.SECTION_INI_DSP,
SettingsFile.KEY_DSP_ENABLE_JIT, "False");
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

View File

@ -2,6 +2,9 @@ package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.Setting;
import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import java.io.File;
public final class FilePicker extends SettingsItem
{
@ -18,9 +21,9 @@ public final class FilePicker extends SettingsItem
mRequestType = requestType;
}
public String getFile()
public File getFile()
{
return mFile + ".ini";
return SettingsFile.getSettingsFile(mFile);
}
public String getSelectedValue()

View File

@ -43,6 +43,7 @@ import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SubmenuViewHold
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;
@ -319,8 +320,10 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
{
FilePicker filePicker = (FilePicker) mClickedItem;
NativeLibrary.SetConfig(filePicker.getFile(), filePicker.getSection(), filePicker.getKey(),
file);
IniFile ini = new IniFile(filePicker.getFile());
ini.setString(filePicker.getSection(), filePicker.getKey(), file);
ini.save(filePicker.getFile());
NativeLibrary.ReloadConfig();
mClickedItem = null;

View File

@ -3,12 +3,12 @@ package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.view.View;
import android.widget.TextView;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
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.IniFile;
public final class FilePickerViewHolder extends SettingViewHolder
{
@ -44,9 +44,10 @@ public final class FilePickerViewHolder extends SettingViewHolder
}
else
{
mTextSettingDescription.setText(NativeLibrary
.GetConfig(mFilePicker.getFile(), item.getSection(), item.getKey(),
mFilePicker.getSelectedValue()));
// TODO: Reopening INI files all the time is slow
IniFile ini = new IniFile(mFilePicker.getFile());
mTextSettingDescription.setText(ini.getString(item.getSection(), item.getKey(),
mFilePicker.getSelectedValue()));
}
}

View File

@ -15,6 +15,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivityView;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
import org.dolphinemu.dolphinemu.utils.BiMap;
import org.dolphinemu.dolphinemu.utils.IniFile;
import org.dolphinemu.dolphinemu.utils.Log;
import java.io.BufferedReader;
@ -464,7 +465,7 @@ public final class SettingsFile
{
Set<String> sortedSections = new TreeSet<>(sections.keySet());
NativeLibrary.NewGameIniFile();
IniFile ini = new IniFile();
for (String sectionKey : sortedSections)
{
SettingSection section = sections.get(sectionKey);
@ -491,12 +492,12 @@ public final class SettingsFile
}
else
{
NativeLibrary.SetUserSetting(gameId, mapSectionNameFromIni(section.getName()),
setting.getKey(), setting.getValueAsString());
ini.setString(mapSectionNameFromIni(section.getName()), setting.getKey(),
setting.getValueAsString());
}
}
}
NativeLibrary.SaveGameIniFile(gameId);
ini.save(getCustomGameSettingsFile(gameId));
}
/**
@ -508,31 +509,40 @@ public final class SettingsFile
* @param padId
*/
private static void saveCustomWiimoteSetting(final String gameId, final String key,
final String value,
final String padId)
final String value, final String padId)
{
String profile = gameId + "_Wii" + padId;
String wiiConfigPath =
DirectoryInitialization.getUserDirectory() + "/Config/Profiles/Wiimote/" +
profile + ".ini";
File wiiProfile = new File(wiiConfigPath);
File wiiProfile = getWiiProfile(profile, padId);
// If it doesn't exist, create it
if (!wiiProfile.exists())
boolean wiiProfileExists = wiiProfile.exists();
if (!wiiProfileExists)
{
String defautlWiiProfilePath =
DirectoryInitialization.getUserDirectory() +
"/Config/Profiles/Wiimote/WiimoteProfile.ini";
DirectoryInitialization.copyFile(defautlWiiProfilePath, wiiConfigPath);
}
NativeLibrary.SetProfileSetting(profile, Settings.SECTION_PROFILE, "Device",
IniFile wiiProfileIni = new IniFile(wiiConfigPath);
if (!wiiProfileExists)
{
wiiProfileIni.setString(Settings.SECTION_PROFILE, "Device",
"Android/" + (Integer.parseInt(padId) + 4) + "/Touchscreen");
}
NativeLibrary.SetProfileSetting(profile, Settings.SECTION_PROFILE, key, value);
wiiProfileIni.setString(Settings.SECTION_PROFILE, key, value);
wiiProfileIni.save(wiiConfigPath);
// Enable the profile
NativeLibrary.SetUserSetting(gameId, Settings.SECTION_CONTROLS,
File gameSettingsFile = SettingsFile.getCustomGameSettingsFile(gameId);
IniFile gameSettingsIni = new IniFile(gameSettingsFile);
gameSettingsIni.setString(Settings.SECTION_CONTROLS,
KEY_WIIMOTE_PROFILE + (Integer.parseInt(padId) + 1), profile);
gameSettingsIni.save(gameSettingsFile);
}
private static String mapSectionNameFromIni(String generalSectionName)
@ -556,7 +566,7 @@ public final class SettingsFile
}
@NonNull
private static File getSettingsFile(String fileName)
public static File getSettingsFile(String fileName)
{
return new File(
DirectoryInitialization.getUserDirectory() + "/Config/" + fileName + ".ini");
@ -578,9 +588,8 @@ public final class SettingsFile
gameId + ".ini");
}
private static File getCustomGameSettingsFile(String gameId)
public static File getCustomGameSettingsFile(String gameId)
{
return new File(
DirectoryInitialization.getUserDirectory() + "/GameSettings/" + gameId + ".ini");
}

View File

@ -7,6 +7,7 @@ import android.preference.PreferenceManager;
import org.dolphinemu.dolphinemu.NativeLibrary;
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,9 +83,10 @@ public class GameFileCache
*/
public boolean scanLibrary(Context context)
{
boolean recursiveScan = NativeLibrary
.GetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", Settings.SECTION_INI_GENERAL,
SettingsFile.KEY_RECURSIVE_ISO_PATHS, "False").equals("True");
IniFile dolphinIni =
new IniFile(SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_DOLPHIN));
boolean recursiveScan = dolphinIni.getBoolean(Settings.SECTION_INI_GENERAL,
SettingsFile.KEY_RECURSIVE_ISO_PATHS, false);
removeNonExistentGameFolders(context);

View File

@ -33,6 +33,7 @@ import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import org.dolphinemu.dolphinemu.utils.IniFile;
import java.util.ArrayList;
import java.util.HashSet;
@ -51,9 +52,9 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
public static final int OVERLAY_WIIMOTE_CLASSIC = 4;
public static final int OVERLAY_NONE = 5;
private static final String DISABLED_GAMECUBE_CONTROLLER = "0";
private static final String EMULATED_GAMECUBE_CONTROLLER = "6";
private static final String GAMECUBE_ADAPTER = "12";
private static final int DISABLED_GAMECUBE_CONTROLLER = 0;
private static final int EMULATED_GAMECUBE_CONTROLLER = 6;
private static final int GAMECUBE_ADAPTER = 12;
private final Set<InputOverlayDrawableButton> overlayButtons = new HashSet<>();
private final Set<InputOverlayDrawableDpad> overlayDpads = new HashSet<>();
@ -703,9 +704,11 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
// Add all the enabled overlay items back to the HashSet.
if (EmulationActivity.isGameCubeGame())
{
switch (NativeLibrary
.GetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", Settings.SECTION_INI_CORE,
SettingsFile.KEY_GCPAD_PLAYER_1, EMULATED_GAMECUBE_CONTROLLER))
IniFile dolphinIni =
new IniFile(SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_DOLPHIN));
switch (dolphinIni.getInt(Settings.SECTION_INI_CORE, SettingsFile.KEY_GCPAD_PLAYER_1,
EMULATED_GAMECUBE_CONTROLLER))
{
case DISABLED_GAMECUBE_CONTROLLER:
if (mIsFirstRun)

View File

@ -33,9 +33,12 @@ 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.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.
@ -272,24 +275,19 @@ public final class MainActivity extends AppCompatActivity implements MainView
public void onTabSelected(@NonNull TabLayout.Tab tab)
{
super.onTabSelected(tab);
NativeLibrary
.SetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", Settings.SECTION_INI_ANDROID,
SettingsFile.KEY_LAST_PLATFORM_TAB, Integer.toString(tab.getPosition()));
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);
}
});
String platformTab = NativeLibrary
.GetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", Settings.SECTION_INI_ANDROID,
SettingsFile.KEY_LAST_PLATFORM_TAB, "0");
try
{
mViewPager.setCurrentItem(Integer.parseInt(platformTab));
}
catch (NumberFormatException ex)
{
mViewPager.setCurrentItem(0);
}
IniFile dolphinIni =
new IniFile(SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_DOLPHIN));
mViewPager.setCurrentItem(dolphinIni.getInt(Settings.SECTION_INI_ANDROID,
SettingsFile.KEY_LAST_PLATFORM_TAB, 0));
showGames();
GameFileCacheService.startLoad(this);

View File

@ -0,0 +1,69 @@
package org.dolphinemu.dolphinemu.utils;
import java.io.File;
// An in-memory copy of an INI file
public class IniFile
{
// This class is non-static to ensure that the IniFile parent does not get garbage collected
// while a section still is accessible. (The finalizer of IniFile deletes the native sections.)
public class Section
{
private long mPointer; // Do not rename or move without editing the native code
private Section(long pointer)
{
mPointer = pointer;
}
}
private long mPointer; // Do not rename or move without editing the native code
public IniFile()
{
mPointer = newIniFile();
}
public IniFile(String path)
{
this();
load(path, false);
}
public IniFile(File file)
{
this();
load(file, false);
}
public native boolean load(String path, boolean keepCurrentData);
public boolean load(File file, boolean keepCurrentData)
{
return load(file.getPath(), keepCurrentData);
}
public native boolean save(String path);
public boolean save(File file)
{
return save(file.getPath());
}
public native String getString(String sectionName, String key, String defaultValue);
public native boolean getBoolean(String sectionName, String key, boolean defaultValue);
public native int getInt(String sectionName, String key, int defaultValue);
public native void setString(String sectionName, String key, String newValue);
public native void setBoolean(String sectionName, String key, boolean newValue);
public native void setInt(String sectionName, String key, int newValue);
@Override
public native void finalize();
private native long newIniFile();
}