mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-12 14:16:58 -04:00
Merge branch 'v3_openjdk' of https://github.com/khanhduytran0/PojavLauncher.git into v3_openjdk
This commit is contained in:
commit
9bcf2de57c
27
.github/workflows/android.yml
vendored
Normal file
27
.github/workflows/android.yml
vendored
Normal file
@ -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
|
@ -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]
|
@ -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
|
||||
|
@ -5,9 +5,20 @@ android {
|
||||
dexOptions {
|
||||
javaMaxHeapSize "4g"
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
customDebug {
|
||||
storeFile file("debug.keystore")
|
||||
storePassword "android"
|
||||
keyAlias "androiddebugkey"
|
||||
keyPassword "android"
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "net.kdt.pojavlaunch"
|
||||
minSdkVersion 21
|
||||
@ -15,9 +26,19 @@ 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.
|
||||
minifyEnabled false
|
||||
@ -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
|
||||
|
BIN
app/debug.keystore
Normal file
BIN
app/debug.keystore
Normal file
Binary file not shown.
@ -41,6 +41,11 @@
|
||||
android:name=".MCLauncherActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"/>
|
||||
|
||||
<activity
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:name=".InstallModActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"/>
|
||||
|
||||
<activity
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:name=".CustomControlsActivity"
|
||||
|
Binary file not shown.
@ -1,44 +0,0 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.system.*;
|
||||
import java.io.*;
|
||||
|
||||
// This clads should be named as 'LoadMe' as original
|
||||
public class BinaryExecutor
|
||||
{
|
||||
private BinaryExecutor() {}
|
||||
|
||||
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 FileDescriptor redirectStdio() throws ErrnoException {
|
||||
File logFile = new File(Tools.MAIN_PATH, "v3log.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 native int chdir(String path);
|
||||
public static native boolean dlopen(String libPath);
|
||||
public static native void setLdLibraryPath(String ldLibraryPath);
|
||||
public static native void setupBridgeEGL();
|
||||
|
||||
// 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("binexecutor");
|
||||
}
|
||||
}
|
112
app/src/main/java/net/kdt/pojavlaunch/InstallModActivity.java
Normal file
112
app/src/main/java/net/kdt/pojavlaunch/InstallModActivity.java
Normal file
@ -0,0 +1,112 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.graphics.*;
|
||||
import android.os.*;
|
||||
import android.support.v7.app.*;
|
||||
import android.view.*;
|
||||
import com.oracle.dalvik.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
public class InstallModActivity extends AppCompatActivity
|
||||
{
|
||||
private TextureView mTextureView;
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.install_mod);
|
||||
|
||||
final File modFile = (File) getIntent().getExtras().getSerializable("modFile");
|
||||
|
||||
mTextureView = findViewById(R.id.installmod_surfaceview);
|
||||
mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener(){
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture tex, int w, int h) {
|
||||
try {
|
||||
Surface surface = new Surface(tex);
|
||||
Field field = surface.getClass().getDeclaredField("mNativeObject");
|
||||
field.setAccessible(true);
|
||||
JREUtils.setupBridgeSurfaceAWT((long) field.get(surface));
|
||||
} catch (Throwable th) {
|
||||
Tools.showError(InstallModActivity.this, th, true);
|
||||
}
|
||||
|
||||
new Thread(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
launchJavaRuntime(modFile);
|
||||
finish();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture tex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture tex, int w, int h) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture tex) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void forceClose(View v) {
|
||||
MainActivity.dialogForceClose(this);
|
||||
}
|
||||
|
||||
private void launchJavaRuntime(File modFile) {
|
||||
try {
|
||||
List<String> javaArgList = new ArrayList<String>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
83
app/src/main/java/net/kdt/pojavlaunch/JREUtils.java
Normal file
83
app/src/main/java/net/kdt/pojavlaunch/JREUtils.java
Normal file
@ -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");
|
||||
}
|
||||
}
|
@ -756,21 +756,18 @@ public class MCLauncherActivity extends AppCompatActivity
|
||||
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
|
||||
case 0: // Mod installer
|
||||
installMod();
|
||||
break;
|
||||
case 1: // Custom controls
|
||||
if (Tools.enableDevFeatures) {
|
||||
startActivity(new Intent(MCLauncherActivity.this, CustomControlsActivity.class));
|
||||
}
|
||||
} break;
|
||||
case 3:{ // Settings
|
||||
break;
|
||||
case 2: // Settings
|
||||
startActivity(new Intent(MCLauncherActivity.this, LauncherPreferenceActivity.class));
|
||||
} break;
|
||||
case 4:{ // About
|
||||
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<File, String, Throwable>
|
||||
{
|
||||
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<Fragment> fragmentList = new ArrayList<>();
|
||||
|
@ -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,34 +629,21 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
|
||||
return true;
|
||||
}
|
||||
});
|
||||
glSurfaceView.setOnTouchListener(glTouchListener);
|
||||
glSurfaceView.setRenderer(new GLTextureView.Renderer() {
|
||||
@Override
|
||||
public void onSurfaceDestroyed(GL10 gl) {
|
||||
Log.d(Tools.APP_NAME, "Surface destroyed.");
|
||||
}
|
||||
minecraftGLView.setOnTouchListener(glTouchListener);
|
||||
minecraftGLView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener(){
|
||||
|
||||
private boolean isCalled = false;
|
||||
@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);
|
||||
// Should we do that?
|
||||
if (!isCalled) {
|
||||
isCalled = true;
|
||||
|
||||
System.out.println(new StringBuffer().append("Gave up context: ").append(AndroidContextImplementation.context).toString());
|
||||
|
||||
// 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);
|
||||
}
|
||||
JREUtils.setupBridgeWindow(new Surface(texture));
|
||||
|
||||
new Thread(new Runnable(){
|
||||
|
||||
@ -720,20 +658,27 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawFrame(GL10 gl) {
|
||||
//mkToast("onDrawFrame");
|
||||
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) {
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
AndroidDisplay.windowWidth = width / scaleFactor;
|
||||
AndroidDisplay.windowHeight = height / scaleFactor;
|
||||
}
|
||||
});
|
||||
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,12 +829,8 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
|
||||
}
|
||||
|
||||
public static void fullyExit() {
|
||||
if (!ExitManager.isExiting()) {
|
||||
ExitManager.enableSystemExit();
|
||||
System.exit(0);
|
||||
}
|
||||
ExitManager.stopExitLoop();
|
||||
}
|
||||
|
||||
public void forceUserHome(String s) throws Exception {
|
||||
Properties props = System.getProperties();
|
||||
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
14
app/src/main/jni/Android.mk
Normal file
14
app/src/main/jni/Android.mk
Normal file
@ -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)
|
||||
|
5
app/src/main/jni/Application.mk
Normal file
5
app/src/main/jni/Application.mk
Normal file
@ -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
|
170
app/src/main/jni/egl_bridge.c
Normal file
170
app/src/main/jni/egl_bridge.c
Normal file
@ -0,0 +1,170 @@
|
||||
#include <jni.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#ifdef GLES_TEST
|
||||
#include <GLES2/gl2.h>
|
||||
#endif
|
||||
|
||||
#include <android/native_window.h>
|
||||
#include <android/native_window_jni.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
200
app/src/main/jni/jre_launcher.c
Normal file
200
app/src/main/jni/jre_launcher.c
Normal file
@ -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 <jni.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <android/log.h>
|
||||
#include <dlfcn.h>
|
||||
// Boardwalk: missing include
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
26
app/src/main/jni/log.h
Normal file
26
app/src/main/jni/log.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
|
||||
#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
|
||||
|
162
app/src/main/jni/utils.c
Normal file
162
app/src/main/jni/utils.c
Normal file
@ -0,0 +1,162 @@
|
||||
#include <jni.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
*/
|
||||
|
9
app/src/main/jni/utils.h
Normal file
9
app/src/main/jni/utils.h
Normal file
@ -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_
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
21
app/src/main/res/layout/install_mod.xml
Normal file
21
app/src/main/res/layout/install_mod.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
<TextureView
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/installmod_surfaceview"/>
|
||||
|
||||
<Button
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:background="@drawable/control_button"
|
||||
android:layout_alignParentRight="true"
|
||||
android:text="@string/control_forceclose"
|
||||
android:onClick="forceClose"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -48,7 +48,7 @@
|
||||
|
||||
<!-- AlertDialog title -->
|
||||
<string name="alerttitle_selectkeymap">Pilih sebuah keymap json</string>
|
||||
<string name="alerttitle_installmod">Pilih sebuah mod untuk di tambah</string>
|
||||
<string name="alerttitle_installmod">Pilih sebuah mod untuk dipasang</string>
|
||||
<string name="alerttitle_installoptifine">Pilih jar-nya OptiFine</string>
|
||||
|
||||
<!-- Error messages -->
|
||||
|
@ -1,9 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="mcl_options">
|
||||
<item>@string/mcl_option_modmgr</item>
|
||||
<!-- <item>@string/mcl_option_forgeinstall</item> -->
|
||||
<item>@string/mcl_option_optifineinstall</item>
|
||||
<item>@string/mcl_option_modinstall</item>
|
||||
<item>@string/mcl_option_customcontrol</item>
|
||||
<item>@string/mcl_option_settings</item>
|
||||
<item>@string/mcl_option_about</item>
|
||||
|
@ -48,8 +48,7 @@
|
||||
|
||||
<!-- AlertDialog title -->
|
||||
<string name="alerttitle_selectkeymap">Select a keymap json</string>
|
||||
<string name="alerttitle_installmod">Select a mod to add</string>
|
||||
<string name="alerttitle_installoptifine">Select OptiFine jar file</string>
|
||||
<string name="alerttitle_installmod">Select a mod to install</string>
|
||||
|
||||
<!-- Error messages -->
|
||||
<string name="error_fatal">PojavLauncher has unexpectedly crashed</string>
|
||||
@ -87,7 +86,7 @@
|
||||
|
||||
<string name="mcl_options">Options</string>
|
||||
<string name="mcl_option_modmgr">Mod manager (no function)</string>
|
||||
<string name="mcl_option_optifineinstall">Install OptiFine</string>
|
||||
<string name="mcl_option_modinstall">Install mod (Forge, LabyMod, Fabric,...)</string>
|
||||
<string name="mcl_option_checkupdate">Check for update</string>
|
||||
<string name="mcl_option_customcontrol">Custom controls</string>
|
||||
<string name="mcl_option_settings">Settings</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user