diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
new file mode 100644
index 000000000..fa0cfecc9
--- /dev/null
+++ b/.github/workflows/android.yml
@@ -0,0 +1,27 @@
+name: Android CI
+
+on: [push]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: Build with Gradle
+ run: |
+ chmod +x gradlew
+ ./gradlew clean assembleDebug
+ ./gradlew test
+# should test???
+
+ - name: Upload APK
+ uses: actions/upload-artifact@v2
+ with:
+ name: app-debug
+ path: app/build/outputs/apk/debug/app-debug.apk
diff --git a/.travis.yml b/.travis.yml.disabled
similarity index 95%
rename from .travis.yml
rename to .travis.yml.disabled
index 08286c419..2ebd745a9 100644
--- a/.travis.yml
+++ b/.travis.yml.disabled
@@ -50,9 +50,9 @@ deploy:
api-key: $GITHUB_API_KEY
file: $TRAVIS_BUILD_DIR/app/build/outputs/apk/debug/app-debug.apk
skip_cleanup: true
- name: PojavLauncher_DevBuild-$TRAVIS_COMMIT
+ name: PojavLauncher-v3_DevBuild-$TRAVIS_COMMIT
body: Automatic build of PojavLauncher from the latest source commit ($TRAVIS_COMMIT) built by Travis CI on $(date +'%F %T %Z').
prerelease: true
overwrite: true
target_commitish: $TRAVIS_COMMIT
- on: [push]
+# on: [push]
diff --git a/README.md b/README.md
index 420124d20..535d3dbed 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+
# PojavLauncher
A Minecraft: Java Edition launcher for Android based from Boardwalk. Support up-to Minecraft 1.11.2
@@ -6,7 +7,8 @@ A Minecraft: Java Edition launcher for Android based from Boardwalk. Support up-
## Current status
- [x] **Removed** ~~BinaryExecutor: execute `java` binary, no `JNIInvocation`.~~
-- [x] JVDroid OpenJDK 11 (32 and 64-bit ARM and x86). Partial, no error `can't lock mutex`, but now exit with none output.
+- [x] **Temporary removed** ~~JVDroid OpenJDK 11 (32 and 64-bit ARM and x86). Partial, no error `can't lock mutex`, but now exit with none output.~~
+- [x] OpenJDK 9 Mobile port
- [ ] AWT/Swing for mod installer. Will use `Caciocavallo` project.
- [ ] OpenGL in OpenJDK environment. Use Boardwalk 2 method or other.
- [ ] OpenAL 64-bit version
diff --git a/app/build.gradle b/app/build.gradle
index af3887bd3..fbdb4076d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,11 +3,22 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 26
dexOptions {
- javaMaxHeapSize "4g"
+ javaMaxHeapSize "4g"
}
- lintOptions {
- abortOnError false
- }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ signingConfigs {
+ customDebug {
+ storeFile file("debug.keystore")
+ storePassword "android"
+ keyAlias "androiddebugkey"
+ keyPassword "android"
+ }
+ }
+
defaultConfig {
applicationId "net.kdt.pojavlaunch"
minSdkVersion 21
@@ -15,11 +26,21 @@ android {
versionCode 156235
versionName "3.2.0_6401b_20200822"
multiDexEnabled true //important
+
+ ndk {
+ abiFilters "armeabi-v7a"
+ }
}
buildTypes {
+ debug {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ signingConfig signingConfigs.customDebug
+ }
+
release {
- // Don't set to true or java.awt will be a.a or something similar.
+ // Don't set to true or java.awt will be a.a or something similar.
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// defaultConfig already set
@@ -28,6 +49,12 @@ android {
}
}
+ externalNativeBuild {
+ ndkBuild {
+ path file('src/main/jni/Android.mk')
+ }
+ }
+
// Keep the following configuration in order to might make Minecraft 1.12 support.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
diff --git a/app/debug.keystore b/app/debug.keystore
new file mode 100644
index 000000000..12fd3e638
Binary files /dev/null and b/app/debug.keystore differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index afda11161..77b8b5412 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -41,6 +41,11 @@
android:name=".MCLauncherActivity"
android:configChanges="keyboardHidden|orientation|screenSize"/>
+
+
javaArgList = new ArrayList();
+
+ javaArgList.add(Tools.homeJreDir + "/bin/java");
+
+ // javaArgList.add("-Xms512m");
+ javaArgList.add("-Xmx512m");
+
+ javaArgList.add("-Djava.home=" + Tools.homeJreDir);
+ javaArgList.add("-Djava.io.tmpdir=" + getCacheDir().getAbsolutePath());
+ javaArgList.add("-Dos.name=Linux");
+
+ File cacioAwtLibPath = new File(Tools.MAIN_PATH, "cacioawtlib");
+ if (cacioAwtLibPath.exists()) {
+ StringBuilder libStr = new StringBuilder();
+ for (File file: cacioAwtLibPath.listFiles()) {
+ if (file.getName().endsWith(".jar")) {
+ libStr.append(":" + file.getAbsolutePath());
+ }
+ }
+ javaArgList.add("-Xbootclasspath/a" + libStr.toString());
+ }
+
+ File cacioArgOverrideFile = new File(cacioAwtLibPath, "overrideargs.txt");
+ if (cacioArgOverrideFile.exists()) {
+ javaArgList.addAll(Arrays.asList(Tools.read(cacioArgOverrideFile.getAbsolutePath()).split(" ")));
+ }
+
+ javaArgList.add("-jar");
+ javaArgList.add(modFile.getAbsolutePath());
+
+ System.out.println(Arrays.toString(javaArgList.toArray(new String[0])));
+
+ JREUtils.setJavaEnvironment(this);
+
+ JREUtils.redirectStdio();
+ JREUtils.setJavaEnvironment(this);
+ JREUtils.initJavaRuntime();
+ JREUtils.chdir(Tools.MAIN_PATH);
+
+ VMLauncher.launchJVM(javaArgList.toArray(new String[0]));
+ } catch (Throwable th) {
+ Tools.showError(this, th, true);
+ }
+ }
+}
diff --git a/app/src/main/java/net/kdt/pojavlaunch/JREUtils.java b/app/src/main/java/net/kdt/pojavlaunch/JREUtils.java
new file mode 100644
index 000000000..33d293b3c
--- /dev/null
+++ b/app/src/main/java/net/kdt/pojavlaunch/JREUtils.java
@@ -0,0 +1,83 @@
+package net.kdt.pojavlaunch;
+
+import android.system.*;
+import java.io.*;
+import android.content.*;
+
+public class JREUtils
+{
+ private JREUtils() {}
+
+ public static void initJavaRuntime() {
+ dlopen(Tools.homeJreDir + "/lib/jli/libjli.so");
+ dlopen(Tools.homeJreDir + "/lib/server/libjvm.so");
+ dlopen(Tools.homeJreDir + "/lib/libverify.so");
+ dlopen(Tools.homeJreDir + "/lib/libjava.so");
+ dlopen(Tools.homeJreDir + "/lib/libnet.so");
+ dlopen(Tools.homeJreDir + "/lib/libnio.so");
+ dlopen(Tools.homeJreDir + "/lib/libawt.so");
+ dlopen(Tools.homeJreDir + "/lib/libawt_headless.so");
+ }
+
+ public static void redirectStdio() throws ErrnoException {
+ File logFile = new File(Tools.MAIN_PATH, "latestlog.txt");
+
+ FileDescriptor fd = Os.open(logFile.getAbsolutePath(), OsConstants.O_WRONLY | OsConstants.O_CREAT | OsConstants.O_TRUNC, 0666);
+ Os.dup2(fd, OsConstants.STDERR_FILENO);
+ Os.dup2(fd, OsConstants.STDOUT_FILENO);
+
+ // return fd;
+ }
+
+ public static void setJavaEnvironment(Context ctx) throws IOException, ErrnoException {
+ String libName = System.getProperty("os.arch").contains("64") ? "lib64" : "lib";
+ String ldLibraryPath = (
+ // To make libjli.so ignore re-execute
+ Tools.homeJreDir + "/lib/server:" +
+
+ "/system/" + libName + ":" +
+ "/vendor/" + libName + ":" +
+ "/vendor/" + libName + "/hw:" +
+
+ ctx.getApplicationInfo().nativeLibraryDir + ":" +
+
+ Tools.homeJreDir + "/lib/jli:" +
+ Tools.homeJreDir + "/lib"
+ );
+
+ setEnvironment("JAVA_HOME", Tools.homeJreDir);
+ setEnvironment("HOME", Tools.MAIN_PATH);
+ setEnvironment("TMPDIR", ctx.getCacheDir().getAbsolutePath());
+ // setEnvironment("LIBGL_MIPMAP", "3");
+ setEnvironment("MESA_GLSL_CACHE_DIR", ctx.getCacheDir().getAbsolutePath());
+ setEnvironment("LD_LIBRARY_PATH", ldLibraryPath);
+ setEnvironment("PATH", Tools.homeJreDir + "/bin:" + Os.getenv("PATH"));
+
+ setLdLibraryPath(ldLibraryPath);
+
+ // return ldLibraryPath;
+ }
+
+ private static void setEnvironment(String name, String value) throws ErrnoException, IOException {
+ if (MainActivity.LAUNCH_TYPE == MainActivity.LTYPE_PROCESS) {
+ MainActivity.mLaunchShell.writeToProcess("export " + name + "=" + value);
+ } else {
+ Os.setenv(name, value, true);
+ }
+ }
+
+ public static native int chdir(String path);
+ public static native boolean dlopen(String libPath);
+ public static native void setLdLibraryPath(String ldLibraryPath);
+ public static native void setupBridgeWindow(Object surface);
+
+ public static native void setupBridgeSurfaceAWT(long surface);
+
+ // BEFORE Load and execute PIE binary using dlopen and dlsym("main")
+ // AFTER: Execute a binary in forked process
+ public static native int executeBinary(String[] args);
+
+ static {
+ System.loadLibrary("pojavexec");
+ }
+}
diff --git a/app/src/main/java/net/kdt/pojavlaunch/MCLauncherActivity.java b/app/src/main/java/net/kdt/pojavlaunch/MCLauncherActivity.java
index 2f3008dfe..cb38cdb22 100644
--- a/app/src/main/java/net/kdt/pojavlaunch/MCLauncherActivity.java
+++ b/app/src/main/java/net/kdt/pojavlaunch/MCLauncherActivity.java
@@ -755,22 +755,19 @@ public class MCLauncherActivity extends AppCompatActivity
@Override
public void onClick(DialogInterface p1, int p2)
{
- switch(p2){
- case 0:{ // Mods manager
- modManager();
- } break;
- case 1:{ // OptiFine installer
- installOptiFine();
- } break;
- case 2:{ // Custom controls
- if (Tools.enableDevFeatures) {
- startActivity(new Intent(MCLauncherActivity.this, CustomControlsActivity.class));
- }
- } break;
- case 3:{ // Settings
- startActivity(new Intent(MCLauncherActivity.this, LauncherPreferenceActivity.class));
- } break;
- case 4:{ // About
+ switch (p2) {
+ case 0: // Mod installer
+ installMod();
+ break;
+ case 1: // Custom controls
+ if (Tools.enableDevFeatures) {
+ startActivity(new Intent(MCLauncherActivity.this, CustomControlsActivity.class));
+ }
+ break;
+ case 2: // Settings
+ startActivity(new Intent(MCLauncherActivity.this, LauncherPreferenceActivity.class));
+ break;
+ case 3:{ // About
final AlertDialog.Builder aboutB = new AlertDialog.Builder(MCLauncherActivity.this);
aboutB.setTitle(R.string.mcl_option_about);
try
@@ -792,70 +789,11 @@ public class MCLauncherActivity extends AppCompatActivity
builder.show();
}
- public void modManager()
- {
- /*
- File file1 = new File(Tools.mpModEnable);
- File file2 = new File(Tools.mpModDisable);
- File file3 = new File(Tools.mpModAddNewMo);
- file1.mkdirs();
- file2.mkdir();
- try
- {
- file3.createNewFile();
- }
- catch (IOException e){}
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle("Mods manager (Forge)");
- builder.setPositiveButton(android.R.string.cancel, null);
-
- AlertDialog dialog = builder.create();
-
- MFileListView flv = new MFileListView(this, dialog);
- flv.listFileAt(Tools.datapath + "/ModsManager");
- flv.setFileSelectedListener(new MFileSelectedListener(){
-
- @Override
- public void onFileLongClick(File file, String path, String nane, String extension)
- {
- // TODO: Implement this method
- }
- @Override
- public void onFileSelected(File file, String path, String nane, String extension)
- {
- // TODO: Implement this method
- if(extension.equals(".jar")) {
-
- } else {
- openSelectMod();
- }
- }
- });
- dialog.setView(flv);
- dialog.show();
- */
-
- Tools.dialogOnUiThread(this, "Mods manager", "This feature is not yet supported!");
- }
-
- public void openSelectMod()
- {
+ private void installMod() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.alerttitle_installmod);
builder.setPositiveButton(android.R.string.cancel, null);
- AlertDialog dialog = builder.create();
- FileListView flv = new FileListView(this);
-
- dialog.setView(flv);
- dialog.show();
- }
-
- private void installOptiFine() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.alerttitle_installoptifine);
- builder.setPositiveButton(android.R.string.cancel, null);
-
final AlertDialog dialog = builder.create();
FileListView flv = new FileListView(this);
flv.setFileSelectedListener(new FileSelectedListener(){
@@ -863,7 +801,9 @@ public class MCLauncherActivity extends AppCompatActivity
@Override
public void onFileSelected(File file, String path, String name) {
if (name.endsWith(".jar")) {
- doInstallOptiFine(file);
+ Intent intent = new Intent(MCLauncherActivity.this, InstallModActivity.class);
+ intent.putExtra("modFile", file);
+ startActivity(intent);
dialog.dismiss();
}
}
@@ -872,143 +812,6 @@ public class MCLauncherActivity extends AppCompatActivity
dialog.show();
}
- private void doInstallOptiFine(File optifineFile) {
- new OptiFineInstaller().execute(optifineFile);
- }
-
- private class OptiFineInstaller extends AsyncTask
- {
- private ProgressDialog dialog;
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- dialog = new ProgressDialog(MCLauncherActivity.this);
- dialog.setTitle("Installing OptiFine");
- dialog.setMessage("Preparing");
- dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- dialog.setMax(5);
- dialog.setCancelable(false);
- dialog.show();
- }
-
- @Override
- protected Throwable doInBackground(File[] file) {
- final StringBuilder currentLog = new StringBuilder();
- LoggerJava.LoggerOutputStream logOut = new LoggerJava.LoggerOutputStream(System.out, new LoggerJava.OnStringPrintListener(){
- @Override
- public void onCharPrint(char c)
- {
- currentLog.append(c);
- }
- });
- LoggerJava.LoggerOutputStream logErr = new LoggerJava.LoggerOutputStream(System.err, new LoggerJava.OnStringPrintListener(){
- @Override
- public void onCharPrint(char c)
- {
- currentLog.append(c);
- }
- });
- Throwable throwable = null;
- File convertedFile = null;
- try {
- publishProgress("Preparing", "5");
-
- String origMd5 = OptiFinePatcher.calculateMD5(file[0]);
- convertedFile = new File(Tools.optifineDir, origMd5 + ".jar");
- if (!convertedFile.exists()) {
- publishProgress("Patching OptiFine Installer", null, "1", "true");
-
- Tools.extractAssetFolder(MCLauncherActivity.this, "optifine_patch", Tools.optifineDir, true);
-
- new File(Tools.optifineDir + "/optifine_patch/AndroidOptiFineUtilities.class.patch").delete();
-
- String[] output = Tools.patchOptifineInstaller(MCLauncherActivity.this, file[0]);
- File patchedFile = new File(output[1]);
-
- publishProgress("Converting OptiFine", null, null, "false");
-
- System.setOut(new PrintStream(logOut));
- System.setErr(new PrintStream(logErr));
-
- if (!convertedFile.exists()) {
- RuntimeException dxError = new RuntimeException(getResources().getString(R.string.error_convert_lib, "OptiFine") + "\n" + currentLog.toString());
- dxError.setStackTrace(new StackTraceElement[0]);
- throw dxError;
- }
-
- patchedFile.delete();
- }
-
- publishProgress("Launching OptiFine installer", null, null, "true");
-
- File optDir = getDir("dalvik-cache", 0);
- optDir.mkdir();
-
- DexClassLoader loader = new DexClassLoader(convertedFile.getAbsolutePath(), optDir.getAbsolutePath(), getApplicationInfo().nativeLibraryDir, getClass().getClassLoader());
- // AndroidOptiFineUtilities.originalOptifineJar = convertedFile.getAbsolutePath();
-
- Class installerClass = loader.loadClass("optifine.AndroidInstaller");
- Method installerMethod = installerClass.getDeclaredMethod("doInstall", File.class);
- installerMethod.invoke(null, new File(Tools.MAIN_PATH));
-
- publishProgress("(4/5) Patching OptiFine Tweaker", null, null);
- File optifineLibFile = new File("unimpl");
- if (!optifineLibFile.exists()) {
- throw new FileNotFoundException(optifineLibFile.getAbsolutePath() + "\n\n--- OptiFine installer log ---\n" + currentLog.toString());
- }
- new OptiFinePatcher(optifineLibFile).saveTweaker();
- convertedFile.delete();
-
- publishProgress("(5/5) Done!", null, null);
- Thread.sleep(500);
- } catch (Throwable th) {
- throwable = th;
- } finally {
- System.setOut(logOut.getRootStream());
- System.setErr(logErr.getRootStream());
- /*
- if (throwable != null && convertedFile != null) {
- convertedFile.delete();
- }
- */
- return throwable;
- }
- }
-/*
- private Object fromConfig(DexClassLoader loader, String name) throws ReflectiveOperationException {
- Field f = loader.loadClass("Config").getDeclaredField(name);
- f.setAccessible(true);
- return f.get(null);
- }
-*/
- @Override
- protected void onProgressUpdate(String[] text) {
- super.onProgressUpdate(text);
- dialog.setMessage(text[0]);
- if (text.length > 1 && text[1] != null) {
- dialog.setMax(Integer.valueOf(text[1]));
- } if (text.length > 2) {
- dialog.setProgress(dialog.getProgress() + 1);
- } if (text.length > 3 && text[3] != null) {
- dialog.setIndeterminate(Boolean.getBoolean(text[3]));
- }
- }
-
- @Override
- protected void onPostExecute(Throwable th) {
- super.onPostExecute(th);
- dialog.dismiss();
-
- new RefreshVersionListTask().execute();
-
- if (th == null) {
- Toast.makeText(MCLauncherActivity.this, R.string.toast_optifine_success, Toast.LENGTH_SHORT).show();
- } else {
- Tools.showError(MCLauncherActivity.this, th);
- }
- }
- }
-
private class ViewPagerAdapter extends FragmentPagerAdapter {
List fragmentList = new ArrayList<>();
diff --git a/app/src/main/java/net/kdt/pojavlaunch/MainActivity.java b/app/src/main/java/net/kdt/pojavlaunch/MainActivity.java
index 73bef549e..738481e10 100644
--- a/app/src/main/java/net/kdt/pojavlaunch/MainActivity.java
+++ b/app/src/main/java/net/kdt/pojavlaunch/MainActivity.java
@@ -68,7 +68,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
}
}
};
- private MinecraftGLView glSurfaceView;
+ private MinecraftGLView minecraftGLView;
private int guiScale;
private DisplayMetrics displayMetrics;
public boolean hiddenTextIgnoreUpdate = true;
@@ -110,6 +110,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
private Button[] controlButtons;
+ private File logFile;
private PrintStream logStream;
/*
@@ -122,10 +123,10 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
private boolean isLogAllow = false;
// private int navBarHeight = 40;
- private static final int LTYPE_PROCESS = 0;
- private static final int LTYPE_INVOCATION = 1;
- private static final int LTYPE_CREATEJAVAVM = 2;
- private static final int LAUNCH_TYPE;
+ public static final int LTYPE_PROCESS = 0;
+ public static final int LTYPE_INVOCATION = 1;
+ public static final int LTYPE_CREATEJAVAVM = 2;
+ public static final int LAUNCH_TYPE;
static {
int launchTypeFinal = LTYPE_INVOCATION;
@@ -155,7 +156,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
setContentView(R.layout.main);
try {
- File logFile = new File(Tools.MAIN_PATH, "latestlog.txt");
+ logFile = new File(Tools.MAIN_PATH, "latestlog.txt");
logFile.delete();
logFile.createNewFile();
logStream = new PrintStream(logFile.getAbsolutePath());
@@ -175,52 +176,6 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
}
});
- ExitManager.setExitTrappedListener(new ExitManager.ExitTrappedListener(){
- @Override
- public void onExitTrapped()
- {
- logStream.close();
- runOnUiThread(new Runnable(){
-
- @Override
- public void run() {
- isExited = true;
-
- AlertDialog.Builder d = new AlertDialog.Builder(MainActivity.this);
- d.setTitle(R.string.mcn_exit_title);
-
- try {
- File crashLog = Tools.lastFileModified(Tools.crashPath);
- if(crashLog != null && Tools.read(crashLog.getAbsolutePath()).startsWith("---- Minecraft Crash Report ----")){
- d.setMessage(R.string.mcn_exit_crash);
- } else {
- fullyExit();
- return;
- }
- } catch (Throwable th) {
- d.setMessage(getStr(R.string.mcn_exit_errcrash) + "\n" + Log.getStackTraceString(th));
- }
- d.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
-
- @Override
- public void onClick(DialogInterface p1, int p2)
- {
- fullyExit();
- }
- });
- d.setCancelable(false);
- d.show();
- }
- });
- }
- });
-
- try {
- ExitManager.disableSystemExit();
- } catch (Throwable th) {
- Log.w(Tools.APP_NAME, "Could not disable System.exit() method!", th);
- }
-
mProfile = PojavProfile.getCurrentProfileContent(this);
mVersionInfo = Tools.getVersionInfo(mProfile.getVersion());
@@ -259,7 +214,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
- case R.id.nav_forceclose: dialogForceClose();
+ case R.id.nav_forceclose: dialogForceClose(MainActivity.this);
break;
case R.id.nav_viewlog: openLogOutput();
break;
@@ -330,22 +285,18 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
this.toggleControlButton.setOnClickListener(this);
this.zoomButton.setVisibility(mVersionInfo.optifineLib == null ? View.GONE : View.VISIBLE);
- this.glSurfaceView = (MinecraftGLView) findViewById(R.id.main_game_render_view);
+ this.minecraftGLView = (MinecraftGLView) findViewById(R.id.main_game_render_view);
ControlButton[] specialButtons = ControlButton.getSpecialButtons();
specialButtons[0].specialButtonListener = new View.OnClickListener(){
-
@Override
- public void onClick(View p1)
- {
+ public void onClick(View view) {
showKeyboard();
}
};
specialButtons[1].specialButtonListener = new View.OnClickListener(){
-
@Override
- public void onClick(View view)
- {
+ public void onClick(View view) {
MainActivity.this.onClick(toggleControlButton);
}
};
@@ -382,11 +333,11 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
if (isPointerCaptureSupported()) {
if (!AndroidDisplay.grab && isCapturing) {
- pointerSurface.releaseCapture(); // glSurfaceView.releasePointerCapture();
+ pointerSurface.releaseCapture(); // minecraftGLView.releasePointerCapture();
isCapturing = false;
} else if (AndroidDisplay.grab && !isCapturing) {
- glSurfaceView.requestFocus();
- pointerSurface.requestCapture(); // glSurfaceView.requestPointerCapture();
+ minecraftGLView.requestFocus();
+ pointerSurface.requestCapture(); // minecraftGLView.requestPointerCapture();
isCapturing = true;
}
}
@@ -465,9 +416,9 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
// System.loadLibrary("Regal");
- glSurfaceView.setFocusable(true);
- glSurfaceView.setFocusableInTouchMode(true);
- glSurfaceView.setEGLContextClientVersion(2);
+ minecraftGLView.setFocusable(true);
+ minecraftGLView.setFocusableInTouchMode(true);
+ // minecraftGLView.setEGLContextClientVersion(2);
glTouchListener = new OnTouchListener(){
private boolean isTouchInHotbar = false;
@@ -478,7 +429,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
// System.out.println("Pre touch, isTouchInHotbar=" + Boolean.toString(isTouchInHotbar) + ", action=" + MotionEvent.actionToString(e.getActionMasked()));
int x = ((int) e.getX()) / scaleFactor;
- int y = (glSurfaceView.getHeight() - ((int) e.getY())) / scaleFactor;
+ int y = (minecraftGLView.getHeight() - ((int) e.getY())) / scaleFactor;
int hudKeyHandled = handleGuiBar(x, y, e);
if (!AndroidDisplay.grab && gestureDetector.onTouchEvent(e)) {
if (hudKeyHandled != -1) {
@@ -660,7 +611,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
};
if (isPointerCaptureSupported()) {
- this.pointerSurface = new PointerOreoWrapper(glSurfaceView);
+ this.pointerSurface = new PointerOreoWrapper(minecraftGLView);
this.pointerSurface.setOnCapturedPointerListener(new PointerOreoWrapper.OnCapturedPointerListener(){
@Override
public boolean onCapturedPointer(View view, MotionEvent event) {
@@ -669,7 +620,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
});
}
- glSurfaceView.setOnHoverListener(new View.OnHoverListener(){
+ minecraftGLView.setOnHoverListener(new View.OnHoverListener(){
@Override
public boolean onHover(View p1, MotionEvent p2) {
if (!AndroidDisplay.grab && mIsResuming) {
@@ -678,62 +629,56 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
return true;
}
});
- glSurfaceView.setOnTouchListener(glTouchListener);
- glSurfaceView.setRenderer(new GLTextureView.Renderer() {
+ minecraftGLView.setOnTouchListener(glTouchListener);
+ minecraftGLView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener(){
+
+ private boolean isCalled = false;
@Override
- public void onSurfaceDestroyed(GL10 gl) {
- Log.d(Tools.APP_NAME, "Surface destroyed.");
- }
-
- @Override
- public void onSurfaceCreated(GL10 gl, javax.microedition.khronos.egl.EGLConfig p2)
- {
+ public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
+ AndroidDisplay.windowWidth = width;
+ AndroidDisplay.windowHeight = height;
calculateMcScale();
-
- EGL10 egl10 = (EGL10) EGLContext.getEGL();
- AndroidContextImplementation.theEgl = egl10;
- AndroidContextImplementation.context = egl10.eglGetCurrentContext();
- AndroidContextImplementation.display = egl10.eglGetCurrentDisplay();
- AndroidContextImplementation.read = egl10.eglGetCurrentSurface(EGL10.EGL_READ);
- AndroidContextImplementation.draw = egl10.eglGetCurrentSurface(EGL10.EGL_DRAW);
- System.out.println(new StringBuffer().append("Gave up context: ").append(AndroidContextImplementation.context).toString());
+ // Should we do that?
+ if (!isCalled) {
+ isCalled = true;
+
+ JREUtils.setupBridgeWindow(new Surface(texture));
+
+ new Thread(new Runnable(){
- // Does it required anymore?
- // AndroidDisplay.windowWidth += navBarHeight;
-
- if (LAUNCH_TYPE != LTYPE_PROCESS) {
- BinaryExecutor.setupBridgeEGL();
- egl10.eglMakeCurrent(AndroidContextImplementation.display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
- }
-
- new Thread(new Runnable(){
-
- @Override
- public void run() {
- try {
- Thread.sleep(200);
- runCraft();
- } catch (Throwable e) {
- Tools.showError(MainActivity.this, e, true);
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(200);
+ runCraft();
+ } catch (Throwable e) {
+ Tools.showError(MainActivity.this, e, true);
+ }
}
- }
- }).start();
+ }).start();
+ }
}
- @Override
- public void onDrawFrame(GL10 gl) {
- //mkToast("onDrawFrame");
- }
@Override
- public void onSurfaceChanged(GL10 gl, int width, int height) {
- AndroidDisplay.windowWidth = width / scaleFactor;
- AndroidDisplay.windowHeight = height / scaleFactor;
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
+ AndroidDisplay.windowWidth = width;
+ AndroidDisplay.windowHeight = height;
+ calculateMcScale();
+
+ // TODO: Implement this method for GLFW window size callback
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture texture) {
+
}
});
- glSurfaceView.setPreserveEGLContextOnPause(true);
- glSurfaceView.setRenderMode(MinecraftGLView.RENDERMODE_CONTINUOUSLY);
- // glSurfaceView.requestRender();
} catch (Throwable e) {
e.printStackTrace();
Tools.showError(this, e, true);
@@ -790,7 +735,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
public void onResume() {
super.onResume();
mIsResuming = true;
- if (glSurfaceView != null) glSurfaceView.requestRender();
+ // if (minecraftGLView != null) minecraftGLView.requestRender();
final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
final View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(uiOptions);
@@ -800,8 +745,8 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
/*
- if (hasFocus && glSurfaceView.getVisibility() == View.GONE) {
- glSurfaceView.setVisibility(View.VISIBLE);
+ if (hasFocus && minecraftGLView.getVisibility() == View.GONE) {
+ minecraftGLView.setVisibility(View.VISIBLE);
}
*/
}
@@ -884,11 +829,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
}
public static void fullyExit() {
- if (!ExitManager.isExiting()) {
- ExitManager.enableSystemExit();
- System.exit(0);
- }
- ExitManager.stopExitLoop();
+ System.exit(0);
}
public void forceUserHome(String s) throws Exception {
@@ -1001,14 +942,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
return args;
}
- private ShellProcessOperation mLaunchShell;
- private void setEnvironment(String name, String value) throws ErrnoException, IOException {
- if (LAUNCH_TYPE == LTYPE_PROCESS) {
- mLaunchShell.writeToProcess("export " + name + "=" + value);
- } else {
- Os.setenv(name, value, true);
- }
- }
+ public static ShellProcessOperation mLaunchShell;
private static void startStrace(int pid) throws Exception {
String[] straceArgs = new String[] {"/system/bin/strace",
@@ -1029,16 +963,12 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
// javaArgList.add("-Xms512m");
javaArgList.add("-Xmx512m");
- /*
- javaArgList.add("-Djava.library.path=" +
- // TODO lwjgl2 vs lwjgl3 native path
- getApplicationInfo().nativeLibraryDir
- );
- */
javaArgList.add("-Djava.home=" + Tools.homeJreDir);
+ javaArgList.add("-Djava.io.tmpdir=" + getCacheDir().getAbsolutePath());
javaArgList.add("-Dos.name=Linux");
+ // javaArgList.add("-Dorg.lwjgl.libname=liblwjgl3.so");
// javaArgList.add("-Dorg.lwjgl.system.jemalloc.libname=libjemalloc.so");
javaArgList.add("-Dorg.lwjgl.opengl.libname=libgl04es.so");
// javaArgList.add("-Dorg.lwjgl.opengl.libname=libRegal.so");
@@ -1052,6 +982,8 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
javaArgList.add("-Dglfwstub.windowWidth=" + AndroidDisplay.windowWidth);
javaArgList.add("-Dglfwstub.windowHeight=" + AndroidDisplay.windowHeight);
+ javaArgList.add("-Dglfwstub.initEgl=false");
+
if (mVersionInfo.arguments != null) {
// Minecraft 1.13+
@@ -1092,35 +1024,11 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
mLaunchShell.initInputStream(this);
}
- String libName = System.getProperty("os.arch").contains("64") ? "lib64" : "lib";
- String ldLibraryPath = (
- // To make libjli.so ignore re-execute
- Tools.homeJreDir + "/lib/server:" +
-
- "/system/" + libName + ":" +
- "/vendor/" + libName + ":" +
- "/vendor/" + libName + "/hw:" +
-
- getApplicationInfo().nativeLibraryDir + ":" +
-
- Tools.homeJreDir + "/lib/jli:" +
- Tools.homeJreDir + "/lib"
-
-
- // "$JAVA_HOME/lib:$JAVA_HOME/lib/jli:$JAVA_HOME/lib/server"
- );
-
- setEnvironment("JAVA_HOME", Tools.homeJreDir);
- setEnvironment("HOME", Tools.MAIN_PATH);
- setEnvironment("TMPDIR", getCacheDir().getAbsolutePath());
- // setEnvironment("LIBGL_MIPMAP", "3");
- setEnvironment("MESA_GLSL_CACHE_DIR", getCacheDir().getAbsolutePath());
- setEnvironment("LD_LIBRARY_PATH", ldLibraryPath);
- setEnvironment("PATH", Tools.homeJreDir + "/bin:" + Os.getenv("PATH"));
-
// can fix java?
// setEnvironment("ORIGIN", Tools.homeJreDir + "/lib");
+ JREUtils.setJavaEnvironment(this);
+
if (LAUNCH_TYPE == LTYPE_PROCESS) {
mLaunchShell.writeToProcess("cd $HOME");
@@ -1130,8 +1038,23 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
Tools.showError(this, new ErrnoException("java", exitCode), false);
}
} else { // Type Invocation
- final FileDescriptor logFile = BinaryExecutor.redirectStdio();
-
+ // Is it need?
+ /*
+ Os.dup2(FileDescriptor.err, OsConstants.STDERR_FILENO);
+ Os.dup2(FileDescriptor.out, OsConstants.STDOUT_FILENO);
+ */
+
+ JREUtils.redirectStdio();
+ // DEPRECATED constructor (String) api 29
+ /*
+ FileObserver fobs = new FileObserver(logFile.getAbsolutePath(), FileObserver.MODIFY){
+ @Override
+ public void onEvent(int event, String str) {
+
+ }
+ };
+ fobs.startWatching();
+ */
new Thread(new Runnable() {
@Override
public void run() {
@@ -1148,9 +1071,8 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
}
}, "RuntimeLogThread").start();
- BinaryExecutor.setLdLibraryPath(ldLibraryPath);
- BinaryExecutor.initJavaRuntime();
- BinaryExecutor.chdir(Tools.MAIN_PATH);
+ JREUtils.initJavaRuntime();
+ JREUtils.chdir(Tools.MAIN_PATH);
if (new File(Tools.MAIN_PATH, "strace.txt").exists()) {
startStrace(android.os.Process.myTid());
@@ -1314,9 +1236,8 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
((Button) view).setText(isVis ? R.string.control_mouseoff: R.string.control_mouseon);
}
- public void dialogForceClose()
- {
- new AlertDialog.Builder(this)
+ public static void dialogForceClose(Context ctx) {
+ new AlertDialog.Builder(ctx)
.setMessage(R.string.mcn_exit_confirm)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
@@ -1350,6 +1271,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
@Override
public void onBackPressed() {
// Prevent back
+ // Catch back as Esc keycode at another place
}
public void hideKeyboard() {
@@ -1365,7 +1287,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
public void showKeyboard() {
((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
- glSurfaceView.requestFocus();
+ minecraftGLView.requestFocus();
}
private void setRightOverride(boolean val) {
diff --git a/app/src/main/java/net/kdt/pojavlaunch/MinecraftGLView.java b/app/src/main/java/net/kdt/pojavlaunch/MinecraftGLView.java
index 8068650d1..0373e660e 100644
--- a/app/src/main/java/net/kdt/pojavlaunch/MinecraftGLView.java
+++ b/app/src/main/java/net/kdt/pojavlaunch/MinecraftGLView.java
@@ -5,7 +5,7 @@ import android.util.*;
import android.view.*;
import com.kdt.glsupport.*;
-public class MinecraftGLView extends GLTextureView
+public class MinecraftGLView extends TextureView
{
// private View.OnTouchListener mTouchListener;
public MinecraftGLView(Context context) {
@@ -17,18 +17,5 @@ public class MinecraftGLView extends GLTextureView
super(context, attributeSet);
//setPreserveEGLContextOnPause(true);
}
-
- @Override
- public void setOnTouchListener(View.OnTouchListener l)
- {
- super.setOnTouchListener(l);
- // mTouchListener = l;
- }
-
- @Override
- public void setOnClickListener(View.OnClickListener l)
- {
- super.setOnClickListener(l);
- }
}
diff --git a/app/src/main/java/net/kdt/pojavlaunch/Tools.java b/app/src/main/java/net/kdt/pojavlaunch/Tools.java
index 5b9a0278e..28e40407f 100644
--- a/app/src/main/java/net/kdt/pojavlaunch/Tools.java
+++ b/app/src/main/java/net/kdt/pojavlaunch/Tools.java
@@ -84,6 +84,7 @@ public final class Tools
String[] classpath = generateLibClasspath(info);
// Debug: LWJGL 3 override
+ File lwjgl2Folder = new File(Tools.MAIN_PATH, "lwjgl2");
File lwjgl3Folder = new File(Tools.MAIN_PATH, "lwjgl3");
if (info.arguments != null && lwjgl3Folder.exists()) {
for (File file: lwjgl3Folder.listFiles()) {
@@ -91,6 +92,12 @@ public final class Tools
libStr.append(file.getAbsolutePath() + ":");
}
}
+ } else if (lwjgl2Folder.exists()) {
+ for (File file: lwjgl2Folder.listFiles()) {
+ if (file.getName().endsWith(".jar")) {
+ libStr.append(file.getAbsolutePath() + ":");
+ }
+ }
}
if (isClientFirst) {
diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk
new file mode 100644
index 000000000..01952f1c1
--- /dev/null
+++ b/app/src/main/jni/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+# Link GLESv2 for test
+LOCAL_LDLIBS := -ldl -llog -landroid -lEGL -lGLESv2
+LOCAL_MODULE := pojavexec
+LOCAL_CFLAGS += -DGLES_TEST
+LOCAL_SRC_FILES := \
+ egl_bridge.c \
+ jre_launcher.c \
+ utils.c
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/app/src/main/jni/Application.mk b/app/src/main/jni/Application.mk
new file mode 100644
index 000000000..c1c040a55
--- /dev/null
+++ b/app/src/main/jni/Application.mk
@@ -0,0 +1,5 @@
+# NDK_TOOLCHAIN_VERSION := 4.9
+APP_PLATFORM := android-21
+APP_STL := system
+APP_ABI := armeabi-v7a
+# x86 arm64-v8a x86_64
diff --git a/app/src/main/jni/egl_bridge.c b/app/src/main/jni/egl_bridge.c
new file mode 100644
index 000000000..8f523dc83
--- /dev/null
+++ b/app/src/main/jni/egl_bridge.c
@@ -0,0 +1,170 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef GLES_TEST
+#include
+#endif
+
+#include
+#include
+
+struct PotatoBridge {
+ ANativeWindow* androidWindow;
+ void* androidDisplay;
+
+ void* eglContext;
+ void* eglDisplay;
+ void* eglSurface;
+/*
+ void* eglSurfaceRead;
+ void* eglSurfaceDraw;
+*/
+};
+struct PotatoBridge potatoBridge;
+
+JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_JREUtils_setupBridgeWindow(JNIEnv* env, jclass clazz, jobject surface) {
+ potatoBridge.androidDisplay = EGL_DEFAULT_DISPLAY;
+ potatoBridge.androidWindow = ANativeWindow_fromSurface(env, surface);
+}
+
+// Called from JNI_OnLoad of liblwjgl_opengl32
+void pojav_openGLOnLoad() {
+
+}
+void pojav_openGLOnUnload() {
+
+}
+
+JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_GLFW_nativeEglInit(JNIEnv* env, jclass clazz) {
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_GLFW_nativeEglMakeCurrent(JNIEnv* env, jclass clazz) {
+ printf("EGLBridge: Initializing\n");
+ printf("ANativeWindow pointer = %p\n", potatoBridge.androidWindow);
+
+ potatoBridge.eglDisplay = eglGetDisplay(potatoBridge.androidDisplay);
+ if (potatoBridge.eglDisplay == EGL_NO_DISPLAY) {
+ printf("Error: eglGetDefaultDisplay() failed: %p\n", eglGetError());
+ return JNI_FALSE;
+ }
+
+ eglMakeCurrent(potatoBridge.eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ if (!eglInitialize(potatoBridge.eglDisplay, NULL, NULL)) {
+ printf("Error: eglInitialize() failed\n");
+ return JNI_FALSE;
+ }
+
+ static const EGLint attribs[] = {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 0,
+ EGL_DEPTH_SIZE, 16,
+ EGL_STENCIL_SIZE, 0,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+ static const EGLint ctx_attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ EGLConfig config;
+ EGLint num_configs;
+ EGLint vid;
+
+ if (!eglChooseConfig(potatoBridge.eglDisplay, attribs, &config, 1, &num_configs)) {
+ printf("Error: couldn't get an EGL visual config\n");
+ return JNI_FALSE;
+ }
+
+ assert(config);
+ assert(num_configs > 0);
+
+ if (!eglGetConfigAttrib(potatoBridge.eglDisplay, config, EGL_NATIVE_VISUAL_ID, &vid)) {
+ printf("Error: eglGetConfigAttrib() failed\n");
+ return JNI_FALSE;
+ }
+
+ eglBindAPI(EGL_OPENGL_ES_API);
+
+ potatoBridge.eglContext = eglCreateContext(potatoBridge.eglDisplay, config, EGL_NO_CONTEXT, ctx_attribs);
+ if (!potatoBridge.eglContext) {
+ printf("Error: eglCreateContext failed\n");
+ return JNI_FALSE;
+ }
+
+ // test eglQueryContext()
+ {
+ EGLint val;
+ eglQueryContext(potatoBridge.eglDisplay, potatoBridge.eglContext, EGL_CONTEXT_CLIENT_VERSION, &val);
+ assert(val == 2);
+ }
+
+ potatoBridge.eglSurface = eglCreateWindowSurface(potatoBridge.eglDisplay, config, potatoBridge.androidWindow, NULL);
+
+ if (!potatoBridge.eglSurface) {
+ printf("Error: eglCreateWindowSurface failed: %p\n", eglGetError());
+ return JNI_FALSE;
+ }
+
+ // sanity checks
+ {
+ EGLint val;
+ assert(eglGetConfigAttrib(potatoBridge.eglDisplay, config, EGL_SURFACE_TYPE, &val));
+ assert(val & EGL_WINDOW_BIT);
+ }
+
+/*
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_GLFW_nativeEglMakeCurrent(JNIEnv* env, jclass clazz) {
+*/
+ printf("EGLBridge: Making current\n");
+ printf("EGLContext=%p, EGLDisplay=%p, EGLSurface=%p\n",
+ potatoBridge.eglContext,
+ potatoBridge.eglDisplay,
+ potatoBridge.eglSurface
+ );
+
+ EGLBoolean success = eglMakeCurrent(potatoBridge.eglDisplay, potatoBridge.eglSurface, potatoBridge.eglSurface, potatoBridge.eglContext);
+ if (success == EGL_FALSE) {
+ printf("Error: eglMakeCurrent() failed: %p\n", eglGetError());
+ }
+
+ // Test
+#ifdef GLES_TEST
+ glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(potatoBridge.eglDisplay, potatoBridge.eglSurface);
+#endif
+
+ return success == EGL_TRUE ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_GLFW_nativeEglTerminate(JNIEnv* env, jclass clazz) {
+ printf("EGLBridge: Terminating\n");
+ eglMakeCurrent(potatoBridge.eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroySurface(potatoBridge.eglDisplay, potatoBridge.eglSurface);
+ eglDestroyContext(potatoBridge.eglDisplay, potatoBridge.eglContext);
+ eglTerminate(potatoBridge.eglDisplay);
+ eglReleaseThread();
+
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_GLFW_nativeEglSwapBuffers(JNIEnv *env, jclass clazz) {
+ return eglSwapBuffers(potatoBridge.eglDisplay, potatoBridge.eglSurface);
+}
+
+JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_GLFW_nativeEglSwapInterval(JNIEnv *env, jclass clazz, jint interval) {
+ return eglSwapInterval(potatoBridge.eglDisplay, interval);
+}
+
diff --git a/app/src/main/jni/jre_launcher.c b/app/src/main/jni/jre_launcher.c
new file mode 100644
index 000000000..06dc15d85
--- /dev/null
+++ b/app/src/main/jni/jre_launcher.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+#include
+#include
+#include
+#include
+#include
+// Boardwalk: missing include
+#include
+
+#include "log.h"
+
+#include "utils.h"
+
+// PojavLancher: fixme: are these wrong?
+#define FULL_VERSION "1.9.0-internal"
+#define DOT_VERSION "1.9"
+
+typedef jint JNI_CreateJavaVM_func(JavaVM **pvm, void **penv, void *args);
+
+typedef jint JLI_Launch_func(int argc, char ** argv, /* main argc, argc */
+ int jargc, const char** jargv, /* java args */
+ int appclassc, const char** appclassv, /* app classpath */
+ const char* fullversion, /* full version defined */
+ const char* dotversion, /* dot version defined */
+ const char* pname, /* program name */
+ const char* lname, /* launcher name */
+ jboolean javaargs, /* JAVA_ARGS */
+ jboolean cpwildcard, /* classpath wildcard*/
+ jboolean javaw, /* windows-only javaw */
+ jint ergo /* ergonomics class policy */
+);
+
+JavaVM *runtimeJavaVMPtr = NULL;;
+JNIEnv *runtimeJNIEnvPtr = NULL;
+
+JavaVM *dalvikJavaVMPtr = NULL;
+JNIEnv *dalvikJNIEnvPtr = NULL;
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ if (dalvikJavaVMPtr == NULL) {
+ //Save dalvik global JavaVM pointer
+ dalvikJavaVMPtr = vm;
+ LOGD("JNI_OnLoad calling GetEnv()");
+ JNIEnv* env = NULL;
+ (*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4);
+/* Boardwalk: not used
+ LOGD("JNI_OnLoad calling initDalvikProxySelectorData()");
+ initDalvikProxySelectorData(env);
+*/
+ }
+ LOGD("JNI_OnLoad returning()");
+ return JNI_VERSION_1_4;
+}
+
+static void logArgs(int argc, char** argv) {
+/* BlockLauncher: disable logging
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ LOGD("arg[%d]: %s", i, argv[i]);
+ }
+*/
+}
+
+JNIEXPORT jint JNICALL Java_com_oracle_dalvik_VMLauncher_createLaunchMainJVM(JNIEnv *env, jclass clazz, jobjectArray vmArgArr, jstring mainClassStr, jobjectArray mainArgArr) {
+ void *libjvm = dlopen("libjvm.so", RTLD_NOW + RTLD_GLOBAL);
+ if (libjvm == NULL) {
+ LOGE("dlopen failed to open libjvm.so (dlerror %s).", dlerror());
+ return -1;
+ }
+
+ JNI_CreateJavaVM_func *jl_JNI_CreateJavaVM = (JNI_CreateJavaVM_func *) dlsym(libjvm, "JNI_CreateJavaVM");
+ if (jl_JNI_CreateJavaVM == NULL) {
+ LOGE("dlsym failed to get JNI_CreateJavaVM (dlerror %s).", dlerror());
+ return -1;
+ }
+
+ int vm_argc = (*env)->GetArrayLength(env, vmArgArr);
+ char **vm_argv = convert_to_char_array(env, vmArgArr);
+
+ int main_argc = (*env)->GetArrayLength(env, mainArgArr);
+ char **main_argv = convert_to_char_array(env, mainArgArr);
+
+ JavaVMInitArgs vm_args;
+ JavaVMOption options[vm_argc];
+ for (int i = 0; i < vm_argc; i++) {
+ options[i].optionString = vm_argv[i];
+ }
+ vm_args.version = JNI_VERSION_1_6;
+ vm_args.options = options;
+ vm_args.nOptions = vm_argc;
+ vm_args.ignoreUnrecognized = JNI_FALSE;
+
+ jint res = (jint) jl_JNI_CreateJavaVM(&runtimeJavaVMPtr, (void**)&runtimeJNIEnvPtr, &vm_args);
+ // delete options;
+
+ char *main_class_c = (*env)->GetStringUTFChars(env, mainClassStr, 0);
+
+ jclass mainClass = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, main_class_c);
+ jmethodID mainMethod = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, mainClass, "main", "([Ljava/lang/String;)V");
+
+ // Need recreate jobjectArray to make JNIEnv is 'runtimeJNIEnvPtr'.
+ jobjectArray runtime_main_argv = convert_from_char_array(runtimeJNIEnvPtr, main_argv, main_argc);
+ (*runtimeJNIEnvPtr)->CallStaticVoidMethod(runtimeJNIEnvPtr, mainClass, mainMethod, runtime_main_argv);
+
+ (*env)->ReleaseStringUTFChars(env, mainClassStr, main_class_c);
+ free_char_array(env, mainArgArr, main_argv);
+ free_char_array(env, vmArgArr, vm_argv);
+
+ return res;
+}
+
+static jint launchJVM(int argc, char** argv) {
+ logArgs(argc, argv);
+
+ void* libjli = dlopen("libjli.so", RTLD_LAZY | RTLD_GLOBAL);
+ // Boardwalk: silence
+ // LOGD("JLI lib = %x", (int)libjli);
+ if (NULL == libjli) {
+ LOGE("JLI lib = NULL: %s", dlerror());
+ return 0;
+ }
+ LOGD("Found JLI lib");
+
+ JLI_Launch_func *pJLI_Launch =
+ (JLI_Launch_func *)dlsym(libjli, "JLI_Launch");
+ // Boardwalk: silence
+ // LOGD("JLI_Launch = 0x%x", *(int*)&pJLI_Launch);
+
+ if (NULL == pJLI_Launch) {
+ LOGE("JLI_Launch = NULL");
+ return 0;
+ }
+
+ LOGD("Calling JLI_Launch");
+
+ return pJLI_Launch(argc, argv,
+ 0, NULL, 0, NULL, FULL_VERSION,
+ DOT_VERSION, *argv, *argv, /* "java", "openjdk", */
+ JNI_FALSE, JNI_TRUE, JNI_FALSE, 0);
+}
+
+/*
+ * Class: com_oracle_embedded_launcher_VMLauncher
+ * Method: launchJVM
+ * Signature: ([Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_oracle_dalvik_VMLauncher_launchJVM(JNIEnv *env, jclass clazz, jobjectArray argsArray) {
+ jint res = 0;
+ // int i;
+
+ // Save dalvik JNIEnv pointer for JVM launch thread
+ dalvikJNIEnvPtr = env;
+
+ if (argsArray == NULL) {
+ LOGE("Args array null, returning");
+ //handle error
+ return 0;
+ }
+
+ int argc = (*env)->GetArrayLength(env, argsArray);
+ char **argv = convert_to_char_array(env, argsArray);
+
+ LOGD("Done processing args");
+
+ res = launchJVM(argc, argv);
+
+ LOGD("Freeing args");
+ free_char_array(env, argsArray, argv);
+
+ LOGD("Free done");
+
+ return res;
+}
+
+
diff --git a/app/src/main/jni/log.h b/app/src/main/jni/log.h
new file mode 100644
index 000000000..f46b02cd0
--- /dev/null
+++ b/app/src/main/jni/log.h
@@ -0,0 +1,26 @@
+#ifdef __ANDROID__
+#include
+
+#define TAG "LaunchJVM"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __ANDROID__
+ #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
+ #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
+ #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
+ #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
+#else
+ #define LOGE(...) printf(__VA_ARGS__)
+ #define LOGW(...) printf(__VA_ARGS__)
+ #define LOGI(...) printf(__VA_ARGS__)
+ #define LOGD(...) printf(__VA_ARGS__)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/app/src/main/jni/utils.c b/app/src/main/jni/utils.c
new file mode 100644
index 000000000..a973d7350
--- /dev/null
+++ b/app/src/main/jni/utils.c
@@ -0,0 +1,162 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "log.h"
+
+#include "utils.h"
+
+typedef int (*Main_Function_t)(int, char**);
+typedef void (*android_update_LD_LIBRARY_PATH_t)(char*);
+
+long shared_awt_surface;
+
+char** convert_to_char_array(JNIEnv *env, jobjectArray jstringArray) {
+ int num_rows = (*env)->GetArrayLength(env, jstringArray);
+ char **cArray = (char **) malloc(num_rows * sizeof(char*));
+ jstring row;
+
+ for (int i = 0; i < num_rows; i++) {
+ row = (jstring) (*env)->GetObjectArrayElement(env, jstringArray, i);
+ cArray[i] = (char*)(*env)->GetStringUTFChars(env, row, 0);
+ }
+
+ return cArray;
+}
+
+jobjectArray convert_from_char_array(JNIEnv *env, char **charArray, int num_rows) {
+ jobjectArray resultArr = (*env)->NewObjectArray(env, num_rows, (*env)->FindClass(env, "java/lang/String"), NULL);
+ jstring row;
+
+ for (int i = 0; i < num_rows; i++) {
+ row = (jstring) (*env)->NewStringUTF(env, charArray[i]);
+ (*env)->SetObjectArrayElement(env, resultArr, i, row);
+ }
+
+ return resultArr;
+}
+
+void free_char_array(JNIEnv *env, jobjectArray jstringArray, const char **charArray) {
+ int num_rows = (*env)->GetArrayLength(env, jstringArray);
+ jstring row;
+
+ for (int i = 0; i < num_rows; i++) {
+ row = (jstring) (*env)->GetObjectArrayElement(env, jstringArray, i);
+ (*env)->ReleaseStringUTFChars(env, row, charArray[i]);
+ }
+}
+
+JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_JREUtils_setupBridgeSurfaceAWT(JNIEnv *env, jclass clazz, jlong surface) {
+ shared_awt_surface = surface;
+}
+
+JNIEXPORT jlong JNICALL Java_android_view_Surface_nativeGetBridgeSurfaceAWT(JNIEnv *env, jclass clazz) {
+ return (jlong) shared_awt_surface;
+}
+
+JNIEXPORT jint JNICALL Java_android_os_OpenJDKNativeRegister_nativeRegisterNatives(JNIEnv *env, jclass clazz, jstring registerSymbol) {
+ const char *register_symbol_c = (*env)->GetStringUTFChars(env, registerSymbol, 0);
+ void *symbol = dlsym(RTLD_DEFAULT, register_symbol_c);
+ if (symbol == NULL) {
+ printf("dlsym %s failed: %s\n", register_symbol_c, dlerror());
+ return -1;
+ }
+
+ int (*registerNativesForClass)(JNIEnv*) = symbol;
+ int result = registerNativesForClass(env);
+ (*env)->ReleaseStringUTFChars(env, registerSymbol, register_symbol_c);
+
+ return (jint) result;
+}
+
+JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_JREUtils_setLdLibraryPath(JNIEnv *env, jclass clazz, jstring ldLibraryPath) {
+ // jclass exception_cls = (*env)->FindClass(env, "java/lang/UnsatisfiedLinkError");
+
+ android_update_LD_LIBRARY_PATH_t android_update_LD_LIBRARY_PATH;
+
+ void *libdl_handle = dlopen("libdl.so", RTLD_LAZY);
+ void *updateLdLibPath = dlsym(libdl_handle, "android_update_LD_LIBRARY_PATH");
+ if (updateLdLibPath == NULL) {
+ updateLdLibPath = dlsym(libdl_handle, "__loader_android_update_LD_LIBRARY_PATH");
+ if (updateLdLibPath == NULL) {
+ char *dl_error_c = dlerror();
+ LOGE("Error getting symbol android_update_LD_LIBRARY_PATH: %s", dl_error_c);
+ // (*env)->ThrowNew(env, exception_cls, dl_error_c);
+ }
+ }
+
+ android_update_LD_LIBRARY_PATH = (android_update_LD_LIBRARY_PATH_t) updateLdLibPath;
+ const char* ldLibPathUtf = (*env)->GetStringUTFChars(env, ldLibraryPath, 0);
+ android_update_LD_LIBRARY_PATH(ldLibPathUtf);
+ (*env)->ReleaseStringUTFChars(env, ldLibraryPath, ldLibPathUtf);
+}
+
+JNIEXPORT jboolean JNICALL Java_net_kdt_pojavlaunch_JREUtils_dlopen(JNIEnv *env, jclass clazz, jstring name) {
+ const char *nameUtf = (*env)->GetStringUTFChars(env, name, 0);
+ void* handle = dlopen(nameUtf, RTLD_GLOBAL | RTLD_LAZY);
+ if (!handle) {
+ LOGE("dlopen %s failed: %s", nameUtf, dlerror());
+ } else {
+ LOGD("dlopen %s success", nameUtf);
+ }
+ (*env)->ReleaseStringUTFChars(env, name, nameUtf);
+ return handle != NULL;
+}
+
+JNIEXPORT jint JNICALL Java_net_kdt_pojavlaunch_JREUtils_chdir(JNIEnv *env, jclass clazz, jstring nameStr) {
+ const char *name = (*env)->GetStringUTFChars(env, nameStr, NULL);
+ int retval = chdir(name);
+ (*env)->ReleaseStringUTFChars(env, nameStr, name);
+ return retval;
+}
+
+JNIEXPORT jint JNICALL Java_net_kdt_pojavlaunch_JREUtils_executeBinary(JNIEnv *env, jclass clazz, jobjectArray cmdArgs) {
+ jclass exception_cls = (*env)->FindClass(env, "java/lang/UnsatisfiedLinkError");
+ jstring execFile = (*env)->GetObjectArrayElement(env, cmdArgs, 0);
+
+ char *exec_file_c = (char*) (*env)->GetStringUTFChars(env, execFile, 0);
+ void *exec_binary_handle = dlopen(exec_file_c, RTLD_LAZY);
+
+ // (*env)->ReleaseStringUTFChars(env, ldLibraryPath, ld_library_path_c);
+ (*env)->ReleaseStringUTFChars(env, execFile, exec_file_c);
+
+ char *exec_error_c = dlerror();
+ if (exec_error_c != NULL) {
+ LOGE("Error: %s", exec_error_c);
+ (*env)->ThrowNew(env, exception_cls, exec_error_c);
+ return -1;
+ }
+
+ Main_Function_t Main_Function;
+ Main_Function = (Main_Function_t) dlsym(exec_binary_handle, "main");
+
+ exec_error_c = dlerror();
+ if (exec_error_c != NULL) {
+ LOGE("Error: %s", exec_error_c);
+ (*env)->ThrowNew(env, exception_cls, exec_error_c);
+ return -1;
+ }
+
+ int cmd_argv = (*env)->GetArrayLength(env, cmdArgs);
+ char **cmd_args_c = convert_to_char_array(env, cmdArgs);
+ int result = Main_Function(cmd_argv, cmd_args_c);
+ free_char_array(env, cmdArgs, cmd_args_c);
+ return result;
+}
+
+// METHOD 2
+/*
+JNIEXPORT jint JNICALL Java_net_kdt_pojavlaunch_JREUtils_executeForkedBinary(JNIEnv *env, jclass clazz, jobjectArray cmdArgs) {
+ int x, status;
+ x = fork();
+ if (x > 0) {
+ wait(&status);
+ } else {
+ execvpe();
+ }
+ return status;
+}
+*/
+
diff --git a/app/src/main/jni/utils.h b/app/src/main/jni/utils.h
new file mode 100644
index 000000000..9eb52db49
--- /dev/null
+++ b/app/src/main/jni/utils.h
@@ -0,0 +1,9 @@
+#ifndef _BINARY_UTILS_H_
+#define _BINARY_UTILS_H_
+
+char** convert_to_char_array(JNIEnv *env, jobjectArray jstringArray);
+jobjectArray convert_from_char_array(JNIEnv *env, char **charArray, int num_rows);
+void free_char_array(JNIEnv *env, jobjectArray jstringArray, const char **charArray);
+
+#endif // _BINARY_UTILS_H_
+
diff --git a/app/src/main/jniLibs/armeabi-v7a/libbinexecutor.so b/app/src/main/jniLibs/armeabi-v7a/libbinexecutor.so
deleted file mode 100644
index a7c4104f6..000000000
Binary files a/app/src/main/jniLibs/armeabi-v7a/libbinexecutor.so and /dev/null differ
diff --git a/app/src/main/jniLibs/armeabi-v7a/liblwjgl.so b/app/src/main/jniLibs/armeabi-v7a/liblwjgl.so
index d027f70ed..dccd33a5b 100644
Binary files a/app/src/main/jniLibs/armeabi-v7a/liblwjgl.so and b/app/src/main/jniLibs/armeabi-v7a/liblwjgl.so differ
diff --git a/app/src/main/jniLibs/armeabi-v7a/liblwjgl_opengl.so b/app/src/main/jniLibs/armeabi-v7a/liblwjgl_opengl.so
index 8a71b82c7..16a712fe1 100644
Binary files a/app/src/main/jniLibs/armeabi-v7a/liblwjgl_opengl.so and b/app/src/main/jniLibs/armeabi-v7a/liblwjgl_opengl.so differ
diff --git a/app/src/main/jniLibs/armeabi-v7a/liblwjgl_stb.so b/app/src/main/jniLibs/armeabi-v7a/liblwjgl_stb.so
index d041485b4..5356f2e9b 100644
Binary files a/app/src/main/jniLibs/armeabi-v7a/liblwjgl_stb.so and b/app/src/main/jniLibs/armeabi-v7a/liblwjgl_stb.so differ
diff --git a/app/src/main/jniLibs_disabled/arm64-v8a/libbinexecutor.so b/app/src/main/jniLibs_disabled/arm64-v8a/libbinexecutor.so
index 17afd5af6..87494f496 100644
Binary files a/app/src/main/jniLibs_disabled/arm64-v8a/libbinexecutor.so and b/app/src/main/jniLibs_disabled/arm64-v8a/libbinexecutor.so differ
diff --git a/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl.so b/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl.so
index 84c246131..95084baf9 100644
Binary files a/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl.so and b/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl.so differ
diff --git a/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl_opengl.so b/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl_opengl.so
index 5a63edc4a..e0f2bffaf 100644
Binary files a/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl_opengl.so and b/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl_opengl.so differ
diff --git a/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl_stb.so b/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl_stb.so
index 63a1121fb..27c9f3106 100644
Binary files a/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl_stb.so and b/app/src/main/jniLibs_disabled/arm64-v8a/liblwjgl_stb.so differ
diff --git a/app/src/main/jniLibs_disabled/x86/libbinexecutor.so b/app/src/main/jniLibs_disabled/x86/libbinexecutor.so
index 44dedb9ca..319db32dc 100644
Binary files a/app/src/main/jniLibs_disabled/x86/libbinexecutor.so and b/app/src/main/jniLibs_disabled/x86/libbinexecutor.so differ
diff --git a/app/src/main/jniLibs_disabled/x86/liblwjgl.so b/app/src/main/jniLibs_disabled/x86/liblwjgl.so
index 821cac13e..596ec90ab 100644
Binary files a/app/src/main/jniLibs_disabled/x86/liblwjgl.so and b/app/src/main/jniLibs_disabled/x86/liblwjgl.so differ
diff --git a/app/src/main/jniLibs_disabled/x86/liblwjgl_opengl.so b/app/src/main/jniLibs_disabled/x86/liblwjgl_opengl.so
index 498f2b952..83c0b0685 100644
Binary files a/app/src/main/jniLibs_disabled/x86/liblwjgl_opengl.so and b/app/src/main/jniLibs_disabled/x86/liblwjgl_opengl.so differ
diff --git a/app/src/main/jniLibs_disabled/x86/liblwjgl_stb.so b/app/src/main/jniLibs_disabled/x86/liblwjgl_stb.so
index 049726864..bc46b37d9 100644
Binary files a/app/src/main/jniLibs_disabled/x86/liblwjgl_stb.so and b/app/src/main/jniLibs_disabled/x86/liblwjgl_stb.so differ
diff --git a/app/src/main/jniLibs_disabled/x86_64/libbinexecutor.so b/app/src/main/jniLibs_disabled/x86_64/libbinexecutor.so
index 35b7d35ae..ab86b718e 100644
Binary files a/app/src/main/jniLibs_disabled/x86_64/libbinexecutor.so and b/app/src/main/jniLibs_disabled/x86_64/libbinexecutor.so differ
diff --git a/app/src/main/jniLibs_disabled/x86_64/liblwjgl.so b/app/src/main/jniLibs_disabled/x86_64/liblwjgl.so
index abcf88002..6c752607a 100644
Binary files a/app/src/main/jniLibs_disabled/x86_64/liblwjgl.so and b/app/src/main/jniLibs_disabled/x86_64/liblwjgl.so differ
diff --git a/app/src/main/jniLibs_disabled/x86_64/liblwjgl_opengl.so b/app/src/main/jniLibs_disabled/x86_64/liblwjgl_opengl.so
index ee9bc1cbb..25a3c0ef5 100644
Binary files a/app/src/main/jniLibs_disabled/x86_64/liblwjgl_opengl.so and b/app/src/main/jniLibs_disabled/x86_64/liblwjgl_opengl.so differ
diff --git a/app/src/main/jniLibs_disabled/x86_64/liblwjgl_stb.so b/app/src/main/jniLibs_disabled/x86_64/liblwjgl_stb.so
index 035f5f8fa..3fcab30c9 100644
Binary files a/app/src/main/jniLibs_disabled/x86_64/liblwjgl_stb.so and b/app/src/main/jniLibs_disabled/x86_64/liblwjgl_stb.so differ
diff --git a/app/src/main/res/layout/install_mod.xml b/app/src/main/res/layout/install_mod.xml
new file mode 100644
index 000000000..b2c86494c
--- /dev/null
+++ b/app/src/main/res/layout/install_mod.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml
index fe422c044..408321dfd 100644
--- a/app/src/main/res/values-id/strings.xml
+++ b/app/src/main/res/values-id/strings.xml
@@ -48,7 +48,7 @@
Pilih sebuah keymap json
- Pilih sebuah mod untuk di tambah
+ Pilih sebuah mod untuk dipasang
Pilih jar-nya OptiFine
diff --git a/app/src/main/res/values/headings_array.xml b/app/src/main/res/values/headings_array.xml
index dfde68294..c1e73b695 100644
--- a/app/src/main/res/values/headings_array.xml
+++ b/app/src/main/res/values/headings_array.xml
@@ -1,9 +1,7 @@
- - @string/mcl_option_modmgr
-
- - @string/mcl_option_optifineinstall
+ - @string/mcl_option_modinstall
- @string/mcl_option_customcontrol
- @string/mcl_option_settings
- @string/mcl_option_about
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 48f139048..a3bf41737 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -48,8 +48,7 @@
Select a keymap json
- Select a mod to add
- Select OptiFine jar file
+ Select a mod to install
PojavLauncher has unexpectedly crashed
@@ -87,7 +86,7 @@
Options
Mod manager (no function)
- Install OptiFine
+ Install mod (Forge, LabyMod, Fabric,...)
Check for update
Custom controls
Settings