mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 23:55:40 +00:00
Android: Implement disc changing via playlists
This commit is contained in:
parent
4701d2480d
commit
3e6bc0e10d
|
@ -28,6 +28,7 @@ Log_SetChannel(AndroidHostInterface);
|
|||
#endif
|
||||
|
||||
static JavaVM* s_jvm;
|
||||
static jclass s_String_class;
|
||||
static jclass s_AndroidHostInterface_class;
|
||||
static jmethodID s_AndroidHostInterface_constructor;
|
||||
static jfieldID s_AndroidHostInterface_field_mNativePointer;
|
||||
|
@ -618,7 +619,10 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|||
|
||||
// Create global reference so it doesn't get cleaned up.
|
||||
JNIEnv* env = AndroidHelpers::GetJNIEnv();
|
||||
if ((s_AndroidHostInterface_class = env->FindClass("com/github/stenzek/duckstation/AndroidHostInterface")) ==
|
||||
if ((s_String_class = env->FindClass("java/lang/String")) == nullptr ||
|
||||
(s_String_class = static_cast<jclass>(env->NewGlobalRef(s_String_class))) ==
|
||||
nullptr ||
|
||||
(s_AndroidHostInterface_class = env->FindClass("com/github/stenzek/duckstation/AndroidHostInterface")) ==
|
||||
nullptr ||
|
||||
(s_AndroidHostInterface_class = static_cast<jclass>(env->NewGlobalRef(s_AndroidHostInterface_class))) ==
|
||||
nullptr ||
|
||||
|
@ -1011,3 +1015,46 @@ DEFINE_JNI_ARGS_METHOD(jstring, AndroidHostInterface_importBIOSImage, jobject ob
|
|||
else
|
||||
return env->NewStringUTF(hash.ToString().c_str());
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getMediaPlaylistPaths, jobject obj)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return nullptr;
|
||||
|
||||
const u32 count = System::GetMediaPlaylistCount();
|
||||
if (count == 0)
|
||||
return nullptr;
|
||||
|
||||
jobjectArray arr = env->NewObjectArray(static_cast<jsize>(count), s_String_class, nullptr);
|
||||
for (u32 i = 0; i < count; i++)
|
||||
{
|
||||
jstring str = env->NewStringUTF(System::GetMediaPlaylistPath(i).c_str());
|
||||
env->SetObjectArrayElement(arr, static_cast<jsize>(i), str);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(jint, AndroidHostInterface_getMediaPlaylistIndex, jobject obj)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return -1;
|
||||
|
||||
return System::GetMediaPlaylistIndex();
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_setMediaPlaylistIndex, jobject obj, jint index)
|
||||
{
|
||||
if (!System::IsValid() || index < 0 || static_cast<u32>(index) >= System::GetMediaPlaylistCount())
|
||||
return false;
|
||||
|
||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||
hi->RunOnEmulationThread([index, hi]() {
|
||||
if (System::IsValid()) {
|
||||
if (!System::SwitchMediaFromPlaylist(index))
|
||||
hi->AddOSDMessage("Disc switch failed. Please make sure the file exists.");
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
|
@ -83,6 +83,10 @@ public class AndroidHostInterface {
|
|||
public native boolean isFastForwardEnabled();
|
||||
public native void setFastForwardEnabled(boolean enabled);
|
||||
|
||||
public native String[] getMediaPlaylistPaths();
|
||||
public native int getMediaPlaylistIndex();
|
||||
public native boolean setMediaPlaylistIndex(int index);
|
||||
|
||||
static {
|
||||
System.loadLibrary("duckstation-native");
|
||||
}
|
||||
|
|
|
@ -409,7 +409,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
|
||||
case 2: // Change Disc
|
||||
{
|
||||
onMenuClosed();
|
||||
showDiscChangeMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -482,6 +482,30 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
}
|
||||
}
|
||||
|
||||
private void showDiscChangeMenu() {
|
||||
final String[] paths = AndroidHostInterface.getInstance().getMediaPlaylistPaths();
|
||||
final int currentPath = AndroidHostInterface.getInstance().getMediaPlaylistIndex();
|
||||
if (paths == null)
|
||||
{
|
||||
onMenuClosed();
|
||||
return;
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
|
||||
CharSequence[] items = new CharSequence[paths.length];
|
||||
for (int i = 0; i < paths.length; i++)
|
||||
items[i] = GameListEntry.getFileNameForPath(paths[i]);
|
||||
|
||||
builder.setSingleChoiceItems(items, currentPath, (dialogInterface, i) -> {
|
||||
AndroidHostInterface.getInstance().setMediaPlaylistIndex(i);
|
||||
dialogInterface.dismiss();
|
||||
onMenuClosed();
|
||||
});
|
||||
builder.setOnCancelListener(dialogInterface -> onMenuClosed());
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Touchscreen controller overlay
|
||||
*/
|
||||
|
|
|
@ -9,7 +9,8 @@ import androidx.core.content.ContextCompat;
|
|||
public class GameListEntry {
|
||||
public enum EntryType {
|
||||
Disc,
|
||||
PSExe
|
||||
PSExe,
|
||||
Playlist
|
||||
}
|
||||
|
||||
public enum CompatibilityRating {
|
||||
|
@ -90,15 +91,17 @@ public class GameListEntry {
|
|||
return mCompatibilityRating;
|
||||
}
|
||||
|
||||
private String getSubTitle() {
|
||||
String sizeString = String.format("%.2f MB", (double) mSize / 1048576.0);
|
||||
String fileName;
|
||||
int lastSlash = mPath.lastIndexOf('/');
|
||||
if (lastSlash > 0 && lastSlash < mPath.length() - 1)
|
||||
fileName = mPath.substring(lastSlash + 1);
|
||||
public static String getFileNameForPath(String path) {
|
||||
int lastSlash = path.lastIndexOf('/');
|
||||
if (lastSlash > 0 && lastSlash < path.length() - 1)
|
||||
return path.substring(lastSlash + 1);
|
||||
else
|
||||
fileName = mPath;
|
||||
return path;
|
||||
}
|
||||
|
||||
private String getSubTitle() {
|
||||
String fileName = getFileNameForPath(mPath);
|
||||
String sizeString = String.format("%.2f MB", (double) mSize / 1048576.0);
|
||||
return String.format("%s (%s)", fileName, sizeString);
|
||||
}
|
||||
|
||||
|
@ -134,6 +137,10 @@ public class GameListEntry {
|
|||
case PSExe:
|
||||
typeDrawableId = R.drawable.ic_emblem_system;
|
||||
break;
|
||||
|
||||
case Playlist:
|
||||
typeDrawableId = R.drawable.ic_baseline_playlist_play_24;
|
||||
break;
|
||||
}
|
||||
|
||||
((ImageView) view.findViewById(R.id.game_list_view_entry_type_icon))
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M4,10h12v2L4,12zM4,6h12v2L4,8zM4,14h8v2L4,16zM14,14v6l5,-3z"/>
|
||||
</vector>
|
|
@ -25,7 +25,7 @@ GameList::~GameList() = default;
|
|||
|
||||
const char* GameList::EntryTypeToString(GameListEntryType type)
|
||||
{
|
||||
static std::array<const char*, 2> names = {{"Disc", "PSExe"}};
|
||||
static std::array<const char*, 3> names = {{"Disc", "PSExe", "Playlist"}};
|
||||
return names[static_cast<int>(type)];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue