FIX ELF LOADER AND OPTIMINIZE JNI-CALBACKS

This commit is contained in:
gabriel 2024-02-17 01:45:36 -04:00
parent 36895ede35
commit 5ec6d8a5d5
13 changed files with 178 additions and 31 deletions

View file

@ -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(); }

View file

@ -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();

View file

@ -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();

View file

@ -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);
}
}

View file

@ -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<LuaFile> 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() {

View file

@ -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<Uri> {
private final ActivityResultContracts.OpenDocument openRomContract = new ActivityResultContracts.OpenDocument();
@ -53,14 +59,41 @@ public class GamesFragment extends Fragment implements ActivityResultCallback<Ur
Toast.makeText(getContext(), "Invalid file path", Toast.LENGTH_LONG).show();
return;
}
FileUtils.makeUriPermanent(uri, FileUtils.MODE_READ);
GameMetadata game = new GameMetadata(uri, FileUtils.getName(uri).split("\\.")[0], "Unknown");
GameUtils.addGame(game);
GameUtils.launch(requireActivity(), game);
String extension = FileUtils.extension(uri);
if (extension.equals("elf") || extension.endsWith("axf")){
importELF(uri);
} else {
FileUtils.makeUriPermanent(uri, FileUtils.MODE_READ);
importGame(uri);
}
}
}
}
private void importGame(String uri){
GameMetadata game = new GameMetadata(uri, FileUtils.getName(uri).split("\\.")[0], getString(R.string.unknown));
GameUtils.addGame(game);
GameUtils.launch(requireActivity(), game);
}
private void importELF(String uri) {
AlertDialog dialog = new LoadingAlertDialog(requireActivity(), R.string.loading).create();
dialog.show();
new Task(()->{
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);

View file

@ -43,6 +43,10 @@ public class GameMetadata {
return romPath;
}
public String getRealPath(){
return GameUtils.resolvePath(romPath);
}
public String getId() {
return id;
}

View file

@ -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";
}

View file

@ -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;
}
}

View file

@ -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<GameMetadata> getGames() {
return new ArrayList<>(data.games);
}

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?colorSurface"
android:padding="30dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="20dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textSize="24sp"/>
</LinearLayout>
<ProgressBar
android:layout_width="match_parent"
android:layout_height="20dp"
android:indeterminate="true"
android:layout_gravity="bottom"
android:indeterminateTint="?colorPrimary"
android:background="#0000"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"/>
</FrameLayout>

View file

@ -54,5 +54,6 @@
<string name="pref_shader_jit_title">Shader Jit</string>
<string name="pref_shader_jit_summary">Usar recompilador de shaders.</string>
<string name="graphics">Gráficos</string>
<string name="loading">Carregando</string>
<string name="rotate">Rotacionar</string>
</resources>

View file

@ -59,4 +59,5 @@
<string name="pref_shader_jit_title">Shader JIT</string>
<string name="pref_shader_jit_summary">Use shader recompiler.</string>
<string name="graphics">Graphics</string>
<string name="loading">Loading</string>
</resources>