From 5ec6d8a5d52354547f3e2fa6d2d5d96cd953bc7b Mon Sep 17 00:00:00 2001 From: gabriel Date: Sat, 17 Feb 2024 01:45:36 -0400 Subject: [PATCH] FIX ELF LOADER AND OPTIMINIZE JNI-CALBACKS --- src/jni_driver.cpp | 16 +++++--- .../com/panda3ds/pandroid/AlberDriver.java | 2 +- .../panda3ds/pandroid/app/MainActivity.java | 16 +------- .../pandroid/app/base/LoadingAlertDialog.java | 22 ++++++++++ .../pandroid/app/game/LuaDialogFragment.java | 6 +-- .../pandroid/app/main/GamesFragment.java | 41 +++++++++++++++++-- .../pandroid/data/game/GameMetadata.java | 4 ++ .../panda3ds/pandroid/utils/Constants.java | 2 + .../panda3ds/pandroid/utils/FileUtils.java | 40 ++++++++++++++++++ .../panda3ds/pandroid/utils/GameUtils.java | 25 +++++++++-- .../src/main/res/layout/dialog_loading.xml | 33 +++++++++++++++ .../src/main/res/values-pt-rBR/strings.xml | 1 + .../app/src/main/res/values/strings.xml | 1 + 13 files changed, 178 insertions(+), 31 deletions(-) create mode 100644 src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/LoadingAlertDialog.java create mode 100644 src/pandroid/app/src/main/res/layout/dialog_loading.xml diff --git a/src/jni_driver.cpp b/src/jni_driver.cpp index bde4824a..24c0f3ac 100644 --- a/src/jni_driver.cpp +++ b/src/jni_driver.cpp @@ -15,6 +15,9 @@ RendererGL* renderer = nullptr; bool romLoaded = false; JavaVM* jvm = nullptr; +jclass alberClass; +jmethodID alberClassOpenDocument; + #define AlberFunction(type, name) JNIEXPORT type JNICALL Java_com_panda3ds_pandroid_AlberDriver_##name void throwException(JNIEnv* env, const char* message) { @@ -37,13 +40,10 @@ JNIEnv* jniEnv() { int AndroidUtils::openDocument(const char* path, const char* perms) { auto env = jniEnv(); - auto clazz = env->FindClass("com/panda3ds/pandroid/AlberDriver"); - auto method = env->GetStaticMethodID(clazz, "openDocument", "(Ljava/lang/String;Ljava/lang/String;)I"); - jstring uri = env->NewStringUTF(path); jstring jmode = env->NewStringUTF(perms); - jint result = env->CallStaticIntMethod(clazz, method, uri, jmode); + jint result = env->CallStaticIntMethod(alberClass, alberClassOpenDocument, uri, jmode); env->DeleteLocalRef(uri); env->DeleteLocalRef(jmode); @@ -60,7 +60,13 @@ MAKE_SETTING(setShaderJitEnabled, jboolean, shaderJitEnabled) #undef MAKE_SETTING -AlberFunction(void, Setup)(JNIEnv* env, jobject obj) { env->GetJavaVM(&jvm); } +AlberFunction(void, Setup)(JNIEnv* env, jobject obj) { + env->GetJavaVM(&jvm); + + alberClass = (jclass)env->NewGlobalRef((jclass)env->FindClass("com/panda3ds/pandroid/AlberDriver")); + alberClassOpenDocument = env->GetStaticMethodID(alberClass, "openDocument", "(Ljava/lang/String;Ljava/lang/String;)I"); +} + AlberFunction(void, Pause)(JNIEnv* env, jobject obj) { emulator->pause(); } AlberFunction(void, Resume)(JNIEnv* env, jobject obj) { emulator->resume(); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java index 9b2bfce6..5aadf5aa 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/AlberDriver.java @@ -44,7 +44,7 @@ public class AlberDriver { if (mode.contains("w")){ throw new IllegalArgumentException("Cannot write to rom-fs"); } - uri = FileUtils.obtainUri(GameUtils.getCurrentGame().getRomPath()); + uri = FileUtils.obtainUri(GameUtils.getCurrentGame().getRealPath()); } parcel = context.getContentResolver().openFileDescriptor(uri, mode); int fd = parcel.detachFd(); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java index 9bb57b6e..f004bc48 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/MainActivity.java @@ -1,32 +1,20 @@ package com.panda3ds.pandroid.app; -import static android.Manifest.permission.READ_EXTERNAL_STORAGE; -import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; -import static android.provider.Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION; - -import android.content.Intent; -import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.view.MenuItem; + import androidx.annotation.NonNull; -import androidx.core.app.ActivityCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; + import com.google.android.material.navigation.NavigationBarView; import com.panda3ds.pandroid.R; -import com.panda3ds.pandroid.app.editor.CodeEditorActivity; import com.panda3ds.pandroid.app.main.GamesFragment; import com.panda3ds.pandroid.app.main.SearchFragment; import com.panda3ds.pandroid.app.main.SettingsFragment; -import java.io.File; - public class MainActivity extends BaseActivity implements NavigationBarView.OnItemSelectedListener { - private static final int PICK_ROM = 2; - private static final int PERMISSION_REQUEST_CODE = 3; - private final GamesFragment gamesFragment = new GamesFragment(); private final SearchFragment searchFragment = new SearchFragment(); private final SettingsFragment settingsFragment = new SettingsFragment(); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/LoadingAlertDialog.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/LoadingAlertDialog.java new file mode 100644 index 00000000..61887fb9 --- /dev/null +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/LoadingAlertDialog.java @@ -0,0 +1,22 @@ +package com.panda3ds.pandroid.app.base; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; +import androidx.appcompat.widget.AppCompatTextView; + +import com.panda3ds.pandroid.R; + +public class LoadingAlertDialog extends BottomAlertDialog { + public LoadingAlertDialog(@NonNull Context context, @StringRes int title) { + super(context); + View view = LayoutInflater.from(context).inflate(R.layout.dialog_loading,null, false); + setView(view); + setCancelable(false); + ((AppCompatTextView)view.findViewById(R.id.title)) + .setText(title); + } +} diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/game/LuaDialogFragment.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/game/LuaDialogFragment.java index da059399..1d573e42 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/game/LuaDialogFragment.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/game/LuaDialogFragment.java @@ -19,6 +19,7 @@ import com.panda3ds.pandroid.app.base.BottomAlertDialog; import com.panda3ds.pandroid.app.base.BottomDialogFragment; import com.panda3ds.pandroid.app.editor.CodeEditorActivity; import com.panda3ds.pandroid.lang.Task; +import com.panda3ds.pandroid.utils.Constants; import com.panda3ds.pandroid.utils.FileUtils; import com.panda3ds.pandroid.view.recycler.AutoFitGridLayout; import com.panda3ds.pandroid.view.recycler.SimpleListAdapter; @@ -94,9 +95,8 @@ public class LuaDialogFragment extends BottomDialogFragment { ((RecyclerView) view.findViewById(R.id.recycler)).setAdapter(adapter); ((RecyclerView) view.findViewById(R.id.recycler)).setLayoutManager(new AutoFitGridLayout(getContext(), 140)); - FileUtils.createDir(FileUtils.getResourcesPath(), "Lua Scripts"); ArrayList files = new ArrayList<>(); - String path = FileUtils.getResourcesPath() + "/Lua Scripts/"; + String path = FileUtils.getResourcePath(Constants.RESOURCE_FOLDER_LUA_SCRIPTS); for (String file : FileUtils.listFiles(path)) { files.add(new LuaFile(file)); } @@ -167,7 +167,7 @@ public class LuaDialogFragment extends BottomDialogFragment { } private LuaFile(String name) { - this(FileUtils.getResourcesPath() + "/Lua Scripts/", name); + this(FileUtils.getResourcePath(Constants.RESOURCE_FOLDER_LUA_SCRIPTS), name); } private String absolutePath() { diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/main/GamesFragment.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/main/GamesFragment.java index 285fd992..7606167d 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/main/GamesFragment.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/main/GamesFragment.java @@ -11,13 +11,19 @@ import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.panda3ds.pandroid.R; +import com.panda3ds.pandroid.app.base.LoadingAlertDialog; import com.panda3ds.pandroid.data.game.GameMetadata; +import com.panda3ds.pandroid.lang.Task; +import com.panda3ds.pandroid.utils.Constants; import com.panda3ds.pandroid.utils.FileUtils; import com.panda3ds.pandroid.utils.GameUtils; import com.panda3ds.pandroid.view.gamesgrid.GamesGridView; +import java.util.UUID; + public class GamesFragment extends Fragment implements ActivityResultCallback { private final ActivityResultContracts.OpenDocument openRomContract = new ActivityResultContracts.OpenDocument(); @@ -53,14 +59,41 @@ public class GamesFragment extends Fragment implements ActivityResultCallback{ + String uuid = UUID.randomUUID().toString() + "." + FileUtils.extension(uri); + String name = FileUtils.getName(uri); + FileUtils.copyFile(uri, FileUtils.getResourcePath(Constants.RESOURCE_FOLDER_ELF), uuid); + gameListView.post(()->{ + dialog.hide(); + GameMetadata game = new GameMetadata("elf://"+uuid, name.substring(0, name.length()-4).trim(), ""); + GameUtils.addGame(game); + GameUtils.launch(requireActivity(), game); + }); + }).start(); + } + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/data/game/GameMetadata.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/data/game/GameMetadata.java index 512a3725..417c77bc 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/data/game/GameMetadata.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/data/game/GameMetadata.java @@ -43,6 +43,10 @@ public class GameMetadata { return romPath; } + public String getRealPath(){ + return GameUtils.resolvePath(romPath); + } + public String getId() { return id; } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java index c72a516a..8136f7d9 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/Constants.java @@ -26,4 +26,6 @@ public class Constants { public static final String PREF_GAME_UTILS = "app.GameUtils"; public static final String PREF_INPUT_MAP = "app.InputMap"; public static final String PREF_SCREEN_CONTROLLER_PROFILES = "app.input.ScreenControllerManager"; + public static final String RESOURCE_FOLDER_ELF = "ELF"; + public static final String RESOURCE_FOLDER_LUA_SCRIPTS = "Lua Scripts"; } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/FileUtils.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/FileUtils.java index 1beadc34..d3da4d42 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/FileUtils.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/FileUtils.java @@ -48,6 +48,13 @@ public class FileUtils { return file.getAbsolutePath(); } + public static String getResourcePath(String name){ + File file = new File(getResourcesPath(), name); + file.mkdirs(); + + return file.getAbsolutePath(); + } + public static String getPrivatePath() { File file = getContext().getFilesDir(); if (!file.exists()) { @@ -268,4 +275,37 @@ public class FileUtils { public static Uri obtainUri(String path) { return parseFile(path).getUri(); } + + public static String extension(String uri) { + String name = getName(uri); + if (!name.contains(".")){ + return name.toLowerCase(); + } + String[] parts = name.split("\\."); + return parts[parts.length-1].toLowerCase(); + } + + public static boolean copyFile(String source, String path, String name) { + try { + String fullPath = path + "/" + name; + if (!FileUtils.exists(fullPath)) { + FileUtils.delete(fullPath); + } + FileUtils.createFile(path, name); + InputStream in = getInputStream(source); + OutputStream out = getOutputStream(fullPath); + byte[] buffer = new byte[1024 * 128]; //128 KB + int length; + while ((length = in.read(buffer)) != -1) { + out.write(buffer, 0, length); + } + out.flush(); + out.close(); + in.close(); + } catch (Exception e){ + Log.e(Constants.LOG_TAG, "ERROR ON COPY FILE", e); + return false; + } + return true; + } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/GameUtils.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/GameUtils.java index ee79e826..37452a67 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/GameUtils.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/GameUtils.java @@ -31,7 +31,7 @@ public class GameUtils { public static GameMetadata findByRomPath(String romPath) { for (GameMetadata game : data.games) { - if (Objects.equals(romPath, game.getRomPath())) { + if (Objects.equals(romPath, game.getRealPath())) { return game; } } @@ -40,9 +40,12 @@ public class GameUtils { public static void launch(Context context, GameMetadata game) { currentGame = game; - String[] parts = Uri.decode(game.getRomPath()).split("/"); - String name = parts[parts.length-1]; - String path = "game://internal/"+name; + String path = game.getRealPath(); + if (path.contains("://")) { + String[] parts = Uri.decode(game.getRomPath()).split("/"); + String name = parts[parts.length - 1]; + path = "game://internal/" + name; + } context.startActivity(new Intent(context, GameActivity.class).putExtra(Constants.ACTIVITY_PARAMETER_PATH, path)); } @@ -60,6 +63,20 @@ public class GameUtils { writeChanges(); } + public static String resolvePath(String path){ + String lower = path.toLowerCase(); + if (!lower.contains("://")){ + return path; + } + Uri uri = Uri.parse(path); + switch (uri.getScheme().toLowerCase()){ + case "elf":{ + return FileUtils.getResourcePath(Constants.RESOURCE_FOLDER_ELF)+"/"+uri.getAuthority(); + } + } + return path; + } + public static ArrayList getGames() { return new ArrayList<>(data.games); } diff --git a/src/pandroid/app/src/main/res/layout/dialog_loading.xml b/src/pandroid/app/src/main/res/layout/dialog_loading.xml new file mode 100644 index 00000000..824aee72 --- /dev/null +++ b/src/pandroid/app/src/main/res/layout/dialog_loading.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/values-pt-rBR/strings.xml b/src/pandroid/app/src/main/res/values-pt-rBR/strings.xml index 26f36faf..96a47941 100644 --- a/src/pandroid/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/pandroid/app/src/main/res/values-pt-rBR/strings.xml @@ -54,5 +54,6 @@ Shader Jit Usar recompilador de shaders. Gráficos + Carregando Rotacionar diff --git a/src/pandroid/app/src/main/res/values/strings.xml b/src/pandroid/app/src/main/res/values/strings.xml index 9ccaa619..20e6c5c8 100644 --- a/src/pandroid/app/src/main/res/values/strings.xml +++ b/src/pandroid/app/src/main/res/values/strings.xml @@ -59,4 +59,5 @@ Shader JIT Use shader recompiler. Graphics + Loading