2009Scape-mobile/app_2009scape/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java
2021-12-23 11:07:55 -08:00

320 lines
13 KiB
Java

package net.kdt.pojavlaunch;
import static net.kdt.pojavlaunch.Architecture.archAsString;
import static net.kdt.pojavlaunch.Tools.getFileName;
import android.Manifest;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class PojavLoginActivity extends BaseActivity {
private final Object mLockStoragePerm = new Object();
private final Object mLockSelectJRE = new Object();
private EditText edit2, edit3;
private final int REQUEST_STORAGE_REQUEST_CODE = 1;
private CheckBox sRemember, sOffline;
private TextView startupTextView;
private SharedPreferences firstLaunchPrefs;
private boolean isSkipInit = false;
private boolean isStarting = false;
public static final String PREF_IS_INSTALLED_JAVARUNTIME = "isJavaRuntimeInstalled";
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState); // false;
if(savedInstanceState != null) {
isStarting = savedInstanceState.getBoolean("isStarting");
isSkipInit = savedInstanceState.getBoolean("isSkipInit");
}
Tools.updateWindowSize(this);
firstLaunchPrefs = getSharedPreferences("pojav_extract", MODE_PRIVATE);
new Thread(new InitRunnable()).start();
// If we get here that's because the client was closed.
finish();
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("isStarting",isStarting);
outState.putBoolean("isSkipInit",isSkipInit);
}
public class InitRunnable implements Runnable{
private int revokeCount = -1;
private int proceedState = 0;
private ProgressBar progress;
public InitRunnable() {
}
public void initLocalUi() {
LinearLayout startScr = new LinearLayout(PojavLoginActivity.this);
LayoutInflater.from(PojavLoginActivity.this).inflate(R.layout.start_screen,startScr);
PojavLoginActivity.this.setContentView(startScr);
progress = (ProgressBar) findViewById(R.id.startscreenProgress);
if(isStarting) progress.setVisibility(View.VISIBLE);
startupTextView = (TextView) findViewById(R.id.startscreen_text);
}
public int _start() {
Log.i("UITest","START initialization");
if(!isStarting) {
//try { Thread.sleep(2000); } catch (InterruptedException e) { }
runOnUiThread(() -> progress.setVisibility(View.VISIBLE));
while (Build.VERSION.SDK_INT >= 23 && Build.VERSION.SDK_INT < 29 && !isStorageAllowed()) { //Do not ask for storage at all on Android 10+
try {
revokeCount++;
if (revokeCount >= 3) {
Toast.makeText(PojavLoginActivity.this, R.string.toast_permission_denied, Toast.LENGTH_LONG).show();
return 2;
}
requestStoragePermission();
synchronized (mLockStoragePerm) {
mLockStoragePerm.wait();
}
} catch (InterruptedException e) {
}
}
isStarting = true;
}
try {
initMain();
} catch (Throwable th) {
Tools.showError(PojavLoginActivity.this, th, true);
return 1;
}
return 0;
}
public void proceed() {
isStarting = false;
switch(proceedState) {
case 2:
finish();
break;
case 0:
uiInit();
break;
}
}
@Override
public void run() {
if(!isSkipInit) {
PojavLoginActivity.this.runOnUiThread(this::initLocalUi);
proceedState = _start();
}
PojavLoginActivity.this.runOnUiThread(this::proceed);
}
}
private void uiInit() {
setContentView(R.layout.launcher_main_v4);
Uri uri = Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.miniclient);
Thread t = new Thread(()->{
try {
final File miniclient = new File(getCacheDir(), getFileName(this, uri));
FileOutputStream fos = new FileOutputStream(miniclient);
IOUtils.copy(getContentResolver().openInputStream(uri), fos);
fos.close();
PojavLoginActivity.this.runOnUiThread(() -> {
Intent intent = new Intent(PojavLoginActivity.this, JavaGUILauncherActivity.class);
intent.putExtra("miniclient", miniclient);
startActivity(intent);
});
}catch(IOException e) {
//Tools.showError(PojavLoginActivity.this,e);
}
});
t.start();
}
@Override
public void onResume() {
super.onResume();
Tools.updateWindowSize(this);
}
private void unpackComponent(AssetManager am, String component) throws IOException {
File versionFile = new File(Tools.DIR_GAME_HOME + "/" + component + "/version");
InputStream is = am.open("components/" + component + "/version");
if(!versionFile.exists()) {
if (versionFile.getParentFile().exists() && versionFile.getParentFile().isDirectory()) {
FileUtils.deleteDirectory(versionFile.getParentFile());
}
versionFile.getParentFile().mkdir();
Log.i("UnpackPrep", component + ": Pack was installed manually, or does not exist, unpacking new...");
String[] fileList = am.list("components/" + component);
for(String s : fileList) {
Tools.copyAssetFile(this, "components/" + component + "/" + s, Tools.DIR_GAME_HOME + "/" + component, true);
}
} else {
FileInputStream fis = new FileInputStream(versionFile);
String release1 = Tools.read(is);
String release2 = Tools.read(fis);
if (!release1.equals(release2)) {
if (versionFile.getParentFile().exists() && versionFile.getParentFile().isDirectory()) {
FileUtils.deleteDirectory(versionFile.getParentFile());
}
versionFile.getParentFile().mkdir();
String[] fileList = am.list("components/" + component);
for (String s : fileList) {
Tools.copyAssetFile(this, "components/" + component + "/" + s, Tools.DIR_GAME_HOME + "/" + component, true);
}
} else {
Log.i("UnpackPrep", component + ": Pack is up-to-date with the launcher, continuing...");
}
}
}
private void initMain() throws Throwable {
mkdirs(Tools.DIR_ACCOUNT_NEW);
mkdirs(Tools.DIR_GAME_HOME);
mkdirs(Tools.DIR_GAME_HOME + "/lwjgl3");
mkdirs(Tools.DIR_GAME_HOME + "/config");
mkdirs(Tools.CTRLMAP_PATH);
try {
Tools.copyAssetFile(this, "components/security/pro-grade.jar", Tools.DIR_DATA, true);
Tools.copyAssetFile(this, "components/security/java_sandbox.policy", Tools.DIR_DATA, true);
Tools.copyAssetFile(this, "options.txt", Tools.DIR_GAME_NEW, false);
// TODO: Remove after implement.
Tools.copyAssetFile(this, "launcher_profiles.json", Tools.DIR_GAME_NEW, false);
Tools.copyAssetFile(this,"resolv.conf",Tools.DIR_DATA, true);
AssetManager am = this.getAssets();
unpackComponent(am, "caciocavallo");
unpackComponent(am, "lwjgl3");
if(!installRuntimeAutomatically(am,MultiRTUtils.getRuntimes().size() > 0)) {
synchronized (mLockSelectJRE) {
mLockSelectJRE.wait();
}
}
LauncherPreferences.loadPreferences(getApplicationContext());
}
catch(Throwable e){
Tools.showError(this, e);
}
}
private boolean installRuntimeAutomatically(AssetManager am, boolean otherRuntimesAvailable) {
/* Check if JRE is included */
String rt_version = null;
String current_rt_version = MultiRTUtils.__internal__readBinpackVersion("Internal");
try {
rt_version = Tools.read(am.open("components/jre/version"));
} catch (IOException e) {
Log.e("JREAuto", "JRE was not included on this APK.", e);
}
if(current_rt_version == null && otherRuntimesAvailable) return true; //Assume user maintains his own runtime
if(rt_version == null) return false;
if(!rt_version.equals(current_rt_version)) { //If we already have an integrated one installed, check if it's up-to-date
try {
MultiRTUtils.installRuntimeNamedBinpack(am.open("components/jre/universal.tar.xz"), am.open("components/jre/bin-" + archAsString(Tools.DEVICE_ARCHITECTURE) + ".tar.xz"), "Internal", rt_version,
(resid, vararg) -> runOnUiThread(()->{if(startupTextView!=null)startupTextView.setText(getString(resid,vararg));}));
MultiRTUtils.postPrepare(PojavLoginActivity.this,"Internal");
// Copy config.json to writable storage
// https://stackoverflow.com/questions/38590996/copy-xml-from-raw-folder-to-internal-storage-and-use-it-in-android
File file = new File(getFilesDir(), "config.json");
try {
Context context = getApplicationContext();
InputStream inputStream = context.getResources().openRawResource(R.raw.config);
FileOutputStream fileOutputStream = new FileOutputStream(file);
byte buf[]=new byte[1024];
int len;
while((len=inputStream.read(buf))>0) {
fileOutputStream.write(buf,0,len);
}
fileOutputStream.close();
inputStream.close();
System.out.println("Write to Local");
} catch (IOException e1) {}
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
}
private static boolean mkdirs(String path)
{
File file = new File(path);
// check necessary???
if(file.getParentFile().exists())
return file.mkdir();
else return file.mkdirs();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
//We are calling this method to check the permission status
private boolean isStorageAllowed() {
//Getting the permission status
int result1 = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
int result2 = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
//If permission is granted returning true
return result1 == PackageManager.PERMISSION_GRANTED &&
result2 == PackageManager.PERMISSION_GRANTED;
}
//Requesting permission
private void requestStoragePermission()
{
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_STORAGE_REQUEST_CODE);
}
// This method will be called when the user will tap on allow or deny
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_STORAGE_REQUEST_CODE) {
synchronized (mLockStoragePerm) {
mLockStoragePerm.notifyAll();
}
}
}
}