Merge branch 'v3_openjdk' into v3-virgl

This commit is contained in:
LegacyGamerHD 2021-11-11 15:50:02 +01:00
commit cc6c6ab14c
53 changed files with 1484 additions and 3119 deletions

View File

@ -19,7 +19,7 @@
- [Credits & Third party components and their licenses](#credits--third-party-components-and-their-licenses)
## Introduction
PojavLauncher is a Minecraft: Java Edition launcher for Android and iOS based on [Boardwalk](https://github.com/zhuowei/Boardwalk). This launcher can launch almost all available Minecraft versions (from rd-132211 to 1.18 snapshots (kinda), including Combat Test versions. Modding via Forge and Fabric are also supported. This repository contains source code for Android. For iOS/iPadOS, check out [PojavLauncher_iOS](https://github.com/PojavLauncherTeam/PojavLauncher_iOS).
PojavLauncher is a Minecraft: Java Edition launcher for Android and iOS based on [Boardwalk](https://github.com/zhuowei/Boardwalk). This launcher can launch almost all available Minecraft versions (from rd-132211 to 1.18 snapshots (kinda)), including Combat Test versions. Modding via Forge (up to 1.16.5) and Fabric are also supported. This repository contains source code for Android. For iOS/iPadOS, check out [PojavLauncher_iOS](https://github.com/PojavLauncherTeam/PojavLauncher_iOS).
## Building
To get started, you can just get prebuilt app from [stable release](https://github.com/PojavLauncherTeam/PojavLauncher/releases) or [automatic builds](https://github.com/PojavLauncherTeam/PojavLauncher/actions). If you want to build after launcher code changes, follow steps below.
@ -80,13 +80,13 @@ cp jre_lwjgl3glfw/build/libs/jre_lwjgl3glfw-3.2.3.jar app_pojavlauncher/src/main
- [ ] More...
## Known Issues
- Minecraft `21w10a` or newer are currently not yet supported due to the new GLSL usage.
- In 1.16 and up spawn eggs banners are white (you can fix this by switching renderer
to `gl4es 1.1.5`, only works on 1.16 and up, do not use under this version)
- Controller mods aren't working
- Minecraft `21w10a` or newer are currently not yet supported due to the new GLSL usage. Fortunately, a workaround is provided and built into the launcher.
- In 1.16 and up, spawn eggs banners are white (you can fix this by switching renderer
to `gl4es 1.1.5`, only works on 1.16 and up, do not use under this version, as the texture
will bug out when hit a mob)
- Controller mods aren't working.
- Random crashes could happen very often on Android 5.x during game load or join world.
- With big modpacks textures could be messed up
- If you're using gl4es 1.1.5 on 1.16 and lower texture will bug out when hit a mob
- probably more, that's why we have a bug tracker ;)
## License
@ -96,7 +96,7 @@ to `gl4es 1.1.5`, only works on 1.16 and up, do not use under this version)
Contributions are welcome! We welcome any type of contribution, not only code.
Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it.
## Credits & Third party components and their licenses
## Credits & Third party components and their licenses (if available)
- [Boardwalk](https://github.com/zhuowei/Boardwalk) (JVM Launcher): Unknown License/[Apache License 2.0](https://github.com/zhuowei/Boardwalk/blob/master/LICENSE) or GNU GPLv2.
- Android Support Libraries: [Apache License 2.0](https://android.googlesource.com/platform/prebuilts/maven_repo/android/+/master/NOTICE.txt).
- [GL4ES](https://github.com/PojavLauncherTeam/gl4es): [MIT License](https://github.com/ptitSeb/gl4es/blob/master/LICENSE).<br>
@ -108,4 +108,3 @@ Any code change should be submitted as a pull request. The description should ex
- [xHook](https://github.com/iqiyi/xHook) (Used for exit code trapping): [MIT and BSD-style licenses](https://github.com/iqiyi/xHook/blob/master/LICENSE).
- [libepoxy](https://github.com/anholt/libepoxy): [MIT License](https://github.com/anholt/libepoxy/blob/master/COPYING).
- [virglrenderer](https://github.com/PojavLauncherTeam/virglrenderer): [MIT License](https://gitlab.freedesktop.org/virgl/virglrenderer/-/blob/master/COPYING).

View File

@ -118,13 +118,13 @@ dependencies {
// implementation 'com.wu-man:android-bsf-api:3.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.legacy:legacy-preference-v14:1.0.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.annotation:annotation:1.2.0'
implementation 'androidx.browser:browser:1.3.0'
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
implementation "androidx.constraintlayout:constraintlayout:2.1.1"
implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:3.0.1'
implementation 'com.github.duanhong169:checkerboarddrawable:1.0.2'

View File

@ -1,5 +1,7 @@
package net.kdt.pojavlaunch;
import static net.kdt.pojavlaunch.Tools.getFileName;
import android.app.*;
import android.content.*;
import android.database.Cursor;
@ -28,12 +30,10 @@ import org.apache.commons.io.IOUtils;
public abstract class BaseLauncherActivity extends BaseActivity {
public Button mPlayButton;
public ConsoleFragment mConsoleView;
public CrashFragment mCrashView;
public ProgressBar mLaunchProgress;
public Spinner mVersionSelector;
public MultiRTConfigDialog mRuntimeConfigDialog;
public TextView mLaunchTextStatus, mTextVersion;
public TextView mLaunchTextStatus;
public JMinecraftVersionList mVersionList;
public MinecraftDownloaderTask mTask;
@ -45,52 +45,24 @@ public abstract class BaseLauncherActivity extends BaseActivity {
public abstract void statusIsLaunching(boolean isLaunching);
public void mcaccLogout(View view) {
//PojavProfile.reset();
finish();
/**
* Used by the custom control button from the layout_main_v4
* @param view The view triggering the function
*/
public void launchCustomControlsActivity(View view){
startActivity(new Intent(BaseLauncherActivity.this, CustomControlsActivity.class));
}
public void launcherMenu(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.mcl_options);
builder.setItems(R.array.mcl_options, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface p1, int p2)
{
switch (p2) {
case 0: // Mod installer
installMod(false);
break;
case 1: // Mod installer with java args
installMod(true);
break;
case 2: // Custom controls
startActivity(new Intent(BaseLauncherActivity.this, CustomControlsActivity.class));
break;
case 3: { // About
final AlertDialog.Builder aboutB = new AlertDialog.Builder(BaseLauncherActivity.this);
aboutB.setTitle(R.string.mcl_option_about);
try {
aboutB.setMessage(Html.fromHtml(String.format(Tools.read(getAssets().open("about_en.txt")),
Tools.APP_NAME,
BuildConfig.VERSION_NAME,
"3.2.3")
));
} catch (Exception e) {
throw new RuntimeException(e);
}
aboutB.setPositiveButton(android.R.string.ok, null);
AlertDialog aboutDialog = aboutB.show();
TextView aboutTv = aboutDialog.findViewById(android.R.id.message);
aboutTv.setMovementMethod(LinkMovementMethod.getInstance());
} break;
}
}
});
builder.show();
/**
* Used by the install button from the layout_main_v4
* @param view The view triggering the function
*/
public void installJarFile(View view){
installMod(false);
}
public static final int RUN_MOD_INSTALLER = 2050;
private void installMod(boolean customJavaArgs) {
if (customJavaArgs) {
@ -101,15 +73,12 @@ public abstract class BaseLauncherActivity extends BaseActivity {
final EditText edit = new EditText(this);
edit.setSingleLine();
edit.setHint("-jar/-cp /path/to/file.jar ...");
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface di, int i) {
Intent intent = new Intent(BaseLauncherActivity.this, JavaGUILauncherActivity.class);
intent.putExtra("skipDetectMod", true);
intent.putExtra("javaArgs", edit.getText().toString());
startActivity(intent);
}
});
builder.setPositiveButton(android.R.string.ok, (di, i) -> {
Intent intent = new Intent(BaseLauncherActivity.this, JavaGUILauncherActivity.class);
intent.putExtra("skipDetectMod", true);
intent.putExtra("javaArgs", edit.getText().toString());
startActivity(intent);
});
dialog = builder.create();
dialog.setView(edit);
dialog.show();
@ -132,7 +101,7 @@ public abstract class BaseLauncherActivity extends BaseActivity {
v.setEnabled(false);
mTask = new MinecraftDownloaderTask(this);
mTask.execute(mProfile.selectedVersion);
mCrashView.resetCrashLog = true;
}
}
@ -160,19 +129,17 @@ public abstract class BaseLauncherActivity extends BaseActivity {
decorView.setSystemUiVisibility(uiOptions);
System.out.println("call to onResume; E");
}
SharedPreferences.OnSharedPreferenceChangeListener listRefreshListener = null;
@Override
protected void onResumeFragments() {
super.onResumeFragments();
if(listRefreshListener == null) {
final BaseLauncherActivity thiz = this;
listRefreshListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.startsWith("vertype_")) {
System.out.println("Verlist update needed!");
new RefreshVersionListTask(thiz).execute();
}
listRefreshListener = (sharedPreferences, key) -> {
if(key.startsWith("vertype_")) {
System.out.println("Verlist update needed!");
new RefreshVersionListTask(thiz).execute();
}
};
}
@ -181,76 +148,11 @@ public abstract class BaseLauncherActivity extends BaseActivity {
System.out.println("call to onResumeFragments");
mRuntimeConfigDialog = new MultiRTConfigDialog();
mRuntimeConfigDialog.prepare(this);
try{
final ProgressDialog barrier = new ProgressDialog(this);
barrier.setMessage(getString(R.string.global_waiting));
barrier.setProgressStyle(barrier.STYLE_SPINNER);
barrier.setCancelable(false);
barrier.show();
new Thread(new Runnable(){
@Override
public void run()
{
while (mConsoleView == null) {
try {
Thread.sleep(20);
} catch (Throwable th) {}
}
try {
Thread.sleep(100);
} catch (Throwable th) {}
runOnUiThread(new Runnable() {
@Override
public void run()
{
try {
mConsoleView.putLog("");
barrier.dismiss();
} catch (Throwable th) {
startActivity(getIntent());
finish();
}
}
});
}
}).start();
File lastCrashFile = Tools.lastFileModified(Tools.DIR_HOME_CRASH);
if(CrashFragment.isNewCrash(lastCrashFile) || !mCrashView.getLastCrash().isEmpty()){
mCrashView.resetCrashLog = false;
initTabs(2);
} /*else throw new Exception();*/
} catch(Throwable e) {
e.printStackTrace();
}
//TODO ADD CRASH CHECK AND FOCUS
System.out.println("call to onResumeFragments; E");
}
public static String getFileName(Context ctx, Uri uri) {
String result = null;
if (uri.getScheme().equals("content")) {
Cursor cursor = ctx.getContentResolver().query(uri, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
} finally {
cursor.close();
}
}
if (result == null) {
result = uri.getPath();
int cut = result.lastIndexOf('/');
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode,resultCode,data);
@ -260,62 +162,58 @@ public abstract class BaseLauncherActivity extends BaseActivity {
barrier.setProgressStyle(barrier.STYLE_SPINNER);
barrier.setCancelable(false);
barrier.show();
if (requestCode == MultiRTConfigDialog.MULTIRT_PICK_RUNTIME) {
if (data != null) {
final Uri uri = data.getData();
Thread t = new Thread(() -> {
try {
String name = getFileName(this, uri);
MultiRTUtils.installRuntimeNamed(getContentResolver().openInputStream(uri), name,
(resid, stuff) -> BaseLauncherActivity.this.runOnUiThread(
() -> barrier.setMessage(BaseLauncherActivity.this.getString(resid, stuff))));
MultiRTUtils.postPrepare(BaseLauncherActivity.this, name);
} catch (IOException e) {
Tools.showError(BaseLauncherActivity.this
, e);
}
BaseLauncherActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
barrier.dismiss();
mRuntimeConfigDialog.refresh();
mRuntimeConfigDialog.dialog.show();
}
});
});
t.start();
}
} else if (requestCode == RUN_MOD_INSTALLER) {
if (data != null) {
final Uri uri = data.getData();
barrier.setMessage(BaseLauncherActivity.this.getString(R.string.multirt_progress_caching));
Thread t = new Thread(()->{
try {
final String name = getFileName(this, uri);
final File modInstallerFile = new File(getCacheDir(), name);
FileOutputStream fos = new FileOutputStream(modInstallerFile);
IOUtils.copy(getContentResolver().openInputStream(uri), fos);
fos.close();
BaseLauncherActivity.this.runOnUiThread(() -> {
barrier.dismiss();
Intent intent = new Intent(BaseLauncherActivity.this, JavaGUILauncherActivity.class);
intent.putExtra("modFile", modInstallerFile);
startActivity(intent);
});
}catch(IOException e) {
Tools.showError(BaseLauncherActivity.this,e);
}
});
t.start();
}
}
}
}
// Catching touch exception
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
// Install the runtime
if (requestCode == MultiRTConfigDialog.MULTIRT_PICK_RUNTIME) {
if (data == null) return;
final Uri uri = data.getData();
Thread t = new Thread(() -> {
try {
String name = getFileName(this, uri);
MultiRTUtils.installRuntimeNamed(getContentResolver().openInputStream(uri), name,
(resid, stuff) -> BaseLauncherActivity.this.runOnUiThread(
() -> barrier.setMessage(BaseLauncherActivity.this.getString(resid, stuff))));
MultiRTUtils.postPrepare(BaseLauncherActivity.this, name);
} catch (IOException e) {
Tools.showError(BaseLauncherActivity.this, e);
}
BaseLauncherActivity.this.runOnUiThread(() -> {
barrier.dismiss();
mRuntimeConfigDialog.refresh();
mRuntimeConfigDialog.dialog.show();
});
});
t.start();
}
// Run a mod installer
if (requestCode == RUN_MOD_INSTALLER) {
if (data == null) return;
final Uri uri = data.getData();
barrier.setMessage(BaseLauncherActivity.this.getString(R.string.multirt_progress_caching));
Thread t = new Thread(()->{
try {
final String name = getFileName(this, uri);
final File modInstallerFile = new File(getCacheDir(), name);
FileOutputStream fos = new FileOutputStream(modInstallerFile);
IOUtils.copy(getContentResolver().openInputStream(uri), fos);
fos.close();
BaseLauncherActivity.this.runOnUiThread(() -> {
barrier.dismiss();
Intent intent = new Intent(BaseLauncherActivity.this, JavaGUILauncherActivity.class);
intent.putExtra("modFile", modInstallerFile);
startActivity(intent);
});
}catch(IOException e) {
Tools.showError(BaseLauncherActivity.this,e);
}
});
t.start();
}
}
}
protected abstract void initTabs(int pageIndex);

View File

@ -48,8 +48,9 @@ public class BaseMainActivity extends LoggableActivity {
public float scaleFactor = 1;
public double sensitivityFactor;
private final int fingerStillThreshold = (int) Tools.dpToPx(9);
private final int fingerScrollThreshold = (int) Tools.dpToPx(6);
private float initialX, initialY;
private int scrollInitialX, scrollInitialY;
private float scrollLastInitialX, scrollLastInitialY;
private float prevX, prevY;
private int currentPointerID;
@ -62,8 +63,8 @@ public class BaseMainActivity extends LoggableActivity {
switch (msg.what) {
case MSG_LEFT_MOUSE_BUTTON_CHECK:
if(LauncherPreferences.PREF_DISABLE_GESTURES) break;
int x = CallbackBridge.mouseX;
int y = CallbackBridge.mouseY;
float x = CallbackBridge.mouseX;
float y = CallbackBridge.mouseY;
if (CallbackBridge.isGrabbing() &&
Math.abs(initialX - x) < fingerStillThreshold &&
Math.abs(initialY - y) < fingerStillThreshold) {
@ -96,8 +97,9 @@ public class BaseMainActivity extends LoggableActivity {
private TextView textLog;
private ScrollView contentScroll;
private ToggleButton toggleLog;
private GestureDetector gestureDetector;
private DoubleTapDetector doubleTapDetector;
private TapDetector singleTapDetector;
private TapDetector doubleTapDetector;
private TextView debugText;
private NavigationView.OnNavigationItemSelectedListener gameActionListener;
@ -164,8 +166,9 @@ public class BaseMainActivity extends LoggableActivity {
System.out.println("WidthHeight: " + windowWidth + ":" + windowHeight);
gestureDetector = new GestureDetector(this, new SingleTapConfirm());
doubleTapDetector = new DoubleTapDetector();
singleTapDetector = new TapDetector(1, TapDetector.DETECTION_METHOD_BOTH);
doubleTapDetector = new TapDetector(2, TapDetector.DETECTION_METHOD_DOWN);
// Menu
@ -262,7 +265,7 @@ public class BaseMainActivity extends LoggableActivity {
float mouseX = mousePointer.getX();
float mouseY = mousePointer.getY();
if (gestureDetector.onTouchEvent(event)) {
if (singleTapDetector.onTouchEvent(event)) {
mouse_x = (mouseX * scaleFactor);
mouse_y = (mouseY * scaleFactor);
CallbackBridge.sendCursorPos(mouse_x, mouse_y);
@ -273,8 +276,8 @@ public class BaseMainActivity extends LoggableActivity {
} else {
switch (action) {
case MotionEvent.ACTION_POINTER_DOWN: // 5
scrollInitialX = CallbackBridge.mouseX;
scrollInitialY = CallbackBridge.mouseY;
scrollLastInitialX = event.getX();
scrollLastInitialY = event.getY();
break;
case MotionEvent.ACTION_DOWN:
@ -285,10 +288,15 @@ public class BaseMainActivity extends LoggableActivity {
case MotionEvent.ACTION_MOVE: // 2
if (!CallbackBridge.isGrabbing() && event.getPointerCount() == 2 && !LauncherPreferences.PREF_DISABLE_GESTURES) { //Scrolling feature
CallbackBridge.sendScroll( Tools.pxToDp(CallbackBridge.mouseX - scrollInitialX)/30, Tools.pxToDp(CallbackBridge.mouseY - scrollInitialY)/30);
scrollInitialX = CallbackBridge.mouseX;
scrollInitialY = CallbackBridge.mouseY;
if (!CallbackBridge.isGrabbing() && event.getPointerCount() >= 2 && !LauncherPreferences.PREF_DISABLE_GESTURES) { //Scrolling feature
int hScroll = ((int) (event.getX() - scrollLastInitialX)) / fingerScrollThreshold;
int vScroll = ((int) (event.getY() - scrollLastInitialY)) / fingerScrollThreshold;
if(vScroll != 0 || hScroll != 0){
CallbackBridge.sendScroll(hScroll, vScroll);
scrollLastInitialX = event.getX();
scrollLastInitialY = event.getY();
}
} else {
if(currentPointerID == event.getPointerId(0)) {
mouseX = Math.max(0, Math.min(displayMetrics.widthPixels, mouseX + (x - prevX) * LauncherPreferences.PREF_MOUSESPEED));
@ -354,7 +362,7 @@ public class BaseMainActivity extends LoggableActivity {
mouse_x = (e.getX() * scaleFactor);
mouse_y = (e.getY() * scaleFactor);
//One android click = one MC click
if(gestureDetector.onTouchEvent(e)){
if(singleTapDetector.onTouchEvent(e)){
CallbackBridge.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (int)mouse_x, (int)mouse_y);
return true;
}
@ -424,8 +432,8 @@ public class BaseMainActivity extends LoggableActivity {
break;
case MotionEvent.ACTION_POINTER_DOWN: // 5
scrollInitialX = CallbackBridge.mouseX;
scrollInitialY = CallbackBridge.mouseY;
scrollLastInitialX = e.getX();
scrollLastInitialY = e.getY();
//Checking if we are pressing the hotbar to select the item
hudKeyHandled = handleGuiBar((int)e.getX(e.getPointerCount()-1), (int) e.getY(e.getPointerCount()-1));
if(hudKeyHandled != -1){
@ -440,10 +448,17 @@ public class BaseMainActivity extends LoggableActivity {
break;
case MotionEvent.ACTION_MOVE:
if (!CallbackBridge.isGrabbing() && e.getPointerCount() == 2 && !LauncherPreferences.PREF_DISABLE_GESTURES) { //Scrolling feature
CallbackBridge.sendScroll(Tools.pxToDp(mouse_x - scrollInitialX)/30 , Tools.pxToDp(mouse_y - scrollInitialY)/30);
scrollInitialX = (int)mouse_x;
scrollInitialY = (int)mouse_y;
if (!CallbackBridge.isGrabbing() && e.getPointerCount() >= 2 && !LauncherPreferences.PREF_DISABLE_GESTURES) { //Scrolling feature
int hScroll = ((int) (e.getX() - scrollLastInitialX)) / fingerScrollThreshold;
int vScroll = ((int) (e.getY() - scrollLastInitialY)) / fingerScrollThreshold;
if(vScroll != 0 || hScroll != 0){
CallbackBridge.sendScroll(hScroll, vScroll);
scrollLastInitialX = e.getX();
scrollLastInitialY = e.getY();
}
} else if (!CallbackBridge.isGrabbing() && e.getPointerCount() == 1) { //Touch hover
CallbackBridge.sendCursorPos(mouse_x, mouse_y);
prevX = e.getX();

View File

@ -1,67 +0,0 @@
package net.kdt.pojavlaunch;
import android.view.MotionEvent;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
/**
* Class aiming at better detecting double tap events for EVERY POINTER
* Only uses the least amount of events possible,
* since we aren't guaranteed to have all events in order
*/
public class DoubleTapDetector {
private final static int DOUBLE_TAP_MIN_DELTA_MS = 50;
private final static int DOUBLE_TAP_MAX_DELTA_MS = 300;
private final static int DOUBLE_TAP_SLOP_SQUARE_PX = (int) Math.pow(Tools.dpToPx(100), 2);
private long mLastEventTime = 0;
private float mLastX = 9999;
private float mLastY = 9999;
/**
* A function to call when you have a touch event.
* @param e The MotionEvent to inspect
* @return whether or not a double tap happened for a pointer
*/
public boolean onTouchEvent(MotionEvent e){
int eventAction = e.getActionMasked();
int pointerIndex;
//Get the pointer index we want to look at
if(eventAction == ACTION_DOWN) pointerIndex = 0;
else if(eventAction == ACTION_POINTER_DOWN) pointerIndex = e.getActionIndex();
else return false;
float eventX = e.getX(pointerIndex);
float eventY = e.getY(pointerIndex);
long eventTime = e.getEventTime();
long deltaTime = eventTime - mLastEventTime;
if(deltaTime > DOUBLE_TAP_MIN_DELTA_MS && deltaTime < DOUBLE_TAP_MAX_DELTA_MS){
int deltaX = (int) mLastX - (int) eventX;
int deltaY = (int) mLastY - (int) eventY;
if((deltaX*deltaX + deltaY*deltaY) < DOUBLE_TAP_SLOP_SQUARE_PX){
//Then I guess there is a double tap :thonk:
resetDoubleTapState();
return true;
}
}
mLastEventTime = eventTime;
mLastX = eventX;
mLastY = eventY;
return false;
}
/**
* Reset the double tap values.
*/
private void resetDoubleTapState(){
mLastEventTime = 0;
mLastX = 9999;
mLastY = 9999;
}
}

View File

@ -49,8 +49,8 @@ public class JavaGUILauncherActivity extends LoggableActivity implements View.On
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_LEFT_MOUSE_BUTTON_CHECK: {
int x = CallbackBridge.mouseX;
int y = CallbackBridge.mouseY;
float x = CallbackBridge.mouseX;
float y = CallbackBridge.mouseY;
if (CallbackBridge.isGrabbing() &&
Math.abs(initialX - x) < fingerStillThreshold &&
Math.abs(initialY - y) < fingerStillThreshold) {

View File

@ -1,7 +1,11 @@
package net.kdt.pojavlaunch;
import static android.os.Build.VERSION_CODES.P;
import static net.kdt.pojavlaunch.Tools.ignoreNotch;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_HIDE_SIDEBAR;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_NOTCH_SIZE;
import android.animation.ValueAnimator;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.Typeface;
@ -9,126 +13,140 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.design.widget.VerticalTabLayout.ViewPagerAdapter;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Guideline;
import androidx.viewpager.widget.ViewPager;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import net.kdt.pojavlaunch.extra.ExtraCore;
import net.kdt.pojavlaunch.extra.ExtraListener;
import net.kdt.pojavlaunch.fragments.ConsoleFragment;
import net.kdt.pojavlaunch.fragments.CrashFragment;
import net.kdt.pojavlaunch.fragments.LauncherFragment;
import net.kdt.pojavlaunch.prefs.LauncherPreferenceFragment;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceFragment;
import net.kdt.pojavlaunch.value.MinecraftAccount;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import static android.os.Build.VERSION_CODES.P;
import static net.kdt.pojavlaunch.Tools.ignoreNotch;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_HIDE_SIDEBAR;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_IGNORE_NOTCH;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_NOTCH_SIZE;
public class PojavLauncherActivity extends BaseLauncherActivity
{
private ViewPager viewPager;
// An equivalent ViewPager2 adapter class
private static class ScreenSlidePagerAdapter extends FragmentStateAdapter {
public ScreenSlidePagerAdapter(FragmentActivity fa) {
super(fa);
}
private TextView tvUsernameView, tvConnectStatus;
@Override
public Fragment createFragment(int position) {
if (position == 0) return new LauncherFragment();
if (position == 1) return new ConsoleFragment();
if (position == 2) return new CrashFragment();
if (position == 3) return new LauncherPreferenceFragment();
return null;
}
@Override
public int getItemCount() {
return 4;
}
}
private TextView tvConnectStatus;
private Spinner accountSelector;
private ViewPagerAdapter viewPageAdapter;
private ViewPager2 viewPager;
private final Button[] Tabs = new Button[4];
private View selected;
private View selectedTab;
private ImageView accountFaceImageView;
private Button logoutBtn; // MineButtons
private ExtraListener backPreferenceListener;
public PojavLauncherActivity() {
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.launcher_main_v4);
if (BuildConfig.DEBUG) {
Toast.makeText(this, "Launcher process id: " + android.os.Process.myPid(), Toast.LENGTH_LONG).show();
}
//Boilerplate linking/initialisation
viewPager = findViewById(R.id.launchermainTabPager);
selected = findViewById(R.id.viewTabSelected);
mConsoleView = new ConsoleFragment();
mCrashView = new CrashFragment();
viewPageAdapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPageAdapter.addFragment(new LauncherFragment(), 0, getString(R.string.mcl_tab_news));
viewPageAdapter.addFragment(mConsoleView, 0, getString(R.string.mcl_tab_console));
viewPageAdapter.addFragment(mCrashView, 0, getString(R.string.mcl_tab_crash));
viewPageAdapter.addFragment(new LauncherPreferenceFragment(), 0, getString(R.string.mcl_option_settings));
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
setTabActive(position);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
viewPager.setAdapter(viewPageAdapter);
tvConnectStatus = (TextView) findViewById(R.id.launchermain_text_accountstatus);
tvUsernameView = (TextView) findViewById(R.id.launchermain_text_welcome);
mTextVersion = (TextView) findViewById(R.id.launcherMainVersionView);
//The following line is used to make this TextView horizontally scroll if the version name is larger than the view
mTextVersion.setSelected(true);
selectedTab = findViewById(R.id.viewTabSelected);
tvConnectStatus = findViewById(R.id.launchermain_text_accountstatus);
accountFaceImageView = findViewById(R.id.launchermain_account_image);
accountSelector = findViewById(R.id.launchermain_spinner_account);
mVersionSelector = findViewById(R.id.launchermain_spinner_version);
mLaunchProgress = findViewById(R.id.progressDownloadBar);
mLaunchTextStatus = findViewById(R.id.progressDownloadText);
logoutBtn = findViewById(R.id.installJarButton);
mPlayButton = findViewById(R.id.launchermainPlayButton);
Tabs[0] = findViewById(R.id.btnTab1);
Tabs[1] = findViewById(R.id.btnTab2);
Tabs[2] = findViewById(R.id.btnTab3);
Tabs[3] = findViewById(R.id.btnTab4);
pickAccount();
if (BuildConfig.DEBUG) {
Toast.makeText(this, "Launcher process id: " + android.os.Process.myPid(), Toast.LENGTH_LONG).show();
}
// Setup the viewPager to slide across fragments
viewPager.setAdapter(new ScreenSlidePagerAdapter(this));
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
setTabActive(position);
}
});
initTabs(0);
//Setup listener to the backPreference system
backPreferenceListener = new ExtraListener() {
@Override
public boolean onValueSet(String key, String value) {
if(value.equals("true")){
onBackPressed();
ExtraCore.setValue(key, "false");
}
return false;
}
};
ExtraCore.addExtraListener("back_preference", backPreferenceListener);
final List<String> accountList = new ArrayList<String>();
final MinecraftAccount tempProfile = PojavProfile.getTempProfileContent(this);
// Try to load the temporary account
final List<String> accountList = new ArrayList<>();
final MinecraftAccount tempProfile = PojavProfile.getTempProfileContent();
if (tempProfile != null) {
accountList.add(tempProfile.username);
}
for (String s : new File(Tools.DIR_ACCOUNT_NEW).list()) {
accountList.add(s.substring(0, s.length() - 5));
}
// Setup account spinner
pickAccount();
ArrayAdapter<String> adapterAcc = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, accountList);
adapterAcc.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
accountSelector = (Spinner) findViewById(R.id.launchermain_spinner_account);
accountSelector.setAdapter(adapterAcc);
if (tempProfile != null) {
accountSelector.setSelection(0);
} else {
@ -157,8 +175,9 @@ public class PojavLauncherActivity extends BaseLauncherActivity
// TODO: Implement this method
}
});
List<String> versions = new ArrayList<String>();
// Setup the minecraft version list
List<String> versions = new ArrayList<>();
final File fVers = new File(Tools.DIR_HOME_VERSION);
try {
@ -179,40 +198,28 @@ public class PojavLauncherActivity extends BaseLauncherActivity
}
//mAvailableVersions;
ArrayAdapter<String> adapterVer = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, mAvailableVersions);
ArrayAdapter<String> adapterVer = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, mAvailableVersions);
adapterVer.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
mVersionSelector = (Spinner) findViewById(R.id.launchermain_spinner_version);
mVersionSelector.setAdapter(adapterVer);
mLaunchProgress = (ProgressBar) findViewById(R.id.progressDownloadBar);
mLaunchTextStatus = (TextView) findViewById(R.id.progressDownloadText);
logoutBtn = (Button) findViewById(R.id.switchUserBtn);
mPlayButton = (Button) findViewById(R.id.launchermainPlayButton);
statusIsLaunching(false);
initTabs(0);
LauncherPreferences.DEFAULT_PREF.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equals("hideSidebar")){
changeLookAndFeel(sharedPreferences.getBoolean("hideSidebar",false));
return;
}
//Add the preference changed listener
LauncherPreferences.DEFAULT_PREF.registerOnSharedPreferenceChangeListener((sharedPreferences, key) -> {
if(key.equals("hideSidebar")){
changeLookAndFeel(sharedPreferences.getBoolean("hideSidebar",false));
return;
}
if(key.equals("ignoreNotch")){
ignoreNotch(sharedPreferences.getBoolean("ignoreNotch", true), PojavLauncherActivity.this);
return;
}
if(key.equals("ignoreNotch")){
ignoreNotch(sharedPreferences.getBoolean("ignoreNotch", true), PojavLauncherActivity.this);
return;
}
});
changeLookAndFeel(PREF_HIDE_SIDEBAR);
ignoreNotch(PREF_IGNORE_NOTCH, PojavLauncherActivity.this);
}
private void selectTabPage(int pageIndex){
viewPager.setCurrentItem(pageIndex);
setTabActive(pageIndex);
@ -221,8 +228,9 @@ public class PojavLauncherActivity extends BaseLauncherActivity
private void pickAccount() {
try {
mProfile = PojavProfile.getCurrentProfileContent(this);
accountFaceImageView.setImageBitmap(mProfile.getSkinFace());
tvUsernameView.setText(getString(R.string.main_welcome, mProfile.username));
//TODO FULL BACKGROUND LOGIN
tvConnectStatus.setText(mProfile.accessToken.equals("0") ? R.string.mcl_account_offline : R.string.mcl_account_connected);
} catch(Exception e) {
mProfile = new MinecraftAccount();
@ -259,21 +267,18 @@ public class PojavLauncherActivity extends BaseLauncherActivity
Tabs[index].setTextColor(Color.WHITE);
//Animating the white bar on the left
ValueAnimator animation = ValueAnimator.ofFloat(selected.getY(), Tabs[index].getY()+(Tabs[index].getHeight()-selected.getHeight())/2f);
ValueAnimator animation = ValueAnimator.ofFloat(selectedTab.getY(), Tabs[index].getY()+(Tabs[index].getHeight()- selectedTab.getHeight())/2f);
animation.setDuration(250);
animation.addUpdateListener(animation1 -> selected.setY((float) animation1.getAnimatedValue()));
animation.addUpdateListener(animation1 -> selectedTab.setY((float) animation1.getAnimatedValue()));
animation.start();
}
protected void initTabs(int activeTab){
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
selectTabPage(activeTab);
}
}, 500);
handler.post(() -> {
//Do something after 100ms
selectTabPage(activeTab);
});
}
private void changeLookAndFeel(boolean useOldLook){
@ -286,8 +291,9 @@ public class PojavLauncherActivity extends BaseLauncherActivity
params.guidePercent = 0; // 0%, range: 0 <-> 1
guideLine.setLayoutParams(params);
//Remove the selected Tab
selected.setVisibility(View.GONE);
//Remove the selected Tab and the head image
selectedTab.setVisibility(View.GONE);
accountFaceImageView.setVisibility(View.GONE);
//Enlarge the button, but just a bit.
params = (ConstraintLayout.LayoutParams) mPlayButton.getLayoutParams();
@ -299,7 +305,8 @@ public class PojavLauncherActivity extends BaseLauncherActivity
guideLine.setLayoutParams(params);
//Show the selected Tab
selected.setVisibility(View.VISIBLE);
selectedTab.setVisibility(View.VISIBLE);
accountFaceImageView.setVisibility(View.VISIBLE);
//Set the default button size
params = (ConstraintLayout.LayoutParams) mPlayButton.getLayoutParams();
@ -323,5 +330,22 @@ public class PojavLauncherActivity extends BaseLauncherActivity
}
}
/**
* Custom back stack system. Use the classic backstack when the focus is on the setting screen,
* finish the activity and remove the back_preference listener otherwise
*/
@Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if(count > 0 && viewPager.getCurrentItem() == 3){
getSupportFragmentManager().popBackStack();
}else{
super.onBackPressed();
//additional code
ExtraCore.removeExtraListenerFromValue("back_preference", backPreferenceListener);
finish();
}
}
}

View File

@ -1,6 +1,7 @@
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;
@ -379,7 +380,7 @@ public class PojavLoginActivity extends BaseActivity
final Uri uri = data.getData();
Thread t = new Thread(() -> {
try {
MultiRTUtils.installRuntimeNamed(getContentResolver().openInputStream(uri), BaseLauncherActivity.getFileName(this, uri),
MultiRTUtils.installRuntimeNamed(getContentResolver().openInputStream(uri), getFileName(this, uri),
(resid, stuff) -> PojavLoginActivity.this.runOnUiThread(
() -> {
if (startupTextView != null)
@ -507,14 +508,8 @@ public class PojavLoginActivity extends BaseActivity
ImageView imageView = child.findViewById(R.id.account_head);
String accNameStr = s.substring(0, s.length() - 5);
String skinFaceBase64 = MinecraftAccount.load(accNameStr).skinFaceBase64;
if (skinFaceBase64 != null) {
byte[] faceIconBytes = Base64.decode(skinFaceBase64, Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(faceIconBytes, 0, faceIconBytes.length);
imageView.setImageBitmap(MinecraftAccount.load(accNameStr).getSkinFace());
imageView.setImageDrawable(new BitmapDrawable(getResources(),
bitmap));
}
accountName.setText(accNameStr);
accountListLayout.addView(child);
@ -635,7 +630,6 @@ public class PojavLoginActivity extends BaseActivity
builder.clientToken = result[2];
builder.profileId = result[3];
builder.username = result[4];
builder.selectedVersion = "1.12.2";
builder.updateSkinFace();
mProfile = builder;
}

View File

@ -25,13 +25,13 @@ public class PojavProfile
public static MinecraftAccount getCurrentProfileContent(Context ctx) throws JsonSyntaxException {
MinecraftAccount build = MinecraftAccount.load(getCurrentProfileName(ctx));
if (build == null) {
System.out.println("isTempProfile null? " + (getTempProfileContent(ctx) == null));
return getTempProfileContent(ctx);
System.out.println("isTempProfile null? " + (getTempProfileContent() == null));
return getTempProfileContent();
}
return build;
}
public static MinecraftAccount getTempProfileContent(Context ctx) {
public static MinecraftAccount getTempProfileContent() {
try {
MinecraftAccount acc = MinecraftAccount.parse(Tools.read(Tools.DIR_DATA+"/cache/tempacc.json"));
if (acc.accessToken == null) {

View File

@ -0,0 +1,122 @@
package net.kdt.pojavlaunch;
import android.view.MotionEvent;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
/**
* Class aiming at better detecting X-tap events regardless of the POINTERS
* Only uses the least amount of events possible,
* since we aren't guaranteed to have all events in order
*/
public class TapDetector {
public final static int DETECTION_METHOD_DOWN = 0x1;
public final static int DETECTION_METHOD_UP = 0x2;
public final static int DETECTION_METHOD_BOTH = 0x3; //Unused for now
private final static int TAP_MIN_DELTA_MS = 10;
private final static int TAP_MAX_DELTA_MS = 300;
private final static int TAP_SLOP_SQUARE_PX = (int) Math.pow(Tools.dpToPx(100), 2);
private final int tapNumberToDetect;
private int currentTapNumber = 0;
private final int detectionMethod;
private long mLastEventTime = 0;
private float mLastX = 9999;
private float mLastY = 9999;
/**
* @param tapNumberToDetect How many taps are needed before onTouchEvent returns True.
* @param detectionMethod Method used to detect touches. See DETECTION_METHOD constants above.
*/
public TapDetector(int tapNumberToDetect, int detectionMethod){
this.detectionMethod = detectionMethod;
//We expect both ACTION_DOWN and ACTION_UP for the DETECTION_METHOD_BOTH
this.tapNumberToDetect = detectBothTouch() ? 2*tapNumberToDetect : tapNumberToDetect;
}
/**
* A function to call when you have a touch event.
* @param e The MotionEvent to inspect
* @return whether or not a X-tap happened for a pointer
*/
public boolean onTouchEvent(MotionEvent e){
int eventAction = e.getActionMasked();
int pointerIndex = -1;
//Get the event to look forward
if(detectDownTouch()){
if(eventAction == ACTION_DOWN) pointerIndex = 0;
else if(eventAction == ACTION_POINTER_DOWN) pointerIndex = e.getActionIndex();
}
if(detectUpTouch()){
if(eventAction == ACTION_UP) pointerIndex = 0;
else if(eventAction == ACTION_POINTER_UP) pointerIndex = e.getActionIndex();
}
if(pointerIndex == -1) return false; // Useless event
//Store current event info
float eventX = e.getX(pointerIndex);
float eventY = e.getY(pointerIndex);
long eventTime = e.getEventTime();
//Compute deltas
long deltaTime = eventTime - mLastEventTime;
int deltaX = (int) mLastX - (int) eventX;
int deltaY = (int) mLastY - (int) eventY;
//Store current event info to persist on next event
mLastEventTime = eventTime;
mLastX = eventX;
mLastY = eventY;
//Check for high enough speed and precision
if(currentTapNumber > 0){
if ((deltaTime < TAP_MIN_DELTA_MS || deltaTime > TAP_MAX_DELTA_MS) ||
((deltaX*deltaX + deltaY*deltaY) > TAP_SLOP_SQUARE_PX)) {
// We invalidate previous taps, not this one though
currentTapNumber = 0;
}
}
//A worthy tap happened
currentTapNumber += 1;
if(currentTapNumber >= tapNumberToDetect){
resetTapDetectionState();
return true;
}
//If not enough taps are reached
return false;
}
/**
* Reset the double tap values.
*/
private void resetTapDetectionState(){
currentTapNumber = 0;
mLastEventTime = 0;
mLastX = 9999;
mLastY = 9999;
}
private boolean detectDownTouch(){
return (detectionMethod & DETECTION_METHOD_DOWN) == DETECTION_METHOD_DOWN;
}
private boolean detectUpTouch(){
return (detectionMethod & DETECTION_METHOD_UP) == DETECTION_METHOD_UP;
}
private boolean detectBothTouch(){
return detectionMethod == DETECTION_METHOD_BOTH;
}
}

View File

@ -2,8 +2,10 @@ package net.kdt.pojavlaunch;
import android.app.*;
import android.content.*;
import android.database.Cursor;
import android.net.*;
import android.os.*;
import android.provider.OpenableColumns;
import android.system.*;
import android.util.*;
import com.google.gson.*;
@ -861,4 +863,26 @@ public final class Tools {
if(displaySideRes % 2 != 0) displaySideRes ++;
return displaySideRes;
}
public static String getFileName(Context ctx, Uri uri) {
String result = null;
if (uri.getScheme().equals("content")) {
Cursor cursor = ctx.getContentResolver().query(uri, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
} finally {
cursor.close();
}
}
if (result == null) {
result = uri.getPath();
int cut = result.lastIndexOf('/');
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
}

View File

@ -71,7 +71,7 @@ public class MicrosoftAuthTask extends AsyncTask<String, Void, Object> {
*/
Msa msa = new Msa(this, Boolean.parseBoolean(args[0]), args[1]);
MinecraftAccount acc = new MinecraftAccount();
MinecraftAccount acc = MinecraftAccount.load(msa.mcName);
if (msa.doesOwnGame) {
acc.clientToken = "0"; /* FIXME */
acc.accessToken = msa.mcToken;

View File

@ -23,6 +23,10 @@ import org.lwjgl.glfw.*;
import static net.kdt.pojavlaunch.BaseMainActivity.sendMouseButton;
import static net.kdt.pojavlaunch.LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_BUTTONSIZE;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_BOTTOM_OFFSET;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_LEFT_OFFSET;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_RIGHT_OFFSET;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_TOP_OFFSET;
@SuppressLint("ViewConstructor")
public class ControlButton extends androidx.appcompat.widget.AppCompatButton implements OnLongClickListener
@ -152,16 +156,57 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
@Override
public void setX(float x) {
// We have to account for control offset preference
if(x + (mProperties.getWidth()/2f) > CallbackBridge.physicalWidth/2f){
x -= PREF_CONTROL_RIGHT_OFFSET;
}else{
x += PREF_CONTROL_LEFT_OFFSET;
}
super.setX(x);
setModified(true);
}
@Override
public void setY(float y) {
// We have to account for control offset preference
if(y - PREF_CONTROL_TOP_OFFSET + (mProperties.getHeight()/2f) > CallbackBridge.physicalHeight/2f){
y -= PREF_CONTROL_BOTTOM_OFFSET;
}else{
y += PREF_CONTROL_TOP_OFFSET;
}
super.setY(y);
setModified(true);
}
@Override
public float getX() {
float x = super.getX();
// We have to account for control offset preference
if(x + (mProperties.getWidth()/2f) > (CallbackBridge.physicalWidth)/2f){
x += PREF_CONTROL_RIGHT_OFFSET;
}else{
x -= PREF_CONTROL_LEFT_OFFSET;
}
return x;
}
@Override
public float getY(){
// We have to account for control offset preference
float y = super.getY();
if(y + (mProperties.getHeight()/2f) > CallbackBridge.physicalHeight/2f){
y += PREF_CONTROL_BOTTOM_OFFSET;
}else{
y -= PREF_CONTROL_TOP_OFFSET;
}
return y;
}
/**
* Apply the dynamic equation on the x axis.
* @param dynamicX The equation to compute the position from

View File

@ -3,6 +3,8 @@ package net.kdt.pojavlaunch.customcontrols.gamepad;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.Choreographer;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
@ -59,10 +61,22 @@ public class Gamepad {
private final boolean mModifierDigitalTriggers;
private boolean mModifierSwappedAxis = true; //Triggers and right stick axis are swapped.
private final Handler inputHandler = new Handler(Looper.getMainLooper());
private final Runnable switchStateRunnable;
private final Choreographer screenChoreographer;
private long lastFrameTime;
public Gamepad(BaseMainActivity gameActivity, InputDevice inputDevice){
screenChoreographer = Choreographer.getInstance();
Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
updateGrabbingState();
tick(frameTimeNanos);
screenChoreographer.postFrameCallback(this);
}
};
screenChoreographer.postFrameCallback(frameCallback);
lastFrameTime = System.nanoTime();
//Toast.makeText(gameActivity.getApplicationContext(),"GAMEPAD CREATED", Toast.LENGTH_LONG).show();
for(InputDevice.MotionRange range : inputDevice.getMotionRanges()){
if(range.getAxis() == MotionEvent.AXIS_RTRIGGER
@ -88,46 +102,11 @@ public class Gamepad {
pointerView.getDrawable().setFilterBitmap(false);
notifyGUISizeChange(gameActivity.getMcScale());
Runnable handlerRunnable = new Runnable() {
@Override
public void run() {
updateGrabbingState();
tick();
inputHandler.postDelayed(this, 16);
}
};
inputHandler.postDelayed(handlerRunnable, 16);
//Initialize runnables to be used by the input system, avoiding generating one each time is better memory.
switchStateRunnable = () -> {
currentMap.resetPressedState();
if(lastGrabbingState){
currentMap = gameMap;
pointerView.setVisibility(View.INVISIBLE);
mouseSensitivity = 18;
return;
}
currentMap = menuMap;
sendDirectionalKeycode(currentJoystickDirection, false, gameMap); // removing what we were doing
gameActivity.mouse_x = CallbackBridge.windowWidth/2;
gameActivity.mouse_y = CallbackBridge.windowHeight/2;
CallbackBridge.sendCursorPos(gameActivity.mouse_x, gameActivity.mouse_y);
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
pointerView.setVisibility(View.VISIBLE);
//sensitivity in menu is MC and HARDWARE resolution dependent
mouseSensitivity = 19 * gameActivity.scaleFactor / gameActivity.sensitivityFactor;
};
}
private void tick(){
public void tick(long frameTimeNanos){
//update mouse position
if(lastHorizontalValue != 0 || lastVerticalValue != 0){
GamepadJoystick currentJoystick = lastGrabbingState ? leftJoystick : rightJoystick;
@ -136,8 +115,15 @@ public class Gamepad {
acceleration = Math.pow(acceleration, mouseMaxAcceleration);
if(acceleration > 1) acceleration = 1;
CallbackBridge.mouseX += Math.cos(mouseAngle) * acceleration * mouseSensitivity;
CallbackBridge.mouseY -= Math.sin(mouseAngle) * acceleration * mouseSensitivity;
// Compute delta since last tick time
float deltaX = (float) (Math.cos(mouseAngle) * acceleration * mouseSensitivity);
float deltaY = (float) (Math.sin(mouseAngle) * acceleration * mouseSensitivity);
float deltaTimeScale = ((frameTimeNanos - lastFrameTime) / 16666666f); // Scale of 1 = 60Hz
deltaX *= deltaTimeScale;
deltaY *= deltaTimeScale;
CallbackBridge.mouseX += deltaX;
CallbackBridge.mouseY -= deltaY;
if(!lastGrabbingState){
CallbackBridge.mouseX = MathUtils.clamp(CallbackBridge.mouseX, 0, CallbackBridge.windowWidth);
@ -152,14 +138,36 @@ public class Gamepad {
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
}
// Update last nano time
lastFrameTime = frameTimeNanos;
}
/** Update the grabbing state, and change the currentMap, mouse position and sensibility */
private void updateGrabbingState() {
boolean lastGrabbingValue = lastGrabbingState;
lastGrabbingState = CallbackBridge.isGrabbing();
if(lastGrabbingValue != lastGrabbingState){
gameActivity.runOnUiThread(switchStateRunnable);
if(lastGrabbingValue == lastGrabbingState) return;
// Switch grabbing state then
currentMap.resetPressedState();
if(lastGrabbingState){
currentMap = gameMap;
pointerView.setVisibility(View.INVISIBLE);
mouseSensitivity = 18;
return;
}
currentMap = menuMap;
sendDirectionalKeycode(currentJoystickDirection, false, gameMap); // removing what we were doing
gameActivity.mouse_x = CallbackBridge.windowWidth/2;
gameActivity.mouse_y = CallbackBridge.windowHeight/2;
CallbackBridge.sendCursorPos(gameActivity.mouse_x, gameActivity.mouse_y);
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
pointerView.setVisibility(View.VISIBLE);
// Sensitivity in menu is MC and HARDWARE resolution dependent
mouseSensitivity = 19 * gameActivity.scaleFactor / gameActivity.sensitivityFactor;
}
public void update(KeyEvent event){
@ -188,10 +196,10 @@ public class Gamepad {
int lastJoystickDirection = currentJoystickDirection;
currentJoystickDirection = currentJoystick.getHeightDirection(event);
if(currentJoystickDirection != lastJoystickDirection){
sendDirectionalKeycode(lastJoystickDirection, false, getCurrentMap());
sendDirectionalKeycode(currentJoystickDirection, true, getCurrentMap());
}
if(currentJoystickDirection == lastJoystickDirection) return;
sendDirectionalKeycode(lastJoystickDirection, false, getCurrentMap());
sendDirectionalKeycode(currentJoystickDirection, true, getCurrentMap());
}
private void updateAnalogTriggers(MotionEvent event){

View File

@ -29,7 +29,7 @@ import static net.kdt.pojavlaunch.customcontrols.handleview.ActionPopupWindow.se
public class EditControlButtonPopup {
protected Dialog dialog;
protected AlertDialog dialog;
protected View v;
protected AlertDialog.Builder builder;
@ -75,7 +75,6 @@ public class EditControlButtonPopup {
dialog = builder.create();
dialog.setOnShowListener(dialogInterface -> setEditDialogValues());
dialog.show();
}

View File

@ -5,6 +5,7 @@ import android.content.DialogInterface;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.customcontrols.ControlData;
@ -32,6 +33,11 @@ public class EditControlDrawerPopup extends EditControlButtonPopup{
checkPassThrough.setVisibility(View.GONE);
checkToggle.setVisibility(View.GONE);
checkBoxSwipeable.setVisibility(View.GONE);
(v.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
(v.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
editDynamicX.setVisibility(View.GONE);
editDynamicY.setVisibility(View.GONE);
}
@Override
@ -52,18 +58,27 @@ public class EditControlDrawerPopup extends EditControlButtonPopup{
super.setEditDialogValues();
spinnerOrientation.setSelection(ControlDrawerData.orientationToInt(drawerData.orientation));
//Using the dialog to replace the button behavior allows us not to dismiss the window
dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener(v -> {
ControlLayout layout = (ControlLayout) drawer.getParent();
ControlData controlData = new ControlData(drawerData.properties);
controlData.name = "new";
layout.addSubButton(drawer, controlData);
Context ctx = dialog.getContext();
Toast.makeText(ctx, ctx.getString(R.string.customctrl_add_subbutton_message,
drawer.getDrawerData().buttonProperties.size()), Toast.LENGTH_SHORT).show();
});
}
@Override
protected void setupDialogButtons() {
super.setupDialogButtons();
builder.setNeutralButton(v.getResources().getString(R.string.customctrl_addsubbutton), (dialogInterface, i) -> {
ControlLayout layout = (ControlLayout) drawer.getParent();
ControlData controlData = new ControlData(drawerData.properties);
controlData.name = "new";
layout.addSubButton(drawer, controlData);
});
builder.setNeutralButton(v.getResources().getString(R.string.customctrl_addsubbutton), null);
}

View File

@ -0,0 +1,129 @@
package net.kdt.pojavlaunch.extra;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Class providing callback across all of a program
* to allow easy thread safe implementations of UI update without context leak
*
* This class uses a singleton pattern to simplify access to it
*/
public final class ExtraCore {
// No unwanted instantiation
private ExtraCore(){}
// Store the key-value pair
private final Map<String, String> valueMap = new ConcurrentHashMap<>();
// Store what each ExtraListener listen to
private final Map<String, ConcurrentLinkedQueue<WeakReference<ExtraListener>>> listenerMap = new ConcurrentHashMap<>();
// Inner class for singleton implementation
private static class ExtraCoreSingleton {
private static final ExtraCore extraCore = new ExtraCore();
}
// All public methods will pass through this one
private static ExtraCore getInstance(){
return ExtraCoreSingleton.extraCore;
}
/**
* Set the value associated to a key and trigger all listeners
* @param key The key
* @param value The value
*/
public static void setValue(String key, String value){
getInstance().valueMap.put(key, value);
ConcurrentLinkedQueue<WeakReference<ExtraListener>> extraListenerList = getInstance().listenerMap.get(key);
for(WeakReference<ExtraListener> listener : extraListenerList){
if(listener.get() == null){
extraListenerList.remove(listener);
continue;
}
listener.get().notifyDataChanged(key, value);
}
}
/** @return The value behind the key */
public static String getValue(String key){
return getInstance().valueMap.get(key);
}
/** Remove the key and its value from the valueMap */
public static void removeValue(String key){
getInstance().valueMap.remove(key);
}
/** Remove all values */
public static void removeAllValues(){
getInstance().valueMap.clear();
}
/**
* Link an ExtraListener to a value
* @param key The value key to look for
* @param listener The ExtraListener to link
*/
public static void addExtraListener(String key, ExtraListener listener){
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().listenerMap.get(key);
// Look for new sets
if(listenerList == null){
listenerList = new ConcurrentLinkedQueue<>();
getInstance().listenerMap.put(key, listenerList);
}
// This is kinda naive, I should look for duplicates
listenerList.add(new WeakReference<>(listener));
}
/**
* Unlink an ExtraListener from a value.
* Unlink null references found along the way
* @param key The value key to ignore now
* @param listener The ExtraListener to unlink
*/
public static void removeExtraListenerFromValue(String key, ExtraListener listener){
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().listenerMap.get(key);
// Look for new sets
if(listenerList == null){
listenerList = new ConcurrentLinkedQueue<>();
getInstance().listenerMap.put(key, listenerList);
}
// Removes all occurrences of ExtraListener and all null references
for(WeakReference<ExtraListener> listenerWeakReference : listenerList){
ExtraListener actualListener = listenerWeakReference.get();
if(actualListener == null || actualListener == listener){
listenerList.remove(listenerWeakReference);
}
}
}
/**
* Unlink all ExtraListeners from a value
* @param key The key to which ExtraListener are linked
*/
public static void removeAllExtraListenersFromValue(String key){
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().listenerMap.get(key);
// Look for new sets
if(listenerList == null){
listenerList = new ConcurrentLinkedQueue<>();
getInstance().listenerMap.put(key, listenerList);
}
listenerList.clear();
}
/**
* Remove all ExtraListeners from listening to any value
*/
public static void removeAllExtraListeners(){
getInstance().listenerMap.clear();
}
}

View File

@ -0,0 +1,26 @@
package net.kdt.pojavlaunch.extra;
/**
* Listener class for the ExtraCore
* An ExtraListener can listen to a virtually unlimited amount of values
*/
public abstract class ExtraListener {
/**
* Called by the ExtraCore after a value is set.
* Technically, it can be triggered from outside but is seems pointless
*/
public final void notifyDataChanged(String key, String value){
if(onValueSet(key, value)){
ExtraCore.removeExtraListenerFromValue(key, this);
}
}
/**
* Called upon a new value being set
* @param key The name of the value
* @param value The new value as a string
* @return Whether you consume the Listener (stop listening)
*/
public abstract boolean onValueSet(String key, String value);
}

View File

@ -0,0 +1,36 @@
package net.kdt.pojavlaunch.prefs;
import android.content.Context;
import android.util.AttributeSet;
import androidx.preference.Preference;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.extra.ExtraCore;
public class BackButtonPreference extends Preference {
public BackButtonPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public BackButtonPreference(Context context) {
this(context, null);
}
private void init(){
if(getTitle() == null){
setTitle(R.string.preference_back_title);
}
if(getIcon() == null){
setIcon(R.drawable.ic_arrow_back_white);
}
}
@Override
protected void onClick() {
// It is caught by an ExtraListener in the LauncherActivity
ExtraCore.setValue("back_preference", "true");
}
}

View File

@ -0,0 +1,127 @@
package net.kdt.pojavlaunch.prefs;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.DEFAULT_PREF;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_BOTTOM_OFFSET;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_LEFT_OFFSET;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_RIGHT_OFFSET;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_CONTROL_TOP_OFFSET;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.AttributeSet;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.preference.Preference;
import net.kdt.pojavlaunch.R;
/** Custom preference class displaying a dialog */
public class ControlOffsetPreference extends Preference {
private AlertDialog preferenceDialog;
public ControlOffsetPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ControlOffsetPreference(Context context) {
super(context);
init();
}
private void init(){
// Setup visual values
if(getTitle() == null){
setTitle(R.string.preference_control_offset_title);
setSummary(R.string.preference_control_offset_description);
}
if(getIcon() == null){
setIcon(android.R.drawable.radiobutton_off_background);
}
// Prepare Alert dialog
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext());
dialogBuilder.setView(R.layout.control_offset_preference_dialog);
dialogBuilder.setTitle(getContext().getString(R.string.control_offset_title));
dialogBuilder.setPositiveButton(android.R.string.ok, null);
dialogBuilder.setNegativeButton(android.R.string.cancel, null);
preferenceDialog = dialogBuilder.create();
}
@Override
protected void onClick() {
preferenceDialog.show();
SeekBar topOffsetSeekbar = preferenceDialog.findViewById(R.id.control_offset_top_seekbar);
SeekBar rightOffsetSeekbar = preferenceDialog.findViewById(R.id.control_offset_right_seekbar);
SeekBar bottomOffsetSeekbar = preferenceDialog.findViewById(R.id.control_offset_bottom_seekbar);
SeekBar leftOffsetSeekbar = preferenceDialog.findViewById(R.id.control_offset_left_seekbar);
TextView topOffsetTextView = preferenceDialog.findViewById(R.id.control_offset_top_textview);
TextView rightOffsetTextView = preferenceDialog.findViewById(R.id.control_offset_right_textview);
TextView bottomOffsetTextView = preferenceDialog.findViewById(R.id.control_offset_bottom_textview);
TextView leftOffsetTextView = preferenceDialog.findViewById(R.id.control_offset_left_textview);
SeekBar.OnSeekBarChangeListener seekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if(seekBar == topOffsetSeekbar){
String text = String.format("%s%d", getContext().getString(R.string.control_top_offset), i);
topOffsetTextView.setText(text);
return;
}
if(seekBar == rightOffsetSeekbar){
String text = String.format("%s%d", getContext().getString(R.string.control_right_offset), i);
rightOffsetTextView.setText(text);
return;
}
if(seekBar == bottomOffsetSeekbar){
String text = String.format("%s%d", getContext().getString(R.string.control_bottom_offset), i);
bottomOffsetTextView.setText(text);
return;
}
if(seekBar == leftOffsetSeekbar){
String text = String.format("%s%d", getContext().getString(R.string.control_left_offset), i);
leftOffsetTextView.setText(text);
return;
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
};
topOffsetSeekbar.setOnSeekBarChangeListener(seekBarChangeListener);
rightOffsetSeekbar.setOnSeekBarChangeListener(seekBarChangeListener);
bottomOffsetSeekbar.setOnSeekBarChangeListener(seekBarChangeListener);
leftOffsetSeekbar.setOnSeekBarChangeListener(seekBarChangeListener);
topOffsetSeekbar.setProgress(PREF_CONTROL_TOP_OFFSET);
rightOffsetSeekbar.setProgress(PREF_CONTROL_RIGHT_OFFSET);
bottomOffsetSeekbar.setProgress(PREF_CONTROL_BOTTOM_OFFSET);
leftOffsetSeekbar.setProgress(PREF_CONTROL_LEFT_OFFSET);
// Custom writing to preferences
preferenceDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(view -> {
DEFAULT_PREF.edit().putInt("controlTopOffset", topOffsetSeekbar.getProgress()).apply();
DEFAULT_PREF.edit().putInt("controlRightOffset", rightOffsetSeekbar.getProgress()).apply();
DEFAULT_PREF.edit().putInt("controlBottomOffset", bottomOffsetSeekbar.getProgress()).apply();
DEFAULT_PREF.edit().putInt("controlLeftOffset", leftOffsetSeekbar.getProgress()).apply();
preferenceDialog.dismiss();
});
}
}

View File

@ -15,10 +15,14 @@ import net.kdt.pojavlaunch.R;
public class CustomSeekBarPreference extends SeekBarPreference {
/** The suffix displayed */
private String suffix = "";
/** Custom minimum value to provide the same behavior as the usual setMin */
private int mMin;
/** The textview associated by default to the preference */
private TextView textView;
public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray a = context.obtainStyledAttributes(
@ -59,22 +63,26 @@ public class CustomSeekBarPreference extends SeekBarPreference {
SeekBar seekBar = (SeekBar) view.findViewById(R.id.seekbar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
progress = progress / getSeekBarIncrement();
progress = progress * getSeekBarIncrement();
textView.setText(String.valueOf(progress + mMin));
updateTextViewWithSuffix();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
setValue(seekBar.getProgress() + mMin);
updateTextViewWithSuffix();
int progress = seekBar.getProgress() / getSeekBarIncrement();
progress *= getSeekBarIncrement();
setValue(progress + mMin);
updateTextViewWithSuffix();
}
});
@ -82,7 +90,6 @@ public class CustomSeekBarPreference extends SeekBarPreference {
}
private void updateTextViewWithSuffix(){
if(!textView.getText().toString().endsWith(suffix)){
textView.setText(String.format("%s%s", textView.getText(), suffix));

View File

@ -1,104 +0,0 @@
package net.kdt.pojavlaunch.prefs;
import android.graphics.Color;
import android.os.*;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.*;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.fragments.LauncherFragment;
import android.content.*;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import static net.kdt.pojavlaunch.Architecture.is32BitsDevice;
import static net.kdt.pojavlaunch.Tools.getTotalDeviceMemory;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_NOTCH_SIZE;
public class LauncherPreferenceFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener
{
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
view.setBackgroundColor(Color.parseColor("#44000000"));
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onCreatePreferences(Bundle b, String str) {
addPreferencesFromResource(R.xml.pref_main);
//Disable notch checking behavior on android 8.1 and below.
findPreference("ignoreNotch").setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && PREF_NOTCH_SIZE != 0);
CustomSeekBarPreference seek2 = findPreference("timeLongPressTrigger");
seek2.setRange(100, 1000);
seek2.setValue(LauncherPreferences.PREF_LONGPRESS_TRIGGER);
seek2.setSuffix(" ms");
CustomSeekBarPreference seek3 = findPreference("buttonscale");
seek3.setRange(80, 250);
seek3.setValue((int) LauncherPreferences.PREF_BUTTONSIZE);
seek3.setSuffix(" %");
CustomSeekBarPreference seek4 = findPreference("mousescale");
seek4.setRange(25, 300);
seek4.setValue((int) LauncherPreferences.PREF_MOUSESCALE);
seek4.setSuffix(" %");
CustomSeekBarPreference seek5 = findPreference("resolutionRatio");
seek5.setMin(25);
seek5.setSuffix(" %");
CustomSeekBarPreference seek6 = findPreference("mousespeed");
seek6.setRange(25, 300);
seek6.setValue((int)(LauncherPreferences.PREF_MOUSESPEED*100f));
seek6.setSuffix(" %");
int maxRAM;
int deviceRam = getTotalDeviceMemory(getContext());
CustomSeekBarPreference seek7 = findPreference("allocation");
seek7.setMin(256);
if(is32BitsDevice()) maxRAM = Math.min(1100, deviceRam);
else maxRAM = deviceRam - (deviceRam < 3064 ? 800 : 1024); //To have a minimum for the device to breathe
seek7.setMax(maxRAM);
seek7.setValue(LauncherPreferences.PREF_RAM_ALLOCATION);
seek7.setSuffix(" MB");
// #724 bug fix
if (seek5.getValue() < 25) {
seek5.setValue(100);
}
EditTextPreference editJVMArgs = findPreference("javaArgs");
if (editJVMArgs != null) {
editJVMArgs.setOnBindEditTextListener((editText) -> editText.setSingleLine());
}
}
@Override
public void onResume() {
super.onResume();
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences p, String s) {
LauncherPreferences.loadPreferences(getContext());
}
}

View File

@ -29,6 +29,12 @@ public class LauncherPreferences
public static float PREF_MOUSESPEED = 1f;
public static int PREF_RAM_ALLOCATION;
public static String PREF_DEFAULT_RUNTIME;
public static int PREF_CONTROL_TOP_OFFSET = 0;
public static int PREF_CONTROL_RIGHT_OFFSET = 0;
public static int PREF_CONTROL_BOTTOM_OFFSET = 0;
public static int PREF_CONTROL_LEFT_OFFSET = 0;
public static void loadPreferences(Context ctx) {
//Required for the data folder.
Tools.initContextConstants(ctx);
@ -51,6 +57,11 @@ public class LauncherPreferences
PREF_DISABLE_GESTURES = DEFAULT_PREF.getBoolean("disableGestures",false);
PREF_RAM_ALLOCATION = DEFAULT_PREF.getInt("allocation", findBestRAMAllocation(ctx));
PREF_CUSTOM_JAVA_ARGS = DEFAULT_PREF.getString("javaArgs", "");
PREF_CONTROL_TOP_OFFSET = DEFAULT_PREF.getInt("controlTopOffset", 0);
PREF_CONTROL_RIGHT_OFFSET = DEFAULT_PREF.getInt("controlRightOffset", 0);
PREF_CONTROL_BOTTOM_OFFSET = DEFAULT_PREF.getInt("controlBottomOffset", 0);
PREF_CONTROL_LEFT_OFFSET = DEFAULT_PREF.getInt("controlTopOffset", 0);
/*
if (PREF_CUSTOM_JAVA_ARGS.isEmpty()) {
String DEFAULT_JAVA_ARGS = "";

View File

@ -0,0 +1,58 @@
package net.kdt.pojavlaunch.prefs.screens;
import android.content.SharedPreferences;
import android.os.Bundle;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.prefs.CustomSeekBarPreference;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
public class LauncherPreferenceControlFragment extends LauncherPreferenceFragment {
@Override
public void onCreatePreferences(Bundle b, String str) {
// Get values
int longPressTrigger = LauncherPreferences.PREF_LONGPRESS_TRIGGER;
int prefButtonSize = (int) LauncherPreferences.PREF_BUTTONSIZE;
int mouseScale = (int) LauncherPreferences.PREF_MOUSESCALE;
float mouseSpeed = LauncherPreferences.PREF_MOUSESPEED;
//Triggers a write for some reason which resets the value
addPreferencesFromResource(R.xml.pref_control);
CustomSeekBarPreference seek2 = findPreference("timeLongPressTrigger");
seek2.setRange(100, 1000);
seek2.setValue(longPressTrigger);
seek2.setSuffix(" ms");
CustomSeekBarPreference seek3 = findPreference("buttonscale");
seek3.setRange(80, 250);
seek3.setValue(prefButtonSize);
seek3.setSuffix(" %");
CustomSeekBarPreference seek4 = findPreference("mousescale");
seek4.setRange(25, 300);
seek4.setValue(mouseScale);
seek4.setSuffix(" %");
CustomSeekBarPreference seek6 = findPreference("mousespeed");
seek6.setRange(25, 300);
seek6.setValue((int)(mouseSpeed *100f));
seek6.setSuffix(" %");
computeVisibility();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences p, String s) {
super.onSharedPreferenceChanged(p, s);
computeVisibility();
}
private void computeVisibility(){
CustomSeekBarPreference seek2 = findPreference("timeLongPressTrigger");
seek2.setVisible(!LauncherPreferences.PREF_DISABLE_GESTURES);
}
}

View File

@ -0,0 +1,13 @@
package net.kdt.pojavlaunch.prefs.screens;
import android.os.Bundle;
import net.kdt.pojavlaunch.R;
public class LauncherPreferenceExperimentalFragment extends LauncherPreferenceFragment {
@Override
public void onCreatePreferences(Bundle b, String str) {
addPreferencesFromResource(R.xml.pref_experimental);
}
}

View File

@ -0,0 +1,57 @@
package net.kdt.pojavlaunch.prefs.screens;
import android.graphics.Color;
import android.os.*;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.*;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import android.content.*;
import android.view.View;
import android.widget.Toast;
import static net.kdt.pojavlaunch.Architecture.is32BitsDevice;
import static net.kdt.pojavlaunch.Tools.getTotalDeviceMemory;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_NOTCH_SIZE;
/**
* Preference for the main screen, any sub-screen should inherit this class for consistent behavior,
* overriding only onCreatePreferences
*/
public class LauncherPreferenceFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
view.setBackgroundColor(Color.parseColor("#232323"));
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onCreatePreferences(Bundle b, String str) {
addPreferencesFromResource(R.xml.pref_main);
}
@Override
public void onResume() {
super.onResume();
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences p, String s) {
LauncherPreferences.loadPreferences(getContext());
}
}

View File

@ -0,0 +1,43 @@
package net.kdt.pojavlaunch.prefs.screens;
import static net.kdt.pojavlaunch.Architecture.is32BitsDevice;
import static net.kdt.pojavlaunch.Tools.getTotalDeviceMemory;
import android.os.Bundle;
import android.widget.TextView;
import androidx.preference.EditTextPreference;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.prefs.CustomSeekBarPreference;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
public class LauncherPreferenceJavaFragment extends LauncherPreferenceFragment {
@Override
public void onCreatePreferences(Bundle b, String str) {
int ramAllocation = LauncherPreferences.PREF_RAM_ALLOCATION;
// Triggers a write for some reason
addPreferencesFromResource(R.xml.pref_java);
int maxRAM;
int deviceRam = getTotalDeviceMemory(getContext());
CustomSeekBarPreference seek7 = findPreference("allocation");
seek7.setMin(256);
if(is32BitsDevice()) maxRAM = Math.min(1100, deviceRam);
else maxRAM = deviceRam - (deviceRam < 3064 ? 800 : 1024); //To have a minimum for the device to breathe
seek7.setMax(maxRAM);
seek7.setValue(ramAllocation);
seek7.setSuffix(" MB");
EditTextPreference editJVMArgs = findPreference("javaArgs");
if (editJVMArgs != null) {
editJVMArgs.setOnBindEditTextListener(TextView::setSingleLine);
}
}
}

View File

@ -0,0 +1,12 @@
package net.kdt.pojavlaunch.prefs.screens;
import android.os.Bundle;
import net.kdt.pojavlaunch.R;
public class LauncherPreferenceMiscellaneousFragment extends LauncherPreferenceFragment {
@Override
public void onCreatePreferences(Bundle b, String str) {
addPreferencesFromResource(R.xml.pref_misc);
}
}

View File

@ -0,0 +1,33 @@
package net.kdt.pojavlaunch.prefs.screens;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_NOTCH_SIZE;
import android.os.Build;
import android.os.Bundle;
import androidx.preference.PreferenceFragmentCompat;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.prefs.CustomSeekBarPreference;
/**
* Fragment for any settings video related
*/
public class LauncherPreferenceVideoFragment extends LauncherPreferenceFragment {
@Override
public void onCreatePreferences(Bundle b, String str) {
addPreferencesFromResource(R.xml.pref_video);
//Disable notch checking behavior on android 8.1 and below.
findPreference("ignoreNotch").setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && PREF_NOTCH_SIZE != 0);
CustomSeekBarPreference seek5 = findPreference("resolutionRatio");
seek5.setMin(25);
seek5.setSuffix(" %");
// #724 bug fix
if (seek5.getValue() < 25) {
seek5.setValue(100);
}
}
}

View File

@ -324,7 +324,7 @@ public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable
}
if (p1.length < 3) {
mActivity.mConsoleView.putLog(p1[1] + "\n");
//mActivity.mConsoleView.putLog(p1[1] + "\n");
}
}
@ -341,7 +341,7 @@ public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable
Tools.showError(mActivity, p1);
}
if(!launchWithError) {
mActivity.mCrashView.setLastCrash("");
//mActivity.mCrashView.setLastCrash("");
try {
Intent mainIntent = new Intent(mActivity, MainActivity.class /* MainActivity.class */);

View File

@ -77,8 +77,7 @@ public class RefreshVersionListTask extends AsyncTask<Void, Void, ArrayList<Stri
@Override
public void onItemSelected(AdapterView<?> p1, View p2, int p3, long p4)
{
String version = p1.getItemAtPosition(p3).toString();
mActivity.mProfile.selectedVersion = version;
mActivity.mProfile.selectedVersion = p1.getItemAtPosition(p3).toString();
PojavProfile.setCurrentProfile(mActivity, mActivity.mProfile);
if (PojavProfile.isFileType(mActivity)) {
@ -89,7 +88,6 @@ public class RefreshVersionListTask extends AsyncTask<Void, Void, ArrayList<Stri
}
}
mActivity.mTextVersion.setText(mActivity.getString(R.string.mcl_version_msg, version));
}
@Override
@ -109,13 +107,8 @@ public class RefreshVersionListTask extends AsyncTask<Void, Void, ArrayList<Stri
}
});
*/
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
return true;
}
});
popup.setOnMenuItemClickListener(item -> true);
mActivity.mTextVersion.setText(mActivity.getString(R.string.mcl_version_msg,mActivity.mVersionSelector.getSelectedItem()));
}
private ArrayList<String> filter(JMinecraftVersionList.Version[] list1, File[] list2) {
@ -145,9 +138,8 @@ public class RefreshVersionListTask extends AsyncTask<Void, Void, ArrayList<Stri
for(String str : strArr){
if (str.equals(select)) {
return count;
} else {
count++;
}
count++;
}
return -1;
}

View File

@ -1,4 +1,7 @@
package net.kdt.pojavlaunch.value;
import android.graphics.BitmapFactory;
import android.util.Log;
import net.kdt.pojavlaunch.*;
@ -49,8 +52,9 @@ public class MinecraftAccount
public static MinecraftAccount parse(String content) throws JsonSyntaxException {
return Tools.GLOBAL_GSON.fromJson(content, MinecraftAccount.class);
}
public static MinecraftAccount load(String name) throws JsonSyntaxException {
if(!accountExists(name)) return new MinecraftAccount();
try {
MinecraftAccount acc = parse(Tools.read(Tools.DIR_ACCOUNT_NEW + "/" + name + ".json"));
if (acc.accessToken == null) {
@ -80,7 +84,19 @@ public class MinecraftAccount
return null;
}
}
public Bitmap getSkinFace(){
if(skinFaceBase64 == null){
return Bitmap.createBitmap(1,1, Bitmap.Config.ARGB_8888);
}
byte[] faceIconBytes = Base64.decode(skinFaceBase64, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(faceIconBytes, 0, faceIconBytes.length);
}
private static boolean accountExists(String username){
return new File(Tools.DIR_ACCOUNT_NEW + "/" + username + ".json").exists();
}
public static void clearTempAccount() {
File tempAccFile = new File(Tools.DIR_DATA, "cache/tempacc.json");
tempAccFile.delete();

View File

@ -15,7 +15,7 @@ public class CallbackBridge {
public static volatile int windowWidth, windowHeight;
public static volatile int physicalWidth, physicalHeight;
public static int mouseX, mouseY;
public static float mouseX, mouseY;
public static StringBuilder DEBUG_STRING = new StringBuilder();
// volatile private static boolean isGrabbing = false;
@ -29,7 +29,7 @@ public class CallbackBridge {
@Override
public void run() {
putMouseEventWithCoords(button, true, x, y);
try { Thread.sleep(40); } catch (InterruptedException e) {}
//try { Thread.sleep(1); } catch (InterruptedException e) {}
putMouseEventWithCoords(button, false, x, y);
}
}
@ -37,7 +37,7 @@ public class CallbackBridge {
new Thread(new PusherRunnable(button,x,y)).run();
}
public static void putMouseEventWithCoords(int button, boolean isDown, int x, int y /* , int dz, long nanos */) {
public static void putMouseEventWithCoords(int button, boolean isDown, float x, float y /* , int dz, long nanos */) {
sendCursorPos(x, y);
sendMouseKeycode(button, CallbackBridge.getCurrentMods(), isDown);
}
@ -49,8 +49,8 @@ public class CallbackBridge {
}
DEBUG_STRING.append("CursorPos=").append(x).append(", ").append(y).append("\n");
mouseX = (int) x;
mouseY = (int) y;
mouseX = x;
mouseY = y;
nativeSendCursorPos(mouseX, mouseY);
}
@ -126,13 +126,6 @@ public class CallbackBridge {
default: return null;
}
}
public static void receiveCallback(int type, String data) {
switch (type) {
case ANDROID_TYPE_GRAB_STATE:
// isGrabbing = Boolean.parseBoolean(data);
break;
}
}
/*
private static String currData;
public static void sendData(int type, Object... dataArr) {
@ -201,7 +194,7 @@ public class CallbackBridge {
private static native boolean nativeSendCharMods(char codepoint, int mods);
private static native void nativeSendKey(int key, int scancode, int action, int mods);
// private static native void nativeSendCursorEnter(int entered);
private static native void nativeSendCursorPos(int x, int y);
private static native void nativeSendCursorPos(float x, float y);
private static native void nativeSendMouseButton(int button, int action, int mods);
private static native void nativeSendScroll(double xoffset, double yoffset);
private static native void nativeSendScreenSize(int width, int height);

View File

@ -37,7 +37,7 @@ typedef void GLFW_invoke_MouseButton_func(void* window, int button, int action,
typedef void GLFW_invoke_Scroll_func(void* window, double xoffset, double yoffset);
typedef void GLFW_invoke_WindowSize_func(void* window, int width, int height);
static int grabCursorX, grabCursorY, lastCursorX, lastCursorY;
static float grabCursorX, grabCursorY, lastCursorX, lastCursorY;
jclass inputBridgeClass_ANDROID, inputBridgeClass_JRE;
jmethodID inputBridgeMethod_ANDROID, inputBridgeMethod_JRE;
@ -255,7 +255,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorEnter(
}
}
*/
JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JNIEnv* env, jclass clazz, jint x, jint y) {
JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendCursorPos(JNIEnv* env, jclass clazz, jfloat x, jfloat y) {
if (GLFW_invoke_CursorPos && isInputReady) {
if (!isCursorEntered) {
if (GLFW_invoke_CursorEnter) {

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:pathData="M16,7L3.8,7l5.6,-5.6L8,0l-8,8 8,8 1.4,-1.4L3.8,9L16,9v-2z"
android:fillColor="#FFF"/>
</vector>

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginHorizontal="15dp">
<TextView
android:id="@+id/control_offset_top_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/control_top_offset"
/>
<SeekBar
android:id="@+id/control_offset_top_seekbar"
android:layout_width="match_parent"
android:layout_height="40dp" />
<TextView
android:id="@+id/control_offset_right_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/control_right_offset"
/>
<SeekBar
android:id="@+id/control_offset_right_seekbar"
android:layout_width="match_parent"
android:layout_height="40dp" />
<TextView
android:id="@+id/control_offset_bottom_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/control_bottom_offset"
/>
<SeekBar
android:id="@+id/control_offset_bottom_seekbar"
android:layout_width="match_parent"
android:layout_height="40dp" />
<TextView
android:id="@+id/control_offset_left_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/control_left_offset"
/>
<SeekBar
android:id="@+id/control_offset_left_seekbar"
android:layout_width="match_parent"
android:layout_height="40dp" />
</LinearLayout>
</ScrollView>

View File

@ -33,17 +33,33 @@
android:orientation="vertical"
app:layout_constraintGuide_percent="0.86" />
<ImageView
android:id="@+id/launchermain_account_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="3dp"
android:layout_marginTop="3dp"
android:src="@mipmap/ic_launcher"
app:layout_constraintEnd_toEndOf="@id/launchermain_spinner_account"
app:layout_constraintHorizontal_bias="0.00"
app:layout_constraintStart_toStartOf="@id/launchermain_spinner_account"
app:layout_constraintTop_toTopOf="parent" />
<Spinner
android:id="@+id/launchermain_spinner_account"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:layout_height="0dp"
android:background="@android:color/transparent"
android:spinnerMode="dropdown"
android:paddingLeft="43dp"
app:layout_constraintBottom_toBottomOf="@+id/launchermain_account_image"
app:layout_constraintEnd_toStartOf="@+id/guidelineLeft"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="@+id/launchermain_account_image" />
<TextView
android:id="@+id/launchermain_text_accountstatus"
@ -89,18 +105,18 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingStart="12dp"
android:paddingEnd="0dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:drawableStart="@drawable/ic_menu_java"
android:focusable="true"
android:gravity="center"
android:onClick="onTabClicked"
android:paddingStart="12dp"
android:paddingTop="10dp"
android:paddingEnd="0dp"
android:paddingBottom="10dp"
android:text="@string/mcl_tab_console"
android:textAlignment="center"
android:textAllCaps="true"
@ -118,18 +134,18 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingStart="12dp"
android:paddingEnd="0dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:drawableStart="@drawable/ic_menu_warning"
android:focusable="true"
android:gravity="center"
android:onClick="onTabClicked"
android:paddingStart="12dp"
android:paddingTop="10dp"
android:paddingEnd="0dp"
android:paddingBottom="10dp"
android:text="@string/mcl_tab_crash"
android:textAlignment="center"
android:textAllCaps="true"
@ -172,7 +188,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guidelineBottom" />
<androidx.viewpager.widget.ViewPager
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/launchermainTabPager"
android:layout_width="0dp"
android:layout_height="0dp"
@ -217,75 +233,46 @@
<Button
style="?android:attr/buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="0dp"
android:onClick="launcherMenu"
android:text="@string/main_options"
style="?android:attr/buttonBarButtonStyle"
android:background="?attr/selectableItemBackground"
android:onClick="launchCustomControlsActivity"
android:text="@string/mcl_option_customcontrol"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/launchermainPlayButton"
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
app:layout_constraintTop_toTopOf="@+id/guidelineBottom2" />
<com.kdt.mcgui.MineButton
android:background="@drawable/mine_button_background"
android:id="@+id/launchermainPlayButton"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignParentBottom="true"
android:background="@drawable/mine_button_background"
android:onClick="launchGame"
android:text="@string/main_play"
android:textColor="@android:color/white"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.25"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
app:layout_constraintTop_toTopOf="@+id/guidelineBottom"
/>
<TextView
android:id="@+id/launchermain_text_welcome"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/main_welcome"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/launchermainPlayButton"
app:layout_constraintTop_toTopOf="@+id/guidelineBottom" />
<TextView
android:id="@+id/launcherMainVersionView"
android:layout_width="0dp"
android:layout_height="20dp"
android:gravity="center"
android:text="@string/global_waiting"
android:textSize="12sp"
android:singleLine="true"
android:scrollHorizontally="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:focusable="true"
android:focusableInTouchMode="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/launchermainPlayButton"
app:layout_constraintTop_toBottomOf="@+id/launchermain_text_welcome" />
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.25" />
<Button
android:id="@+id/switchUserBtn"
android:id="@+id/installJarButton"
style="?android:attr/buttonBarButtonStyle"
android:background="?attr/selectableItemBackground"
android:layout_width="0dp"
android:layout_height="0dp"
android:onClick="mcaccLogout"
android:text="@string/main_switchuser"
android:background="?attr/selectableItemBackground"
android:onClick="installJarFile"
android:text="@string/main_install_jar_file"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"

View File

@ -1,12 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="mcl_options">
<item>@string/mcl_option_modinstall</item>
<item>@string/mcl_option_modinstallwitharg</item>
<item>@string/mcl_option_customcontrol</item>
<item>@string/mcl_option_about</item>
</string-array>
<string-array name="renderer">
<item name="2">@string/mcl_setting_renderer_gles2_4</item>
<item name="3">@string/mcl_setting_renderer_gles2_5</item>

View File

@ -203,9 +203,12 @@
<string name="customctrl_addbutton">Add button</string>
<string name="customctrl_addbutton_drawer">Add button drawer</string>
<string name="customctrl_addsubbutton">Add sub-button</string>
<string name="customctrl_add_subbutton_message">Sub-button n°%d has been added !</string>
<string name="customctrl_selectdefault">Select default Control json</string>
<string name="main_install_jar_file">Install .jar</string>
<string name="main_options">Options</string>
<string name="main_play">Play</string>
<string name="main_welcome">Welcome, %s</string>
@ -253,4 +256,26 @@
<string name="pvc_title">Per-version settings</string>
<string name="storage_warning_title">Storage changes</string>
<string name="storage_warning_text"> <![CDATA[Due to Google\'s new scoped storage enforcements added in Android 10 and higher, we are required to move the game directory into an app-private folder.<br /> The new folder for Pojav files is <b>Android/data/%s/files/</b> (also accessible using a storage provider in your file explorer).<br /> If you need to copy your game files, please copy everything from the original folder at <b>games/PojavLauncher</b> manually.]]></string>
<string name="control_offset_title">Control offset</string>
<string name="control_top_offset">Top offset: </string>
<string name="control_right_offset">right offset: </string>
<string name="control_bottom_offset">bottom offset: </string>
<string name="control_left_offset">left offset: </string>
<string name="preference_control_offset_title">Control side offsets</string>
<string name="preference_control_offset_description">Set a custom offset to each side of the screen</string>
<string name="preference_video_title">Video and renderer</string>
<string name="preference_video_description">Resolution, scaling type, and renderer</string>
<string name="preference_control_title">Control customization</string>
<string name="preference_control_description">Gestures types, triggers, and scaling</string>
<string name="preference_java_title">Java Tweaks</string>
<string name="preference_java_description">Java versions, JVM Arguments, and RAM amount</string>
<string name="preference_misc_title">Miscellaneous settings</string>
<string name="preference_misc_description">Version list, and libs checks</string>
<string name="preference_experimental_title">Experimental Stuff</string>
<string name="preference_experimental_description">Use things there with consideration, no support.</string>
<string name="preference_back_title">Back to the last screen</string>
</resources>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app2="http://schemas.android.com/apk/res-auto">
<net.kdt.pojavlaunch.prefs.BackButtonPreference/>
<PreferenceCategory
android:title="Gestures ">
<androidx.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_disable_gestures"
android:key="disableGestures"
android:summary="@string/mcl_disable_gestures_subtitle"
android:title="@string/mcl_disable_gestures" />
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="timeLongPressTrigger"
android:summary="@string/mcl_setting_subtitle_longpresstrigger"
android:title="@string/mcl_setting_title_longpresstrigger"
app2:showSeekBarValue="true"
app2:selectable="false"
app2:seekBarIncrement="10"
app2:icon="@drawable/tap_len" />
</PreferenceCategory>
<PreferenceCategory
android:title="Buttons">
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="buttonscale"
android:title="@string/mcl_setting_title_buttonscale"
android:summary="@string/mcl_setting_subtitle_buttonscale"
app2:showSeekBarValue="true"
app2:selectable="false"
app2:icon="@drawable/btn_scale"/>
<net.kdt.pojavlaunch.prefs.ControlOffsetPreference/>
</PreferenceCategory>
<PreferenceCategory
android:title="Virtual mouse">
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="mousescale"
android:summary="@string/mcl_setting_subtitle_mousescale"
android:title="@string/mcl_setting_title_mousescale"
app2:icon="@drawable/mouse_pointer_1"
app2:selectable="false"
app2:showSeekBarValue="true" />
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="mousespeed"
android:summary="@string/mcl_setting_subtitle_mousespeed"
android:title="@string/mcl_setting_title_mousespeed"
app2:icon="@drawable/mouse_pointer_spd"
app2:selectable="false"
app2:showSeekBarValue="true" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<net.kdt.pojavlaunch.prefs.BackButtonPreference/>
<PreferenceCategory android:title="Experimental fuckury">
</PreferenceCategory>
</PreferenceScreen>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app2="http://schemas.android.com/apk/res-auto">
<net.kdt.pojavlaunch.prefs.BackButtonPreference/>
<PreferenceCategory android:title="Java Tweaks">
<net.kdt.pojavlaunch.prefs.RuntimeManagerPreference
android:summary="@string/multirt_subtitle"
android:title="@string/multirt_title"/>
<androidx.preference.EditTextPreference
android:dialogTitle="@string/mcl_setting_title_javaargs"
android:icon="@drawable/jre_args"
android:key="javaArgs"
android:singleLine="true"
android:summary="@string/mcl_setting_subtitle_javaargs"
android:title="@string/mcl_setting_title_javaargs" />
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="allocation"
android:icon="@drawable/ic_auto_ram"
android:summary="@string/mcl_memory_allocation_subtitle"
android:title="@string/mcl_memory_allocation"
app2:showSeekBarValue="true"
app2:selectable="false"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@ -1,129 +1,39 @@
<?xml version="1.0" encoding="utf-8" ?>
<androidx.preference.PreferenceScreen xmlns:app2="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.chom/apk/res-auto">
<androidx.preference.PreferenceCategory
android:title="@string/mcl_setting_category_general">
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<net.kdt.pojavlaunch.prefs.RuntimeManagerPreference
android:summary="@string/multirt_subtitle"
android:title="@string/multirt_title"/>
<androidx.preference.ListPreference
android:title="@string/mcl_setting_category_renderer"
android:key="renderer"
android:defaultValue="opengles2"
android:entries="@array/renderer"
android:entryValues="@array/renderer_values"/>
<Preference
android:key="video_screen_setting"
android:title="@string/preference_video_title"
android:summary="@string/preference_video_description"
android:fragment="net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceVideoFragment"
/>
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="timeLongPressTrigger"
android:summary="@string/mcl_setting_subtitle_longpresstrigger"
android:title="@string/mcl_setting_title_longpresstrigger"
app2:showSeekBarValue="true"
app2:selectable="false"
app2:icon="@drawable/tap_len" />
<Preference
android:key="control_screen_setting"
android:title="@string/preference_control_title"
android:summary="@string/preference_control_description"
android:fragment="net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceControlFragment"
/>
<Preference
android:key="java_screen_setting"
android:title="@string/preference_java_title"
android:summary="@string/preference_java_description"
android:fragment="net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceJavaFragment"
/>
<androidx.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:icon="@drawable/ic_disable_gestures"
android:key="disableGestures"
android:summary="@string/mcl_disable_gestures_subtitle"
android:title="@string/mcl_disable_gestures" />
<Preference
android:key="misc_screen_setting"
android:title="@string/preference_misc_title"
android:summary="@string/preference_misc_description"
android:fragment="net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceMiscellaneousFragment"
/>
<androidx.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="hideSidebar"
android:summary="@string/mcl_setting_subtitle_hide_sidebar"
android:title="@string/mcl_setting_title_hide_sidebar"
app2:icon="@drawable/hide_sidebar" />
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="allocation"
android:icon="@drawable/ic_auto_ram"
android:summary="@string/mcl_memory_allocation_subtitle"
android:title="@string/mcl_memory_allocation"
app2:showSeekBarValue="true"
app2:selectable="false"/>
<androidx.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="ignoreNotch"
android:summary="@string/mcl_setting_subtitle_ignore_notch"
android:title="@string/mcl_setting_title_ignore_notch"
app2:icon="@drawable/ignore_notch" />
<Preference
android:key="experimental_screen_setting"
android:title="@string/preference_experimental_title"
android:summary="@string/preference_experimental_description"
android:fragment="net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceExperimentalFragment"
/>
<androidx.preference.EditTextPreference
android:dialogTitle="@string/mcl_setting_title_javaargs"
android:icon="@drawable/jre_args"
android:key="javaArgs"
android:singleLine="true"
android:summary="@string/mcl_setting_subtitle_javaargs"
android:title="@string/mcl_setting_title_javaargs" />
<androidx.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:icon="@drawable/ic_lib_check"
android:key="checkLibraries"
android:summary="@string/mcl_setting_check_libraries_subtitle"
android:title="@string/mcl_setting_check_libraries" />
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory
android:title="@string/mcl_setting_category_scaling">
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="resolutionRatio"
android:summary="@string/mcl_setting_subtitle_resolution_scaler"
android:title="@string/mcl_setting_title_resolution_scaler"
app2:showSeekBarValue="true"
app2:selectable="false"
app2:icon="@drawable/resolution_scaler"/>
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="buttonscale"
android:title="@string/mcl_setting_title_buttonscale"
android:summary="@string/mcl_setting_subtitle_buttonscale"
app2:showSeekBarValue="true"
app2:selectable="false"
app2:icon="@drawable/btn_scale"/>
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="mousescale"
android:summary="@string/mcl_setting_subtitle_mousescale"
android:title="@string/mcl_setting_title_mousescale"
app2:icon="@drawable/mouse_pointer_1"
app2:selectable="false"
app2:showSeekBarValue="true" />
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="mousespeed"
android:summary="@string/mcl_setting_subtitle_mousespeed"
android:title="@string/mcl_setting_title_mousespeed"
app2:icon="@drawable/mouse_pointer_spd"
app2:selectable="false"
app2:showSeekBarValue="true" />
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory
android:title="@string/mcl_setting_category_veroption">
<androidx.preference.CheckBoxPreference
android:defaultValue="true"
android:key="vertype_release"
android:title="@string/mcl_setting_veroption_release" />
<androidx.preference.CheckBoxPreference
android:defaultValue="false"
android:key="vertype_snapshot"
android:title="@string/mcl_setting_veroption_snapshot" />
<androidx.preference.CheckBoxPreference
android:defaultValue="false"
android:key="vertype_oldalpha"
android:title="@string/mcl_setting_veroption_oldalpha" />
<androidx.preference.CheckBoxPreference
android:defaultValue="false"
android:key="vertype_oldbeta"
android:title="@string/mcl_setting_veroption_oldbeta" />
</androidx.preference.PreferenceCategory>
</androidx.preference.PreferenceScreen>
</PreferenceScreen>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app2="http://schemas.android.com/apk/res-auto">
<net.kdt.pojavlaunch.prefs.BackButtonPreference/>
<PreferenceCategory android:title="Miscellaneous settings">
<SwitchPreference
android:defaultValue="false"
android:key="hideSidebar"
android:summary="@string/mcl_setting_subtitle_hide_sidebar"
android:title="@string/mcl_setting_title_hide_sidebar"
app2:icon="@drawable/hide_sidebar" />
<SwitchPreference
android:defaultValue="true"
android:icon="@drawable/ic_lib_check"
android:key="checkLibraries"
android:summary="@string/mcl_setting_check_libraries_subtitle"
android:title="@string/mcl_setting_check_libraries" />
</PreferenceCategory>
<PreferenceCategory
android:title="@string/mcl_setting_category_veroption">
<CheckBoxPreference
android:defaultValue="true"
android:key="vertype_release"
android:title="@string/mcl_setting_veroption_release" />
<CheckBoxPreference
android:defaultValue="false"
android:key="vertype_snapshot"
android:title="@string/mcl_setting_veroption_snapshot" />
<CheckBoxPreference
android:defaultValue="false"
android:key="vertype_oldalpha"
android:title="@string/mcl_setting_veroption_oldalpha" />
<CheckBoxPreference
android:defaultValue="false"
android:key="vertype_oldbeta"
android:title="@string/mcl_setting_veroption_oldbeta" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app2="http://schemas.android.com/apk/res-auto">
<net.kdt.pojavlaunch.prefs.BackButtonPreference/>
<PreferenceCategory android:title="Video settings" >
<androidx.preference.ListPreference
android:title="@string/mcl_setting_category_renderer"
android:key="renderer"
android:defaultValue="opengles2"
android:entries="@array/renderer"
android:entryValues="@array/renderer_values"
app2:useSimpleSummaryProvider="true"/>
<androidx.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="ignoreNotch"
android:summary="@string/mcl_setting_subtitle_ignore_notch"
android:title="@string/mcl_setting_title_ignore_notch"
app2:icon="@drawable/ignore_notch" />
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
android:key="resolutionRatio"
android:summary="@string/mcl_setting_subtitle_resolution_scaler"
android:title="@string/mcl_setting_title_resolution_scaler"
app2:showSeekBarValue="true"
app2:selectable="false"
app2:icon="@drawable/resolution_scaler"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@ -2,6 +2,3 @@ android.enableJetifier=true
android.useAndroidX=true
android.bundle.enableUncompressedNativeLibs=false
android.bundle.language.enableSplit=false
systemProp.http.ssl.insecure=true
systemProp.http.ssl.allowall=true
systemProp.http.ssl.ignore.validity.dates=true

View File

@ -53,7 +53,7 @@ public class CallbackBridge {
}
// Called from Android side
public static void receiveCallback(int type, int i1, int i2, int i3, int i4) {
public static void receiveCallback(int type, float i1, float i2, int i3, int i4) {
/*
if (INPUT_DEBUG_ENABLED) {
System.out.println("LWJGL GLFW Callback received type=" + Integer.toString(type) + ", data=" + i1 + ", " + i2 + ", " + i3 + ", " + i4);
@ -61,10 +61,10 @@ public class CallbackBridge {
*/
if (PENDING_EVENT_READY) {
if (type == EVENT_TYPE_CURSOR_POS) {
GLFW.mGLFWCursorX = i1;
GLFW.mGLFWCursorY = i2;
GLFW.mGLFWCursorX = (double) i1;
GLFW.mGLFWCursorY = (double) i2;
} else {
PENDING_EVENT_LIST.add(new Integer[]{type, i1, i2, i3, i4});
PENDING_EVENT_LIST.add(new Integer[]{type, (int) i1, (int)i2, i3, i4});
}
} // else System.out.println("Event input is not ready yet!");
}