+ * Basically, how it works is the user selects a file.
+ * Then, we iterate over all the cores and check what their supported extensions are.
+ * Then, if any cores contain the supported extension, they are added to a list and
+ * displayed to the user to choose from.
+ *
+ * The only exception is if only one core matches the extension of the chosen file.
+ * In this case, we just attempt to launch the core with that file directly.
+ */
+// TODO: This is ugly as hell. Clean this up sometime.
+// For example, maybe breaking this out into two fragments
+// to handle the behavior would be better. One for browsing,
+// one for handling the list of selectable cores.
+public final class DetectCoreDirectoryFragment extends DirectoryFragment
+{
+ private ListView backingListView = null;
+ private boolean inFileBrowser = true;
+ private ArrayList supportedCorePaths = new ArrayList();
+
+ /**
+ * Retrieves a new instance of a DetectCoreDirectoryFragment
+ * with a title specified by the given resource ID.
+ *
+ * @param titleResId String resource ID for the title
+ * of this DetectCoreDirectoryFragment.
+ *
+ * @return A new instance of a DetectCoreDirectoryFragment.
+ */
+ public static DetectCoreDirectoryFragment newInstance(int titleResId)
+ {
+ final DetectCoreDirectoryFragment dFrag = new DetectCoreDirectoryFragment();
+ final Bundle bundle = new Bundle();
+ bundle.putInt("titleResId", titleResId);
+ dFrag.setArguments(bundle);
+
+ return dFrag;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
+ {
+ backingListView = (ListView) inflater.inflate(R.layout.line_list, container, false);
+ backingListView.setOnItemClickListener(onItemClickListener);
+
+ // Get whether or not we were in the file browser prior to recreation.
+ if (savedInstanceState != null)
+ {
+ inFileBrowser = savedInstanceState.getBoolean("inFileBrowser");
+
+ if (inFileBrowser)
+ backStack = savedInstanceState.getParcelableArrayList("BACKSTACK");
+ }
+
+ // Set the dialog title.
+ if (inFileBrowser)
+ getDialog().setTitle(getArguments().getInt("titleResId"));
+ else
+ getDialog().setTitle(R.string.multiple_cores_detected);
+
+ // If we're in the file browser, reinitialize the file list adapter.
+ if (savedInstanceState == null || inFileBrowser)
+ {
+ // Setup the list
+ adapter = new IconAdapter(getActivity(), R.layout.line_list_item);
+ backingListView.setAdapter(adapter);
+ }
+
+ if (inFileBrowser)
+ {
+ if (backStack == null || backStack.isEmpty())
+ {
+ backStack = new ArrayList();
+ String startPath = (startDirectory == null || startDirectory.isEmpty()) ? Environment
+ .getExternalStorageDirectory().getPath() : startDirectory;
+ backStack.add(new BackStackItem(startPath, false));
+ }
+
+ wrapFiles();
+ }
+ else // Rebuild the core adapter.
+ {
+ supportedCorePaths = savedInstanceState.getStringArrayList("coreFilePaths");
+ CoreSelectionAdapter adapter = new CoreSelectionAdapter(getActivity(), android.R.layout.simple_list_item_2);
+
+ for (String path : supportedCorePaths)
+ {
+ ModuleWrapper mw = new ModuleWrapper(getActivity(), path);
+ adapter.add(new CoreItem(mw.getInternalName(), mw.getEmulatedSystemName()));
+ }
+
+ backingListView.setAdapter(adapter);
+ }
+
+ return backingListView;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState)
+ {
+ // Save whether or not we're in core selection or the file browser.
+ outState.putBoolean("inFileBrowser", inFileBrowser);
+
+ if (!inFileBrowser)
+ outState.putStringArrayList("coreFilePaths", supportedCorePaths);
+ }
+
+ private File chosenFile = null;
+ private final OnItemClickListener onItemClickListener = new OnItemClickListener()
+ {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id)
+ {
+ final FileWrapper item = adapter.getItem(position);
+
+ if (inFileBrowser && item.isParentItem() && backStack.get(backStack.size() - 1).parentIsBack)
+ {
+ backStack.remove(backStack.size() - 1);
+ wrapFiles();
+ return;
+ }
+
+ final File selected = item.isParentItem() ? listedDirectory.getParentFile() : item.getFile();
+ if (inFileBrowser && selected.isDirectory())
+ {
+ Log.d("DirectoryFrag", "Is Directory.");
+ backStack.add(new BackStackItem(selected.getAbsolutePath(), !item.isParentItem()));
+ wrapFiles();
+ return;
+ }
+ else if (inFileBrowser && selected.isFile())
+ {
+ String filePath = selected.getAbsolutePath();
+ String fileExt = "";
+ chosenFile = selected;
+
+ // Attempt to get the file extension.
+ int i = filePath.lastIndexOf('.');
+ if (i >= 0)
+ fileExt = filePath.substring(i+1);
+
+ // Enumerate the cores and check for the extension
+ File coreDir = new File(getActivity().getApplicationInfo().dataDir + File.separator + "cores");
+ File[] coreFiles = coreDir.listFiles();
+ ListsupportedCores = new ArrayList();
+
+ for (File core : coreFiles)
+ {
+ ModuleWrapper mw = new ModuleWrapper(getActivity(), core);
+
+ if (mw.getSupportedExtensions().contains(fileExt))
+ {
+ supportedCores.add(mw);
+ supportedCorePaths.add(mw.getUnderlyingFile().getAbsolutePath());
+ }
+ }
+
+ // If only one core is supported,
+ if (supportedCores.size() == 1)
+ {
+ launchCore(selected.getPath(), supportedCores.get(0).getUnderlyingFile().getPath());
+ }
+ // Otherwise build the list for the user to choose from.
+ else if (supportedCores.size() > 1)
+ {
+ // Modify the title to notify of multiple cores.
+ getDialog().setTitle(R.string.multiple_cores_detected);
+
+ // Add all the cores to the adapter and swap it with the one in the ListView.
+ final CoreSelectionAdapter csa = new CoreSelectionAdapter(getActivity(), android.R.layout.simple_list_item_2);
+
+ for (ModuleWrapper core : supportedCores)
+ {
+ csa.add(new CoreItem(core.getInternalName(), core.getEmulatedSystemName()));
+ }
+
+ backingListView.setAdapter(csa);
+ }
+ }
+ else // Selection made
+ {
+ launchCore(chosenFile.getPath(), DetectCoreDirectoryFragment.this.supportedCorePaths.get(position));
+ }
+
+ // Not in the file browser any more.
+ inFileBrowser = false;
+ }
+ };
+
+ private void launchCore(String contentPath, String corePath)
+ {
+ Intent retro;
+ if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB))
+ retro = new Intent(getActivity(), RetroActivityFuture.class);
+ else
+ retro = new Intent(getActivity(), RetroActivityPast.class);
+
+ UserPreferences.updateConfigFile(getActivity());
+ String current_ime = Settings.Secure.getString(getActivity().getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+ retro.putExtra("ROM", contentPath);
+ retro.putExtra("LIBRETRO", corePath);
+ retro.putExtra("CONFIGFILE", UserPreferences.getDefaultConfigPath(getActivity()));
+ retro.putExtra("IME", current_ime);
+ startActivity(retro);
+ dismiss();
+ }
+
+ // Used to represent data in the ListView after the user chooses an item.
+ private static final class CoreItem
+ {
+ public final String Title;
+ public final String Subtitle;
+
+ public CoreItem(String title, String subtitle)
+ {
+ this.Title = title;
+ this.Subtitle = subtitle;
+ }
+ }
+
+ // Adapter that the ListView is flipped to after choosing a file to launch.
+ private static final class CoreSelectionAdapter extends ArrayAdapter
+ {
+ private final int resourceId;
+
+ /**
+ * Constructor
+ *
+ * @param context The current {@link Context}.
+ * @param resourceId The resource ID for a layout file.
+ */
+ public CoreSelectionAdapter(Context context, int resourceId)
+ {
+ super(context, resourceId);
+
+ this.resourceId = resourceId;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent)
+ {
+ if (convertView == null)
+ {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ convertView = inflater.inflate(resourceId, parent, false);
+ }
+
+ final CoreItem core = getItem(position);
+ if (core != null)
+ {
+ final TextView title = (TextView) convertView.findViewById(android.R.id.text1);
+ final TextView subtitle = (TextView) convertView.findViewById(android.R.id.text2);
+
+ if (title != null)
+ title.setText(core.Title);
+
+ if (subtitle != null)
+ subtitle.setText(core.Subtitle);
+ }
+
+ return convertView;
+ }
+ }
+}
diff --git a/android/phoenix/src/com/retroarch/browser/dirfragment/DirectoryFragment.java b/android/phoenix/src/com/retroarch/browser/dirfragment/DirectoryFragment.java
index 6007e81d2f..2317eb8136 100644
--- a/android/phoenix/src/com/retroarch/browser/dirfragment/DirectoryFragment.java
+++ b/android/phoenix/src/com/retroarch/browser/dirfragment/DirectoryFragment.java
@@ -6,7 +6,6 @@ import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.app.DialogFragment;
-import android.support.v4.app.ListFragment;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -25,7 +24,7 @@ import java.io.*;
/**
- * {@link ListFragment} subclass that provides a file-browser
+ * {@link DialogFragment} subclass that provides a file-browser
* like UI for browsing for specific files.
*
* This file browser also allows for custom filtering
@@ -38,15 +37,15 @@ import java.io.*;
* To instantiate a new instance of this class
* you must use the {@code newInstance} method.
*/
-public final class DirectoryFragment extends DialogFragment
+public class DirectoryFragment extends DialogFragment
{
- private IconAdapter adapter;
- private File listedDirectory;
+ protected IconAdapter adapter;
+ protected File listedDirectory;
public static final class BackStackItem implements Parcelable
{
- private final String path;
- private final boolean parentIsBack;
+ protected final String path;
+ protected boolean parentIsBack;
public BackStackItem(String path, boolean parentIsBack)
{
@@ -101,12 +100,11 @@ public final class DirectoryFragment extends DialogFragment
}
- private ArrayList backStack;
-
- private String startDirectory;
- private String pathSettingKey;
- private boolean isDirectoryTarget;
- private OnDirectoryFragmentClosedListener onClosedListener;
+ protected ArrayList backStack;
+ protected String startDirectory;
+ protected String pathSettingKey;
+ protected boolean isDirectoryTarget;
+ protected OnDirectoryFragmentClosedListener onClosedListener;
/**
* Sets the starting directory for this DirectoryFragment
@@ -349,7 +347,7 @@ public final class DirectoryFragment extends DialogFragment
disallowedExt.addAll(Arrays.asList(exts));
}
- private void wrapFiles()
+ protected void wrapFiles()
{
listedDirectory = new File(backStack.get(backStack.size() - 1).path);
diff --git a/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuFragment.java b/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuFragment.java
index 5c783f4acd..6d12e39c9a 100644
--- a/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuFragment.java
+++ b/android/phoenix/src/com/retroarch/browser/mainmenu/MainMenuFragment.java
@@ -28,6 +28,7 @@ import com.retroarch.R;
import com.retroarch.browser.CoreSelection;
import com.retroarch.browser.HistorySelection;
import com.retroarch.browser.NativeInterface;
+import com.retroarch.browser.dirfragment.DetectCoreDirectoryFragment;
import com.retroarch.browser.dirfragment.DirectoryFragment;
import com.retroarch.browser.dirfragment.DirectoryFragment.OnDirectoryFragmentClosedListener;
import com.retroarch.browser.mainmenu.gplwaiver.GPLWaiverDialogFragment;
@@ -65,10 +66,11 @@ public final class MainMenuFragment extends PreferenceListFragment implements On
addPreferencesFromResource(R.xml.main_menu);
// Set the listeners for the menu items
- findPreference("retroTVMode").setOnPreferenceClickListener(this);
+ findPreference("resumeContentPref").setOnPreferenceClickListener(this);
findPreference("loadCorePref").setOnPreferenceClickListener(this);
- findPreference("loadRomPref").setOnPreferenceClickListener(this);
- findPreference("loadRomHistoryPref").setOnPreferenceClickListener(this);
+ findPreference("loadContentAutoPref").setOnPreferenceClickListener(this);
+ findPreference("loadContentPref").setOnPreferenceClickListener(this);
+ findPreference("loadContentHistoryPref").setOnPreferenceClickListener(this);
findPreference("quitRetroArch").setOnPreferenceClickListener(this);
// Extract assets.
@@ -340,8 +342,8 @@ public final class MainMenuFragment extends PreferenceListFragment implements On
{
final String prefKey = preference.getKey();
- // TV Mode
- if (prefKey.equals("retroTVMode"))
+ // Resume Content
+ if (prefKey.equals("resumeContentPref"))
{
UserPreferences.updateConfigFile(ctx);
@@ -360,30 +362,43 @@ public final class MainMenuFragment extends PreferenceListFragment implements On
CoreSelection.newInstance().show(getFragmentManager(), "core_selection");
}
// Load ROM Preference
- else if (prefKey.equals("loadRomPref"))
+ else if (prefKey.equals("loadContentPref"))
{
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
final String libretro_path = prefs.getString("libretro_path", ctx.getApplicationInfo().dataDir + "/cores");
-
+
if (!new File(libretro_path).isDirectory())
{
- final DirectoryFragment romBrowser = DirectoryFragment.newInstance(R.string.load_game);
- romBrowser.addDisallowedExts(".state", ".srm", ".state.auto", ".rtc");
- romBrowser.setOnDirectoryFragmentClosedListener(this);
+ final DirectoryFragment contentBrowser = DirectoryFragment.newInstance(R.string.load_content);
+ contentBrowser.addDisallowedExts(".state", ".srm", ".state.auto", ".rtc");
+ contentBrowser.setOnDirectoryFragmentClosedListener(this);
final String startPath = prefs.getString("rgui_browser_directory", "");
if (!startPath.isEmpty() && new File(startPath).exists())
- romBrowser.setStartDirectory(startPath);
+ contentBrowser.setStartDirectory(startPath);
- romBrowser.show(getFragmentManager(), "romBrowser");
+ contentBrowser.show(getFragmentManager(), "contentBrowser");
}
else
{
Toast.makeText(ctx, R.string.load_a_core_first, Toast.LENGTH_SHORT).show();
}
}
- // Load ROM (History) Preference
- else if (prefKey.equals("loadRomHistoryPref"))
+ else if (prefKey.equals("loadContentAutoPref"))
+ {
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
+ final DetectCoreDirectoryFragment contentBrowser = DetectCoreDirectoryFragment.newInstance(R.string.load_content_auto);
+ contentBrowser.addDisallowedExts(".state", ".srm", ".state.auto", ".rtc");
+ contentBrowser.setOnDirectoryFragmentClosedListener(this);
+
+ final String startPath = prefs.getString("rgui_browser_directory", "");
+ if (!startPath.isEmpty() && new File(startPath).exists())
+ contentBrowser.setStartDirectory(startPath);
+
+ contentBrowser.show(getFragmentManager(), "contentBrowser");
+ }
+ // Load Content (History) Preference
+ else if (prefKey.equals("loadContentHistoryPref"))
{
HistorySelection.newInstance().show(getFragmentManager(), "history_selection");
}