diff --git a/android/phoenix/res/layout/coremanager_listview_layout.xml b/android/phoenix/res/layout/coremanager_listview.xml
similarity index 69%
rename from android/phoenix/res/layout/coremanager_listview_layout.xml
rename to android/phoenix/res/layout/coremanager_listview.xml
index 5583543704..7e1f57d214 100644
--- a/android/phoenix/res/layout/coremanager_listview_layout.xml
+++ b/android/phoenix/res/layout/coremanager_listview.xml
@@ -2,7 +2,5 @@
-
-
-
+ android:layout_height="match_parent"
+ android:orientation="vertical" />
diff --git a/android/phoenix/res/values/strings.xml b/android/phoenix/res/values/strings.xml
index 790c2f15bb..b909b60509 100644
--- a/android/phoenix/res/values/strings.xml
+++ b/android/phoenix/res/values/strings.xml
@@ -26,6 +26,10 @@
Installed Cores
+ Uninstall Core
+ Would you like to uninstall %1$s?
+ Failed to uninstall core: %1$s.
+ Successfully uninstalled core: %1$s.
Downloadable Cores
@@ -214,8 +218,10 @@
OK
Close
- General
Enable
+ General
+ No
+ Yes
diff --git a/android/phoenix/src/com/retroarch/browser/CoreSelection.java b/android/phoenix/src/com/retroarch/browser/CoreSelection.java
index 548f56e0da..2b5c1f4a77 100644
--- a/android/phoenix/src/com/retroarch/browser/CoreSelection.java
+++ b/android/phoenix/src/com/retroarch/browser/CoreSelection.java
@@ -44,7 +44,7 @@ public final class CoreSelection extends ListActivity {
setTitle(R.string.select_libretro_core);
// Populate the list
- final File[] libs = new File(getApplicationInfo().dataDir, "cores").listFiles();
+ final File[] libs = new File(getApplicationInfo().dataDir, "/cores").listFiles();
for (final File lib : libs) {
String libName = lib.getName();
diff --git a/android/phoenix/src/com/retroarch/browser/coremanager/CoreManagerListItem.java b/android/phoenix/src/com/retroarch/browser/coremanager/CoreManagerListItem.java
index 6145002b50..7b60afd688 100644
--- a/android/phoenix/src/com/retroarch/browser/coremanager/CoreManagerListItem.java
+++ b/android/phoenix/src/com/retroarch/browser/coremanager/CoreManagerListItem.java
@@ -5,7 +5,7 @@ import java.io.File;
/**
* Represents a list item within the CoreManager fragments.
*/
-public final class CoreManagerListItem
+public final class CoreManagerListItem implements Comparable
{
private final String name;
private final String subtitle;
@@ -66,4 +66,13 @@ public final class CoreManagerListItem
{
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 a8114ad626..29eca73171 100644
--- a/android/phoenix/src/com/retroarch/browser/coremanager/fragments/InstalledCoresFragment.java
+++ b/android/phoenix/src/com/retroarch/browser/coremanager/fragments/InstalledCoresFragment.java
@@ -1,39 +1,123 @@
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.preferences.util.UserPreferences;
+import android.app.AlertDialog;
import android.content.Context;
+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;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
+import android.widget.Toast;
/**
* {@link ListFragment} that displays all of the currently installed cores
*/
public final class InstalledCoresFragment extends ListFragment
{
+ // Adapter backing this ListFragment.
+ private InstalledCoresAdapter adapter;
+
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
- // List which will contain all of the items for the list.
- List items = new ArrayList();
+ // The list of items that will be added to the adapter backing this ListFragment.
+ final List items = new ArrayList();
- // TODO: Populate list adapter.
+ // 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.");
+ }
- // Set the list adapter.
- final InstalledCoresAdapter adapter = new InstalledCoresAdapter(getActivity(), R.layout.coremanager_list_item, items);
+ // Check if the device supports NEON.
+ final String cpuInfo = UserPreferences.readCPUInfo();
+ final boolean supportsNeon = cpuInfo.contains("neon");
+
+ // Populate the list
+ final File[] libs = new File(getActivity().getApplicationInfo().dataDir, "/cores").listFiles();
+ for (File lib : libs)
+ {
+ String libName = lib.getName();
+
+ // Never append a NEON lib if we don't have NEON.
+ if (libName.contains("neon") && !supportsNeon)
+ continue;
+
+ // If we have a NEON version with NEON capable CPU,
+ // never append a non-NEON version.
+ if (supportsNeon && !libName.contains("neon"))
+ {
+ boolean hasNeonVersion = false;
+ for (File lib_ : libs)
+ {
+ String otherName = lib_.getName();
+ String baseName = libName.replace(".so", "");
+
+ if (otherName.contains("neon") && otherName.startsWith(baseName))
+ {
+ hasNeonVersion = true;
+ break;
+ }
+ }
+
+ if (hasNeonVersion)
+ 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()));
+ }
+
+ // Sort the list alphabetically
+ Collections.sort(items);
+
+ // Initialize and set the backing adapter for this ListFragment.
+ adapter = new InstalledCoresAdapter(getActivity(), R.layout.coremanager_list_item, items);
setListAdapter(adapter);
}
@@ -41,11 +125,51 @@ public final class InstalledCoresFragment extends ListFragment
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the layout for this ListFragment.
- View parentView = inflater.inflate(R.layout.coremanager_listview_layout, container, false);
+ View parentView = inflater.inflate(R.layout.coremanager_listview, container, false);
+
+ // Set the long click listener.
+ ListView mainList = (ListView) parentView.findViewById(android.R.id.list);
+ mainList.setOnItemLongClickListener(itemLongClickListener);
- return parentView.findViewById(android.R.id.list);
+ return mainList;
}
+ // This will be the handler for long clicks on individual list items in this ListFragment.
+ private final OnItemLongClickListener itemLongClickListener = new OnItemLongClickListener()
+ {
+ @Override
+ public boolean onItemLongClick(AdapterView> parent, View view, int position, long id)
+ {
+ // Begin building the AlertDialog
+ final CoreManagerListItem 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.setNegativeButton(R.string.no, null);
+ alert.setPositiveButton(R.string.yes, new OnClickListener()
+ {
+ @Override
+ public void onClick(DialogInterface dialog, int which)
+ {
+ // 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();
+ 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();
+ }
+ }
+ });
+ alert.show();
+
+ return true;
+ }
+ };
+
/**
* The {@link ArrayAdapter} that backs this InstalledCoresFragment.
*/
@@ -60,7 +184,7 @@ public final class InstalledCoresFragment extends ListFragment
*
* @param context The current {@link Context}.
* @param resourceId The resource ID for a layout file containing a layout to use when instantiating views.
- * @param objects The items to represent in the {@link ListView}.
+ * @param items The list of items to represent in this adapter.
*/
public InstalledCoresAdapter(Context context, int resourceId, List items)
{