mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-22 04:24:59 +00:00
FIX ELF LOADER AND OPTIMINIZE JNI-CALBACKS
This commit is contained in:
parent
36895ede35
commit
5ec6d8a5d5
13 changed files with 178 additions and 31 deletions
|
@ -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(); }
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -43,6 +43,10 @@ public class GameMetadata {
|
|||
return romPath;
|
||||
}
|
||||
|
||||
public String getRealPath(){
|
||||
return GameUtils.resolvePath(romPath);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
33
src/pandroid/app/src/main/res/layout/dialog_loading.xml
Normal file
33
src/pandroid/app/src/main/res/layout/dialog_loading.xml
Normal 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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Reference in a new issue