diff --git a/android/phoenix/src/com/retroarch/browser/CoreSelection.java b/android/phoenix/src/com/retroarch/browser/CoreSelection.java index 2b5c1f4a77..ac4f230875 100644 --- a/android/phoenix/src/com/retroarch/browser/CoreSelection.java +++ b/android/phoenix/src/com/retroarch/browser/CoreSelection.java @@ -71,7 +71,7 @@ public final class CoreSelection extends ListActivity { continue; } - adapter.add(new ModuleWrapper(this, lib, core_config)); + adapter.add(new ModuleWrapper(this, lib)); } this.setVolumeControlStream(AudioManager.STREAM_MUSIC); @@ -80,7 +80,7 @@ public final class CoreSelection extends ListActivity { @Override public void onListItemClick(ListView listView, View view, int position, long id) { final ModuleWrapper item = adapter.getItem(position); - MainMenuActivity.getInstance().setModule(item.file.getAbsolutePath(), item.getText()); + MainMenuActivity.getInstance().setModule(item.getUnderlyingFile().getAbsolutePath(), item.getText()); UserPreferences.updateConfigFile(this); finish(); } diff --git a/android/phoenix/src/com/retroarch/browser/ModuleWrapper.java b/android/phoenix/src/com/retroarch/browser/ModuleWrapper.java index b786d397ba..d8acae7da4 100644 --- a/android/phoenix/src/com/retroarch/browser/ModuleWrapper.java +++ b/android/phoenix/src/com/retroarch/browser/ModuleWrapper.java @@ -1,51 +1,158 @@ package com.retroarch.browser; -import java.io.File; - import com.retroarch.browser.preferences.util.ConfigFile; +import java.io.File; + import android.content.Context; import android.graphics.drawable.Drawable; +import android.util.Log; -final class ModuleWrapper implements IconAdapterItem { - public final File file; - private final ConfigFile config; +/** + * Wrapper class that encapsulates a libretro core + * along with information about said core. + */ +public final class ModuleWrapper implements IconAdapterItem, Comparable +{ + private final File file; + private final String displayName; + private final String coreName; + private final String manufacturer; + private final String systemName; + private final String license; + private final String[] supportedExtensions; - public ModuleWrapper(Context context, File file, ConfigFile config) { + /** + * Constructor + * + * @param context The current {@link Context}. + * @param file The {@link File} instance of the core being wrapped. + */ + public ModuleWrapper(Context context, File file) + { this.file = file; - this.config = config; + + // Attempt to get the core's info file. + // Basically this is dataDir/info/[core name].info + + Log.d("ModuleWrapper", "File Name: " + file.getName()); + // So first, since the core name will contain platform specific strings at the end of name, we trim this. + final String coreName = file.getName().substring(0, file.getName().lastIndexOf("_android.so")); + + // Now get the directory where all of the info files are kept (dataDir/info) + final String infoFileDir = context.getApplicationInfo().dataDir + File.separator + "info"; + + // Now, based off of the trimmed core name, we can get the core info file. + // and attempt to read it as a config file (since it has the same key-value layout). + final String infoFilePath = infoFileDir + File.separator + coreName + ".info"; + final ConfigFile infoFile = new ConfigFile(infoFilePath); + Log.d("ModuleWrapper", "Info file path: " + infoFilePath); + Log.d("ModuleWrapper", "Info file exists: " + new File(infoFilePath).exists()); + + // Now read info out of the info file. Make them an empty string if the key doesn't exist. + this.displayName = (infoFile.keyExists("display_name")) ? infoFile.getString("display_name") : ""; + this.coreName = (infoFile.keyExists("corename")) ? infoFile.getString("corename") : ""; + this.systemName = (infoFile.keyExists("systemname")) ? infoFile.getString("systemname") : ""; + this.manufacturer = (infoFile.keyExists("manufacturer")) ? infoFile.getString("manufacturer") : ""; + this.license = (infoFile.keyExists("license")) ? infoFile.getString("license") : ""; + + // Getting supported extensions is a little different. + // We need to split at every '|' character, since it is + // the delimiter for a new extension that the core supports. + // + // Cores that don't have multiple extensions supported + // don't contain the '|' delimiter, so we just create a String array with + // a size of 1, and just directly assign the retrieved extensions to it. + final String supportedExts = infoFile.getString("supported_extensions"); + if (supportedExts.contains("|")) + { + this.supportedExtensions = supportedExts.split("|"); + } + else + { + this.supportedExtensions = new String[1]; + this.supportedExtensions[0] = supportedExts; + } + } + + /** + * Gets the underlying {@link File} instance for this ModuleWrapper. + * + * @return the underlying {@link File} instance for this ModuleWrapper. + */ + public File getUnderlyingFile() + { + return file; + } + + /** + * Gets the display name for this wrapped core. + * + * @return the display name for this wrapped core. + */ + public String getDisplayName() + { + return displayName; + } + + /** + * Gets the license that this core is protected under. + * + * @return the license that this core is protected under. + */ + public String getCoreLicense() + { + return license; + } + + /** + * Gets the name of the manufacturer of the console that + * this core emulates. + * + * @return the name of the manufacturer of the console that + * this core emulates. + */ + public String getManufacturer() + { + return manufacturer; } @Override - public boolean isEnabled() { + public boolean isEnabled() + { return true; } @Override - public String getText() { - String stripped = file.getName().replace(".so", ""); - if (config.keyExists(stripped)) { - return config.getString(stripped); - } else - return stripped; + public String getText() + { + return coreName; } @Override - public String getSubText() { - String stripped = file.getName().replace(".so", "") + "_system"; - if (config.keyExists(stripped)) { - return config.getString(stripped); - } else - return null; + public String getSubText() + { + return systemName; } @Override - public int getIconResourceId() { + public int getIconResourceId() + { return 0; } @Override - public Drawable getIconDrawable() { + public Drawable getIconDrawable() + { return null; } + + @Override + public int compareTo(ModuleWrapper other) + { + if(coreName != null) + return coreName.toLowerCase().compareTo(other.coreName.toLowerCase()); + else + throw new NullPointerException("The name of this ModuleWrapper is null"); + } } \ No newline at end of file diff --git a/android/phoenix/src/com/retroarch/browser/coremanager/CoreManagerListItem.java b/android/phoenix/src/com/retroarch/browser/coremanager/CoreManagerListItem.java deleted file mode 100644 index 7b60afd688..0000000000 --- a/android/phoenix/src/com/retroarch/browser/coremanager/CoreManagerListItem.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.retroarch.browser.coremanager; - -import java.io.File; - -/** - * Represents a list item within the CoreManager fragments. - */ -public final class CoreManagerListItem implements Comparable -{ - private final String name; - private final String subtitle; - private final String path; - private final File underlyingFile; - - /** - * Constructor - * - * @param name The name of the core represented by this CoreManagerListItem. - * @param subtitle The subtitle description of the core represented by this CoreManagerListItem. - * @param path The path to the core represented by this CoreManagerListItem. - */ - public CoreManagerListItem(String name, String subtitle, String path) - { - this.name = name; - this.subtitle = subtitle; - this.path = path; - this.underlyingFile = new File(path); - } - - /** - * Gets the name of the core represented by this CoreManagerListItem. - * - * @return the name of the core represented by this CoreManagerListItem. - */ - public String getName() - { - return name; - } - - /** - * Gets the subtitle description of the core represented by this CoreManagerListItem. - * - * @return the subtitle description of the core represented by this CoreManagerListItem. - */ - public String getSubtitle() - { - return subtitle; - } - - /** - * Gets the path to the core represented by this CoreManagerListItem. - * - * @return the path to the core represented by this CoreManagerListItem. - */ - public String getPath() - { - return path; - } - - /** - * Gets the underlying {@link File} instance to the core represented by this CoreManagerListItem. - * - * @return the underlying {@link File} instance to the core represented by this CoreManagerListItem. - */ - public File getUnderlyingFile() - { - return underlyingFile; - } - - @Override - public int compareTo(CoreManagerListItem other) - { - if(name != null) - return name.toLowerCase().compareTo(other.getName().toLowerCase()); - else - throw new NullPointerException("The name of this CoreManagerListItem is null"); - } -} diff --git a/android/phoenix/src/com/retroarch/browser/coremanager/fragments/InstalledCoresFragment.java b/android/phoenix/src/com/retroarch/browser/coremanager/fragments/InstalledCoresFragment.java index 29eca73171..6446930e42 100644 --- a/android/phoenix/src/com/retroarch/browser/coremanager/fragments/InstalledCoresFragment.java +++ b/android/phoenix/src/com/retroarch/browser/coremanager/fragments/InstalledCoresFragment.java @@ -1,14 +1,12 @@ package com.retroarch.browser.coremanager.fragments; import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.retroarch.R; -import com.retroarch.browser.coremanager.CoreManagerListItem; -import com.retroarch.browser.preferences.util.ConfigFile; +import com.retroarch.browser.ModuleWrapper; import com.retroarch.browser.preferences.util.UserPreferences; import android.app.AlertDialog; @@ -17,7 +15,6 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; import android.support.v4.app.ListFragment; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -43,18 +40,7 @@ public final class InstalledCoresFragment extends ListFragment super.onCreate(savedInstanceState); // The list of items that will be added to the adapter backing this ListFragment. - final List items = new ArrayList(); - - // Initialize the core config for retrieving core names. - ConfigFile coreConfig = new ConfigFile(); - try - { - coreConfig.append(getActivity().getAssets().open("libretro_cores.cfg")); - } - catch (IOException ioe) - { - Log.e("InstalledCoresFragment", "Failed to load libretro_cores.cfg from assets."); - } + final List items = new ArrayList(); // Check if the device supports NEON. final String cpuInfo = UserPreferences.readCPUInfo(); @@ -91,26 +77,8 @@ public final class InstalledCoresFragment extends ListFragment continue; } - // Attempt to get the core name. - String coreName; - String strippedName = libName.replace(".so", ""); - if (coreConfig.keyExists(strippedName)) - coreName = coreConfig.getString(strippedName); - else - coreName = strippedName; - - // Attempt to get the core subtitle. - String subtitle = strippedName + "_system"; - if (coreConfig.keyExists(subtitle)) - subtitle = coreConfig.getString(subtitle); - else - subtitle = ""; - - Log.d("InstalledCoresFragment", "Core Name: " + coreName); - Log.d("InstalledCoresFragment", "Core Subtitle: " + subtitle); - // Add it to the list. - items.add(new CoreManagerListItem(coreName, subtitle, lib.getPath())); + items.add(new ModuleWrapper(getActivity(), lib)); } // Sort the list alphabetically @@ -141,10 +109,10 @@ public final class InstalledCoresFragment extends ListFragment public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { // Begin building the AlertDialog - final CoreManagerListItem item = adapter.getItem(position); + final ModuleWrapper item = adapter.getItem(position); final AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); alert.setTitle(R.string.uninstall_core); - alert.setMessage(String.format(getString(R.string.uninstall_core_message), item.getName())); + alert.setMessage(String.format(getString(R.string.uninstall_core_message), item.getText())); alert.setNegativeButton(R.string.no, null); alert.setPositiveButton(R.string.yes, new OnClickListener() { @@ -154,13 +122,13 @@ public final class InstalledCoresFragment extends ListFragment // Attempt to uninstall the core item. if (item.getUnderlyingFile().delete()) { - Toast.makeText(getActivity(), String.format(getString(R.string.uninstall_success), item.getName()), Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity(), String.format(getString(R.string.uninstall_success), item.getText()), Toast.LENGTH_LONG).show(); adapter.remove(item); adapter.notifyDataSetChanged(); } else // Failed to uninstall. { - Toast.makeText(getActivity(), String.format(getString(R.string.uninstall_failure), item.getName()), Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity(), String.format(getString(R.string.uninstall_failure), item.getText()), Toast.LENGTH_LONG).show(); } } }); @@ -173,11 +141,11 @@ public final class InstalledCoresFragment extends ListFragment /** * The {@link ArrayAdapter} that backs this InstalledCoresFragment. */ - private final class InstalledCoresAdapter extends ArrayAdapter + private final class InstalledCoresAdapter extends ArrayAdapter { private final Context context; private final int resourceId; - private final List items; + private final List items; /** * Constructor @@ -186,7 +154,7 @@ public final class InstalledCoresFragment extends ListFragment * @param resourceId The resource ID for a layout file containing a layout to use when instantiating views. * @param items The list of items to represent in this adapter. */ - public InstalledCoresAdapter(Context context, int resourceId, List items) + public InstalledCoresAdapter(Context context, int resourceId, List items) { super(context, resourceId, items); @@ -196,7 +164,7 @@ public final class InstalledCoresFragment extends ListFragment } @Override - public CoreManagerListItem getItem(int i) + public ModuleWrapper getItem(int i) { return items.get(i); } @@ -210,7 +178,7 @@ public final class InstalledCoresFragment extends ListFragment convertView = vi.inflate(resourceId, parent, false); } - final CoreManagerListItem item = items.get(position); + final ModuleWrapper item = items.get(position); if (item != null) { TextView title = (TextView) convertView.findViewById(R.id.CoreManagerListItemTitle); @@ -219,12 +187,12 @@ public final class InstalledCoresFragment extends ListFragment if (title != null) { - title.setText(item.getName()); + title.setText(item.getText()); } if (subtitle != null) { - subtitle.setText(item.getSubtitle()); + subtitle.setText(item.getSubText()); } if (icon != null) diff --git a/android/phoenix/src/com/retroarch/browser/preferences/util/ConfigFile.java b/android/phoenix/src/com/retroarch/browser/preferences/util/ConfigFile.java index 6d4db7f376..8c57d1b0c0 100644 --- a/android/phoenix/src/com/retroarch/browser/preferences/util/ConfigFile.java +++ b/android/phoenix/src/com/retroarch/browser/preferences/util/ConfigFile.java @@ -4,16 +4,54 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.FileInputStream; -import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; -public final class ConfigFile { - private HashMap map = new HashMap(); +import android.util.Log; - public void append(InputStream stream) throws IOException { +/** + * Represents a configuration file that works off of a key-value pair + * in the form [key name] = "[value]". + */ +public final class ConfigFile +{ + // Map containing all of the key-value pairs. + private final HashMap map = new HashMap(); + + /** + * Constructor + */ + public ConfigFile() + { + } + + /** + * Constructor + * + * @param filePath The path to the configuration file to open. + */ + public ConfigFile(String filePath) + { + try + { + open(filePath); + } + catch (IOException ioe) + { + Log.e("ConfigFile", "Stream reading the configuration file was suddenly closed for an unknown reason."); + } + } + + /** + * Parses a configuration file from the given stream + * and appends the parsed values to the key-value map. + * + * @param stream The {@link InputStream} containing the configuration file to parse. + */ + public void append(InputStream stream) throws IOException + { BufferedReader br = new BufferedReader(new InputStreamReader(stream)); String line; @@ -23,18 +61,21 @@ public final class ConfigFile { br.close(); } - public void open(File file) throws IOException { + /** + * Opens a configuration file given by configPath + * and parses all of its key-value pairs, adding + * them to the key-value map. + * + * @param configPath Path to the configuration file to parse. + */ + public void open(String configPath) throws IOException + { clear(); - append(new FileInputStream(file)); + append(new FileInputStream(configPath)); } - - public ConfigFile(File file) throws IOException { - open(file); - } - - public ConfigFile() {} - private void parseLine(String line) { + private void parseLine(String line) + { String[] tokens = line.split("=", 2); if (tokens.length < 2) return; @@ -54,75 +95,181 @@ public final class ConfigFile { map.put(key, value); } - public void clear() { + /** + * Clears the key-value map of all currently set keys and values. + */ + public void clear() + { map.clear(); } - public void write(File file) throws IOException { - PrintWriter writer = new PrintWriter(file.getAbsolutePath()); + /** + * Writes the currently set key-value pairs to + * + * @param path The path to save the + * + * @throws IOException + */ + public void write(String path) throws IOException + { + PrintWriter writer = new PrintWriter(path); + for (Map.Entry entry : map.entrySet()) + { writer.println(entry.getKey() + " = \"" + entry.getValue() + "\""); + } + writer.close(); } - public void setString(String key, String value) { - map.put(key, value); - } - - public void setBoolean(String key, boolean value) { - map.put(key, Boolean.toString(value)); - } - - public void setInt(String key, int value) { - map.put(key, Integer.toString(value)); - } - - public void setDouble(String key, double value) { - map.put(key, Double.toString(value)); - } - - public void setFloat(String key, float value) { - map.put(key, Float.toString(value)); - } - - public boolean keyExists(String key) { + /** + * Checks if a key exists in the {@link HashMap} + * backing this ConfigFile instance. + * + * @param key The key to check for. + * + * @return true if the key exists in the HashMap backing + * this ConfigFile; false if it doesn't. + */ + public boolean keyExists(String key) + { return map.containsKey(key); } - public String getString(String key) { + /** + * Sets a key to the given String value. + * + * @param key The key to set the String value to. + * @param value The String value to set to the key. + */ + public void setString(String key, String value) + { + map.put(key, value); + } + + /** + * Sets a key to the given boolean value. + * + * @param key The key to set the boolean value to. + * @param value The boolean value to set to the key. + */ + public void setBoolean(String key, boolean value) + { + map.put(key, Boolean.toString(value)); + } + + /** + * Sets a key to the given Integer value. + * + * @param key The key to set the Integer value to. + * @param value The Integer value to set to the key. + */ + public void setInt(String key, int value) + { + map.put(key, Integer.toString(value)); + } + + /** + * Sets a key to the given double value. + * + * @param key The key to set the double value to. + * @param value The double value to set to the key. + */ + public void setDouble(String key, double value) + { + map.put(key, Double.toString(value)); + } + + /** + * Sets a key to the given float value. + * + * @param key The key to set the float value to. + * @param value The float value to set to the key. + */ + public void setFloat(String key, float value) + { + map.put(key, Float.toString(value)); + } + + /** + * Gets the String value associated with the given key. + * + * @param key The key to get the String value from. + * + * @return the String object associated with the given key. + */ + public String getString(String key) + { String ret = map.get(key); + if (ret != null) return ret; else return null; } - public int getInt(String key) throws NumberFormatException { + /** + * Gets the Integer value associated with the given key. + * + * @param key The key to get the Integer value from. + * + * @return the Integer value associated with the given key. + */ + public int getInt(String key) throws NumberFormatException + { String str = getString(key); + if (str != null) return Integer.parseInt(str); else throw new NumberFormatException(); } - public double getDouble(String key) throws NumberFormatException { + /** + * Gets the double value associated with the given key. + * + * @param key The key to get the double value from. + * + * @return the double value associated with the given key. + */ + public double getDouble(String key) throws NumberFormatException + { String str = getString(key); + if (str != null) return Double.parseDouble(str); else throw new NumberFormatException(); } - - public float getFloat(String key) throws NumberFormatException { + + /** + * Gets the float value associated with the given key. + * + * @param key The key to get the float value from. + * + * @return the float value associated with the given key. + */ + public float getFloat(String key) throws NumberFormatException + { String str = getString(key); + if (str != null) return Float.parseFloat(str); else throw new NumberFormatException(); } - public boolean getBoolean(String key) { + /** + * Gets the boolean value associated with the given key. + * + * @param key The key to get the boolean value from. + * + * @return the boolean value associated with the given key. + */ + public boolean getBoolean(String key) + { String str = getString(key); + return Boolean.parseBoolean(str); } } diff --git a/android/phoenix/src/com/retroarch/browser/preferences/util/UserPreferences.java b/android/phoenix/src/com/retroarch/browser/preferences/util/UserPreferences.java index 10aa5f1435..48268455e8 100644 --- a/android/phoenix/src/com/retroarch/browser/preferences/util/UserPreferences.java +++ b/android/phoenix/src/com/retroarch/browser/preferences/util/UserPreferences.java @@ -104,15 +104,7 @@ public final class UserPreferences public static void readbackConfigFile(Context ctx) { String path = getDefaultConfigPath(ctx); - ConfigFile config; - try - { - config = new ConfigFile(new File(path)); - } - catch (IOException e) - { - return; - } + ConfigFile config = new ConfigFile(path); Log.i(TAG, "Config readback from: " + path); @@ -164,15 +156,7 @@ public final class UserPreferences 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(); - } + ConfigFile config = new ConfigFile(path); Log.i(TAG, "Writing config to: " + path); @@ -315,7 +299,7 @@ public final class UserPreferences try { - config.write(new File(path)); + config.write(path); } catch (IOException e) {