Actual useful multi-runtime

Note: it's not yet exposed in Per-Version-Config and doesn't select automatically for versions that require certain runtimes
This commit is contained in:
artdeell 2021-07-14 20:32:29 +03:00
parent 7d00a2aee3
commit 4fc232cc16
14 changed files with 204 additions and 276 deletions

View File

@ -234,10 +234,10 @@ public abstract class BaseLauncherActivity extends BaseActivity {
} }
System.out.println("call to onResumeFragments; E"); System.out.println("call to onResumeFragments; E");
} }
public String getFileName(Uri uri) { public static String getFileName(Context ctx, Uri uri) {
String result = null; String result = null;
if (uri.getScheme().equals("content")) { if (uri.getScheme().equals("content")) {
Cursor cursor = getContentResolver().query(uri, null, null, null, null); Cursor cursor = ctx.getContentResolver().query(uri, null, null, null, null);
try { try {
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
@ -268,9 +268,11 @@ public abstract class BaseLauncherActivity extends BaseActivity {
barrier.show(); barrier.show();
Thread t = new Thread(()->{ Thread t = new Thread(()->{
try { try {
MultiRTUtils.installRuntimeNamed(getContentResolver().openInputStream(uri), getFileName(uri), String name = getFileName(this,uri);
MultiRTUtils.installRuntimeNamed(getContentResolver().openInputStream(uri), name,
(resid, stuff) -> BaseLauncherActivity.this.runOnUiThread( (resid, stuff) -> BaseLauncherActivity.this.runOnUiThread(
() -> barrier.setMessage(BaseLauncherActivity.this.getString(resid,stuff)))); () -> barrier.setMessage(BaseLauncherActivity.this.getString(resid,stuff))));
MultiRTUtils.postPrepare(BaseLauncherActivity.this, name);
}catch (IOException e) { }catch (IOException e) {
Tools.showError(BaseLauncherActivity.this Tools.showError(BaseLauncherActivity.this
,e); ,e);

View File

@ -20,6 +20,7 @@ import java.nio.ByteBuffer;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.util.*; import java.util.*;
import net.kdt.pojavlaunch.customcontrols.*; import net.kdt.pojavlaunch.customcontrols.*;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.prefs.*; import net.kdt.pojavlaunch.prefs.*;
import net.kdt.pojavlaunch.utils.*; import net.kdt.pojavlaunch.utils.*;
import net.kdt.pojavlaunch.value.*; import net.kdt.pojavlaunch.value.*;
@ -129,6 +130,7 @@ public class BaseMainActivity extends LoggableActivity {
// FIXME: is it safe fot multi thread? // FIXME: is it safe fot multi thread?
GLOBAL_CLIPBOARD = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); GLOBAL_CLIPBOARD = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
MultiRTUtils.setRuntimeNamed(this,LauncherPreferences.PREF_DEFAULT_RUNTIME);
logFile = new File(Tools.DIR_GAME_HOME, "latestlog.txt"); logFile = new File(Tools.DIR_GAME_HOME, "latestlog.txt");
logFile.delete(); logFile.delete();
logFile.createNewFile(); logFile.createNewFile();

View File

@ -9,6 +9,8 @@ import android.widget.*;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.prefs.*; import net.kdt.pojavlaunch.prefs.*;
import net.kdt.pojavlaunch.utils.*; import net.kdt.pojavlaunch.utils.*;
import org.lwjgl.glfw.*; import org.lwjgl.glfw.*;
@ -63,11 +65,13 @@ public class JavaGUILauncherActivity extends LoggableActivity implements View.On
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.install_mod); setContentView(R.layout.install_mod);
Tools.updateWindowSize(this); Tools.updateWindowSize(this);
try { try {
MultiRTUtils.setRuntimeNamed(this,LauncherPreferences.PREF_DEFAULT_RUNTIME);
gestureDetector = new GestureDetector(this, new SingleTapConfirm()); gestureDetector = new GestureDetector(this, new SingleTapConfirm());
findViewById(R.id.installmod_mouse_pri).setOnTouchListener(this); findViewById(R.id.installmod_mouse_pri).setOnTouchListener(this);

View File

@ -55,7 +55,7 @@ public class PojavApplication extends Application
Tools.APP_NAME = getResources().getString(R.string.app_short_name); Tools.APP_NAME = getResources().getString(R.string.app_short_name);
Tools.DIR_DATA = getDir("files", MODE_PRIVATE).getParent(); Tools.DIR_DATA = getDir("files", MODE_PRIVATE).getParent();
Tools.DIR_HOME_JRE = Tools.DIR_DATA + "/jre_runtime".replace("/data/user/0", "/data/data"); //Tools.DIR_HOME_JRE = Tools.DIR_DATA + "/jre_runtime".replace("/data/user/0", "/data/data");
Tools.DIR_ACCOUNT_OLD = Tools.DIR_DATA + "/Users"; Tools.DIR_ACCOUNT_OLD = Tools.DIR_DATA + "/Users";
Tools.DIR_ACCOUNT_NEW = Tools.DIR_DATA + "/accounts"; Tools.DIR_ACCOUNT_NEW = Tools.DIR_DATA + "/accounts";
// Tools.FILE_ACCOUNT_JSON = getFilesDir().getAbsolutePath() + "/account_profiles.json"; // Tools.FILE_ACCOUNT_JSON = getFilesDir().getAbsolutePath() + "/account_profiles.json";

View File

@ -2,7 +2,10 @@ package net.kdt.pojavlaunch;
import android.Manifest; import android.Manifest;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -40,6 +43,7 @@ import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
@ -62,6 +66,8 @@ import net.kdt.pojavlaunch.authenticator.mojang.LoginTask;
import net.kdt.pojavlaunch.authenticator.mojang.RefreshListener; import net.kdt.pojavlaunch.authenticator.mojang.RefreshListener;
import net.kdt.pojavlaunch.customcontrols.ControlData; import net.kdt.pojavlaunch.customcontrols.ControlData;
import net.kdt.pojavlaunch.customcontrols.CustomControls; import net.kdt.pojavlaunch.customcontrols.CustomControls;
import net.kdt.pojavlaunch.multirt.MultiRTConfigDialog;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.prefs.LauncherPreferences; import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.utils.JREUtils; import net.kdt.pojavlaunch.utils.JREUtils;
import net.kdt.pojavlaunch.utils.LocaleUtils; import net.kdt.pojavlaunch.utils.LocaleUtils;
@ -278,17 +284,6 @@ public class PojavLoginActivity extends BaseActivity
PojavProfile.setCurrentProfile(this, null); PojavProfile.setCurrentProfile(this, null);
} }
private boolean isJavaRuntimeInstalled(AssetManager am) {
boolean prefValue = firstLaunchPrefs.getBoolean(PREF_IS_INSTALLED_JAVARUNTIME, false);
try {
return prefValue && (
am.open("components/jre/bin-" + Tools.CURRENT_ARCHITECTURE.split("/")[0] + ".tar.xz") == null ||
Tools.read(new FileInputStream(Tools.DIR_HOME_JRE+"/version")).equals(Tools.read(am.open("components/jre/version"))));
} catch(IOException e) {
Log.e("JVMCtl","failed to read file",e);
return prefValue;
}
}
private void unpackComponent(AssetManager am, String component) throws IOException { private void unpackComponent(AssetManager am, String component) throws IOException {
File versionFile = new File(Tools.DIR_GAME_HOME + "/" + component + "/version"); File versionFile = new File(Tools.DIR_GAME_HOME + "/" + component + "/version");
@ -368,204 +363,65 @@ public class PojavLoginActivity extends BaseActivity
unpackComponent(am, "caciocavallo"); unpackComponent(am, "caciocavallo");
unpackComponent(am, "lwjgl3"); unpackComponent(am, "lwjgl3");
if (!isJavaRuntimeInstalled(am)) { if(!installRuntimeAutomatically(am,MultiRTUtils.getRuntimes().size() > 0)) {
if(!installRuntimeAutomatically(am)) { MultiRTConfigDialog.openRuntimeSelector(this, MultiRTConfigDialog.MULTIRT_PICK_RUNTIME_STARTUP);
File jreTarFile = selectJreTarFile(); synchronized (mLockSelectJRE) {
uncompressTarXZ(jreTarFile, new File(Tools.DIR_HOME_JRE)); mLockSelectJRE.wait();
} else {
Tools.copyAssetFile(this, "components/jre/version", Tools.DIR_HOME_JRE + "/","version", true);
} }
firstLaunchPrefs.edit().putBoolean(PREF_IS_INSTALLED_JAVARUNTIME, true).commit();
} }
JREUtils.relocateLibPath(this);
File ftIn = new File(Tools.DIR_HOME_JRE, Tools.DIRNAME_HOME_JRE + "/libfreetype.so.6");
File ftOut = new File(Tools.DIR_HOME_JRE, Tools.DIRNAME_HOME_JRE + "/libfreetype.so");
if (ftIn.exists() && (!ftOut.exists() || ftIn.length() != ftOut.length())) {
ftIn.renameTo(ftOut);
}
// Refresh libraries
copyDummyNativeLib("libawt_xawt.so");
// copyDummyNativeLib("libfontconfig.so");
} }
catch(Throwable e){ catch(Throwable e){
Tools.showError(this, e); Tools.showError(this, e);
} }
} }
private boolean installRuntimeAutomatically(AssetManager am) {
try {
am.open("components/jre/version");
} catch (IOException e) {
Log.e("JREAuto", "JRE was not included on this APK.", e);
return false;
}
File rtUniversal = new File(Tools.DIR_HOME_JRE+"/universal.tar.xz");
File rtPlatformDependent = new File(Tools.DIR_HOME_JRE+"/cust-bin.tar.xz");
if(!new File(Tools.DIR_HOME_JRE).exists()) new File(Tools.DIR_HOME_JRE).mkdirs(); else {
//SANITY: remove the existing files
for (File f : new File(Tools.DIR_HOME_JRE).listFiles()) {
if (f.isDirectory()){
try {
FileUtils.deleteDirectory(f);
} catch(IOException e1) {
Log.e("JREAuto","da fuq is wrong wit ur device? n2",e1);
}
} else{
f.delete();
}
}
}
InputStream is;
FileOutputStream os;
try {
is = am.open("components/jre/universal.tar.xz");
os = new FileOutputStream(rtUniversal);
IOUtils.copy(is,os);
is.close();
os.close();
uncompressTarXZ(rtUniversal, new File(Tools.DIR_HOME_JRE));
} catch (IOException e){
Log.e("JREAuto","Failed to unpack universal. Custom embedded-less build?",e);
return false;
}
try {
is = am.open("components/jre/bin-" + Tools.CURRENT_ARCHITECTURE.split("/")[0] + ".tar.xz");
os = new FileOutputStream(rtPlatformDependent);
IOUtils.copy(is, os);
is.close();
os.close();
uncompressTarXZ(rtPlatformDependent, new File(Tools.DIR_HOME_JRE));
} catch (IOException e) {
// Something's very wrong, or user's using an unsupported arch (MIPS phone? ARMv6 phone?),
// in both cases, redirecting to manual install, and removing the universal stuff
for (File f : new File(Tools.DIR_HOME_JRE).listFiles()) {
if (f.isDirectory()){
try {
FileUtils.deleteDirectory(f);
} catch(IOException e1) {
Log.e("JREAuto","da fuq is wrong wit ur device?",e1);
}
} else{
f.delete();
}
}
return false;
}
return true;
}
private void copyDummyNativeLib(String name) throws Throwable {
File fileLib = new File(Tools.DIR_HOME_JRE, Tools.DIRNAME_HOME_JRE + "/" + name);
fileLib.delete();
FileInputStream is = new FileInputStream(new File(getApplicationInfo().nativeLibraryDir, name));
FileOutputStream os = new FileOutputStream(fileLib);
IOUtils.copy(is, os);
is.close();
os.close();
}
private File selectJreTarFile() throws InterruptedException {
final StringBuilder selectedFile = new StringBuilder();
runOnUiThread(new Runnable() {
@Override @Override
public void run() { protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
AlertDialog.Builder builder = new AlertDialog.Builder(PojavLoginActivity.this); super.onActivityResult(requestCode, resultCode, data);
builder.setTitle(getString(R.string.alerttitle_install_jre, Tools.CURRENT_ARCHITECTURE)); if(requestCode == MultiRTConfigDialog.MULTIRT_PICK_RUNTIME_STARTUP && resultCode == Activity.RESULT_OK) {
builder.setCancelable(false); if (data != null) {
final Uri uri = data.getData();
final AlertDialog dialog = builder.create(); Thread t = new Thread(()->{
FileListView flv = new FileListView(dialog, "tar.xz"); try {
flv.setFileSelectedListener(new FileSelectedListener(){ MultiRTUtils.installRuntimeNamed(getContentResolver().openInputStream(uri), BaseLauncherActivity.getFileName(this,uri),
(resid, stuff) ->PojavLoginActivity.this.runOnUiThread(
@Override () -> startupTextView.setText(PojavLoginActivity.this.getString(resid,stuff))));
public void onFileSelected(File file, String path) {
selectedFile.append(path);
dialog.dismiss();
synchronized (mLockSelectJRE) { synchronized (mLockSelectJRE) {
mLockSelectJRE.notifyAll(); mLockSelectJRE.notifyAll();
} }
}catch (IOException e) {
Tools.showError(PojavLoginActivity.this
,e);
} }
}); });
dialog.setView(flv); t.start();
dialog.show();
} }
});
synchronized (mLockSelectJRE) {
mLockSelectJRE.wait();
} }
return new File(selectedFile.toString());
} }
private boolean installRuntimeAutomatically(AssetManager am, boolean otherRuntimesAvailable) {
private void uncompressTarXZ(final File tarFile, final File dest) throws IOException { /* Check if JRE is included */
String rt_version = null;
dest.mkdirs(); String current_rt_version = MultiRTUtils.__internal__readBinpackVersion("Internal");
TarArchiveInputStream tarIn = null;
tarIn = new TarArchiveInputStream(
new XZCompressorInputStream(
new BufferedInputStream(
new FileInputStream(tarFile)
)
)
);
TarArchiveEntry tarEntry = tarIn.getNextTarEntry();
// tarIn is a TarArchiveInputStream
while (tarEntry != null) {
/*
* Unpacking very small files in short time cause
* application to ANR or out of memory, so delay
* a little if size is below than 20kb (20480 bytes)
*/
if (tarEntry.getSize() <= 20480) {
try { try {
// 40 small files per second rt_version = Tools.read(am.open("components/jre/version"));
Thread.sleep(25); } catch (IOException e) {
} catch (InterruptedException e) {} Log.e("JREAuto", "JRE was not included on this APK.", e);
} }
final String tarEntryName = tarEntry.getName(); if(current_rt_version == null && otherRuntimesAvailable) return true; //Assume user maintains his own runtime
runOnUiThread(new Runnable(){ if(rt_version == null) return false;
@SuppressLint("StringFormatInvalid") if(!current_rt_version.equals(rt_version)) { //If we already have an integrated one installed, check if it's up-to-date
@Override
public void run() {
startupTextView.setText(getString(R.string.global_unpacking, tarEntryName));
}
});
// publishProgress(null, "Unpacking " + tarEntry.getName());
File destPath = new File(dest, tarEntry.getName());
if (tarEntry.isSymbolicLink()) {
destPath.getParentFile().mkdirs();
try { try {
// android.system.Os MultiRTUtils.installRuntimeNamedBinpack(am.open("components/jre/universal.tar.xz"), am.open("components/jre/bin-" + Tools.CURRENT_ARCHITECTURE.split("/")[0] + ".tar.xz"), "Internal", rt_version,
// Libcore one support all Android versions (resid, vararg) -> {
Os.symlink(tarEntry.getName(), tarEntry.getLinkName()); runOnUiThread(()->{startupTextView.setText(getString(resid,vararg));});
} catch (Throwable e) { });
e.printStackTrace(); MultiRTUtils.postPrepare(PojavLoginActivity.this,"Internal");
return true;
}catch (IOException e) {
Log.e("JREAuto", "Internal JRE unpack failed", e);
return false;
} }
}else return true; // we have at least one runtime, and it's compartible, good to go
} else if (tarEntry.isDirectory()) {
destPath.mkdirs();
destPath.setExecutable(true);
} else if (!destPath.exists() || destPath.length() != tarEntry.getSize()) {
destPath.getParentFile().mkdirs();
destPath.createNewFile();
FileOutputStream os = new FileOutputStream(destPath);
IOUtils.copy(tarIn, os);
os.close();
}
tarEntry = tarIn.getNextTarEntry();
}
tarIn.close();
} }
private static boolean mkdirs(String path) private static boolean mkdirs(String path)

View File

@ -1,5 +1,6 @@
package net.kdt.pojavlaunch.multirt; package net.kdt.pojavlaunch.multirt;
import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -13,7 +14,7 @@ import net.kdt.pojavlaunch.R;
public class MultiRTConfigDialog { public class MultiRTConfigDialog {
public static final int MULTIRT_PICK_RUNTIME = 2048; public static final int MULTIRT_PICK_RUNTIME = 2048;
public static final int MULTIRT_PICK_RUNTIME_NORETURN = 2049; public static final int MULTIRT_PICK_RUNTIME_STARTUP = 2049;
public AlertDialog dialog; public AlertDialog dialog;
public RecyclerView dialogView; public RecyclerView dialogView;
public void prepare(BaseLauncherActivity ctx) { public void prepare(BaseLauncherActivity ctx) {
@ -29,10 +30,7 @@ public class MultiRTConfigDialog {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
/* Initialte import */ /* Initialte import */
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); openRuntimeSelector(ctx,MULTIRT_PICK_RUNTIME);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/x-xz");
ctx.startActivityForResult(intent,MULTIRT_PICK_RUNTIME);
} }
}); });
builder.setNegativeButton(R.string.mcn_exit_call, new DialogInterface.OnClickListener() { builder.setNegativeButton(R.string.mcn_exit_call, new DialogInterface.OnClickListener() {
@ -46,4 +44,10 @@ public class MultiRTConfigDialog {
public void refresh() { public void refresh() {
dialogView.getAdapter().notifyDataSetChanged(); dialogView.getAdapter().notifyDataSetChanged();
} }
public static void openRuntimeSelector(Activity ctx, int code) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/x-xz");
ctx.startActivityForResult(intent,code);
}
} }

View File

@ -1,11 +1,14 @@
package net.kdt.pojavlaunch.multirt; package net.kdt.pojavlaunch.multirt;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context;
import android.system.Os; import android.system.Os;
import android.util.Log; import android.util.Log;
import net.kdt.pojavlaunch.PojavLoginActivity;
import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.utils.JREUtils;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
@ -31,6 +34,7 @@ public class MultiRTUtils {
} }
public String name; public String name;
public String versionString; public String versionString;
public String arch;
public int javaVersion; public int javaVersion;
} }
public static interface ProgressReporterThingy { public static interface ProgressReporterThingy {
@ -38,6 +42,7 @@ public class MultiRTUtils {
} }
private static File runtimeFolder = new File(Tools.MULTIRT_HOME); private static File runtimeFolder = new File(Tools.MULTIRT_HOME);
private static final String JAVA_VERSION_str = "JAVA_VERSION=\""; private static final String JAVA_VERSION_str = "JAVA_VERSION=\"";
private static final String OS_ARCH_str = "OS_ARCH=\"";
public static List<Runtime> getRuntimes() { public static List<Runtime> getRuntimes() {
ArrayList<Runtime> ret = new ArrayList<>(); ArrayList<Runtime> ret = new ArrayList<>();
System.out.println("Fetch runtime list"); System.out.println("Fetch runtime list");
@ -61,6 +66,67 @@ public class MultiRTUtils {
tmp.delete(); tmp.delete();
return read(name); return read(name);
} }
private static void __installRuntimeNamed__NoRM(InputStream runtimeInputStream, File dest, ProgressReporterThingy thingy) throws IOException {
File tmp = new File(dest,"temporary");
FileOutputStream fos = new FileOutputStream(tmp);
thingy.reportStringProgress(R.string.multirt_progress_caching);
IOUtils.copy(runtimeInputStream,fos);
fos.close();
runtimeInputStream.close();
uncompressTarXZ(tmp,dest,thingy);
tmp.delete();
}
public static void postPrepare(Context ctx, String name) throws IOException {
File dest = new File(runtimeFolder,"/"+name);
if(!dest.exists()) return;
Runtime r = read(name);
String libFolder = "lib";
if(new File(dest,libFolder+"/"+r.arch).exists()) libFolder = libFolder+"/"+r.arch;
File ftIn = new File(dest, libFolder+ "/libfreetype.so.6");
File ftOut = new File(dest, libFolder + "/libfreetype.so");
if (ftIn.exists() && (!ftOut.exists() || ftIn.length() != ftOut.length())) {
ftIn.renameTo(ftOut);
}
// Refresh libraries
copyDummyNativeLib(ctx,"libawt_xawt.so",libFolder);
}
private static void copyDummyNativeLib(Context ctx, String name, String libFolder) throws IOException {
File fileLib = new File(MultiRTUtils.runtimeFolder, name+"/"+libFolder + "/" + name);
fileLib.delete();
FileInputStream is = new FileInputStream(new File(ctx.getApplicationInfo().nativeLibraryDir, name));
FileOutputStream os = new FileOutputStream(fileLib);
IOUtils.copy(is, os);
is.close();
os.close();
}
public static Runtime installRuntimeNamedBinpack(InputStream universalFileInputStream, InputStream platformBinsInputStream, String name, String binpackVersion, ProgressReporterThingy thingy) throws IOException {
File dest = new File(runtimeFolder,"/"+name);
if(dest.exists()) FileUtils.deleteDirectory(dest);
dest.mkdirs();
__installRuntimeNamed__NoRM(universalFileInputStream,dest,thingy);
__installRuntimeNamed__NoRM(platformBinsInputStream,dest,thingy);
File binpack_verfile = new File(runtimeFolder,"/"+name+"/pojav_version");
FileOutputStream fos = new FileOutputStream(binpack_verfile);
fos.write(binpackVersion.getBytes());
fos.close();
cache.remove(name); // Force reread
return read(name);
}
public static String __internal__readBinpackVersion(String name) {
File binpack_verfile = new File(runtimeFolder,"/"+name+"/pojav_version");
try {
if (binpack_verfile.exists()) {
return Tools.read(binpack_verfile.getAbsolutePath());
}else{
return null;
}
}catch (IOException e) {
e.printStackTrace();
return null;
}
}
public static void removeRuntimeNamed(String name) throws IOException { public static void removeRuntimeNamed(String name) throws IOException {
File dest = new File(runtimeFolder,"/"+name); File dest = new File(runtimeFolder,"/"+name);
if(dest.exists()) { if(dest.exists()) {
@ -68,18 +134,27 @@ public class MultiRTUtils {
cache.remove(name); cache.remove(name);
} }
} }
public static boolean setRuntimeNamed(Context ctx, String name) throws IOException {
File dest = new File(runtimeFolder,"/"+name);
if(!dest.exists()) return false;
Tools.DIR_HOME_JRE = dest.getAbsolutePath();
JREUtils.relocateLibPath(ctx);
return true;
}
private static Runtime read(String name) { private static Runtime read(String name) {
if(cache.containsKey(name)) return cache.get(name); if(cache.containsKey(name)) return cache.get(name);
Runtime retur; Runtime retur;
File release = new File(runtimeFolder,"/"+name+"/release"); File release = new File(runtimeFolder,"/"+name+"/release");
if(!release.exists()) { if(!release.exists()) {
return null; return new Runtime(name);
} }
try { try {
String content = Tools.read(release.getAbsolutePath()); String content = Tools.read(release.getAbsolutePath());
int _JAVA_VERSION_index = content.indexOf(JAVA_VERSION_str); int _JAVA_VERSION_index = content.indexOf(JAVA_VERSION_str);
if(_JAVA_VERSION_index != -1) { int _OS_ARCH_index = content.indexOf(OS_ARCH_str);
if(_JAVA_VERSION_index != -1 && _OS_ARCH_index != -1) {
_JAVA_VERSION_index += JAVA_VERSION_str.length(); _JAVA_VERSION_index += JAVA_VERSION_str.length();
_OS_ARCH_index += OS_ARCH_str.length();
String javaVersion = content.substring(_JAVA_VERSION_index,content.indexOf('"',_JAVA_VERSION_index)); String javaVersion = content.substring(_JAVA_VERSION_index,content.indexOf('"',_JAVA_VERSION_index));
String[] javaVersionSplit = javaVersion.split("\\."); String[] javaVersionSplit = javaVersion.split("\\.");
int javaVersionInt; int javaVersionInt;
@ -89,6 +164,7 @@ public class MultiRTUtils {
javaVersionInt = Integer.parseInt(javaVersionSplit[0]); javaVersionInt = Integer.parseInt(javaVersionSplit[0]);
} }
Runtime r = new Runtime(name); Runtime r = new Runtime(name);
r.arch = content.substring(_OS_ARCH_index,content.indexOf('"',_OS_ARCH_index));
r.javaVersion = javaVersionInt; r.javaVersion = javaVersionInt;
r.versionString = javaVersion; r.versionString = javaVersion;
retur = r; retur = r;

View File

@ -7,6 +7,7 @@ import android.graphics.Color;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
@ -15,6 +16,7 @@ import androidx.recyclerview.widget.RecyclerView;
import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -34,9 +36,11 @@ public class RTRecyclerViewAdapter extends RecyclerView.Adapter {
@Override @Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
final List<MultiRTUtils.Runtime> runtimes = MultiRTUtils.getRuntimes(); final List<MultiRTUtils.Runtime> runtimes = MultiRTUtils.getRuntimes();
((RTViewHolder)holder).bindRuntime(runtimes.get(position)); ((RTViewHolder)holder).bindRuntime(runtimes.get(position),position);
}
public boolean isDefaultRuntime(MultiRTUtils.Runtime rt) {
return LauncherPreferences.PREF_DEFAULT_RUNTIME.equals(rt.name);
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return MultiRTUtils.getRuntimes().size(); return MultiRTUtils.getRuntimes().size();
@ -45,52 +49,69 @@ public class RTRecyclerViewAdapter extends RecyclerView.Adapter {
final TextView javaVersionView; final TextView javaVersionView;
final TextView fullJavaVersionView; final TextView fullJavaVersionView;
final ColorStateList defaultColors; final ColorStateList defaultColors;
final Button setDefaultButton;
final Context ctx; final Context ctx;
MultiRTUtils.Runtime currentRuntime; MultiRTUtils.Runtime currentRuntime;
int currentPosition;
public RTViewHolder(View itemView) { public RTViewHolder(View itemView) {
super(itemView); super(itemView);
javaVersionView = itemView.findViewById(R.id.multirt_view_java_version); javaVersionView = itemView.findViewById(R.id.multirt_view_java_version);
fullJavaVersionView = itemView.findViewById(R.id.multirt_view_java_version_full); fullJavaVersionView = itemView.findViewById(R.id.multirt_view_java_version_full);
itemView.findViewById(R.id.multirt_view_removebtn).setOnClickListener(this); itemView.findViewById(R.id.multirt_view_removebtn).setOnClickListener(this);
setDefaultButton = itemView.findViewById(R.id.multirt_view_setdefaultbtn);
setDefaultButton.setOnClickListener(this);
defaultColors = fullJavaVersionView.getTextColors(); defaultColors = fullJavaVersionView.getTextColors();
ctx = itemView.getContext(); ctx = itemView.getContext();
} }
public void bindRuntime(MultiRTUtils.Runtime rt) { public void bindRuntime(MultiRTUtils.Runtime rt, int pos) {
currentRuntime = rt; currentRuntime = rt;
currentPosition = pos;
if(rt.versionString != null) { if(rt.versionString != null) {
javaVersionView.setText(ctx.getString(R.string.multirt_java_ver, rt.name, rt.javaVersion)); javaVersionView.setText(ctx.getString(R.string.multirt_java_ver, rt.name, rt.javaVersion));
fullJavaVersionView.setText(rt.versionString); fullJavaVersionView.setText(rt.versionString);
fullJavaVersionView.setTextColor(defaultColors); fullJavaVersionView.setTextColor(defaultColors);
setDefaultButton.setVisibility(View.VISIBLE);
boolean default_ = isDefaultRuntime(rt);
setDefaultButton.setEnabled(!default_);
setDefaultButton.setText(default_?R.string.multirt_config_setdefault_already:R.string.multirt_config_setdefault);
}else{ }else{
javaVersionView.setText(rt.name); javaVersionView.setText(rt.name);
fullJavaVersionView.setText(R.string.multirt_runtime_corrupt); fullJavaVersionView.setText(R.string.multirt_runtime_corrupt);
fullJavaVersionView.setTextColor(Color.RED); fullJavaVersionView.setTextColor(Color.RED);
setDefaultButton.setVisibility(View.GONE);
} }
} }
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if(v.getId() == R.id.multirt_view_removebtn) {
if (currentRuntime != null) { if (currentRuntime != null) {
final ProgressDialog barrier = new ProgressDialog(ctx); final ProgressDialog barrier = new ProgressDialog(ctx);
barrier.setMessage(ctx.getString(R.string.global_waiting)); barrier.setMessage(ctx.getString(R.string.global_waiting));
barrier.setProgressStyle(barrier.STYLE_SPINNER); barrier.setProgressStyle(barrier.STYLE_SPINNER);
barrier.setCancelable(false); barrier.setCancelable(false);
barrier.show(); barrier.show();
Thread t = new Thread(()->{ Thread t = new Thread(() -> {
try { try {
MultiRTUtils.removeRuntimeNamed(currentRuntime.name); MultiRTUtils.removeRuntimeNamed(currentRuntime.name);
}catch (IOException e) { } catch (IOException e) {
Tools.showError(itemView.getContext(),e); Tools.showError(itemView.getContext(), e);
} }
v.post(() ->{ v.post(() -> {
barrier.dismiss(); barrier.dismiss();
RTRecyclerViewAdapter.this.notifyDataSetChanged(); RTRecyclerViewAdapter.this.notifyItemRemoved(currentPosition);
dialog.dialog.show(); dialog.dialog.show();
}); });
}); });
t.start(); t.start();
} }
}else if(v.getId() == R.id.multirt_view_setdefaultbtn) {
if(currentRuntime != null) {
LauncherPreferences.PREF_DEFAULT_RUNTIME = currentRuntime.name;
LauncherPreferences.DEFAULT_PREF.edit().putString("defaultRuntime",LauncherPreferences.PREF_DEFAULT_RUNTIME).apply();
RTRecyclerViewAdapter.this.notifyDataSetChanged();
}
}
} }
} }
} }

View File

@ -2,6 +2,7 @@ package net.kdt.pojavlaunch.prefs;
import android.content.*; import android.content.*;
import net.kdt.pojavlaunch.*; import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
public class LauncherPreferences public class LauncherPreferences
{ {
@ -29,6 +30,7 @@ public class LauncherPreferences
public static boolean PREF_DISABLE_GESTURES = false; public static boolean PREF_DISABLE_GESTURES = false;
public static float PREF_MOUSESPEED = 1f; public static float PREF_MOUSESPEED = 1f;
public static int PREF_RAM_ALLOCATION=300; public static int PREF_RAM_ALLOCATION=300;
public static String PREF_DEFAULT_RUNTIME;
public static void loadPreferences() { public static void loadPreferences() {
PREF_RENDERER = DEFAULT_PREF.getString("renderer", "opengles2"); PREF_RENDERER = DEFAULT_PREF.getString("renderer", "opengles2");
PREF_BUTTONSIZE = DEFAULT_PREF.getInt("buttonscale", 100); PREF_BUTTONSIZE = DEFAULT_PREF.getInt("buttonscale", 100);
@ -108,5 +110,11 @@ public class LauncherPreferences
PREF_CUSTOM_JAVA_ARGS.replace(arg, "")).commit(); PREF_CUSTOM_JAVA_ARGS.replace(arg, "")).commit();
} }
} }
if(DEFAULT_PREF.contains("defaultRuntime")) {
PREF_DEFAULT_RUNTIME = DEFAULT_PREF.getString("defaultRuntime","");
}else{
PREF_DEFAULT_RUNTIME = MultiRTUtils.getRuntimes().get(0).name;
LauncherPreferences.DEFAULT_PREF.edit().putString("defaultRuntime",LauncherPreferences.PREF_DEFAULT_RUNTIME).apply();
}
} }
} }

View File

@ -1,53 +0,0 @@
package net.kdt.pojavlaunch.prefs;
import android.content.*;
import androidx.appcompat.app.*;
import androidx.preference.*;
import android.util.*;
import android.widget.*;
import java.io.*;
import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.R;
import org.apache.commons.io.*;
public class UninstallJREDialogPreference extends Preference implements DialogInterface.OnClickListener
{
private AlertDialog mDialog;
public UninstallJREDialogPreference(Context ctx) {
this(ctx, null);
}
public UninstallJREDialogPreference(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
setPersistent(false);
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
dialog.setMessage(R.string.mcl_setting_title_uninstalljre);
dialog.setPositiveButton(android.R.string.ok, this);
dialog.setNegativeButton(android.R.string.cancel, this);
mDialog = dialog.create();
}
@Override
protected void onClick() {
super.onClick();
mDialog.show();
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
try {
FileUtils.deleteDirectory(new File(Tools.DIR_HOME_JRE));
getContext().getSharedPreferences("pojav_extract", Context.MODE_PRIVATE)
.edit().putBoolean(PojavLoginActivity.PREF_IS_INSTALLED_JAVARUNTIME, false).commit();
Toast.makeText(getContext(), R.string.toast_uninstalljre_done, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
Tools.showError(getContext(), e);
}
}
}
}

View File

@ -168,7 +168,7 @@ public class JREUtils
Log.i("jrelog-logcat","Logcat thread started"); Log.i("jrelog-logcat","Logcat thread started");
} }
public static void relocateLibPath(final Context ctx) throws Exception { public static void relocateLibPath(final Context ctx) throws IOException {
if (JRE_ARCHITECTURE == null) { if (JRE_ARCHITECTURE == null) {
JRE_ARCHITECTURE = readJREReleaseProperties().get("OS_ARCH"); JRE_ARCHITECTURE = readJREReleaseProperties().get("OS_ARCH");
if (JRE_ARCHITECTURE.startsWith("i") && JRE_ARCHITECTURE.endsWith("86") && Tools.CURRENT_ARCHITECTURE.contains("x86") && !Tools.CURRENT_ARCHITECTURE.contains("64")) { if (JRE_ARCHITECTURE.startsWith("i") && JRE_ARCHITECTURE.endsWith("86") && Tools.CURRENT_ARCHITECTURE.contains("x86") && !Tools.CURRENT_ARCHITECTURE.contains("64")) {

View File

@ -39,4 +39,14 @@
app:layout_constraintTop_toTopOf="@+id/multirt_view_java_version" app:layout_constraintTop_toTopOf="@+id/multirt_view_java_version"
app:srcCompat="@drawable/ic_remove" /> app:srcCompat="@drawable/ic_remove" />
<Button
android:id="@+id/multirt_view_setdefaultbtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="@string/multirt_config_setdefault"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/multirt_view_removebtn"
app:layout_constraintTop_toTopOf="@+id/multirt_view_removebtn" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -219,4 +219,6 @@
<string name="multirt_title">Runtime Manager</string> <string name="multirt_title">Runtime Manager</string>
<string name="multirt_subtitle">Manage installed Java VMs</string> <string name="multirt_subtitle">Manage installed Java VMs</string>
<string name="multirt_progress_caching">Caching...</string> <string name="multirt_progress_caching">Caching...</string>
<string name="multirt_config_setdefault">Set default</string>
<string name="multirt_config_setdefault_already">Default</string>
</resources> </resources>

View File

@ -6,10 +6,6 @@
<androidx.preference.PreferenceCategory <androidx.preference.PreferenceCategory
android:title="@string/mcl_setting_category_general"> android:title="@string/mcl_setting_category_general">
<net.kdt.pojavlaunch.prefs.UninstallJREDialogPreference
android:summary="@string/mcl_setting_subtitle_uninstalljre"
android:title="@string/mcl_setting_title_uninstalljre"
app2:icon="@drawable/rm_jre" />
<net.kdt.pojavlaunch.prefs.RuntimeManagerPreference <net.kdt.pojavlaunch.prefs.RuntimeManagerPreference
android:summary="@string/multirt_subtitle" android:summary="@string/multirt_subtitle"
android:title="@string/multirt_title"/> android:title="@string/multirt_title"/>