mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
[Android most of new UserPreferences class finish. Not implemented however.
This commit is contained in:
parent
348cdb32b6
commit
010e691993
@ -0,0 +1,433 @@
|
||||
package org.retroarch.browser.preferences;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.retroarch.R;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioTrack;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
|
||||
/**
|
||||
* Class retrieving, saving, or loading preferences.
|
||||
*/
|
||||
public final class UserPreferences
|
||||
{
|
||||
// Logging tag.
|
||||
private static final String TAG = "UserPreferences";
|
||||
|
||||
public static String getDefaultConfigPath(Context ctx)
|
||||
{
|
||||
// Internal/External storage dirs.
|
||||
final String internal = System.getenv("INTERNAL_STORAGE");
|
||||
final String external = System.getenv("EXTERNAL_STORAGE");
|
||||
|
||||
// Native library directory and data directory for this front-end.
|
||||
final String nativeLibraryDir = ctx.getApplicationInfo().nativeLibraryDir;
|
||||
final String dataDir = ctx.getApplicationInfo().dataDir;
|
||||
|
||||
// Get libretro name and path
|
||||
final SharedPreferences prefs = getPreferences(ctx);
|
||||
final String libretro_path = prefs.getString("libretro_path", nativeLibraryDir);
|
||||
final String libretro_name = prefs.getString("libretro_name", ctx.getString(R.string.no_core));
|
||||
|
||||
// Check if global config is being used. Return true upon failure.
|
||||
final boolean globalConfigEnabled = prefs.getBoolean("global_config_enable", true);
|
||||
|
||||
String append_path;
|
||||
// If we aren't using the global config.
|
||||
if (!globalConfigEnabled && !libretro_path.equals(nativeLibraryDir))
|
||||
{
|
||||
String sanitized_name = sanitizeLibretroPath(libretro_path);
|
||||
append_path = File.separator + sanitized_name + ".cfg";
|
||||
}
|
||||
else // Using global config.
|
||||
{
|
||||
append_path = File.separator + "retroarch.cfg";
|
||||
}
|
||||
|
||||
if (external != null)
|
||||
{
|
||||
String confPath = external + append_path;
|
||||
if (new File(confPath).exists())
|
||||
return confPath;
|
||||
}
|
||||
else if (internal != null)
|
||||
{
|
||||
String confPath = internal + append_path;
|
||||
if (new File(confPath).exists())
|
||||
return confPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
String confPath = "/mnt/extsd" + append_path;
|
||||
if (new File(confPath).exists())
|
||||
return confPath;
|
||||
}
|
||||
|
||||
if (internal != null && new File(internal + append_path).canWrite())
|
||||
return internal + append_path;
|
||||
else if (external != null && new File(internal + append_path).canWrite())
|
||||
return external + append_path;
|
||||
else if (dataDir != null)
|
||||
return dataDir + append_path;
|
||||
else
|
||||
// emergency fallback, all else failed
|
||||
return "/mnt/sd" + append_path;
|
||||
}
|
||||
|
||||
public static void readbackConfigFile(Context ctx)
|
||||
{
|
||||
String path = getDefaultConfigPath(ctx);
|
||||
ConfigFile config;
|
||||
try
|
||||
{
|
||||
config = new ConfigFile(new File(path));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(TAG, "Config readback from: " + path);
|
||||
|
||||
SharedPreferences prefs = getPreferences(ctx);
|
||||
SharedPreferences.Editor edit = prefs.edit();
|
||||
|
||||
readbackString(config, edit, "rgui_browser_directory");
|
||||
readbackString(config, edit, "savefile_directory");
|
||||
readbackString(config, edit, "savestate_directory");
|
||||
readbackBool(config, edit, "savefile_directory_enable"); // Ignored by RetroArch
|
||||
readbackBool(config, edit, "savestate_directory_enable"); // Ignored by RetroArch
|
||||
|
||||
readbackString(config, edit, "input_overlay");
|
||||
readbackBool(config, edit, "input_overlay_enable");
|
||||
readbackBool(config, edit, "video_scale_integer");
|
||||
readbackBool(config, edit, "video_smooth");
|
||||
readbackBool(config, edit, "video_threaded");
|
||||
readbackBool(config, edit, "rewind_enable");
|
||||
readbackBool(config, edit, "savestate_auto_load");
|
||||
readbackBool(config, edit, "savestate_auto_save");
|
||||
//readbackDouble(config, edit, "video_refresh_rate");
|
||||
|
||||
readbackBool(config, edit, "audio_rate_control");
|
||||
readbackBool(config, edit, "audio_enable");
|
||||
// TODO: other audio settings
|
||||
|
||||
readbackDouble(config, edit, "input_overlay_opacity");
|
||||
readbackBool(config, edit, "input_autodetect_enable");
|
||||
//readbackInt(config, edit, "input_back_behavior");
|
||||
|
||||
readbackBool(config, edit, "video_allow_rotate");
|
||||
readbackBool(config, edit, "video_font_enable");
|
||||
|
||||
readbackBool(config, edit, "video_vsync");
|
||||
|
||||
edit.commit();
|
||||
}
|
||||
|
||||
public static void updateConfigFile(Context ctx)
|
||||
{
|
||||
String path = getDefaultConfigPath(ctx);
|
||||
ConfigFile config;
|
||||
try
|
||||
{
|
||||
config = new ConfigFile(new File(path));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
config = new ConfigFile();
|
||||
}
|
||||
|
||||
Log.i(TAG, "Writing config to: " + path);
|
||||
|
||||
// Native library and data directories.
|
||||
final String dataDir = ctx.getApplicationInfo().dataDir;
|
||||
final String nativeLibraryDir = ctx.getApplicationInfo().nativeLibraryDir;
|
||||
|
||||
final SharedPreferences prefs = getPreferences(ctx);
|
||||
final String libretro_path = prefs.getString("libretro_path", nativeLibraryDir);
|
||||
|
||||
|
||||
config.setString("libretro_path", libretro_path);
|
||||
config.setString("rgui_browser_directory", prefs.getString("rgui_browser_directory", ""));
|
||||
config.setBoolean("audio_rate_control", prefs.getBoolean("audio_rate_control", true));
|
||||
|
||||
int optimalRate = getOptimalSamplingRate(ctx);
|
||||
config.setInt("audio_out_rate", optimalRate);
|
||||
|
||||
// Refactor this entire mess and make this usable for per-core config
|
||||
if (Build.VERSION.SDK_INT >= 17 && prefs.getBoolean("audio_latency_auto", true))
|
||||
{
|
||||
int buffersize = getLowLatencyBufferSize(ctx);
|
||||
|
||||
boolean lowLatency = hasLowLatencyAudio(ctx);
|
||||
Log.i(TAG, "Audio is low latency: " + (lowLatency ? "yes" : "no"));
|
||||
|
||||
config.setInt("audio_latency", 64);
|
||||
if (lowLatency)
|
||||
{
|
||||
config.setInt("audio_block_frames", buffersize);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.setInt("audio_block_frames", 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
String latency_audio = prefs.getString("audio_latency", "64");
|
||||
config.setInt("audio_latency", Integer.parseInt(latency_audio));
|
||||
}
|
||||
|
||||
config.setBoolean("audio_enable", prefs.getBoolean("audio_enable", true));
|
||||
config.setBoolean("video_smooth", prefs.getBoolean("video_smooth", true));
|
||||
config.setBoolean("video_allow_rotate", prefs.getBoolean("video_allow_rotate", true));
|
||||
config.setBoolean("savestate_auto_load", prefs.getBoolean("savestate_auto_load", true));
|
||||
config.setBoolean("savestate_auto_save", prefs.getBoolean("savestate_auto_save", false));
|
||||
config.setBoolean("rewind_enable", prefs.getBoolean("rewind_enable", false));
|
||||
config.setBoolean("video_vsync", prefs.getBoolean("video_vsync", true));
|
||||
config.setBoolean("input_autodetect_enable", prefs.getBoolean("input_autodetect_enable", true));
|
||||
config.setBoolean("input_debug_enable", prefs.getBoolean("input_debug_enable", false));
|
||||
config.setInt("input_back_behavior", Integer.parseInt(prefs.getString("input_back_behavior", "0")));
|
||||
|
||||
// Set the iCade profiles
|
||||
config.setInt("input_autodetect_icade_profile_pad1", Integer.parseInt(prefs.getString("", "0")));
|
||||
config.setInt("input_autodetect_icade_profile_pad2", Integer.parseInt(prefs.getString("input_autodetect_icade_profile_pad2", "0")));
|
||||
config.setInt("input_autodetect_icade_profile_pad3", Integer.parseInt(prefs.getString("input_autodetect_icade_profile_pad3", "0")));
|
||||
config.setInt("input_autodetect_icade_profile_pad4", Integer.parseInt(prefs.getString("input_autodetect_icade_profile_pad4", "0")));
|
||||
|
||||
// Set the video refresh rate.
|
||||
config.setDouble("video_refresh_rate", getRefreshRate(ctx));
|
||||
|
||||
// Set whether or not we're using threaded video.
|
||||
config.setBoolean("video_threaded", prefs.getBoolean("video_threaded", true));
|
||||
|
||||
// Refactor these weird values - 'full', 'auto', 'square', whatever -
|
||||
// go by what we have in RGUI - makes maintaining state easier too
|
||||
String aspect = prefs.getString("video_aspect_ratio", "auto");
|
||||
if (aspect.equals("full"))
|
||||
{
|
||||
config.setBoolean("video_force_aspect", false);
|
||||
}
|
||||
else if (aspect.equals("auto"))
|
||||
{
|
||||
config.setBoolean("video_force_aspect", true);
|
||||
config.setBoolean("video_force_aspect_auto", true);
|
||||
config.setDouble("video_aspect_ratio", -1.0);
|
||||
}
|
||||
else if (aspect.equals("square"))
|
||||
{
|
||||
config.setBoolean("video_force_aspect", true);
|
||||
config.setBoolean("video_force_aspect_auto", false);
|
||||
config.setDouble("video_aspect_ratio", -1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
double aspect_ratio = Double.parseDouble(aspect);
|
||||
config.setBoolean("video_force_aspect", true);
|
||||
config.setDouble("video_aspect_ratio", aspect_ratio);
|
||||
}
|
||||
|
||||
// Set whether or not integer scaling is enabled.
|
||||
config.setBoolean("video_scale_integer", prefs.getBoolean("video_scale_integer", false));
|
||||
|
||||
// Set whether or not shaders are being used.
|
||||
String shaderPath = prefs.getString("video_shader", "");
|
||||
config.setString("video_shader", shaderPath);
|
||||
config.setBoolean("video_shader_enable", prefs.getBoolean("video_shader_enable", false) && new File(shaderPath).exists());
|
||||
|
||||
// Set whether or not custom overlays are being used.
|
||||
final boolean useOverlay = prefs.getBoolean("input_overlay_enable", true);
|
||||
config.setBoolean("input_overlay_enable", useOverlay); // Not used by RetroArch directly.
|
||||
if (useOverlay)
|
||||
{
|
||||
String overlayPath = prefs.getString("input_overlay", dataDir + "/overlays/snes-landscape.cfg");
|
||||
config.setString("input_overlay", overlayPath);
|
||||
config.setDouble("input_overlay_opacity", prefs.getFloat("input_overlay_opacity", 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
config.setString("input_overlay", "");
|
||||
}
|
||||
|
||||
// Set whether or not custom directories are being used.
|
||||
final boolean usingCustomSaveFileDir = prefs.getBoolean("savefile_directory_enable", false);
|
||||
final boolean usingCustomSaveStateDir = prefs.getBoolean("savestate_directory_enable", false);
|
||||
final boolean usingCustomSystemDir = prefs.getBoolean("system_directory_enable", false);
|
||||
config.setString("savefile_directory", usingCustomSaveFileDir ? prefs.getString("savefile_directory", "") : "");
|
||||
config.setString("savestate_directory", usingCustomSaveStateDir ? prefs.getString("savestate_directory", "") : "");
|
||||
config.setString("system_directory", usingCustomSystemDir ? prefs.getString("system_directory", "") : "");
|
||||
|
||||
config.setBoolean("video_font_enable", prefs.getBoolean("video_font_enable", true));
|
||||
config.setString("game_history_path", dataDir + "/retroarch-history.txt");
|
||||
|
||||
for (int i = 1; i <= 4; i++)
|
||||
{
|
||||
final String[] btns =
|
||||
{
|
||||
"up", "down", "left", "right",
|
||||
"a", "b", "x", "y", "start", "select",
|
||||
"l", "r", "l2", "r2", "l3", "r3"
|
||||
};
|
||||
|
||||
for (String b : btns)
|
||||
{
|
||||
String p = "input_player" + i + "_" + b + "_btn";
|
||||
config.setInt(p, prefs.getInt(p, 0));
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
config.write(new File(path));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.e(TAG, "Failed to save config file to: " + path);
|
||||
}
|
||||
}
|
||||
|
||||
private static void readbackString(ConfigFile cfg, SharedPreferences.Editor edit, String key)
|
||||
{
|
||||
if (cfg.keyExists(key))
|
||||
edit.putString(key, cfg.getString(key));
|
||||
else
|
||||
edit.remove(key);
|
||||
}
|
||||
|
||||
private static void readbackBool(ConfigFile cfg, SharedPreferences.Editor edit, String key)
|
||||
{
|
||||
if (cfg.keyExists(key))
|
||||
edit.putBoolean(key, cfg.getBoolean(key));
|
||||
else
|
||||
edit.remove(key);
|
||||
}
|
||||
|
||||
private static void readbackDouble(ConfigFile cfg, SharedPreferences.Editor edit, String key)
|
||||
{
|
||||
if (cfg.keyExists(key))
|
||||
edit.putFloat(key, (float)cfg.getDouble(key));
|
||||
else
|
||||
edit.remove(key);
|
||||
}
|
||||
|
||||
private static void readbackFloat(ConfigFile cfg, SharedPreferences.Editor edit, String key)
|
||||
{
|
||||
if (cfg.keyExists(key))
|
||||
edit.putFloat(key, cfg.getFloat(key));
|
||||
else
|
||||
edit.remove(key);
|
||||
}
|
||||
|
||||
private static void readbackInt(ConfigFile cfg, SharedPreferences.Editor edit, String key)
|
||||
{
|
||||
if (cfg.keyExists(key))
|
||||
edit.putInt(key, cfg.getInt(key));
|
||||
else
|
||||
edit.remove(key);
|
||||
}
|
||||
|
||||
public static SharedPreferences getPreferences(Context ctx)
|
||||
{
|
||||
return PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
}
|
||||
|
||||
private static String sanitizeLibretroPath(String path)
|
||||
{
|
||||
String sanitized_name = path.substring(
|
||||
path.lastIndexOf("/") + 1,
|
||||
path.lastIndexOf("."));
|
||||
sanitized_name = sanitized_name.replace("neon", "");
|
||||
sanitized_name = sanitized_name.replace("libretro_", "");
|
||||
return sanitized_name;
|
||||
}
|
||||
|
||||
public static double getRefreshRate(Context ctx)
|
||||
{
|
||||
double rate = 0;
|
||||
SharedPreferences prefs = getPreferences(ctx);
|
||||
String refresh_rate = prefs.getString("video_refresh_rate", "");
|
||||
if (!refresh_rate.isEmpty())
|
||||
{
|
||||
try
|
||||
{
|
||||
rate = Double.parseDouble(refresh_rate);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
Log.e(TAG, "Cannot parse: " + refresh_rate + " as a double!");
|
||||
rate = getDisplayRefreshRate(ctx);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rate = getDisplayRefreshRate(ctx);
|
||||
}
|
||||
|
||||
Log.i(TAG, "Using refresh rate: " + rate + " Hz.");
|
||||
return rate;
|
||||
}
|
||||
|
||||
private static double getDisplayRefreshRate(Context ctx)
|
||||
{
|
||||
// Android is *very* likely to screw this up.
|
||||
// It is rarely a good value to use, so make sure it's not
|
||||
// completely wrong. Some phones return refresh rates that are
|
||||
// completely bogus
|
||||
// (like 0.3 Hz, etc), so try to be very conservative here.
|
||||
final WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
|
||||
final Display display = wm.getDefaultDisplay();
|
||||
double rate = display.getRefreshRate();
|
||||
if (rate > 61.0 || rate < 58.0)
|
||||
rate = 59.95;
|
||||
return rate;
|
||||
}
|
||||
|
||||
@TargetApi(17)
|
||||
public static int getLowLatencyOptimalSamplingRate(Context ctx)
|
||||
{
|
||||
AudioManager manager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);
|
||||
|
||||
return Integer.parseInt(manager
|
||||
.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
|
||||
}
|
||||
|
||||
@TargetApi(17)
|
||||
public static int getLowLatencyBufferSize(Context ctx)
|
||||
{
|
||||
AudioManager manager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);
|
||||
int buffersize = Integer.parseInt(manager
|
||||
.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER));
|
||||
Log.i(TAG, "Queried ideal buffer size (frames): " + buffersize);
|
||||
return buffersize;
|
||||
}
|
||||
|
||||
@TargetApi(17)
|
||||
public static boolean hasLowLatencyAudio(Context ctx)
|
||||
{
|
||||
PackageManager pm = ctx.getPackageManager();
|
||||
return pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
|
||||
}
|
||||
|
||||
public static int getOptimalSamplingRate(Context ctx)
|
||||
{
|
||||
int ret;
|
||||
if (Build.VERSION.SDK_INT >= 17)
|
||||
ret = getLowLatencyOptimalSamplingRate(ctx);
|
||||
else
|
||||
ret = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
|
||||
|
||||
Log.i(TAG, "Using sampling rate: " + ret + " Hz");
|
||||
return ret;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user