Implement basic framework for new Settings UI

This commit is contained in:
sigmabeta 2016-01-18 18:27:04 -05:00
parent e49f9b10a8
commit ce8a3d9bfb
36 changed files with 1508 additions and 831 deletions

View File

@ -56,7 +56,7 @@
android:label="@string/add_directory_title"/> android:label="@string/add_directory_title"/>
<activity <activity
android:name=".activities.SettingsActivity" android:name=".ui.settings.SettingsActivity"
android:theme="@style/DolphinSettingsGamecube" android:theme="@style/DolphinSettingsGamecube"
android:label="@string/grid_menu_settings"/> android:label="@string/grid_menu_settings"/>
@ -71,8 +71,6 @@
<service android:name=".services.AssetCopyService"/> <service android:name=".services.AssetCopyService"/>
<service android:name=".services.SettingsSaveService"/>
<provider <provider
android:name=".model.GameProvider" android:name=".model.GameProvider"
android:authorities="${applicationId}.provider" android:authorities="${applicationId}.provider"

View File

@ -1,48 +0,0 @@
package org.dolphinemu.dolphinemu.activities;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import org.dolphinemu.dolphinemu.fragments.SettingsFragment;
import org.dolphinemu.dolphinemu.services.SettingsSaveService;
import org.dolphinemu.dolphinemu.utils.Log;
public final class SettingsActivity extends AppCompatActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Display the fragment as the main content.
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment(), "settings_fragment")
.commit();
}
/**
* 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.
*/
@Override
protected void onStop()
{
super.onStop();
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
// Copy assets into appropriate locations.
Intent settingsSaver = new Intent(this, SettingsSaveService.class);
startService(settingsSaver);
}
public static void launch(Context context)
{
Intent settings = new Intent(context, SettingsActivity.class);
context.startActivity(settings);
}
}

View File

@ -1,155 +0,0 @@
package org.dolphinemu.dolphinemu.fragments;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Environment;
import android.preference.ListPreference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.utils.EGLHelper;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.microedition.khronos.opengles.GL10;
public final class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener
{
private SharedPreferences mPreferences;
private ListPreference mVideoBackendPreference;
private final EGLHelper mEglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT);
private final String mVendor = mEglHelper.getGL().glGetString(GL10.GL_VENDOR);
private final String mVersion = mEglHelper.getGL().glGetString(GL10.GL_VERSION);
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
// TODO Below here is effectively ported from the old VideoSettingsFragment. There is
// TODO probably a simpler way to do this, but potentially could require UI discussion/feedback.
// Setting valid video backends.
mVideoBackendPreference = (ListPreference) findPreference("gpuPref");
final boolean deviceSupportsGL = mEglHelper.supportsOpenGL();
final boolean deviceSupportsGLES3 = mEglHelper.supportsGLES3();
if (deviceSupportsGL)
{
mVideoBackendPreference.setEntries(R.array.videoBackendEntriesGL);
mVideoBackendPreference.setEntryValues(R.array.videoBackendValuesGL);
}
else if (deviceSupportsGLES3)
{
mVideoBackendPreference.setEntries(R.array.videoBackendEntriesGLES3);
mVideoBackendPreference.setEntryValues(R.array.videoBackendValuesGLES3);
}
else
{
mVideoBackendPreference.setEntries(R.array.videoBackendEntriesNoGLES3);
mVideoBackendPreference.setEntryValues(R.array.videoBackendValuesNoGLES3);
}
//
// Set available post processing shaders
//
List<CharSequence> shader_names = new ArrayList<CharSequence>();
List<CharSequence> shader_values = new ArrayList<CharSequence>();
// Disabled option
shader_names.add("Disabled");
shader_values.add("");
// TODO Since shaders are included with the APK, we know what they are at build-time. We should
// TODO be able to run this logic somehow at build-time and not rely on the device doing it.
File shaders_folder = new File(Environment.getExternalStorageDirectory() + File.separator + "dolphin-emu" + File.separator + "Shaders");
if (shaders_folder.exists())
{
File[] shaders = shaders_folder.listFiles();
for (File file : shaders)
{
if (file.isFile())
{
String filename = file.getName();
if (filename.endsWith(".glsl"))
{
// Strip the extension and put it in to the list
shader_names.add(filename.substring(0, filename.lastIndexOf('.')));
shader_values.add(filename.substring(0, filename.lastIndexOf('.')));
}
}
}
}
final ListPreference shader_preference = (ListPreference) findPreference("postProcessingShader");
shader_preference.setEntries(shader_names.toArray(new CharSequence[shader_names.size()]));
shader_preference.setEntryValues(shader_values.toArray(new CharSequence[shader_values.size()]));
//
// Disable all options if Software Rendering is used.
//
// Note that the numeric value in 'getPreference()'
// denotes the placement on the UI. So if more elements are
// added to the video settings, these may need to change.
//
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
if (mVideoBackendPreference.getValue().equals("Software Renderer"))
{
findPreference("enhancements").setEnabled(false);
findPreference("hacks").setEnabled(false);
findPreference("showFPS").setEnabled(false);
}
else if (mVideoBackendPreference.getValue().equals("OGL"))
{
findPreference("enhancements").setEnabled(true);
findPreference("hacks").setEnabled(true);
findPreference("showFPS").setEnabled(true);
// Check if we support stereo
// If we support desktop GL then we must support at least OpenGL 3.2
// If we only support OpenGLES then we need both OpenGLES 3.1 and AEP
if ((mEglHelper.supportsOpenGL() && mEglHelper.GetVersion() >= 320) ||
(mEglHelper.supportsGLES3() && mEglHelper.GetVersion() >= 310 && mEglHelper.SupportsExtension("GL_ANDROID_extension_pack_es31a")))
findPreference("StereoscopyScreen").setEnabled(true);
else
findPreference("StereoscopyScreen").setEnabled(false);
}
// Also set a listener, so that if someone changes the video backend, it will disable
// the video settings, upon the user choosing "Software Rendering".
mPreferences.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key)
{
if (key.equals("gpuPref"))
{
if (preferences.getString(key, "Software Renderer").equals("Software Renderer"))
{
findPreference("enhancements").setEnabled(false);
findPreference("hacks").setEnabled(false);
findPreference("showFPS").setEnabled(false);
}
else if (preferences.getString(key, "Software Renderer").equals("OGL"))
{
findPreference("enhancements").setEnabled(true);
findPreference("hacks").setEnabled(true);
findPreference("showFPS").setEnabled(true);
}
}
}
}

View File

@ -0,0 +1,31 @@
package org.dolphinemu.dolphinemu.model.settings.view;
import org.dolphinemu.dolphinemu.model.settings.BooleanSetting;
import org.dolphinemu.dolphinemu.model.settings.Setting;
public class CheckBoxSetting extends SettingsItem
{
public CheckBoxSetting(String key, Setting setting, int titleId, int descriptionId)
{
super(key, setting, titleId, descriptionId);
}
public boolean isChecked()
{
BooleanSetting setting = (BooleanSetting) getSetting();
return setting.getValue();
}
public void setChecked(boolean checked)
{
BooleanSetting setting = (BooleanSetting) getSetting();
setting.setValue(checked);
}
@Override
public int getType()
{
return TYPE_CHECKBOX;
}
}

View File

@ -0,0 +1,18 @@
package org.dolphinemu.dolphinemu.model.settings.view;
import org.dolphinemu.dolphinemu.model.settings.Setting;
public class HeaderSetting extends SettingsItem
{
public HeaderSetting(String key, Setting setting, int titleId, int descriptionId)
{
super(key, setting, titleId, descriptionId);
}
@Override
public int getType()
{
return SettingsItem.TYPE_HEADER;
}
}

View File

@ -0,0 +1,48 @@
package org.dolphinemu.dolphinemu.model.settings.view;
import org.dolphinemu.dolphinemu.model.settings.Setting;
public abstract class SettingsItem
{
public static final int TYPE_HEADER = 0;
public static final int TYPE_CHECKBOX = 1;
public static final int TYPE_SINGLE_CHOICE = 2;
public static final int TYPE_SLIDER = 3;
public static final int TYPE_SUBMENU = 4;
private String mKey;
private Setting mSetting;
private int mTitleId;
private int mDescriptionId;
public SettingsItem(String key, Setting setting, int titleId, int descriptionId)
{
mKey = key;
mSetting = setting;
mTitleId = titleId;
mDescriptionId = descriptionId;
}
public String getKey()
{
return mKey;
}
public Setting getSetting()
{
return mSetting;
}
public int getNameId()
{
return mTitleId;
}
public int getDescriptionId()
{
return mDescriptionId;
}
public abstract int getType();
}

View File

@ -0,0 +1,45 @@
package org.dolphinemu.dolphinemu.model.settings.view;
import org.dolphinemu.dolphinemu.model.settings.IntSetting;
import org.dolphinemu.dolphinemu.model.settings.Setting;
public class SingleChoiceSetting extends SettingsItem
{
private int mChoicesId;
private int mValuesId;
public SingleChoiceSetting(String key, Setting setting, int titleId, int descriptionId, int choicesId, int valuesId)
{
super(key, setting, titleId, descriptionId);
mChoicesId = choicesId;
mValuesId = valuesId;
}
public int getChoicesId()
{
return mChoicesId;
}
public int getValuesId()
{
return mValuesId;
}
public int getSelectedValue()
{
IntSetting setting = (IntSetting) getSetting();
return setting.getValue();
}
public void setSelectedValue(int selection)
{
IntSetting setting = (IntSetting) getSetting();
setting.setValue(selection);
}
@Override
public int getType()
{
return TYPE_SINGLE_CHOICE;
}
}

View File

@ -0,0 +1,61 @@
package org.dolphinemu.dolphinemu.model.settings.view;
import org.dolphinemu.dolphinemu.model.settings.FloatSetting;
import org.dolphinemu.dolphinemu.model.settings.IntSetting;
import org.dolphinemu.dolphinemu.model.settings.Setting;
import org.dolphinemu.dolphinemu.utils.Log;
public class SliderSetting extends SettingsItem
{
private int mMax;
public SliderSetting(String key, Setting setting, int titleId, int descriptionId, int max)
{
super(key, setting, titleId, descriptionId);
mMax = max;
}
public int getMax()
{
return mMax;
}
public int getSelectedValue()
{
Setting setting = getSetting();
if (setting instanceof IntSetting)
{
IntSetting intSetting = (IntSetting) setting;
return intSetting.getValue();
}
else if (setting instanceof FloatSetting)
{
FloatSetting floatSetting = (FloatSetting) setting;
return Math.round(floatSetting.getValue());
}
else
{
Log.error("[SliderSetting] Error casting setting type.");
return -1;
}
}
public void setSelectedValue(int selection)
{
IntSetting setting = (IntSetting) getSetting();
setting.setValue(selection);
}
public void setSelectedValue(float selection)
{
FloatSetting setting = (FloatSetting) getSetting();
setting.setValue(selection);
}
@Override
public int getType()
{
return TYPE_SLIDER;
}
}

View File

@ -0,0 +1,25 @@
package org.dolphinemu.dolphinemu.model.settings.view;
import org.dolphinemu.dolphinemu.model.settings.Setting;
public class SubmenuSetting extends SettingsItem
{
private String mMenuKey;
public SubmenuSetting(String key, Setting setting, int titleId, int descriptionId, String menuKey)
{
super(key, setting, titleId, descriptionId);
mMenuKey = menuKey;
}
public String getMenuKey()
{
return mMenuKey;
}
@Override
public int getType()
{
return TYPE_SUBMENU;
}
}

View File

@ -13,7 +13,6 @@ import android.preference.PreferenceManager;
import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.utils.Log; import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.utils.UserPreferences;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -61,10 +60,6 @@ public final class AssetCopyService extends IntentService
copyAsset("GCPadNew.ini", ConfigDir + File.separator + "GCPadNew.ini"); copyAsset("GCPadNew.ini", ConfigDir + File.separator + "GCPadNew.ini");
copyAsset("WiimoteNew.ini", ConfigDir + File.separator + "WiimoteNew.ini"); copyAsset("WiimoteNew.ini", ConfigDir + File.separator + "WiimoteNew.ini");
// Load the configuration keys set in the Dolphin ini and gfx ini files
// into the application's shared preferences.
UserPreferences.LoadIniToPrefs(this);
// Record the fact that we've done this before, so we don't do it on every launch. // Record the fact that we've done this before, so we don't do it on every launch.
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = preferences.edit(); SharedPreferences.Editor editor = preferences.edit();

View File

@ -1,28 +0,0 @@
package org.dolphinemu.dolphinemu.services;
import android.app.IntentService;
import android.content.Intent;
import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.utils.UserPreferences;
/**
* IntentServices, unlike regular services, inherently run on a background thread.
* This IntentService saves all the options the user set in the Java-based UI into
* INI files the native code can read.
*/
public final class SettingsSaveService extends IntentService
{
public SettingsSaveService()
{
super("SettingsSaveService");
}
@Override
protected void onHandleIntent(Intent intent)
{
Log.verbose("[SettingsSaveService] Saving settings to INI files...");
UserPreferences.SavePrefsToIni(this);
Log.verbose("[SettingsSaveService] Save successful.");
}
}

View File

@ -0,0 +1,157 @@
package org.dolphinemu.dolphinemu.ui;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
/**
* Implementation from:
* https://gist.github.com/lapastillaroja/858caf1a82791b6c1a36
*/
public class DividerItemDecoration extends RecyclerView.ItemDecoration
{
private Drawable mDivider;
private boolean mShowFirstDivider = false;
private boolean mShowLastDivider = false;
public DividerItemDecoration(Context context, AttributeSet attrs)
{
final TypedArray a = context
.obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
mDivider = a.getDrawable(0);
a.recycle();
}
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
boolean showLastDivider)
{
this(context, attrs);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
public DividerItemDecoration(Drawable divider)
{
mDivider = divider;
}
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
boolean showLastDivider)
{
this(divider);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state)
{
super.getItemOffsets(outRect, view, parent, state);
if (mDivider == null)
{
return;
}
if (parent.getChildPosition(view) < 1)
{
return;
}
if (getOrientation(parent) == LinearLayoutManager.VERTICAL)
{
outRect.top = mDivider.getIntrinsicHeight();
}
else
{
outRect.left = mDivider.getIntrinsicWidth();
}
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state)
{
if (mDivider == null)
{
super.onDrawOver(c, parent, state);
return;
}
// Initialization needed to avoid compiler warning
int left = 0, right = 0, top = 0, bottom = 0, size;
int orientation = getOrientation(parent);
int childCount = parent.getChildCount();
if (orientation == LinearLayoutManager.VERTICAL)
{
size = mDivider.getIntrinsicHeight();
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
}
else
{ //horizontal
size = mDivider.getIntrinsicWidth();
top = parent.getPaddingTop();
bottom = parent.getHeight() - parent.getPaddingBottom();
}
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++)
{
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL)
{
top = child.getTop() - params.topMargin;
bottom = top + size;
}
else
{ //horizontal
left = child.getLeft() - params.leftMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
// show last divider
if (mShowLastDivider && childCount > 0)
{
View child = parent.getChildAt(childCount - 1);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL)
{
top = child.getBottom() + params.bottomMargin;
bottom = top + size;
}
else
{ // horizontal
left = child.getRight() + params.rightMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private int getOrientation(RecyclerView parent)
{
if (parent.getLayoutManager() instanceof LinearLayoutManager)
{
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getOrientation();
}
else
{
throw new IllegalStateException(
"DividerItemDecoration can only be used with a LinearLayoutManager.");
}
}
}

View File

@ -16,10 +16,11 @@ import android.view.View;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity; import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity;
import org.dolphinemu.dolphinemu.activities.SettingsActivity;
import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter; import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter;
import org.dolphinemu.dolphinemu.model.GameProvider; import org.dolphinemu.dolphinemu.model.GameProvider;
import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView; import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView;
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
import org.dolphinemu.dolphinemu.utils.SettingsFile;
import org.dolphinemu.dolphinemu.utils.StartupHandler; import org.dolphinemu.dolphinemu.utils.StartupHandler;
/** /**
@ -117,7 +118,7 @@ public final class MainActivity extends AppCompatActivity implements MainView
@Override @Override
public void launchSettingsActivity() public void launchSettingsActivity()
{ {
SettingsActivity.launch(this); SettingsActivity.launch(this, SettingsFile.FILE_NAME_DOLPHIN);
} }
@Override @Override

View File

@ -20,11 +20,12 @@ import android.support.v17.leanback.widget.RowPresenter;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity; import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity;
import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.activities.SettingsActivity;
import org.dolphinemu.dolphinemu.adapters.GameRowPresenter; import org.dolphinemu.dolphinemu.adapters.GameRowPresenter;
import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter; import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter;
import org.dolphinemu.dolphinemu.model.Game; import org.dolphinemu.dolphinemu.model.Game;
import org.dolphinemu.dolphinemu.model.TvSettingsItem; import org.dolphinemu.dolphinemu.model.TvSettingsItem;
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
import org.dolphinemu.dolphinemu.utils.SettingsFile;
import org.dolphinemu.dolphinemu.utils.StartupHandler; import org.dolphinemu.dolphinemu.utils.StartupHandler;
import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder; import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder;
@ -114,7 +115,7 @@ public final class TvMainActivity extends Activity implements MainView
@Override @Override
public void launchSettingsActivity() public void launchSettingsActivity()
{ {
SettingsActivity.launch(this); SettingsActivity.launch(this, SettingsFile.FILE_NAME_DOLPHIN);
} }
@Override @Override

View File

@ -0,0 +1,106 @@
package org.dolphinemu.dolphinemu.ui.settings;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import org.dolphinemu.dolphinemu.BuildConfig;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.SettingSection;
import java.util.HashMap;
public final class SettingsActivity extends AppCompatActivity implements SettingsActivityView
{
private SettingsActivityPresenter mPresenter = new SettingsActivityPresenter(this);
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Intent launcher = getIntent();
String filename = launcher.getStringExtra(ARGUMENT_FILE_NAME);
mPresenter.onCreate(savedInstanceState, filename);
}
/**
* 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.
*/
@Override
protected void onStop()
{
super.onStop();
mPresenter.onStop(isFinishing());
}
@Override
public void showSettingsFragment(String menuTag, boolean addToStack)
{
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_content, SettingsFragment.newInstance(menuTag), SettingsFragment.FRAGMENT_TAG);
if (addToStack)
{
transaction.addToBackStack(null);
}
transaction.commit();
}
@Override
public HashMap<String, SettingSection> getSettings()
{
return mPresenter.getSettings();
}
@Override
public void setSettings(HashMap<String, SettingSection> settings)
{
mPresenter.setSettings(settings);
}
@Override
public void onSettingsFileLoaded(HashMap<String, SettingSection> settings)
{
SettingsFragmentView fragment = getFragment();
if (fragment != null)
{
fragment.onSettingsFileLoaded(settings);
}
}
@Override
public void showToastMessage(String message)
{
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
private SettingsFragment getFragment()
{
return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(SettingsFragment.FRAGMENT_TAG);
}
public static final String ARGUMENT_FILE_NAME = BuildConfig.APPLICATION_ID + ".file_name";
public static void launch(Context context, String menuTag)
{
Intent settings = new Intent(context, SettingsActivity.class);
settings.putExtra(ARGUMENT_FILE_NAME, menuTag);
context.startActivity(settings);
}
}

View File

@ -0,0 +1,88 @@
package org.dolphinemu.dolphinemu.ui.settings;
import android.os.Bundle;
import org.dolphinemu.dolphinemu.model.settings.SettingSection;
import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.utils.SettingsFile;
import java.util.HashMap;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
public class SettingsActivityPresenter
{
private SettingsActivityView mView;
private String mFileName;
private HashMap<String, SettingSection> mSettingsBySection;
public SettingsActivityPresenter(SettingsActivityView view)
{
mView = view;
}
public void onCreate(Bundle savedInstanceState, String filename)
{
mFileName = filename;
if (savedInstanceState == null)
{
SettingsFile.readFile(mFileName)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<HashMap<String, SettingSection>>()
{
@Override
public void call(HashMap<String, SettingSection> settingsBySection)
{
mSettingsBySection = settingsBySection;
mView.onSettingsFileLoaded(settingsBySection);
}
});
mView.showSettingsFragment(mFileName, false);
}
}
public void setSettings(HashMap<String, SettingSection> settings)
{
mSettingsBySection = settings;
}
public HashMap<String, SettingSection> getSettings()
{
return mSettingsBySection;
}
public void onStop(boolean finishing)
{
if (mSettingsBySection != null && finishing)
{
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
SettingsFile.saveFile(mFileName, mSettingsBySection)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Action1<Boolean>()
{
@Override
public void call(Boolean aBoolean)
{
mView.showToastMessage("Saved successfully to " + mFileName + ".ini");
}
},
new Action1<Throwable>()
{
@Override
public void call(Throwable throwable)
{
mView.showToastMessage("Error saving " + mFileName + ".ini: " + throwable.getMessage());
}
});
}
}
}

View File

@ -0,0 +1,18 @@
package org.dolphinemu.dolphinemu.ui.settings;
import org.dolphinemu.dolphinemu.model.settings.SettingSection;
import java.util.HashMap;
public interface SettingsActivityView
{
void showSettingsFragment(String menuTag, boolean addToStack);
HashMap<String, SettingSection> getSettings();
void setSettings(HashMap<String, SettingSection> settings);
void onSettingsFileLoaded(HashMap<String, SettingSection> settings);
void showToastMessage(String message);
}

View File

@ -0,0 +1,121 @@
package org.dolphinemu.dolphinemu.ui.settings;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem;
import org.dolphinemu.dolphinemu.model.settings.view.SingleChoiceSetting;
import org.dolphinemu.dolphinemu.model.settings.view.SliderSetting;
import org.dolphinemu.dolphinemu.model.settings.view.SubmenuSetting;
import org.dolphinemu.dolphinemu.ui.settings.viewholder.CheckBoxSettingViewHolder;
import org.dolphinemu.dolphinemu.ui.settings.viewholder.HeaderViewHolder;
import org.dolphinemu.dolphinemu.ui.settings.viewholder.SettingViewHolder;
import org.dolphinemu.dolphinemu.ui.settings.viewholder.SingleChoiceViewHolder;
import org.dolphinemu.dolphinemu.ui.settings.viewholder.SliderViewHolder;
import org.dolphinemu.dolphinemu.ui.settings.viewholder.SubmenuViewHolder;
import org.dolphinemu.dolphinemu.utils.Log;
import java.util.ArrayList;
public class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder>
{
private SettingsFragmentView mView;
private Context mContext;
private ArrayList<SettingsItem> mSettings;
public SettingsAdapter(SettingsFragmentView view, Context context)
{
mView = view;
mContext = context;
}
@Override
public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType)
{
case SettingsItem.TYPE_HEADER:
view = inflater.inflate(R.layout.list_item_settings_header, parent, false);
return new HeaderViewHolder(view, this);
case SettingsItem.TYPE_CHECKBOX:
view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false);
return new CheckBoxSettingViewHolder(view, this);
case SettingsItem.TYPE_SINGLE_CHOICE:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new SingleChoiceViewHolder(view, this);
case SettingsItem.TYPE_SLIDER:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new SliderViewHolder(view, this);
case SettingsItem.TYPE_SUBMENU:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new SubmenuViewHolder(view, this);
default:
Log.error("[SettingsAdapter] Invalid view type: " + viewType);
return null;
}
}
@Override
public void onBindViewHolder(SettingViewHolder holder, int position)
{
holder.bind(getItem(position));
}
private SettingsItem getItem(int position)
{
return mSettings.get(position);
}
@Override
public int getItemCount()
{
if (mSettings != null)
{
return mSettings.size();
}
else
{
return 0;
}
}
@Override
public int getItemViewType(int position)
{
return getItem(position).getType();
}
public void setSettings(ArrayList<SettingsItem> settings)
{
mSettings = settings;
notifyDataSetChanged();
}
public void onSingleChoiceClick(SingleChoiceSetting item)
{
Toast.makeText(mContext, "Single choice item clicked", Toast.LENGTH_SHORT).show();
}
public void onSliderClick(SliderSetting item)
{
Toast.makeText(mContext, "Slider item clicked", Toast.LENGTH_SHORT).show();
}
public void onSubmenuClick(SubmenuSetting item)
{
Toast.makeText(mContext, "Submenu item clicked", Toast.LENGTH_SHORT).show();
}
}

View File

@ -0,0 +1,118 @@
package org.dolphinemu.dolphinemu.ui.settings;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.dolphinemu.dolphinemu.BuildConfig;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.SettingSection;
import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem;
import org.dolphinemu.dolphinemu.ui.DividerItemDecoration;
import java.util.ArrayList;
import java.util.HashMap;
public final class SettingsFragment extends Fragment implements SettingsFragmentView
{
private SettingsFragmentPresenter mPresenter = new SettingsFragmentPresenter(this);
private SettingsActivityView mView;
private SettingsAdapter mAdapter;
@Override
public void onAttach(Context context)
{
super.onAttach(context);
mView = (SettingsActivityView) context;
mPresenter.onAttach();
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setRetainInstance(true);
String menuTag = getArguments().getString(ARGUMENT_MENU_TAG);
mAdapter = new SettingsAdapter(this, getActivity());
mPresenter.onCreate(menuTag);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_settings, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
{
LinearLayoutManager manager = new LinearLayoutManager(getActivity());
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.list_settings);
recyclerView.setAdapter(mAdapter);
recyclerView.setLayoutManager(manager);
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null));
SettingsActivityView activity = (SettingsActivityView) getActivity();
HashMap<String, SettingSection> settings = activity.getSettings();
mPresenter.onViewCreated(settings);
}
@Override
public void onDetach()
{
super.onDetach();
mView = null;
}
@Override
public void onSettingsFileLoaded(HashMap<String, SettingSection> settings)
{
mPresenter.setSettings(settings);
}
@Override
public void passOptionsToActivity(HashMap<String, SettingSection> settings)
{
if (mView != null)
{
mView.setSettings(settings);
}
}
@Override
public void showSettingsList(ArrayList<SettingsItem> settingsList)
{
mAdapter.setSettings(settingsList);
}
public static final String FRAGMENT_TAG = BuildConfig.APPLICATION_ID + ".fragment.settings";
public static final String ARGUMENT_MENU_TAG = FRAGMENT_TAG + ".menu_tag";
public static Fragment newInstance(String menuTag)
{
SettingsFragment fragment = new SettingsFragment();
Bundle arguments = new Bundle();
arguments.putString(ARGUMENT_MENU_TAG, menuTag);
fragment.setArguments(arguments);
return fragment;
}
}

View File

@ -0,0 +1,102 @@
package org.dolphinemu.dolphinemu.ui.settings;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.Setting;
import org.dolphinemu.dolphinemu.model.settings.SettingSection;
import org.dolphinemu.dolphinemu.model.settings.view.CheckBoxSetting;
import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem;
import org.dolphinemu.dolphinemu.model.settings.view.SingleChoiceSetting;
import org.dolphinemu.dolphinemu.model.settings.view.SliderSetting;
import org.dolphinemu.dolphinemu.utils.SettingsFile;
import java.util.ArrayList;
import java.util.HashMap;
public class SettingsFragmentPresenter
{
private SettingsFragmentView mView;
private String mMenuTag;
private HashMap<String, SettingSection> mSettings;
private ArrayList<SettingsItem> mSettingsList;
public SettingsFragmentPresenter(SettingsFragmentView view)
{
mView = view;
}
public void onCreate(String menuTag)
{
mMenuTag = menuTag;
}
public void onViewCreated(HashMap<String, SettingSection> settings)
{
setSettings(settings);
}
/**
* If the screen is rotated, the Activity will forget the settings map. This fragment
* won't, though; so rather than have the Activity reload from disk, have the fragment pass
* the settings map back to the Activity.
*/
public void onAttach()
{
if (mSettings != null)
{
mView.passOptionsToActivity(mSettings);
}
}
public void setSettings(HashMap<String, SettingSection> settings)
{
if (mSettingsList == null)
{
if (settings != null)
{
mSettings = settings;
}
if (mSettings != null)
{
loadSettingsList();
}
}
else
{
mView.showSettingsList(mSettingsList);
}
}
private void loadSettingsList()
{
ArrayList<SettingsItem> sl = new ArrayList<>();
switch (mMenuTag)
{
case SettingsFile.FILE_NAME_DOLPHIN:
addCoreSettings(sl);
break;
}
mSettingsList = sl;
mView.showSettingsList(mSettingsList);
}
private void addCoreSettings(ArrayList<SettingsItem> sl)
{
Setting cpuCore = mSettings.get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_CPU_CORE);
sl.add(new SingleChoiceSetting(cpuCore.getKey(), cpuCore, R.string.cpu_core, 0, R.array.string_emu_cores, R.array.int_emu_cores));
Setting dualCore = mSettings.get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_DUAL_CORE);
sl.add(new CheckBoxSetting(dualCore.getKey(), dualCore, R.string.dual_core, R.string.dual_core_descrip));
Setting overclockEnable = mSettings.get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_OVERCLOCK_ENABLE);
sl.add(new CheckBoxSetting(overclockEnable.getKey(), overclockEnable, R.string.overclock_enable, R.string.overclock_enable_description));
Setting overclock = mSettings.get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_OVERCLOCK_PERCENT);
sl.add(new SliderSetting(overclock.getKey(), overclock, R.string.overclock_title, 0, 400));
}
}

View File

@ -0,0 +1,16 @@
package org.dolphinemu.dolphinemu.ui.settings;
import org.dolphinemu.dolphinemu.model.settings.SettingSection;
import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem;
import java.util.ArrayList;
import java.util.HashMap;
public interface SettingsFragmentView
{
void onSettingsFileLoaded(HashMap<String, SettingSection> settings);
void passOptionsToActivity(HashMap<String, SettingSection> settings);
void showSettingsList(ArrayList<SettingsItem> settingsList);
}

View File

@ -0,0 +1,57 @@
package org.dolphinemu.dolphinemu.ui.settings.viewholder;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.view.CheckBoxSetting;
import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem;
import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter;
public class CheckBoxSettingViewHolder extends SettingViewHolder
{
private CheckBoxSetting mItem;
private TextView mTextSettingName;
private TextView mTextSettingDescription;
private CheckBox mCheckbox;
public CheckBoxSettingViewHolder(View itemView, SettingsAdapter adapter)
{
super(itemView, adapter);
}
@Override
protected void findViews(View root)
{
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
mCheckbox = (CheckBox) root.findViewById(R.id.checkbox);
}
@Override
public void bind(SettingsItem item)
{
mItem = (CheckBoxSetting) item;
mTextSettingName.setText(item.getNameId());
if (item.getDescriptionId() > 0)
{
mTextSettingDescription.setText(item.getDescriptionId());
}
mCheckbox.setChecked(mItem.isChecked());
}
@Override
public void onClick(View clicked)
{
mCheckbox.toggle();
mItem.setChecked(mCheckbox.isChecked());
getAdapter().notifyItemChanged(getAdapterPosition());
}
}

View File

@ -0,0 +1,37 @@
package org.dolphinemu.dolphinemu.ui.settings.viewholder;
import android.view.View;
import android.widget.TextView;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem;
import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter;
public class HeaderViewHolder extends SettingViewHolder
{
private TextView mHeaderName;
public HeaderViewHolder(View itemView, SettingsAdapter adapter)
{
super(itemView, adapter);
itemView.setOnClickListener(null);
}
@Override
protected void findViews(View root)
{
mHeaderName = (TextView) root.findViewById(R.id.text_header_name);
}
@Override
public void bind(SettingsItem item)
{
mHeaderName.setText(item.getNameId());
}
@Override
public void onClick(View clicked)
{
// no-op
}
}

View File

@ -0,0 +1,34 @@
package org.dolphinemu.dolphinemu.ui.settings.viewholder;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem;
import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter;
public abstract class SettingViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
private SettingsAdapter mAdapter;
public SettingViewHolder(View itemView, SettingsAdapter adapter)
{
super(itemView);
mAdapter = adapter;
itemView.setOnClickListener(this);
findViews(itemView);
}
protected SettingsAdapter getAdapter()
{
return mAdapter;
}
protected abstract void findViews(View root);
public abstract void bind(SettingsItem item);
public abstract void onClick(View clicked);
}

View File

@ -0,0 +1,48 @@
package org.dolphinemu.dolphinemu.ui.settings.viewholder;
import android.view.View;
import android.widget.TextView;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem;
import org.dolphinemu.dolphinemu.model.settings.view.SingleChoiceSetting;
import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter;
public class SingleChoiceViewHolder extends SettingViewHolder
{
private SingleChoiceSetting mItem;
private TextView mTextSettingName;
private TextView mTextSettingDescription;
public SingleChoiceViewHolder(View itemView, SettingsAdapter adapter)
{
super(itemView, adapter);
}
@Override
protected void findViews(View root)
{
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
}
@Override
public void bind(SettingsItem item)
{
mItem = (SingleChoiceSetting) item;
mTextSettingName.setText(item.getNameId());
if (item.getDescriptionId() > 0)
{
mTextSettingDescription.setText(item.getDescriptionId());
}
}
@Override
public void onClick(View clicked)
{
getAdapter().onSingleChoiceClick(mItem);
}
}

View File

@ -0,0 +1,50 @@
package org.dolphinemu.dolphinemu.ui.settings.viewholder;
import android.view.View;
import android.widget.TextView;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem;
import org.dolphinemu.dolphinemu.model.settings.view.SliderSetting;
import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter;
public class SliderViewHolder extends SettingViewHolder
{
private SliderSetting mItem;
private TextView mTextSettingName;
private TextView mTextSettingDescription;
public SliderViewHolder(View itemView, SettingsAdapter adapter)
{
super(itemView, adapter);
}
@Override
protected void findViews(View root)
{
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
}
@Override
public void bind(SettingsItem item)
{
mItem = (SliderSetting) item;
mTextSettingName.setText(item.getNameId());
if (item.getDescriptionId() > 0)
{
mTextSettingDescription.setText(item.getDescriptionId());
}
}
@Override
public void onClick(View clicked)
{
getAdapter().onSliderClick(mItem);
}
}

View File

@ -0,0 +1,48 @@
package org.dolphinemu.dolphinemu.ui.settings.viewholder;
import android.view.View;
import android.widget.TextView;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem;
import org.dolphinemu.dolphinemu.model.settings.view.SubmenuSetting;
import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter;
public class SubmenuViewHolder extends SettingViewHolder
{
private SubmenuSetting mItem;
private TextView mTextSettingName;
private TextView mTextSettingDescription;
public SubmenuViewHolder(View itemView, SettingsAdapter adapter)
{
super(itemView, adapter);
}
@Override
protected void findViews(View root)
{
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
}
@Override
public void bind(SettingsItem item)
{
mItem = (SubmenuSetting) item;
mTextSettingName.setText(item.getNameId());
if (item.getDescriptionId() > 0)
{
mTextSettingDescription.setText(item.getDescriptionId());
}
}
@Override
public void onClick(View clicked)
{
getAdapter().onSubmenuClick(mItem);
}
}

View File

@ -20,62 +20,166 @@ import java.io.UnsupportedEncodingException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Set; import java.util.Set;
import rx.Observable;
import rx.Subscriber;
public final class SettingsFile 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_GCPAD = "GCPadNew";
public static final String FILE_NAME_WIIMOTE = "WiimoteNew";
public static final String SECTION_CORE = "Core";
public static final String SECTION_GFX_SETTINGS = "Settings";
public static final String SECTION_GFX_ENHANCEMENTS = "Enhancements";
public static final String SECTION_GFX_HACKS = "Hacks";
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_VIDEO_BACKEND= "GFXBackend";
public static final String KEY_SHOW_FPS= "ShowFPS";
public static final String KEY_INTERNAL_RES= "EFBScale";
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_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_COPY= "EFBCopyEnable";
public static final String KEY_EFB_TEXTURE= "EFBToTextureEnable";
public static final String KEY_EFB_CACHE= "EFBCopyCacheEnable";
public static final String KEY_TEXCACHE_ACCURACY= "SafeTextureCacheColorSamples";
public static final String KEY_XFB= "UseXFB";
public static final String KEY_XFB_REAL= "UseRealXFB";
public static final String KEY_FAST_DEPTH= "FastDepthCalc";
public static final String KEY_ASPECT_RATIO= "AspectRatio";
private SettingsFile() private SettingsFile()
{ {
} }
public static HashMap<String, SettingSection> readFile(String fileName) public static Observable<HashMap<String, SettingSection>> readFile(final String fileName)
{ {
HashMap<String, SettingSection> sections = new HashMap<>(); return Observable.create(new Observable.OnSubscribe<HashMap<String, SettingSection>>()
File ini = getSettingsFile(fileName);
BufferedReader reader = null;
try
{ {
reader = new BufferedReader(new FileReader(ini)); @Override
public void call(Subscriber<? super HashMap<String, SettingSection>> subscriber)
SettingSection current = null;
for (String line; (line = reader.readLine()) != null; )
{
if (line.startsWith("[") && line.endsWith("]"))
{
current = sectionFromLine(line);
sections.put(current.getName(), current);
}
else if ((current != null) && line.contains("="))
{
Setting setting = settingFromLine(current, line);
current.putSetting(setting.getKey(), setting);
}
}
}
catch (FileNotFoundException e)
{
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
}
catch (IOException e)
{
Log.error("[SettingsFile] Error reading from: " + fileName + ".ini: " + e.getMessage());
} finally
{
if (reader != null)
{ {
HashMap<String, SettingSection> sections = new HashMap<>();
File ini = getSettingsFile(fileName);
BufferedReader reader = null;
try try
{ {
reader.close(); reader = new BufferedReader(new FileReader(ini));
SettingSection current = null;
for (String line; (line = reader.readLine()) != null; )
{
if (line.startsWith("[") && line.endsWith("]"))
{
current = sectionFromLine(line);
sections.put(current.getName(), current);
}
else if ((current != null) && line.contains("="))
{
Setting setting = settingFromLine(current, line);
current.putSetting(setting.getKey(), setting);
}
}
}
catch (FileNotFoundException e)
{
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
subscriber.onError(e);
} }
catch (IOException e) catch (IOException e)
{ {
Log.error("[SettingsFile] Error closing: " + fileName + ".ini: " + e.getMessage()); Log.error("[SettingsFile] Error reading from: " + fileName + ".ini: " + e.getMessage());
subscriber.onError(e);
} finally
{
if (reader != null)
{
try
{
reader.close();
}
catch (IOException e)
{
Log.error("[SettingsFile] Error closing: " + fileName + ".ini: " + e.getMessage());
subscriber.onError(e);
}
}
} }
}
}
return sections; subscriber.onNext(sections);
subscriber.onCompleted();
}
});
}
public static Observable<Boolean> saveFile(final String fileName, final HashMap<String, SettingSection> sections)
{
return Observable.create(new Observable.OnSubscribe<Boolean>()
{
@Override
public void call(Subscriber<? super Boolean> subscriber)
{
File ini = getSettingsFile(fileName);
PrintWriter writer = null;
try
{
writer = new PrintWriter(ini, "UTF-8");
Set<String> keySet = sections.keySet();
for (String key : keySet)
{
SettingSection section = sections.get(key);
writeSection(writer, section);
}
}
catch (FileNotFoundException e)
{
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
subscriber.onError(e);
}
catch (UnsupportedEncodingException e)
{
Log.error("[SettingsFile] Bad encoding; please file a bug report: " + fileName + ".ini: " + e.getMessage());
subscriber.onError(e);
} finally
{
if (writer != null)
{
writer.close();
}
}
subscriber.onNext(true);
subscriber.onCompleted();
}
});
} }
@NonNull @NonNull
@ -85,39 +189,6 @@ public final class SettingsFile
return new File(storagePath + "/dolphin-emu/Config/" + fileName + ".ini"); return new File(storagePath + "/dolphin-emu/Config/" + fileName + ".ini");
} }
public static void saveFile(String fileName, HashMap<String, SettingSection> sections)
{
File ini = getSettingsFile(fileName);
PrintWriter writer = null;
try
{
writer = new PrintWriter(ini, "UTF-8");
Set<String> keySet = sections.keySet();
for (String key : keySet)
{
SettingSection section = sections.get(key);
writeSection(writer, section);
}
}
catch (FileNotFoundException e)
{
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
}
catch (UnsupportedEncodingException e)
{
Log.error("[SettingsFile] Bad encoding; please file a bug report: " + fileName + ".ini: " + e.getMessage());
} finally
{
if (writer != null)
{
writer.close();
}
}
}
private static SettingSection sectionFromLine(String line) private static SettingSection sectionFromLine(String line)
{ {
String sectionName = line.substring(1, line.length() - 1); String sectionName = line.substring(1, line.length() - 1);

View File

@ -1,495 +0,0 @@
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2+
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.PreferenceManager;
import org.dolphinemu.dolphinemu.NativeLibrary;
/**
* A class that retrieves all of the set user preferences in Android, in a safe way.
* <p>
* If any preferences are added to this emulator, an accessor for that preference
* should be added here. This way lengthy calls to getters from SharedPreferences
* aren't made necessary.
*/
public final class UserPreferences
{
private UserPreferences()
{
// Disallows instantiation.
}
/**
* Loads the settings stored in the Dolphin ini config files to the shared preferences of this front-end.
*
* @param ctx The context used to retrieve the SharedPreferences instance.
*/
public static void LoadIniToPrefs(Context ctx)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
// Get an editor.
SharedPreferences.Editor editor = prefs.edit();
// Add the settings.
if (Build.CPU_ABI.contains("arm64"))
editor.putString("cpuCorePref", getConfig("Dolphin.ini", "Core", "CPUCore", "4"));
else
editor.putString("cpuCorePref", getConfig("Dolphin.ini", "Core", "CPUCore", "3"));
editor.putBoolean("dualCorePref", getConfig("Dolphin.ini", "Core", "CPUThread", "True").equals("True"));
editor.putBoolean("OverclockEnable", getConfig("Dolphin.ini", "Core", "OverclockEnable", "False").equals("True"));
editor.putString("Overclock", getConfig("Dolphin.ini", "Core", "Overclock", "100"));
// Load analog ranges from GCPadNew.ini and WiimoteNew.ini
editor.putString("mainRadius0", getConfig("GCPadNew.ini", "GCPad1", "Main Stick/Radius", "100,000000"));
editor.putString("cStickRadius0", getConfig("GCPadNew.ini", "GCPad1", "C-Stick/Radius", "100,000000"));
editor.putString("inputThres0", getConfig("GCPadNew.ini", "GCPad1", "Triggers/Threshold", "90,000000"));
editor.putString("mainRadius1", getConfig("GCPadNew.ini", "GCPad2", "Main Stick/Radius", "100,000000"));
editor.putString("cStickRadius1", getConfig("GCPadNew.ini", "GCPad2", "C-Stick/Radius", "100,000000"));
editor.putString("inputThres1", getConfig("GCPadNew.ini", "GCPad2", "Triggers/Threshold", "90,000000"));
editor.putString("mainRadius2", getConfig("GCPadNew.ini", "GCPad3", "Main Stick/Radius", "100,000000"));
editor.putString("cStickRadius2", getConfig("GCPadNew.ini", "GCPad3", "C-Stick/Radius", "100,000000"));
editor.putString("inputThres2", getConfig("GCPadNew.ini", "GCPad3", "Triggers/Threshold", "90,000000"));
editor.putString("mainRadius3", getConfig("GCPadNew.ini", "GCPad4", "Main Stick/Radius", "100,000000"));
editor.putString("cStickRadius3", getConfig("GCPadNew.ini", "GCPad4", "C-Stick/Radius", "100,000000"));
editor.putString("inputThres3", getConfig("GCPadNew.ini", "GCPad4", "Triggers/Threshold", "90,000000"));
editor.putString("tiltRange4", getConfig("WiimoteNew.ini", "Wiimote1", "Tilt/Modifier/Range", "50,00000"));
editor.putString("tiltRange5", getConfig("WiimoteNew.ini", "Wiimote2", "Tilt/Modifier/Range", "50,00000"));
editor.putString("tiltRange6", getConfig("WiimoteNew.ini", "Wiimote3", "Tilt/Modifier/Range", "50,00000"));
editor.putString("tiltRange7", getConfig("WiimoteNew.ini", "Wiimote4", "Tilt/Modifier/Range", "50,00000"));
editor.putString("nunchukRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Nunchuk/Stick/Radius", "100,000000"));
editor.putString("nunchukRange4", getConfig("WiimoteNew.ini", "Wiimote1", "Nunchuk/Tilt/Modifier/Range", "50,00000"));
editor.putString("nunchukRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Nunchuk/Stick/Radius", "100,000000"));
editor.putString("nunchukRange5", getConfig("WiimoteNew.ini", "Wiimote2", "Nunchuk/Tilt/Modifier/Range", "50,00000"));
editor.putString("nunchukRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Nunchuk/Stick/Radius", "100,000000"));
editor.putString("nunchukRange6", getConfig("WiimoteNew.ini", "Wiimote3", "Nunchuk/Tilt/Modifier/Range", "50,00000"));
editor.putString("nunchukRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Nunchuk/Stick/Radius", "100,000000"));
editor.putString("nunchukRange7", getConfig("WiimoteNew.ini", "Wiimote4", "Nunchuk/Tilt/Modifier/Range", "50,00000"));
editor.putString("classicLRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Classic/Left Stick/Radius", "100,000000"));
editor.putString("classicRRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Classic/Right Stick/Radius", "100,000000"));
editor.putString("classicThres4", getConfig("WiimoteNew.ini", "Wiimote1", "Classic/Triggers/Threshold", "90,000000"));
editor.putString("classicLRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Classic/Left Stick/Radius", "100,000000"));
editor.putString("classicRRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Classic/Right Stick/Radius", "100,000000"));
editor.putString("classicThres5", getConfig("WiimoteNew.ini", "Wiimote2", "Classic/Triggers/Threshold", "90,000000"));
editor.putString("classicLRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Classic/Left Stick/Radius", "100,000000"));
editor.putString("classicRRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Classic/Right Stick/Radius", "100,000000"));
editor.putString("classicThres6", getConfig("WiimoteNew.ini", "Wiimote3", "Classic/Triggers/Threshold", "90,000000"));
editor.putString("classicLRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Classic/Left Stick/Radius", "100,000000"));
editor.putString("classicRRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Classic/Right Stick/Radius", "100,000000"));
editor.putString("classicThres7", getConfig("WiimoteNew.ini", "Wiimote4", "Classic/Triggers/Threshold", "90,000000"));
editor.putString("guitarRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Guitar/Stick/Radius", "100,000000"));
editor.putString("guitarRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Guitar/Stick/Radius", "100,000000"));
editor.putString("guitarRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Guitar/Stick/Radius", "100,000000"));
editor.putString("guitarRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Guitar/Stick/Radius", "100,000000"));
editor.putString("drumsRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Drums/Stick/Radius", "100,000000"));
editor.putString("drumsRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Drums/Stick/Radius", "100,000000"));
editor.putString("drumsRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Drums/Stick/Radius", "100,000000"));
editor.putString("drumsRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Drums/Stick/Radius", "100,000000"));
editor.putString("turntableRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Turntable/Stick/Radius", "100,000000"));
editor.putString("turntableRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Turntable/Stick/Radius", "100,000000"));
editor.putString("turntableRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Turntable/Stick/Radius", "100,000000"));
editor.putString("turntableRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Turntable/Stick/Radius", "100,000000"));
// Load Wiimote Extension settings from WiimoteNew.ini
editor.putString("wiimoteExtension4", getConfig("WiimoteNew.ini", "Wiimote1", "Extension", "None"));
editor.putString("wiimoteExtension5", getConfig("WiimoteNew.ini", "Wiimote2", "Extension", "None"));
editor.putString("wiimoteExtension6", getConfig("WiimoteNew.ini", "Wiimote3", "Extension", "None"));
editor.putString("wiimoteExtension7", getConfig("WiimoteNew.ini", "Wiimote4", "Extension", "None"));
editor.putString("gpuPref", getConfig("Dolphin.ini", "Core", "GFXBackend", "OGL"));
editor.putBoolean("showFPS", getConfig("GFX.ini", "Settings", "ShowFPS", "False").equals("True"));
editor.putBoolean("drawOnscreenControls", getConfig("Dolphin.ini", "Android", "ScreenControls", "True").equals("True"));
editor.putString("internalResolution", getConfig("GFX.ini", "Settings", "EFBScale", "2"));
editor.putString("FSAA", getConfig("GFX.ini", "Settings", "MSAA", "0"));
editor.putString("anisotropicFiltering", getConfig("GFX.ini", "Enhancements", "MaxAnisotropy", "0"));
editor.putString("postProcessingShader", getConfig("GFX.ini", "Enhancements", "PostProcessingShader", ""));
editor.putBoolean("scaledEFBCopy", getConfig("GFX.ini", "Hacks", "EFBScaledCopy", "True").equals("True"));
editor.putBoolean("perPixelLighting", getConfig("GFX.ini", "Settings", "EnablePixelLighting", "False").equals("True"));
editor.putBoolean("forceTextureFiltering", getConfig("GFX.ini", "Enhancements", "ForceFiltering", "False").equals("True"));
editor.putBoolean("disableFog", getConfig("GFX.ini", "Settings", "DisableFog", "False").equals("True"));
editor.putBoolean("skipEFBAccess", getConfig("GFX.ini", "Hacks", "EFBAccessEnable", "False").equals("True"));
editor.putBoolean("ignoreFormatChanges", getConfig("GFX.ini", "Hacks", "EFBEmulateFormatChanges", "False").equals("True"));
editor.putString("stereoscopyMode", getConfig("GFX.ini", "Stereoscopy", "StereoMode", "0"));
editor.putBoolean("stereoSwapEyes", getConfig("GFX.ini", "Stereoscopy", "StereoSwapEyes", "False").equals("True"));
editor.putString("stereoDepth", getConfig("GFX.ini", "Stereoscopy", "StereoDepth", "20"));
editor.putString("stereoConvergencePercentage", getConfig("GFX.ini", "Stereoscopy", "StereoConvergencePercentage", "100"));
editor.putBoolean("enableController1", getConfig("Dolphin.ini", "Core", "SIDevice0", "6") == "6");
editor.putBoolean("enableController2", getConfig("Dolphin.ini", "Core", "SIDevice1", "0") == "6");
editor.putBoolean("enableController3", getConfig("Dolphin.ini", "Core", "SIDevice2", "0") == "6");
editor.putBoolean("enableController4", getConfig("Dolphin.ini", "Core", "SIDevice3", "0") == "6");
String efbCopyOn = getConfig("GFX.ini", "Hacks", "EFBCopyEnable", "True");
String efbToTexture = getConfig("GFX.ini", "Hacks", "EFBToTextureEnable", "True");
String efbCopyCache = getConfig("GFX.ini", "Hacks", "EFBCopyCacheEnable", "False");
if (efbCopyOn.equals("False"))
{
editor.putString("efbCopyMethod", "Off");
}
else if (efbCopyOn.equals("True") && efbToTexture.equals("True"))
{
editor.putString("efbCopyMethod", "Texture");
}
else if(efbCopyOn.equals("True") && efbToTexture.equals("False") && efbCopyCache.equals("False"))
{
editor.putString("efbCopyMethod", "RAM (uncached)");
}
else if(efbCopyOn.equals("True") && efbToTexture.equals("False") && efbCopyCache.equals("True"))
{
editor.putString("efbCopyMethod", "RAM (cached)");
}
editor.putString("textureCacheAccuracy", getConfig("GFX.ini", "Settings", "SafeTextureCacheColorSamples", "128"));
String usingXFB = getConfig("GFX.ini", "Settings", "UseXFB", "False");
String usingRealXFB = getConfig("GFX.ini", "Settings", "UseRealXFB", "False");
if (usingXFB.equals("False"))
{
editor.putString("externalFrameBuffer", "Disabled");
}
else if (usingXFB.equals("True") && usingRealXFB.equals("False"))
{
editor.putString("externalFrameBuffer", "Virtual");
}
else if (usingXFB.equals("True") && usingRealXFB.equals("True"))
{
editor.putString("externalFrameBuffer", "Real");
}
editor.putBoolean("fastDepthCalculation", getConfig("GFX.ini", "Settings", "FastDepthCalc", "True").equals("True"));
editor.putString("aspectRatio", getConfig("GFX.ini", "Settings", "AspectRatio", "0"));
// Apply the changes.
editor.apply();
}
// Small utility method that shortens calls to NativeLibrary.GetConfig.
private static String getConfig(String ini, String section, String key, String defaultValue)
{
return NativeLibrary.GetConfig(ini, section, key, defaultValue);
}
/**
* Writes the preferences set in the front-end to the Dolphin ini files.
*
* @param ctx The context used to retrieve the user settings.
* */
public static void SavePrefsToIni(Context ctx)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
// Whether or not the user is using dual core.
boolean isUsingDualCore = prefs.getBoolean("dualCorePref", true);
// Current CPU core being used. Falls back to interpreter upon error.
String currentEmuCore = prefs.getString("cpuCorePref", "0");
boolean overclockEnabled = prefs.getBoolean("OverclockEnable", false);
String overclockSetting = prefs.getString("Overclock", "100");
// Current GC analog range setup. Falls back to default upon error.
String currentMainRadius0 = prefs.getString("mainRadius0", "100,000000");
String currentCStickRadius0 = prefs.getString("cStickRadius0", "100,000000");
String currentInputThres0 = prefs.getString("inputThres0", "90,000000");
String currentMainRadius1 = prefs.getString("mainRadius1", "100,000000");
String currentCStickRadius1 = prefs.getString("cStickRadius1", "100,000000");
String currentInputThres1 = prefs.getString("inputThres1", "90,000000");
String currentMainRadius2 = prefs.getString("mainRadius2", "100,000000");
String currentCStickRadius2 = prefs.getString("cStickRadius2", "100,000000");
String currentInputThres2 = prefs.getString("inputThres2", "90,000000");
String currentMainRadius3 = prefs.getString("mainRadius3", "100,000000");
String currentCStickRadius3 = prefs.getString("cStickRadius3", "100,000000");
String currentInputThres3 = prefs.getString("inputThres3", "90,000000");
// Current Wii analog range setup. Falls back to default on error.
String currentTiltRange4 = prefs.getString("tiltRange4", "50,000000");
String currentTiltRange5 = prefs.getString("tiltRange5", "50,000000");
String currentTiltRange6 = prefs.getString("tiltRange6", "50,000000");
String currentTiltRange7 = prefs.getString("tiltRange7", "50,000000");
// Current Nunchuk analog range setup. Falls back to default upon error.
String currentNunchukRadius4 = prefs.getString("nunchukRadius4", "100,000000");
String currentNunchukRange4 = prefs.getString("nunchukRange4", "50,000000");
String currentNunchukRadius5 = prefs.getString("nunchukRadius5", "100,000000");
String currentNunchukRange5 = prefs.getString("nunchukRange5", "50,000000");
String currentNunchukRadius6 = prefs.getString("nunchukRadius6", "100,000000");
String currentNunchukRange6 = prefs.getString("nunchukRange6", "50,000000");
String currentNunchukRadius7 = prefs.getString("nunchukRadius7", "100,000000");
String currentNunchukRange7 = prefs.getString("nunchukRange7", "50,000000");
// Current Classic analog range setup. Falls back to 100,000000 upon error.
String currentClassicLRadius4 = prefs.getString("classicLRadius4", "100,000000");
String currentClassicRRadius4 = prefs.getString("classicRRadius4", "100,000000");
String currentClassicThres4 = prefs.getString("classicThres4", "90,000000");
String currentClassicLRadius5 = prefs.getString("classicLRadius5", "100,000000");
String currentClassicRRadius5 = prefs.getString("classicRRadius5", "100,000000");
String currentClassicThres5 = prefs.getString("classicThres5", "90,000000");
String currentClassicLRadius6 = prefs.getString("classicLRadius6", "100,000000");
String currentClassicRRadius6 = prefs.getString("classicRRadius6", "100,000000");
String currentClassicThres6 = prefs.getString("classicThres6", "90,000000");
String currentClassicLRadius7 = prefs.getString("classicLRadius7", "100,000000");
String currentClassicRRadius7 = prefs.getString("classicRRadius7", "100,000000");
String currentClassicThres7 = prefs.getString("classicThres7", "90,000000");
// Current Guitar analog range setup. Falls back to default upon error.
String currentGuitarRadius4 = prefs.getString("guitarRadius4", "100,000000");
String currentGuitarRadius5 = prefs.getString("guitarRadius5", "100,000000");
String currentGuitarRadius6 = prefs.getString("guitarRadius6", "100,000000");
String currentGuitarRadius7 = prefs.getString("guitarRadius7", "100,000000");
// Current Drums modifier Radius setup. Falls back to default upon error.
String currentDrumsRadius4 = prefs.getString("drumsRadius4", "100,000000");
String currentDrumsRadius5 = prefs.getString("drumsRadius5", "100,000000");
String currentDrumsRadius6 = prefs.getString("drumsRadius6", "100,000000");
String currentDrumsRadius7 = prefs.getString("drumsRadius7", "100,000000");
// Current Turntable analog range setup. Falls back to default upon error.
String currentTurntableRadius4 = prefs.getString("turntableRadius4", "100,000000");
String currentTurntableRadius5 = prefs.getString("turntableRadius5", "100,000000");
String currentTurntableRadius6 = prefs.getString("turntableRadius6", "100,000000");
String currentTurntableRadius7 = prefs.getString("turntableRadius7", "100,000000");
// Current wiimote extension setup. Falls back to no extension upon error.
String currentWiimoteExtension4 = prefs.getString("wiimoteExtension4", "None");
String currentWiimoteExtension5 = prefs.getString("wiimoteExtension5", "None");
String currentWiimoteExtension6 = prefs.getString("wiimoteExtension6", "None");
String currentWiimoteExtension7 = prefs.getString("wiimoteExtension7", "None");
// Current video backend being used. Falls back to software rendering upon error.
String currentVideoBackend = prefs.getString("gpuPref", "Software Rendering");
// Whether or not FPS will be displayed on-screen.
boolean showingFPS = prefs.getBoolean("showFPS", false);
// Whether or not to draw on-screen controls.
boolean drawingOnscreenControls = prefs.getBoolean("drawOnscreenControls", true);
// Whether or not to ignore all EFB access requests from the CPU.
boolean skipEFBAccess = prefs.getBoolean("skipEFBAccess", false);
// Whether or not to ignore changes to the EFB format.
boolean ignoreFormatChanges = prefs.getBoolean("ignoreFormatChanges", false);
// EFB copy method to use.
String efbCopyMethod = prefs.getString("efbCopyMethod", "Texture");
// Texture cache accuracy. Falls back to "Fast" up error.
String textureCacheAccuracy = prefs.getString("textureCacheAccuracy", "128");
// External frame buffer emulation. Falls back to disabled upon error.
String externalFrameBuffer = prefs.getString("externalFrameBuffer", "Disabled");
// Whether or not to use fast depth calculation.
boolean useFastDepthCalc = prefs.getBoolean("fastDepthCalculation", true);
// Aspect ratio selection
String aspectRatio = prefs.getString("aspectRatio", "0");
// Internal resolution. Falls back to 1x Native upon error.
String internalResolution = prefs.getString("internalResolution", "2");
// FSAA Level. Falls back to 1x upon error.
String FSAALevel = prefs.getString("FSAA", "0");
// Anisotropic Filtering Level. Falls back to 1x upon error.
String anisotropicFiltLevel = prefs.getString("anisotropicFiltering", "0");
// Post processing shader setting
String postProcessing = prefs.getString("postProcessingShader", "");
// Whether or not Scaled EFB copies are used.
boolean usingScaledEFBCopy = prefs.getBoolean("scaledEFBCopy", true);
// Whether or not per-pixel lighting is used.
boolean usingPerPixelLighting = prefs.getBoolean("perPixelLighting", false);
// Whether or not texture filtering is being forced.
boolean isForcingTextureFiltering = prefs.getBoolean("forceTextureFiltering", false);
// Whether or not fog is disabled.
boolean fogIsDisabled = prefs.getBoolean("disableFog", false);
// Stereoscopy setting
String stereoscopyMode = prefs.getString("stereoscopyMode", "0");
// Stereoscopy swap eyes
boolean stereoscopyEyeSwap = prefs.getBoolean("stereoSwapEyes", false);
// Stereoscopy separation
String stereoscopySeparation = prefs.getString("stereoDepth", "20");
// Stereoscopy convergence
String stereoConvergencePercentage = prefs.getString("stereoConvergencePercentage", "100");
// Controllers
// Controller 1 never gets disconnected due to touch screen
//boolean enableController1 = prefs.getBoolean("enableController1", true);
boolean enableController2 = prefs.getBoolean("enableController2", false);
boolean enableController3 = prefs.getBoolean("enableController3", false);
boolean enableController4 = prefs.getBoolean("enableController4", false);
// CPU related Settings
NativeLibrary.SetConfig("Dolphin.ini", "Core", "CPUCore", currentEmuCore);
NativeLibrary.SetConfig("Dolphin.ini", "Core", "CPUThread", isUsingDualCore ? "True" : "False");
NativeLibrary.SetConfig("Dolphin.ini", "Core", "OverclockEnable", overclockEnabled ? "True" : "False");
NativeLibrary.SetConfig("Dolphin.ini", "Core", "Overclock", overclockSetting);
// GameCube analog ranges Setup
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad1", "Main Stick/Radius", currentMainRadius0);
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad1", "C-Stick/Radius", currentCStickRadius0);
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad1", "Triggers/Threshold", currentInputThres0);
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad2", "Main Stick/Radius", currentMainRadius1);
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad2", "C-Stick/Radius", currentCStickRadius1);
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad2", "Triggers/Threshold", currentInputThres1);
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad3", "Main Stick/Radius", currentMainRadius2);
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad3", "C-Stick/Radius", currentCStickRadius2);
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad3", "Triggers/Threshold", currentInputThres2);
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad4", "Main Stick/Radius", currentMainRadius3);
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad4", "C-Stick/Radius", currentCStickRadius3);
NativeLibrary.SetConfig("GCPadNew.ini", "GCPad4", "Triggers/Threshold", currentInputThres3);
// Wiimote analog ranges Setup
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Tilt/Modifier/Range", currentTiltRange4);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Tilt/Modifier/Range", currentTiltRange5);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Tilt/Modifier/Range", currentTiltRange6);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Tilt/Modifier/Range", currentTiltRange7);
// Nunchuk analog ranges Setup
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Nunchuk/Stick/Radius", currentNunchukRadius4);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Nunchuk/Stick/Radius", currentNunchukRange4);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Nunchuk/Stick/Radius", currentNunchukRadius5);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Nunchuk/Stick/Radius", currentNunchukRange5);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Nunchuk/Stick/Radius", currentNunchukRadius6);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Nunchuk/Stick/Radius", currentNunchukRange6);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Nunchuk/Stick/Radius", currentNunchukRadius7);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Nunchuk/Stick/Radius", currentNunchukRange7);
// Classic analog ranges Setup
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Classic/Left Stick/Radius", currentClassicLRadius4);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Classic/Right Stick/Radius", currentClassicRRadius4);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Classic/Triggers/Threshold", currentClassicThres4);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Classic/Left Stick/Radius", currentClassicLRadius5);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Classic/Right Stick/Radius", currentClassicRRadius5);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Classic/Triggers/Threshold", currentClassicThres5);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Classic/Left Stick/Radius", currentClassicLRadius6);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Classic/Right Stick/Radius", currentClassicRRadius6);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Classic/Triggers/Threshold", currentClassicThres6);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Classic/Left Stick/Radius", currentClassicLRadius7);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Classic/Right Stick/Radius", currentClassicRRadius7);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Classic/Triggers/Threshold", currentClassicThres7);
// Guitar analog ranges Setup
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Guitar/Stick/Radius", currentGuitarRadius4);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Guitar/Stick/Radius", currentGuitarRadius5);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Guitar/Stick/Radius", currentGuitarRadius6);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Guitar/Stick/Radius", currentGuitarRadius7);
// Drums analog ranges Setup
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Drums/Stick/Radius", currentDrumsRadius4);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Drums/Stick/Radius", currentDrumsRadius5);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Drums/Stick/Radius", currentDrumsRadius6);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Drums/Stick/Radius", currentDrumsRadius7);
// Turntable analog ranges Setup
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Turntable/Stick/Radius", currentTurntableRadius4);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Turntable/Stick/Radius", currentTurntableRadius5);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Turntable/Stick/Radius", currentTurntableRadius6);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Turntable/Stick/Radius", currentTurntableRadius7);
// Wiimote Extension Settings
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Extension", currentWiimoteExtension4);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Extension", currentWiimoteExtension5);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Extension", currentWiimoteExtension6);
NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Extension", currentWiimoteExtension7);
// General Video Settings
NativeLibrary.SetConfig("Dolphin.ini", "Core", "GFXBackend", currentVideoBackend);
NativeLibrary.SetConfig("GFX.ini", "Settings", "ShowFPS", showingFPS ? "True" : "False");
NativeLibrary.SetConfig("Dolphin.ini", "Android", "ScreenControls", drawingOnscreenControls ? "True" : "False");
// Video Hack Settings
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBAccessEnable", skipEFBAccess ? "False" : "True");
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBEmulateFormatChanges", ignoreFormatChanges ? "True" : "False");
NativeLibrary.SetConfig("GFX.ini", "Settings", "AspectRatio", aspectRatio);
// Set EFB Copy Method
if (efbCopyMethod.equals("Off"))
{
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyEnable", "False");
}
else if (efbCopyMethod.equals("Texture"))
{
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyEnable", "True");
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBToTextureEnable", "True");
}
else if (efbCopyMethod.equals("RAM (uncached)"))
{
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyEnable", "True");
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBToTextureEnable", "False");
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyCacheEnable", "False");
}
else if (efbCopyMethod.equals("RAM (cached)"))
{
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyEnable", "True");
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBToTextureEnable", "False");
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyCacheEnable", "True");
}
// Set texture cache accuracy
NativeLibrary.SetConfig("GFX.ini", "Settings", "SafeTextureCacheColorSamples", textureCacheAccuracy);
// Set external frame buffer.
if (externalFrameBuffer.equals("Disabled"))
{
NativeLibrary.SetConfig("GFX.ini", "Settings", "UseXFB", "False");
}
else if (externalFrameBuffer.equals("Virtual"))
{
NativeLibrary.SetConfig("GFX.ini", "Settings", "UseXFB", "True");
NativeLibrary.SetConfig("GFX.ini", "Settings", "UseRealXFB", "False");
}
else if (externalFrameBuffer.equals("Real"))
{
NativeLibrary.SetConfig("GFX.ini", "Settings", "UseXFB", "True");
NativeLibrary.SetConfig("GFX.ini", "Settings", "UseRealXFB", "True");
}
NativeLibrary.SetConfig("GFX.ini", "Settings", "FastDepthCalc", useFastDepthCalc ? "True" : "False");
//-- Enhancement Settings --//
NativeLibrary.SetConfig("GFX.ini", "Settings", "EFBScale", internalResolution);
NativeLibrary.SetConfig("GFX.ini", "Settings", "MSAA", FSAALevel);
NativeLibrary.SetConfig("GFX.ini", "Enhancements", "MaxAnisotropy", anisotropicFiltLevel);
NativeLibrary.SetConfig("GFX.ini", "Enhancements", "PostProcessingShader", postProcessing);
NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBScaledCopy", usingScaledEFBCopy ? "True" : "False");
NativeLibrary.SetConfig("GFX.ini", "Settings", "EnablePixelLighting", usingPerPixelLighting ? "True" : "False");
NativeLibrary.SetConfig("GFX.ini", "Enhancements", "ForceFiltering", isForcingTextureFiltering ? "True" : "False");
NativeLibrary.SetConfig("GFX.ini", "Settings", "DisableFog", fogIsDisabled ? "True" : "False");
NativeLibrary.SetConfig("GFX.ini", "Stereoscopy", "StereoMode", stereoscopyMode);
NativeLibrary.SetConfig("GFX.ini", "Stereoscopy", "StereoSwapEyes", stereoscopyEyeSwap ? "True" : "False");
NativeLibrary.SetConfig("GFX.ini", "Stereoscopy", "StereoDepth", stereoscopySeparation);
NativeLibrary.SetConfig("GFX.ini", "Stereoscopy", "StereoConvergence", stereoConvergencePercentage);
NativeLibrary.SetConfig("Dolphin.ini", "Core", "SIDevice0", "6");
NativeLibrary.SetConfig("Dolphin.ini", "Core", "SIDevice1", enableController2 ? "6" : "0");
NativeLibrary.SetConfig("Dolphin.ini", "Core", "SIDevice2", enableController3 ? "6" : "0");
NativeLibrary.SetConfig("Dolphin.ini", "Core", "SIDevice3", enableController4 ? "6" : "0");
}
}

View File

@ -1,20 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="match_parent"
android:layout_height="match_parent" android:id="@+id/frame_content"/>
android:orientation="vertical">
<FrameLayout
android:id="@+id/frame_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
tools:listitem="@layout/list_item_file"
android:elevation="4dp"
android:background="@android:color/white"/>
</LinearLayout>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/list_settings"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="72dp"
android:background="?android:attr/selectableItemBackground"
android:focusable="true"
android:clickable="true">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/TextAppearance.AppCompat.Headline"
tools:text="Setting Name"
android:layout_alignParentEnd="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:layout_marginTop="@dimen/spacing_large"
android:id="@+id/text_setting_name"
android:textSize="16sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="@string/overclock_enable_description"
android:layout_alignParentEnd="true"
android:layout_alignParentStart="true"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:layout_marginBottom="@dimen/spacing_large"
android:layout_marginTop="@dimen/spacing_small"
android:id="@+id/text_setting_description"
android:layout_below="@+id/text_setting_name"
android:layout_alignStart="@+id/text_setting_name"/>
</RelativeLayout>

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="72dp"
android:background="?android:attr/selectableItemBackground"
android:focusable="true"
android:clickable="true">
<TextView
android:id="@+id/text_setting_name"
style="@style/TextAppearance.AppCompat.Headline"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginEnd="@dimen/spacing_large"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginTop="@dimen/spacing_large"
android:layout_toStartOf="@+id/checkbox"
android:textSize="16sp"
tools:text="@string/overclock_enable"/>
<TextView
android:id="@+id/text_setting_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignStart="@+id/text_setting_name"
android:layout_below="@+id/text_setting_name"
android:layout_marginBottom="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginTop="@dimen/spacing_small"
android:layout_toStartOf="@+id/checkbox"
tools:text="@string/overclock_enable_description"/>
<CheckBox
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/spacing_large"
android:focusable="false"
android:clickable="false"/>
</RelativeLayout>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="48dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/text_header_name"
tools:text="CPU Settings"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginBottom="@dimen/spacing_small"
android:textColor="?android:colorAccent"
android:textStyle="bold"
android:layout_gravity="left|bottom"/>
</FrameLayout>

View File

@ -9,4 +9,11 @@
<dimen name="add_button_margin">16dp</dimen> <dimen name="add_button_margin">16dp</dimen>
<dimen name="main_appbar_height">128dp</dimen> <dimen name="main_appbar_height">128dp</dimen>
<dimen name="spacing_xsmall">2dp</dimen>
<dimen name="spacing_small">4dp</dimen>
<dimen name="spacing_medium">8dp</dimen>
<dimen name="spacing_medlarge">12dp</dimen>
<dimen name="spacing_large">16dp</dimen>
<dimen name="spacing_xlarge">32dp</dimen>
</resources> </resources>

View File

@ -17,7 +17,7 @@
</style> </style>
<!-- Same as above, but use default action bar, and mandate margins. --> <!-- Same as above, but use default action bar, and mandate margins. -->
<style name="DolphinSettingsBase" parent="Theme.AppCompat.Light.NoActionBar"> <style name="DolphinSettingsBase" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/dolphin_blue</item> <item name="colorPrimary">@color/dolphin_blue</item>
<item name="colorPrimaryDark">@color/dolphin_blue_dark</item> <item name="colorPrimaryDark">@color/dolphin_blue_dark</item>
</style> </style>