diff --git a/android/app/src/cpp/android_host_interface.cpp b/android/app/src/cpp/android_host_interface.cpp index e0943f521..7713c6917 100644 --- a/android/app/src/cpp/android_host_interface.cpp +++ b/android/app/src/cpp/android_host_interface.cpp @@ -1503,4 +1503,22 @@ DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_setMediaPlaylistIndex, job }); return true; -} \ No newline at end of file +} + +DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_setMediaFilename, jstring obj, jstring filename) +{ + if (!System::IsValid() || !filename) + return false; + + std::string filename_str(AndroidHelpers::JStringToString(env, filename)); + AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj); + hi->RunOnEmulationThread([filename_str, hi]() { + if (System::IsValid()) + { + if (!System::InsertMedia(filename_str.c_str())) + hi->AddOSDMessage("Disc switch failed. Please make sure the file exists and is a supported disc image."); + } + }); + + return true; +} diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java b/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java index 741f5d45f..303029d4b 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java @@ -124,6 +124,8 @@ public class AndroidHostInterface { public native boolean setMediaPlaylistIndex(int index); + public native boolean setMediaFilename(String filename); + static { System.loadLibrary("duckstation-native"); } diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java index 53e983205..a8d6a3850 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java @@ -300,8 +300,19 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde applySettings(); } } else if (requestCode == REQUEST_IMPORT_PATCH_CODES) { - if (data != null) - importPatchesFromFile(data.getData()); + if (data == null) + return; + + importPatchesFromFile(data.getData()); + } else if (requestCode == REQUEST_CHANGE_DISC_FILE) { + if (data == null) + return; + + String path = GameDirectoriesActivity.getPathFromUri(this, data.getData()); + if (path == null) + return; + + AndroidHostInterface.getInstance().setMediaFilename(path); } } @@ -378,6 +389,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde private static final int REQUEST_CODE_SETTINGS = 0; private static final int REQUEST_IMPORT_PATCH_CODES = 1; + private static final int REQUEST_CHANGE_DISC_FILE = 2; private void onMenuClosed() { enableFullscreenImmersive(); @@ -560,21 +572,27 @@ 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; - } + final int numPaths = (paths != null) ? paths.length : 0; AlertDialog.Builder builder = new AlertDialog.Builder(this); - CharSequence[] items = new CharSequence[paths.length]; - for (int i = 0; i < paths.length; i++) + CharSequence[] items = new CharSequence[numPaths + 1]; + for (int i = 0; i < numPaths; i++) items[i] = GameListEntry.getFileNameForPath(paths[i]); + items[numPaths] = "Select New File..."; - builder.setSingleChoiceItems(items, currentPath, (dialogInterface, i) -> { - AndroidHostInterface.getInstance().setMediaPlaylistIndex(i); + builder.setSingleChoiceItems(items, (currentPath < numPaths) ? currentPath : -1, (dialogInterface, i) -> { dialogInterface.dismiss(); onMenuClosed(); + + if (i < numPaths) { + AndroidHostInterface.getInstance().setMediaPlaylistIndex(i); + } else { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("*/*"); + intent.addCategory(Intent.CATEGORY_OPENABLE); + startActivityForResult(Intent.createChooser(intent, getString(R.string.main_activity_choose_disc_image)), REQUEST_CHANGE_DISC_FILE); + } }); builder.setOnCancelListener(dialogInterface -> onMenuClosed()); builder.create().show(); diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/GameDirectoriesActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/GameDirectoriesActivity.java index ee975a09f..a5cfe5e21 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/GameDirectoriesActivity.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/GameDirectoriesActivity.java @@ -235,6 +235,22 @@ public class GameDirectoriesActivity extends AppCompatActivity { return path; } + public static String getPathFromUri(Context context, Uri uri) { + String path = FileUtil.getFullPathFromUri(uri, context); + if (path.length() < 5) { + new AlertDialog.Builder(context) + .setTitle(R.string.main_activity_error) + .setMessage(R.string.main_activity_get_path_from_file_error) + .setPositiveButton(R.string.main_activity_ok, (dialog, button) -> { + }) + .create() + .show(); + return null; + } + + return path; + } + public static void addSearchDirectory(Context context, String path, boolean recursive) { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); final String key = recursive ? "GameList/RecursivePaths" : "GameList/Paths"; diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/MainActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/MainActivity.java index 3e763ce57..8a7b6fcd5 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/MainActivity.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/MainActivity.java @@ -242,22 +242,6 @@ public class MainActivity extends AppCompatActivity { return super.onOptionsItemSelected(item); } - private String getPathFromUri(Uri uri) { - String path = FileUtil.getFullPathFromUri(uri, this); - if (path.length() < 5) { - new AlertDialog.Builder(this) - .setTitle(R.string.main_activity_error) - .setMessage(R.string.main_activity_get_path_from_file_error) - .setPositiveButton(R.string.main_activity_ok, (dialog, button) -> { - }) - .create() - .show(); - return null; - } - - return path; - } - @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); @@ -288,7 +272,7 @@ public class MainActivity extends AppCompatActivity { if (resultCode != RESULT_OK) return; - String path = getPathFromUri(data.getData()); + String path = GameDirectoriesActivity.getPathFromUri(this, data.getData()); if (path == null) return;