Merge pull request #2917 from PojavLauncherTeam/merge-profiles

Merge and resolve conflicts
This commit is contained in:
ArtDev
2022-03-17 17:50:18 +03:00
committed by GitHub
144 changed files with 2876 additions and 4722 deletions

View File

@@ -108,3 +108,4 @@ 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).
- Thanks to [MCHeads](https://mc-heads.net) for providing Minecraft avatars.

View File

@@ -59,12 +59,12 @@
</activity>
<activity
android:theme="@style/MenuDialog"
android:theme="@style/Theme.AppCompat.DayNight.Dialog"
android:screenOrientation="sensorLandscape"
android:name=".FatalErrorActivity"
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"/>
<activity
android:theme="@style/MenuDialog"
android:theme="@style/Theme.AppCompat.DayNight.Dialog"
android:screenOrientation="sensorLandscape"
android:name=".ExitActivity"
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"/>

View File

@@ -1 +1 @@
20211115
20220304

View File

@@ -5,15 +5,15 @@ import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.ScrollView;
/**
Class allowing to ignore the focusing from an item such an EditText within it.
Ignoring it will stop the scrollView from refocusing on the view
*/
public class DefocusableScrollView extends ScrollView {
/*
What is this class for ?
It allows to ignore the focusing from an item such an EditText.
Ignoring it will stop the scrollView from refocusing on the view
*/
private boolean keepFocusing = false;
private boolean mKeepFocusing = false;
public DefocusableScrollView(Context context) {
@@ -33,16 +33,16 @@ public class DefocusableScrollView extends ScrollView {
}
public void setKeepFocusing(boolean shouldKeepFocusing){
keepFocusing = shouldKeepFocusing;
mKeepFocusing = shouldKeepFocusing;
}
public boolean isKeepFocusing(){
return keepFocusing;
return mKeepFocusing;
}
@Override
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
if(!keepFocusing) return 0;
if(!mKeepFocusing) return 0;
return super.computeScrollDeltaToGetChildRectOnScreen(rect);
}

View File

@@ -21,10 +21,10 @@ import net.kdt.pojavlaunch.R;
* It has support for the Logger class
*/
public class LoggerView extends ConstraintLayout {
private Logger.eventLogListener logListener;
private ToggleButton toggleButton;
private ScrollView scrollView;
private TextView log;
private Logger.eventLogListener mLogListener;
private ToggleButton mToggleButton;
private ScrollView mScrollView;
private TextView mLogTextView;
public LoggerView(@NonNull Context context) {
@@ -36,50 +36,51 @@ public class LoggerView extends ConstraintLayout {
init();
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
// Triggers the log view shown state by default when viewing it
mToggleButton.setChecked(visibility == VISIBLE);
}
/**
* Inflate the layout, and add component behaviors
*/
private void init(){
inflate(getContext(), R.layout.loggerview_layout, this);
log = findViewById(R.id.content_log_view);
log.setTypeface(Typeface.MONOSPACE);
inflate(getContext(), R.layout.view_logger, this);
mLogTextView = findViewById(R.id.content_log_view);
mLogTextView.setTypeface(Typeface.MONOSPACE);
//TODO clamp the max text so it doesn't go oob
log.setMaxLines(Integer.MAX_VALUE);
log.setEllipsize(null);
log.setVisibility(GONE);
mLogTextView.setMaxLines(Integer.MAX_VALUE);
mLogTextView.setEllipsize(null);
mLogTextView.setVisibility(GONE);
// Toggle log visibility
toggleButton = findViewById(R.id.content_log_toggle_log);
toggleButton.setOnCheckedChangeListener(
mToggleButton = findViewById(R.id.content_log_toggle_log);
mToggleButton.setOnCheckedChangeListener(
(compoundButton, isChecked) -> {
log.setVisibility(isChecked ? VISIBLE : GONE);
if(!isChecked) log.setText("");
mLogTextView.setVisibility(isChecked ? VISIBLE : GONE);
if(!isChecked) mLogTextView.setText("");
});
toggleButton.setChecked(false);
mToggleButton.setChecked(false);
// Remove the loggerView from the user View
ImageButton cancelButton = findViewById(R.id.log_view_cancel);
cancelButton.setOnClickListener(view -> LoggerView.this.setVisibility(GONE));
// Set the scroll view
scrollView = findViewById(R.id.content_log_scroll);
mScrollView = findViewById(R.id.content_log_scroll);
// Listen to logs
logListener = text -> {
if(log.getVisibility() != VISIBLE) return;
mLogListener = text -> {
if(mLogTextView.getVisibility() != VISIBLE) return;
post(() -> {
log.append(text + '\n');
scrollView.fullScroll(View.FOCUS_DOWN);
mLogTextView.append(text + '\n');
mScrollView.fullScroll(View.FOCUS_DOWN);
});
};
Logger.getInstance().setLogListener(logListener);
Logger.getInstance().setLogListener(mLogListener);
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
// Triggers the log view shown state by default when viewing it
toggleButton.setChecked(visibility == VISIBLE);
}
}

View File

@@ -8,8 +8,7 @@ import androidx.core.content.res.ResourcesCompat;
import net.kdt.pojavlaunch.R;
public class MineButton extends androidx.appcompat.widget.AppCompatButton
{
public class MineButton extends androidx.appcompat.widget.AppCompatButton {
public MineButton(Context ctx) {
this(ctx, null);

View File

@@ -4,22 +4,18 @@ import android.content.*;
import android.util.*;
import android.graphics.*;
public class MineEditText extends com.google.android.material.textfield.TextInputEditText
{
public MineEditText(Context ctx)
{
public class MineEditText extends com.google.android.material.textfield.TextInputEditText {
public MineEditText(Context ctx) {
super(ctx);
init();
}
public MineEditText(Context ctx, AttributeSet attrs)
{
public MineEditText(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
init();
}
public void init()
{
public void init() {
setBackgroundColor(Color.parseColor("#131313"));
setPadding(5, 5, 5, 5);
}

View File

@@ -10,56 +10,20 @@ import net.kdt.pojavlaunch.utils.*;
import org.lwjgl.glfw.*;
public class AWTCanvasView extends TextureView implements TextureView.SurfaceTextureListener, Runnable {
private final int MAX_SIZE = 100;
private final double NANOS = 1000000000.0;
private int mScaleFactor;
private int[] mScales;
private int mWidth, mHeight;
private boolean mIsDestroyed = false;
private TextPaint fpsPaint;
private boolean attached = false;
private final TextPaint mFpsPaint;
private boolean mAttached = false;
private boolean mDrawing;
// Temporary count fps https://stackoverflow.com/a/13729241
private LinkedList<Long> times = new LinkedList<Long>(){{add(System.nanoTime());}};
private final int MAX_SIZE = 100;
private final double NANOS = 1000000000.0;
/** Calculates and returns frames per second */
private double fps() {
long lastTime = System.nanoTime();
double difference = (lastTime - times.getFirst()) / NANOS;
times.addLast(lastTime);
int size = times.size();
if (size > MAX_SIZE) {
times.removeFirst();
}
return difference > 0 ? times.size() / difference : 0.0;
}
/** Computes the scale to better fit the screen */
void initScaleFactors(){
initScaleFactors(0);
}
void initScaleFactors(int forcedScale){
//Could be optimized
if(forcedScale < 1) { //Auto scale
int minDimension = Math.min(CallbackBridge.physicalHeight, CallbackBridge.physicalWidth);
mScaleFactor = Math.max(((3 * minDimension) / 1080) - 1, 1);
}else{
mScaleFactor = forcedScale;
}
int[] scales = new int[2]; //Left, Top
scales[0] = (CallbackBridge.physicalWidth/2);
scales[0] -= scales[0]/mScaleFactor;
scales[1] = (CallbackBridge.physicalHeight/2);
scales[1] -= scales[1]/mScaleFactor;
mScales = scales;
}
private final LinkedList<Long> mTimes = new LinkedList<Long>(){{add(System.nanoTime());}};
public AWTCanvasView(Context ctx) {
this(ctx, null);
@@ -67,11 +31,10 @@ public class AWTCanvasView extends TextureView implements TextureView.SurfaceTex
public AWTCanvasView(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
// setWillNotDraw(false);
fpsPaint = new TextPaint();
fpsPaint.setColor(Color.WHITE);
fpsPaint.setTextSize(20);
mFpsPaint = new TextPaint();
mFpsPaint.setColor(Color.WHITE);
mFpsPaint.setTextSize(20);
setSurfaceTextureListener(this);
initScaleFactors();
@@ -101,21 +64,19 @@ public class AWTCanvasView extends TextureView implements TextureView.SurfaceTex
@Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
}
private boolean mDrawing;
private Surface mSurface;
@Override
public void run() {
Canvas canvas;
mSurface = new Surface(getSurfaceTexture());
Surface surface = new Surface(getSurfaceTexture());
try {
while (!mIsDestroyed && mSurface.isValid()) {
canvas = mSurface.lockCanvas(null);
while (!mIsDestroyed && surface.isValid()) {
canvas = surface.lockCanvas(null);
canvas.drawRGB(0, 0, 0);
if (!attached) {
attached = CallbackBridge.nativeAttachThreadToOther(true, BaseMainActivity.isInputStackCall);
if (!mAttached) {
mAttached = CallbackBridge.nativeAttachThreadToOther(true, BaseMainActivity.isInputStackCall);
} else {
int[] rgbArray = JREUtils.renderAWTScreenFrame(/* canvas, mWidth, mHeight */);
mDrawing = rgbArray != null;
@@ -123,22 +84,55 @@ public class AWTCanvasView extends TextureView implements TextureView.SurfaceTex
canvas.save();
canvas.scale(mScaleFactor, mScaleFactor);
canvas.translate(-mScales[0],-mScales[1]);
canvas.translate(-mScales[0], -mScales[1]);
canvas.drawBitmap(rgbArray, 0, CallbackBridge.physicalWidth, 0, 0, CallbackBridge.physicalWidth, CallbackBridge.physicalHeight, true, null);
canvas.restore();
}
rgbArray = null;
// System.gc();
}
canvas.drawText("FPS: " + (Math.round(fps() * 10) / 10) + ", attached=" + attached + ", drawing=" + mDrawing, 50, 50, fpsPaint);
mSurface.unlockCanvasAndPost(canvas);
canvas.drawText("FPS: " + (Math.round(fps() * 10) / 10) + ", attached=" + mAttached + ", drawing=" + mDrawing, 50, 50, mFpsPaint);
surface.unlockCanvasAndPost(canvas);
}
} catch (Throwable th) {
Tools.showError(getContext(), th);
} catch (Throwable throwable) {
Tools.showError(getContext(), throwable);
}
surface.release();
}
/** Computes the scale to better fit the screen */
void initScaleFactors(){
initScaleFactors(0);
}
void initScaleFactors(int forcedScale){
//Could be optimized
if(forcedScale < 1) { //Auto scale
int minDimension = Math.min(CallbackBridge.physicalHeight, CallbackBridge.physicalWidth);
mScaleFactor = Math.max(((3 * minDimension) / 1080) - 1, 1);
}else{
mScaleFactor = forcedScale;
}
int[] scales = new int[2]; //Left, Top
scales[0] = (CallbackBridge.physicalWidth/2);
scales[0] -= scales[0]/mScaleFactor;
scales[1] = (CallbackBridge.physicalHeight/2);
scales[1] -= scales[1]/mScaleFactor;
mScales = scales;
}
/** Calculates and returns frames per second */
private double fps() {
long lastTime = System.nanoTime();
double difference = (lastTime - mTimes.getFirst()) / NANOS;
mTimes.addLast(lastTime);
int size = mTimes.size();
if (size > MAX_SIZE) {
mTimes.removeFirst();
}
return difference > 0 ? mTimes.size() / difference : 0.0;
}
}

View File

@@ -24,8 +24,7 @@ package net.kdt.pojavlaunch;
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public class AWTInputEvent
{
public class AWTInputEvent {
// InputEvent
/**
* This flag indicates that the Shift key was down when the event

View File

@@ -7,8 +7,7 @@ import net.kdt.pojavlaunch.utils.*;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_IGNORE_NOTCH;
public class BaseActivity extends AppCompatActivity
{
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -24,7 +23,7 @@ public class BaseActivity extends AppCompatActivity
@Override
public void startActivity(Intent i) {
super.startActivity(i);
new Throwable("StartActivity").printStackTrace();
//new Throwable("StartActivity").printStackTrace();
}
@Override

View File

@@ -4,22 +4,16 @@ import static net.kdt.pojavlaunch.Tools.getFileName;
import android.app.*;
import android.content.*;
import android.database.Cursor;
import android.net.Uri;
import android.provider.OpenableColumns;
import android.text.*;
import android.text.method.*;
import android.view.*;
import android.webkit.MimeTypeMap;
import android.widget.*;
import androidx.annotation.Nullable;
import androidx.appcompat.app.*;
import com.kdt.pickafile.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Map;
import net.kdt.pojavlaunch.extra.ExtraCore;
import net.kdt.pojavlaunch.extra.ExtraListener;
import net.kdt.pojavlaunch.fragments.*;
@@ -74,7 +68,7 @@ public abstract class BaseLauncherActivity extends BaseActivity {
public static final int RUN_MOD_INSTALLER = 2050;
private void installMod(boolean customJavaArgs) {
if (MultiRTUtils.getExactJREName(8) == null) {
if (MultiRTUtils.getExactJreName(8) == null) {
Toast.makeText(this, R.string.multirt_nojava8rt, Toast.LENGTH_LONG).show();
return;
}
@@ -118,6 +112,19 @@ public abstract class BaseLauncherActivity extends BaseActivity {
if (LauncherProfiles.mainProfileJson != null && LauncherProfiles.mainProfileJson.profiles != null && LauncherProfiles.mainProfileJson.profiles.containsKey(mProfile.selectedProfile + "")) {
MinecraftProfile prof = LauncherProfiles.mainProfileJson.profiles.get(mProfile.selectedProfile + "");
if (prof != null && prof.lastVersionId != null) {
if (mProfile.accessToken.equals("0")) {
File verJsonFile = new File(Tools.DIR_HOME_VERSION,
mProfile.selectedVersion + "/" + mProfile.selectedVersion + ".json");
if (verJsonFile.exists()) {
mTask.onPostExecute(null);
} else {
new AlertDialog.Builder(this)
.setTitle(R.string.global_error)
.setMessage(R.string.mcl_launch_error_localmode)
.setPositiveButton(android.R.string.ok, null)
.show();
}
}
mTask.execute(getVersionId(prof.lastVersionId));
}
}
@@ -300,7 +307,7 @@ public abstract class BaseLauncherActivity extends BaseActivity {
BaseLauncherActivity.this.runOnUiThread(() -> {
barrier.dismiss();
mRuntimeConfigDialog.refresh();
mRuntimeConfigDialog.dialog.show();
mRuntimeConfigDialog.mDialog.show();
});
});
t.start();

View File

@@ -11,7 +11,6 @@ import static org.lwjgl.glfw.CallbackBridge.windowWidth;
import android.app.*;
import android.content.*;
import android.content.pm.PackageManager;
import android.graphics.*;
import android.os.*;
import android.util.*;
import android.view.*;
@@ -178,17 +177,31 @@ public class BaseMainActivity extends BaseActivity {
final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
final View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(uiOptions);
CallbackBridge.nativeSetWindowAttrib(LwjglGlfwKeycode.GLFW_HOVERED, 1);
}
@Override
protected void onPause() {
if (CallbackBridge.isGrabbing()){
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_ESCAPE);
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_ESCAPE);
}
CallbackBridge.nativeSetWindowAttrib(LwjglGlfwKeycode.GLFW_HOVERED, 0);
mIsResuming = false;
super.onPause();
}
@Override
protected void onStart() {
super.onStart();
CallbackBridge.nativeSetWindowAttrib(LwjglGlfwKeycode.GLFW_VISIBLE, 1);
}
@Override
protected void onStop() {
CallbackBridge.nativeSetWindowAttrib(LwjglGlfwKeycode.GLFW_VISIBLE, 0);
super.onStop();
}
public static void fullyExit() {
android.os.Process.killProcess(android.os.Process.myPid());
}
@@ -217,6 +230,7 @@ public class BaseMainActivity extends BaseActivity {
((mVersionInfo.inheritsFrom == null || mVersionInfo.inheritsFrom.equals(mVersionInfo.id)) ?
"" : " (" + mVersionInfo.inheritsFrom + ")"));
JREUtils.redirectAndPrintJRELog(this);
if(!LauncherPreferences.PREF_ENABLE_PROFILES){
Tools.launchMinecraft(this, mProfile, mProfile.selectedVersion);
@@ -225,7 +239,6 @@ public class BaseMainActivity extends BaseActivity {
Tools.launchMinecraft(this, mProfile, BaseLauncherActivity.getVersionId(
LauncherProfiles.mainProfileJson.profiles.get(mProfile.selectedProfile).lastVersionId));
}
}
private void checkJavaArgsIsLaunchable(String jreVersion) throws Throwable {
@@ -347,7 +360,7 @@ public class BaseMainActivity extends BaseActivity {
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && !touchCharInput.isEnabled()) {
if(event.getAction() != KeyEvent.ACTION_UP) return true; // We eat it anyway
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_ESCAPE);
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_ESCAPE);
return true;
}
return super.dispatchKeyEvent(event);
@@ -362,7 +375,7 @@ public class BaseMainActivity extends BaseActivity {
public void adjustMouseSpeedLive() {
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.setTitle(R.string.mcl_setting_title_mousespeed);
View v = LayoutInflater.from(this).inflate(R.layout.live_mouse_speed_editor,null);
View v = LayoutInflater.from(this).inflate(R.layout.dialog_live_mouse_speed_editor,null);
final SeekBar sb = v.findViewById(R.id.mouseSpeed);
final TextView tv = v.findViewById(R.id.mouseSpeedTV);
sb.setMax(275);

View File

@@ -5,13 +5,13 @@ import android.content.*;
import android.os.*;
import androidx.appcompat.app.*;
import androidx.preference.*;
import android.view.*;
import android.widget.*;
import androidx.drawerlayout.widget.DrawerLayout;
import com.google.android.material.navigation.NavigationView;
import com.google.gson.JsonSyntaxException;
import com.kdt.pickafile.*;
import java.io.*;
@@ -19,18 +19,13 @@ import net.kdt.pojavlaunch.prefs.*;
import net.kdt.pojavlaunch.customcontrols.*;
public class CustomControlsActivity extends BaseActivity
{
private DrawerLayout drawerLayout;
private NavigationView navDrawer;
private ControlLayout ctrlLayout;
private SharedPreferences mPref;
public class CustomControlsActivity extends BaseActivity {
private DrawerLayout mDrawerLayout;
private NavigationView mDrawerNavigationView;
private ControlLayout mControlLayout;
public boolean isModified = false;
public boolean isFromMainActivity = false;
private static String selectedName = "new_control";
private static String sSelectedName = "new_control";
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -41,48 +36,41 @@ public class CustomControlsActivity extends BaseActivity
// setTheme(androidx.appcompat.R.style.Theme_AppCompat_Translucent);
}
setContentView(R.layout.control_mapping);
mPref = PreferenceManager.getDefaultSharedPreferences(this);
setContentView(R.layout.activity_custom_controls);
ctrlLayout = (ControlLayout) findViewById(R.id.customctrl_controllayout);
mControlLayout = (ControlLayout) findViewById(R.id.customctrl_controllayout);
mDrawerLayout = (DrawerLayout) findViewById(R.id.customctrl_drawerlayout);
mDrawerNavigationView = (NavigationView) findViewById(R.id.customctrl_navigation_view);
// Menu
drawerLayout = (DrawerLayout) findViewById(R.id.customctrl_drawerlayout);
navDrawer = (NavigationView) findViewById(R.id.customctrl_navigation_view);
navDrawer.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
mDrawerNavigationView.setNavigationItemSelectedListener(
menuItem -> {
switch (menuItem.getItemId()) {
case R.id.menu_ctrl_load:
load(ctrlLayout);
load(mControlLayout);
break;
case R.id.menu_ctrl_add:
ctrlLayout.addControlButton(new ControlData("New"));
mControlLayout.addControlButton(new ControlData("New"));
break;
case R.id.menu_ctrl_add_drawer:
ctrlLayout.addDrawer(new ControlDrawerData());
mControlLayout.addDrawer(new ControlDrawerData());
break;
case R.id.menu_ctrl_selectdefault:
dialogSelectDefaultCtrl(ctrlLayout);
dialogSelectDefaultCtrl(mControlLayout);
break;
case R.id.menu_ctrl_save:
save(false,ctrlLayout);
save(false, mControlLayout);
break;
}
//Toast.makeText(MainActivity.this, menuItem.getTitle() + ":" + menuItem.getItemId(), Toast.LENGTH_SHORT).show();
drawerLayout.closeDrawers();
mDrawerLayout.closeDrawers();
return true;
}
});
});
ctrlLayout.setActivity(this);
ctrlLayout.setModifiable(true);
mControlLayout.setActivity(this);
mControlLayout.setModifiable(true);
loadControl(LauncherPreferences.PREF_DEFAULTCTRL_PATH,ctrlLayout);
loadControl(LauncherPreferences.PREF_DEFAULTCTRL_PATH, mControlLayout);
}
@Override
@@ -93,18 +81,7 @@ public class CustomControlsActivity extends BaseActivity
return;
}
save(true,ctrlLayout);
}
private static void setDefaultControlJson(String path,ControlLayout ctrlLayout) {
try {
// Load before save to make sure control is not error
ctrlLayout.loadLayout(Tools.GLOBAL_GSON.fromJson(Tools.read(path), CustomControls.class));
LauncherPreferences.DEFAULT_PREF.edit().putString("defaultCtrl", path).commit();
LauncherPreferences.PREF_DEFAULTCTRL_PATH = path;
} catch (Throwable th) {
Tools.showError(ctrlLayout.getContext(), th);
}
save(true, mControlLayout);
}
public static void dialogSelectDefaultCtrl(final ControlLayout layout) {
@@ -127,18 +104,12 @@ public class CustomControlsActivity extends BaseActivity
dialog.show();
}
private static String doSaveCtrl(String name, final ControlLayout layout) throws Exception {
String jsonPath = Tools.CTRLMAP_PATH + "/" + name + ".json";
layout.saveLayout(jsonPath);
return jsonPath;
}
public static void save(final boolean exit, final ControlLayout layout) {
final Context ctx = layout.getContext();
final EditText edit = new EditText(ctx);
edit.setSingleLine();
edit.setText(selectedName);
edit.setText(sSelectedName);
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setTitle(R.string.global_save);
@@ -162,51 +133,38 @@ public class CustomControlsActivity extends BaseActivity
});
}
final AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
dialog.setOnShowListener(dialogInterface -> {
@Override
public void onShow(DialogInterface dialogInterface) {
Button button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (edit.getText().toString().isEmpty()) {
edit.setError(ctx.getResources().getString(R.string.global_error_field_empty));
} else {
try {
String jsonPath = doSaveCtrl(edit.getText().toString(),layout);
Toast.makeText(ctx, ctx.getString(R.string.global_save) + ": " + jsonPath, Toast.LENGTH_SHORT).show();
dialog.dismiss();
if (exit) {
if(ctx instanceof MainActivity) {
((MainActivity) ctx).leaveCustomControls();
}else{
((Activity)ctx).onBackPressed();
}
//CustomControlsActivity.super.onBackPressed();
}
} catch (Throwable th) {
Tools.showError(ctx, th, exit);
}
}
}
});
Button button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(view -> {
if (edit.getText().toString().isEmpty()) {
edit.setError(ctx.getResources().getString(R.string.global_error_field_empty));
return;
}
try {
String jsonPath = doSaveCtrl(edit.getText().toString(),layout);
Toast.makeText(ctx, ctx.getString(R.string.global_save) + ": " + jsonPath, Toast.LENGTH_SHORT).show();
dialog.dismiss();
if (!exit) return;
if(ctx instanceof MainActivity) {
((MainActivity) ctx).leaveCustomControls();
}else{
((Activity)ctx).onBackPressed();
}
} catch (Throwable th) {
Tools.showError(ctx, th, exit);
}
});
});
dialog.show();
}
public static void load(final ControlLayout layout) {
/*ControlJsonSelector sel = new ControlJsonSelector(layout.getContext(), R.string.global_load);
sel.setFinishCallback((f)->{
loadControl(f.getAbsolutePath(),layout);
});
sel.show();*/
AlertDialog.Builder builder = new AlertDialog.Builder(layout.getContext());
builder.setTitle(R.string.global_load);
builder.setPositiveButton(android.R.string.cancel, null);
@@ -227,12 +185,30 @@ public class CustomControlsActivity extends BaseActivity
dialog.show();
}
private static void setDefaultControlJson(String path,ControlLayout ctrlLayout) {
// Load before save to make sure control is not error
try {
ctrlLayout.loadLayout(Tools.GLOBAL_GSON.fromJson(Tools.read(path), CustomControls.class));
LauncherPreferences.DEFAULT_PREF.edit().putString("defaultCtrl", path).apply();
LauncherPreferences.PREF_DEFAULTCTRL_PATH = path;
} catch (IOException| JsonSyntaxException exception) {
Tools.showError(ctrlLayout.getContext(), exception);
}
}
private static String doSaveCtrl(String name, final ControlLayout layout) throws Exception {
String jsonPath = Tools.CTRLMAP_PATH + "/" + name + ".json";
layout.saveLayout(jsonPath);
return jsonPath;
}
private static void loadControl(String path,ControlLayout layout) {
try {
layout.loadLayout(path);
selectedName = new File(path).getName();
sSelectedName = new File(path).getName();
// Remove `.json`
selectedName = selectedName.substring(0, selectedName.length() - 5);
sSelectedName = sSelectedName.substring(0, sSelectedName.length() - 5);
} catch (Exception e) {
Tools.showError(layout.getContext(), e);
}

View File

@@ -1,16 +0,0 @@
package net.kdt.pojavlaunch;
import android.content.*;
import android.net.*;
import androidx.browser.customtabs.*;
public class CustomTabs {
public static void openTab(Context context, String url) {
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
builder.setShowTitle(true);
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(context, Uri.parse(url));
}
}

View File

@@ -4,8 +4,6 @@ import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
import android.view.KeyEvent;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import org.lwjgl.glfw.CallbackBridge;
import java.util.Arrays;
@@ -16,168 +14,158 @@ public class EfficientAndroidLWJGLKeycode {
//The key being the android keycode from a KeyEvent
//The value its LWJGL equivalent.
private static final int KEYCODE_COUNT = 103;
private static final int[] androidKeycodes = new int[KEYCODE_COUNT];
private static final short[] LWJGLKeycodes = new short[KEYCODE_COUNT];
private static final int[] sAndroidKeycodes = new int[KEYCODE_COUNT];
private static final short[] sLwjglKeycodes = new short[KEYCODE_COUNT];
private static String[] androidKeyNameArray; /* = new String[androidKeycodes.length]; */
private static int mTmpCount = 0;
static {
/* BINARY SEARCH IS PERFORMED ON THE androidKeycodes ARRAY !
WHEN ADDING A MAPPING, ADD IT SO THE androidKeycodes ARRAY STAYS SORTED ! */
// Mapping Android Keycodes to LWJGL Keycodes
add(KeyEvent.KEYCODE_UNKNOWN,LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN);
add(KeyEvent.KEYCODE_HOME, LWJGLGLFWKeycode.GLFW_KEY_HOME);
add(KeyEvent.KEYCODE_UNKNOWN, LwjglGlfwKeycode.GLFW_KEY_UNKNOWN);
add(KeyEvent.KEYCODE_HOME, LwjglGlfwKeycode.GLFW_KEY_HOME);
// Escape key
add(KeyEvent.KEYCODE_BACK, LWJGLGLFWKeycode.GLFW_KEY_ESCAPE);
add(KeyEvent.KEYCODE_BACK, LwjglGlfwKeycode.GLFW_KEY_ESCAPE);
// 0-9 keys
add(KeyEvent.KEYCODE_0, LWJGLGLFWKeycode.GLFW_KEY_0); //7
add(KeyEvent.KEYCODE_1, LWJGLGLFWKeycode.GLFW_KEY_1);
add(KeyEvent.KEYCODE_2, LWJGLGLFWKeycode.GLFW_KEY_2);
add(KeyEvent.KEYCODE_3, LWJGLGLFWKeycode.GLFW_KEY_3);
add(KeyEvent.KEYCODE_4, LWJGLGLFWKeycode.GLFW_KEY_4);
add(KeyEvent.KEYCODE_5, LWJGLGLFWKeycode.GLFW_KEY_5);
add(KeyEvent.KEYCODE_6, LWJGLGLFWKeycode.GLFW_KEY_6);
add(KeyEvent.KEYCODE_7, LWJGLGLFWKeycode.GLFW_KEY_7);
add(KeyEvent.KEYCODE_8, LWJGLGLFWKeycode.GLFW_KEY_8);
add(KeyEvent.KEYCODE_9, LWJGLGLFWKeycode.GLFW_KEY_9); //16
add(KeyEvent.KEYCODE_0, LwjglGlfwKeycode.GLFW_KEY_0); //7
add(KeyEvent.KEYCODE_1, LwjglGlfwKeycode.GLFW_KEY_1);
add(KeyEvent.KEYCODE_2, LwjglGlfwKeycode.GLFW_KEY_2);
add(KeyEvent.KEYCODE_3, LwjglGlfwKeycode.GLFW_KEY_3);
add(KeyEvent.KEYCODE_4, LwjglGlfwKeycode.GLFW_KEY_4);
add(KeyEvent.KEYCODE_5, LwjglGlfwKeycode.GLFW_KEY_5);
add(KeyEvent.KEYCODE_6, LwjglGlfwKeycode.GLFW_KEY_6);
add(KeyEvent.KEYCODE_7, LwjglGlfwKeycode.GLFW_KEY_7);
add(KeyEvent.KEYCODE_8, LwjglGlfwKeycode.GLFW_KEY_8);
add(KeyEvent.KEYCODE_9, LwjglGlfwKeycode.GLFW_KEY_9); //16
add(KeyEvent.KEYCODE_POUND,LWJGLGLFWKeycode.GLFW_KEY_3);
add(KeyEvent.KEYCODE_POUND, LwjglGlfwKeycode.GLFW_KEY_3);
// Arrow keys
add(KeyEvent.KEYCODE_DPAD_UP, LWJGLGLFWKeycode.GLFW_KEY_UP); //19
add(KeyEvent.KEYCODE_DPAD_DOWN, LWJGLGLFWKeycode.GLFW_KEY_DOWN);
add(KeyEvent.KEYCODE_DPAD_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT);
add(KeyEvent.KEYCODE_DPAD_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT); //22
add(KeyEvent.KEYCODE_DPAD_UP, LwjglGlfwKeycode.GLFW_KEY_UP); //19
add(KeyEvent.KEYCODE_DPAD_DOWN, LwjglGlfwKeycode.GLFW_KEY_DOWN);
add(KeyEvent.KEYCODE_DPAD_LEFT, LwjglGlfwKeycode.GLFW_KEY_LEFT);
add(KeyEvent.KEYCODE_DPAD_RIGHT, LwjglGlfwKeycode.GLFW_KEY_RIGHT); //22
// A-Z keys
add(KeyEvent.KEYCODE_A, LWJGLGLFWKeycode.GLFW_KEY_A); //29
add(KeyEvent.KEYCODE_B, LWJGLGLFWKeycode.GLFW_KEY_B);
add(KeyEvent.KEYCODE_C, LWJGLGLFWKeycode.GLFW_KEY_C);
add(KeyEvent.KEYCODE_D, LWJGLGLFWKeycode.GLFW_KEY_D);
add(KeyEvent.KEYCODE_E, LWJGLGLFWKeycode.GLFW_KEY_E);
add(KeyEvent.KEYCODE_F, LWJGLGLFWKeycode.GLFW_KEY_F);
add(KeyEvent.KEYCODE_G, LWJGLGLFWKeycode.GLFW_KEY_G);
add(KeyEvent.KEYCODE_H, LWJGLGLFWKeycode.GLFW_KEY_H);
add(KeyEvent.KEYCODE_I, LWJGLGLFWKeycode.GLFW_KEY_I);
add(KeyEvent.KEYCODE_J, LWJGLGLFWKeycode.GLFW_KEY_J);
add(KeyEvent.KEYCODE_K, LWJGLGLFWKeycode.GLFW_KEY_K);
add(KeyEvent.KEYCODE_L, LWJGLGLFWKeycode.GLFW_KEY_L);
add(KeyEvent.KEYCODE_M, LWJGLGLFWKeycode.GLFW_KEY_M);
add(KeyEvent.KEYCODE_N, LWJGLGLFWKeycode.GLFW_KEY_N);
add(KeyEvent.KEYCODE_O, LWJGLGLFWKeycode.GLFW_KEY_O);
add(KeyEvent.KEYCODE_P, LWJGLGLFWKeycode.GLFW_KEY_P);
add(KeyEvent.KEYCODE_Q, LWJGLGLFWKeycode.GLFW_KEY_Q);
add(KeyEvent.KEYCODE_R, LWJGLGLFWKeycode.GLFW_KEY_R);
add(KeyEvent.KEYCODE_S, LWJGLGLFWKeycode.GLFW_KEY_S);
add(KeyEvent.KEYCODE_T, LWJGLGLFWKeycode.GLFW_KEY_T);
add(KeyEvent.KEYCODE_U, LWJGLGLFWKeycode.GLFW_KEY_U);
add(KeyEvent.KEYCODE_V, LWJGLGLFWKeycode.GLFW_KEY_V);
add(KeyEvent.KEYCODE_W, LWJGLGLFWKeycode.GLFW_KEY_W);
add(KeyEvent.KEYCODE_X, LWJGLGLFWKeycode.GLFW_KEY_X);
add(KeyEvent.KEYCODE_Y, LWJGLGLFWKeycode.GLFW_KEY_Y);
add(KeyEvent.KEYCODE_Z, LWJGLGLFWKeycode.GLFW_KEY_Z); //54
add(KeyEvent.KEYCODE_A, LwjglGlfwKeycode.GLFW_KEY_A); //29
add(KeyEvent.KEYCODE_B, LwjglGlfwKeycode.GLFW_KEY_B);
add(KeyEvent.KEYCODE_C, LwjglGlfwKeycode.GLFW_KEY_C);
add(KeyEvent.KEYCODE_D, LwjglGlfwKeycode.GLFW_KEY_D);
add(KeyEvent.KEYCODE_E, LwjglGlfwKeycode.GLFW_KEY_E);
add(KeyEvent.KEYCODE_F, LwjglGlfwKeycode.GLFW_KEY_F);
add(KeyEvent.KEYCODE_G, LwjglGlfwKeycode.GLFW_KEY_G);
add(KeyEvent.KEYCODE_H, LwjglGlfwKeycode.GLFW_KEY_H);
add(KeyEvent.KEYCODE_I, LwjglGlfwKeycode.GLFW_KEY_I);
add(KeyEvent.KEYCODE_J, LwjglGlfwKeycode.GLFW_KEY_J);
add(KeyEvent.KEYCODE_K, LwjglGlfwKeycode.GLFW_KEY_K);
add(KeyEvent.KEYCODE_L, LwjglGlfwKeycode.GLFW_KEY_L);
add(KeyEvent.KEYCODE_M, LwjglGlfwKeycode.GLFW_KEY_M);
add(KeyEvent.KEYCODE_N, LwjglGlfwKeycode.GLFW_KEY_N);
add(KeyEvent.KEYCODE_O, LwjglGlfwKeycode.GLFW_KEY_O);
add(KeyEvent.KEYCODE_P, LwjglGlfwKeycode.GLFW_KEY_P);
add(KeyEvent.KEYCODE_Q, LwjglGlfwKeycode.GLFW_KEY_Q);
add(KeyEvent.KEYCODE_R, LwjglGlfwKeycode.GLFW_KEY_R);
add(KeyEvent.KEYCODE_S, LwjglGlfwKeycode.GLFW_KEY_S);
add(KeyEvent.KEYCODE_T, LwjglGlfwKeycode.GLFW_KEY_T);
add(KeyEvent.KEYCODE_U, LwjglGlfwKeycode.GLFW_KEY_U);
add(KeyEvent.KEYCODE_V, LwjglGlfwKeycode.GLFW_KEY_V);
add(KeyEvent.KEYCODE_W, LwjglGlfwKeycode.GLFW_KEY_W);
add(KeyEvent.KEYCODE_X, LwjglGlfwKeycode.GLFW_KEY_X);
add(KeyEvent.KEYCODE_Y, LwjglGlfwKeycode.GLFW_KEY_Y);
add(KeyEvent.KEYCODE_Z, LwjglGlfwKeycode.GLFW_KEY_Z); //54
add(KeyEvent.KEYCODE_COMMA, LWJGLGLFWKeycode.GLFW_KEY_COMMA);
add(KeyEvent.KEYCODE_PERIOD, LWJGLGLFWKeycode.GLFW_KEY_PERIOD);
add(KeyEvent.KEYCODE_COMMA, LwjglGlfwKeycode.GLFW_KEY_COMMA);
add(KeyEvent.KEYCODE_PERIOD, LwjglGlfwKeycode.GLFW_KEY_PERIOD);
// Alt keys
add(KeyEvent.KEYCODE_ALT_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT_ALT);
add(KeyEvent.KEYCODE_ALT_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_ALT);
add(KeyEvent.KEYCODE_ALT_LEFT, LwjglGlfwKeycode.GLFW_KEY_LEFT_ALT);
add(KeyEvent.KEYCODE_ALT_RIGHT, LwjglGlfwKeycode.GLFW_KEY_RIGHT_ALT);
// Shift keys
add(KeyEvent.KEYCODE_SHIFT_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT);
add(KeyEvent.KEYCODE_SHIFT_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_SHIFT);
add(KeyEvent.KEYCODE_SHIFT_LEFT, LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT);
add(KeyEvent.KEYCODE_SHIFT_RIGHT, LwjglGlfwKeycode.GLFW_KEY_RIGHT_SHIFT);
add(KeyEvent.KEYCODE_TAB, LWJGLGLFWKeycode.GLFW_KEY_TAB);
add(KeyEvent.KEYCODE_SPACE, LWJGLGLFWKeycode.GLFW_KEY_SPACE);
add(KeyEvent.KEYCODE_ENTER, LWJGLGLFWKeycode.GLFW_KEY_ENTER); //66
add(KeyEvent.KEYCODE_DEL, LWJGLGLFWKeycode.GLFW_KEY_BACKSPACE); // Backspace
add(KeyEvent.KEYCODE_GRAVE, LWJGLGLFWKeycode.GLFW_KEY_GRAVE_ACCENT);
add(KeyEvent.KEYCODE_MINUS, LWJGLGLFWKeycode.GLFW_KEY_MINUS);
add(KeyEvent.KEYCODE_EQUALS, LWJGLGLFWKeycode.GLFW_KEY_EQUAL);
add(KeyEvent.KEYCODE_LEFT_BRACKET, LWJGLGLFWKeycode.GLFW_KEY_LEFT_BRACKET);
add(KeyEvent.KEYCODE_RIGHT_BRACKET, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_BRACKET);
add(KeyEvent.KEYCODE_BACKSLASH, LWJGLGLFWKeycode.GLFW_KEY_BACKSLASH);
add(KeyEvent.KEYCODE_SEMICOLON, LWJGLGLFWKeycode.GLFW_KEY_SEMICOLON); //74
add(KeyEvent.KEYCODE_TAB, LwjglGlfwKeycode.GLFW_KEY_TAB);
add(KeyEvent.KEYCODE_SPACE, LwjglGlfwKeycode.GLFW_KEY_SPACE);
add(KeyEvent.KEYCODE_ENTER, LwjglGlfwKeycode.GLFW_KEY_ENTER); //66
add(KeyEvent.KEYCODE_DEL, LwjglGlfwKeycode.GLFW_KEY_BACKSPACE); // Backspace
add(KeyEvent.KEYCODE_GRAVE, LwjglGlfwKeycode.GLFW_KEY_GRAVE_ACCENT);
add(KeyEvent.KEYCODE_MINUS, LwjglGlfwKeycode.GLFW_KEY_MINUS);
add(KeyEvent.KEYCODE_EQUALS, LwjglGlfwKeycode.GLFW_KEY_EQUAL);
add(KeyEvent.KEYCODE_LEFT_BRACKET, LwjglGlfwKeycode.GLFW_KEY_LEFT_BRACKET);
add(KeyEvent.KEYCODE_RIGHT_BRACKET, LwjglGlfwKeycode.GLFW_KEY_RIGHT_BRACKET);
add(KeyEvent.KEYCODE_BACKSLASH, LwjglGlfwKeycode.GLFW_KEY_BACKSLASH);
add(KeyEvent.KEYCODE_SEMICOLON, LwjglGlfwKeycode.GLFW_KEY_SEMICOLON); //74
add(KeyEvent.KEYCODE_SLASH, LWJGLGLFWKeycode.GLFW_KEY_SLASH); //76
add(KeyEvent.KEYCODE_AT,LWJGLGLFWKeycode.GLFW_KEY_2);
add(KeyEvent.KEYCODE_SLASH, LwjglGlfwKeycode.GLFW_KEY_SLASH); //76
add(KeyEvent.KEYCODE_AT, LwjglGlfwKeycode.GLFW_KEY_2);
add(KeyEvent.KEYCODE_PLUS, LWJGLGLFWKeycode.GLFW_KEY_KP_ADD);
add(KeyEvent.KEYCODE_PLUS, LwjglGlfwKeycode.GLFW_KEY_KP_ADD);
// Page keys
add(KeyEvent.KEYCODE_PAGE_UP, LWJGLGLFWKeycode.GLFW_KEY_PAGE_UP); //92
add(KeyEvent.KEYCODE_PAGE_DOWN, LWJGLGLFWKeycode.GLFW_KEY_PAGE_DOWN);
add(KeyEvent.KEYCODE_PAGE_UP, LwjglGlfwKeycode.GLFW_KEY_PAGE_UP); //92
add(KeyEvent.KEYCODE_PAGE_DOWN, LwjglGlfwKeycode.GLFW_KEY_PAGE_DOWN);
add(KeyEvent.KEYCODE_ESCAPE, LWJGLGLFWKeycode.GLFW_KEY_ESCAPE);
add(KeyEvent.KEYCODE_ESCAPE, LwjglGlfwKeycode.GLFW_KEY_ESCAPE);
// Control keys
add(KeyEvent.KEYCODE_CTRL_LEFT, LWJGLGLFWKeycode.GLFW_KEY_LEFT_CONTROL);
add(KeyEvent.KEYCODE_CTRL_RIGHT, LWJGLGLFWKeycode.GLFW_KEY_RIGHT_CONTROL);
add(KeyEvent.KEYCODE_CTRL_LEFT, LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL);
add(KeyEvent.KEYCODE_CTRL_RIGHT, LwjglGlfwKeycode.GLFW_KEY_RIGHT_CONTROL);
add(KeyEvent.KEYCODE_CAPS_LOCK, LWJGLGLFWKeycode.GLFW_KEY_CAPS_LOCK);
add(KeyEvent.KEYCODE_BREAK, LWJGLGLFWKeycode.GLFW_KEY_PAUSE);
add(KeyEvent.KEYCODE_INSERT, LWJGLGLFWKeycode.GLFW_KEY_INSERT);
add(KeyEvent.KEYCODE_CAPS_LOCK, LwjglGlfwKeycode.GLFW_KEY_CAPS_LOCK);
add(KeyEvent.KEYCODE_BREAK, LwjglGlfwKeycode.GLFW_KEY_PAUSE);
add(KeyEvent.KEYCODE_INSERT, LwjglGlfwKeycode.GLFW_KEY_INSERT);
// Fn keys
add(KeyEvent.KEYCODE_F1, LWJGLGLFWKeycode.GLFW_KEY_F1); //131
add(KeyEvent.KEYCODE_F2, LWJGLGLFWKeycode.GLFW_KEY_F2);
add(KeyEvent.KEYCODE_F3, LWJGLGLFWKeycode.GLFW_KEY_F3);
add(KeyEvent.KEYCODE_F4, LWJGLGLFWKeycode.GLFW_KEY_F4);
add(KeyEvent.KEYCODE_F5, LWJGLGLFWKeycode.GLFW_KEY_F5);
add(KeyEvent.KEYCODE_F6, LWJGLGLFWKeycode.GLFW_KEY_F6);
add(KeyEvent.KEYCODE_F7, LWJGLGLFWKeycode.GLFW_KEY_F7);
add(KeyEvent.KEYCODE_F8, LWJGLGLFWKeycode.GLFW_KEY_F8);
add(KeyEvent.KEYCODE_F9, LWJGLGLFWKeycode.GLFW_KEY_F9);
add(KeyEvent.KEYCODE_F10, LWJGLGLFWKeycode.GLFW_KEY_F10);
add(KeyEvent.KEYCODE_F11, LWJGLGLFWKeycode.GLFW_KEY_F11);
add(KeyEvent.KEYCODE_F12, LWJGLGLFWKeycode.GLFW_KEY_F12); //142
add(KeyEvent.KEYCODE_F1, LwjglGlfwKeycode.GLFW_KEY_F1); //131
add(KeyEvent.KEYCODE_F2, LwjglGlfwKeycode.GLFW_KEY_F2);
add(KeyEvent.KEYCODE_F3, LwjglGlfwKeycode.GLFW_KEY_F3);
add(KeyEvent.KEYCODE_F4, LwjglGlfwKeycode.GLFW_KEY_F4);
add(KeyEvent.KEYCODE_F5, LwjglGlfwKeycode.GLFW_KEY_F5);
add(KeyEvent.KEYCODE_F6, LwjglGlfwKeycode.GLFW_KEY_F6);
add(KeyEvent.KEYCODE_F7, LwjglGlfwKeycode.GLFW_KEY_F7);
add(KeyEvent.KEYCODE_F8, LwjglGlfwKeycode.GLFW_KEY_F8);
add(KeyEvent.KEYCODE_F9, LwjglGlfwKeycode.GLFW_KEY_F9);
add(KeyEvent.KEYCODE_F10, LwjglGlfwKeycode.GLFW_KEY_F10);
add(KeyEvent.KEYCODE_F11, LwjglGlfwKeycode.GLFW_KEY_F11);
add(KeyEvent.KEYCODE_F12, LwjglGlfwKeycode.GLFW_KEY_F12); //142
// Num keys
add(KeyEvent.KEYCODE_NUM_LOCK, LWJGLGLFWKeycode.GLFW_KEY_NUM_LOCK); //143
add(KeyEvent.KEYCODE_NUMPAD_0, LWJGLGLFWKeycode.GLFW_KEY_0);
add(KeyEvent.KEYCODE_NUMPAD_1, LWJGLGLFWKeycode.GLFW_KEY_1);
add(KeyEvent.KEYCODE_NUMPAD_2, LWJGLGLFWKeycode.GLFW_KEY_2);
add(KeyEvent.KEYCODE_NUMPAD_3, LWJGLGLFWKeycode.GLFW_KEY_3);
add(KeyEvent.KEYCODE_NUMPAD_4, LWJGLGLFWKeycode.GLFW_KEY_4);
add(KeyEvent.KEYCODE_NUMPAD_5, LWJGLGLFWKeycode.GLFW_KEY_5);
add(KeyEvent.KEYCODE_NUMPAD_6, LWJGLGLFWKeycode.GLFW_KEY_6);
add(KeyEvent.KEYCODE_NUMPAD_7, LWJGLGLFWKeycode.GLFW_KEY_7);
add(KeyEvent.KEYCODE_NUMPAD_8, LWJGLGLFWKeycode.GLFW_KEY_8);
add(KeyEvent.KEYCODE_NUMPAD_9, LWJGLGLFWKeycode.GLFW_KEY_9);
add(KeyEvent.KEYCODE_NUMPAD_DIVIDE, LWJGLGLFWKeycode.GLFW_KEY_KP_DIVIDE);
add(KeyEvent.KEYCODE_NUMPAD_MULTIPLY, LWJGLGLFWKeycode.GLFW_KEY_KP_MULTIPLY);
add(KeyEvent.KEYCODE_NUMPAD_SUBTRACT, LWJGLGLFWKeycode.GLFW_KEY_KP_SUBTRACT);
add(KeyEvent.KEYCODE_NUMPAD_ADD, LWJGLGLFWKeycode.GLFW_KEY_KP_ADD);
add(KeyEvent.KEYCODE_NUMPAD_DOT, LWJGLGLFWKeycode.GLFW_KEY_PERIOD);
add(KeyEvent.KEYCODE_NUMPAD_COMMA, LWJGLGLFWKeycode.GLFW_KEY_COMMA);
add(KeyEvent.KEYCODE_NUMPAD_ENTER, LWJGLGLFWKeycode.GLFW_KEY_ENTER);
add(KeyEvent.KEYCODE_NUMPAD_EQUALS, LWJGLGLFWKeycode.GLFW_KEY_EQUAL); //161
add(KeyEvent.KEYCODE_NUM_LOCK, LwjglGlfwKeycode.GLFW_KEY_NUM_LOCK); //143
add(KeyEvent.KEYCODE_NUMPAD_0, LwjglGlfwKeycode.GLFW_KEY_0);
add(KeyEvent.KEYCODE_NUMPAD_1, LwjglGlfwKeycode.GLFW_KEY_1);
add(KeyEvent.KEYCODE_NUMPAD_2, LwjglGlfwKeycode.GLFW_KEY_2);
add(KeyEvent.KEYCODE_NUMPAD_3, LwjglGlfwKeycode.GLFW_KEY_3);
add(KeyEvent.KEYCODE_NUMPAD_4, LwjglGlfwKeycode.GLFW_KEY_4);
add(KeyEvent.KEYCODE_NUMPAD_5, LwjglGlfwKeycode.GLFW_KEY_5);
add(KeyEvent.KEYCODE_NUMPAD_6, LwjglGlfwKeycode.GLFW_KEY_6);
add(KeyEvent.KEYCODE_NUMPAD_7, LwjglGlfwKeycode.GLFW_KEY_7);
add(KeyEvent.KEYCODE_NUMPAD_8, LwjglGlfwKeycode.GLFW_KEY_8);
add(KeyEvent.KEYCODE_NUMPAD_9, LwjglGlfwKeycode.GLFW_KEY_9);
add(KeyEvent.KEYCODE_NUMPAD_DIVIDE, LwjglGlfwKeycode.GLFW_KEY_KP_DIVIDE);
add(KeyEvent.KEYCODE_NUMPAD_MULTIPLY, LwjglGlfwKeycode.GLFW_KEY_KP_MULTIPLY);
add(KeyEvent.KEYCODE_NUMPAD_SUBTRACT, LwjglGlfwKeycode.GLFW_KEY_KP_SUBTRACT);
add(KeyEvent.KEYCODE_NUMPAD_ADD, LwjglGlfwKeycode.GLFW_KEY_KP_ADD);
add(KeyEvent.KEYCODE_NUMPAD_DOT, LwjglGlfwKeycode.GLFW_KEY_PERIOD);
add(KeyEvent.KEYCODE_NUMPAD_COMMA, LwjglGlfwKeycode.GLFW_KEY_COMMA);
add(KeyEvent.KEYCODE_NUMPAD_ENTER, LwjglGlfwKeycode.GLFW_KEY_ENTER);
add(KeyEvent.KEYCODE_NUMPAD_EQUALS, LwjglGlfwKeycode.GLFW_KEY_EQUAL); //161
}
private static short index = 0;
private static void add(int androidKeycode, short LWJGLKeycode){
androidKeycodes[index] = androidKeycode;
LWJGLKeycodes[index] = LWJGLKeycode;
++index;
}
public static boolean containsKey(int keycode){
return getIndexByKey(keycode) >= 0;
}
public static String[] generateKeyName() {
if (androidKeyNameArray == null) {
androidKeyNameArray = new String[androidKeycodes.length];
androidKeyNameArray = new String[sAndroidKeycodes.length];
for(int i=0; i < androidKeyNameArray.length; ++i){
androidKeyNameArray[i] = KeyEvent.keyCodeToString(androidKeycodes[i]).replace("KEYCODE_", "");
androidKeyNameArray[i] = KeyEvent.keyCodeToString(sAndroidKeycodes[i]).replace("KEYCODE_", "");
}
}
return androidKeyNameArray;
@@ -187,7 +175,6 @@ public class EfficientAndroidLWJGLKeycode {
execKey(keyEvent, getIndexByKey(keyEvent.getKeyCode()));
}
public static void execKey(KeyEvent keyEvent, int valueIndex) {
//valueIndex points to where the value is stored in the array.
CallbackBridge.holdingAlt = keyEvent.isAltPressed();
@@ -196,19 +183,14 @@ public class EfficientAndroidLWJGLKeycode {
CallbackBridge.holdingNumlock = keyEvent.isNumLockOn();
CallbackBridge.holdingShift = keyEvent.isShiftPressed();
try {
System.out.println(keyEvent.getKeyCode() + " " +keyEvent.getDisplayLabel());
char key = (char)(keyEvent.getUnicodeChar() != 0 ? keyEvent.getUnicodeChar() : '\u0000');
sendKeyPress(
getValueByIndex(valueIndex),
key,
0,
CallbackBridge.getCurrentMods(),
keyEvent.getAction() == KeyEvent.ACTION_DOWN);
} catch (Throwable th) {
th.printStackTrace();
}
System.out.println(keyEvent.getKeyCode() + " " +keyEvent.getDisplayLabel());
char key = (char)(keyEvent.getUnicodeChar() != 0 ? keyEvent.getUnicodeChar() : '\u0000');
sendKeyPress(
getValueByIndex(valueIndex),
key,
0,
CallbackBridge.getCurrentMods(),
keyEvent.getAction() == KeyEvent.ACTION_DOWN);
}
public static void execKeyIndex(int index){
@@ -217,24 +199,29 @@ public class EfficientAndroidLWJGLKeycode {
}
public static int getValueByIndex(int index) {
return LWJGLKeycodes[index];
return sLwjglKeycodes[index];
}
public static int getIndexByKey(int key){
return Arrays.binarySearch(androidKeycodes, key);
return Arrays.binarySearch(sAndroidKeycodes, key);
}
public static short getValue(int key){
return LWJGLKeycodes[Arrays.binarySearch(androidKeycodes, key)];
return sLwjglKeycodes[Arrays.binarySearch(sAndroidKeycodes, key)];
}
/** @return the index at which the key is in the array, searching linearly */
public static int getIndexByValue(int lwjglKey) {
//Since the LWJGL keycodes aren't sorted, linear search is used.
//You should avoid using this function on performance critical areas
for (int i = 0; i < LWJGLKeycodes.length; i++) {
if(LWJGLKeycodes[i] == lwjglKey) return i;
for (int i = 0; i < sLwjglKeycodes.length; i++) {
if(sLwjglKeycodes[i] == lwjglKey) return i;
}
return 0;
}
private static void add(int androidKeycode, short LWJGLKeycode){
sAndroidKeycodes[mTmpCount] = androidKeycode;
sLwjglKeycodes[mTmpCount] = LWJGLKeycode;
mTmpCount ++;
}
}

View File

@@ -1,6 +1,7 @@
package net.kdt.pojavlaunch;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
@@ -11,13 +12,7 @@ import androidx.appcompat.app.AppCompatActivity;
@Keep
public class ExitActivity extends AppCompatActivity {
public static void showExitMessage(Context ctx, int code) {
Intent i = new Intent(ctx,ExitActivity.class);
i.putExtra("code",code);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(i);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -26,14 +21,20 @@ public class ExitActivity extends AppCompatActivity {
if(extras != null) {
code = extras.getInt("code",-1);
}
new AlertDialog.Builder(this)
.setMessage(getString(R.string.mcn_exit_title,code))
.setPositiveButton(android.R.string.ok,(dialog,which)->{
dialog.dismiss();
ExitActivity.this.finish();
}).setOnCancelListener((z)->{
ExitActivity.this.finish();
})
.setPositiveButton(android.R.string.ok, null)
.setOnDismissListener(dialog -> ExitActivity.this.finish())
.show();
}
public static void showExitMessage(Context ctx, int code) {
Intent i = new Intent(ctx,ExitActivity.class);
i.putExtra("code",code);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(i);
}
}

View File

@@ -1,70 +1,47 @@
package net.kdt.pojavlaunch;
import android.app.*;
import android.content.*;
import android.os.*;
import androidx.appcompat.app.*;
import android.util.*;
import androidx.appcompat.app.AlertDialog;
public class FatalErrorActivity extends AppCompatActivity
{
public static void showError(Context ctx, String savePath, boolean storageAllow, /* boolean isFatalErr, */ Throwable th) {
Intent ferrorIntent = new Intent(ctx, FatalErrorActivity.class);
ferrorIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
ferrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ferrorIntent.putExtra("throwable", th);
ferrorIntent.putExtra("savePath", savePath);
ferrorIntent.putExtra("storageAllow", storageAllow);
// ferrorIntent.putExtra("isFatal", isFatalErr);
ctx.startActivity(ferrorIntent);
}
public class FatalErrorActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
boolean storageAllow = extras.getBoolean("storageAllow");
final String strStackTrace = Log.getStackTraceString((Throwable) extras.getSerializable("throwable"));
final String stackTrace = Log.getStackTraceString((Throwable) extras.getSerializable("throwable"));
String strSavePath = extras.getString("savePath");
String errHeader = storageAllow ?
"Crash stack trace saved to " + strSavePath + "." :
"Storage permission is required to save crash stack trace!";
// boolean isFatalError = extras.getBoolean("isFatal", false);
new AlertDialog.Builder(this)
.setTitle(R.string.error_fatal)
.setMessage(errHeader + "\n\n" + strStackTrace)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
.setMessage(errHeader + "\n\n" + stackTrace)
.setPositiveButton(android.R.string.ok, (p1, p2) -> finish())
.setNegativeButton(R.string.global_restart, (p1, p2) -> startActivity(new Intent(FatalErrorActivity.this, PojavLoginActivity.class)))
.setNeutralButton(android.R.string.copy, (p1, p2) -> {
ClipboardManager mgr = (ClipboardManager) FatalErrorActivity.this.getSystemService(CLIPBOARD_SERVICE);
mgr.setPrimaryClip(ClipData.newPlainText("error", stackTrace));
@Override
public void onClick(DialogInterface p1, int p2) {
finish();
}
finish();
})
.setNegativeButton(R.string.global_restart, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface p1, int p2) {
startActivity(new Intent(FatalErrorActivity.this, PojavLoginActivity.class));
}
})
.setNeutralButton(android.R.string.copy, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface p1, int p2) {
ClipboardManager mgr = (ClipboardManager) FatalErrorActivity.this.getSystemService(CLIPBOARD_SERVICE);
mgr.setPrimaryClip(ClipData.newPlainText("error", strStackTrace));
finish();
}
})
//.setNegativeButton("Report (not available)", null)
.setCancelable(false)
.show();
// Tools.showError(this, isFatalError ? R.string.error_fatal : R.string.global_error, th, true);
}
public static void showError(Context ctx, String savePath, boolean storageAllow, Throwable th) {
Intent ferrorIntent = new Intent(ctx, FatalErrorActivity.class);
ferrorIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
ferrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ferrorIntent.putExtra("throwable", th);
ferrorIntent.putExtra("savePath", savePath);
ferrorIntent.putExtra("storageAllow", storageAllow);
ctx.startActivity(ferrorIntent);
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -43,7 +43,7 @@ public class ImportControlActivity extends Activity {
super.onCreate(savedInstanceState);
Tools.initContextConstants(getApplicationContext());
setContentView(R.layout.import_control_layout);
setContentView(R.layout.activity_import_control);
mEditText = findViewById(R.id.editText_import_control_file_name);
}
@@ -185,12 +185,10 @@ public class ImportControlActivity extends Activity {
String jsonLayoutData = Tools.read(Tools.CTRLMAP_PATH + "/TMP_IMPORT_FILE.json");
JSONObject layoutJobj = new JSONObject(jsonLayoutData);
return layoutJobj.has("version") && layoutJobj.has("mControlDataList");
}catch (JSONException | IOException e) {
e.printStackTrace();
return false;
}
}
public String getNameFromURI(Uri uri) {

View File

@@ -1,52 +0,0 @@
package net.kdt.pojavlaunch;
import android.os.*;
public class InstallerTask extends AsyncTask<String, Void, String>
{
@Override
protected String doInBackground(String[] p1)
{
try
{
downloadLibraries(p1[0]);
dexMinecraftLibs();
downloadMinecraft(p1[0]);
dexMinecraftClient(p1[0]);
downloadAssets(p1[0]);
}
catch (Exception e)
{
return e.getMessage();
}
return null;
}
@Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
if(result == null){
//No errors
}
}
private void downloadLibraries(String versionName) throws Exception
{
}
private void dexMinecraftLibs() throws Exception
{
}
private void downloadMinecraft(String versionName) throws Exception
{
}
private void dexMinecraftClient(String version) throws Exception
{
}
private void downloadAssets(String versionName) throws Exception
{
}
}

View File

@@ -1,9 +1,11 @@
package net.kdt.pojavlaunch;
import com.google.gson.annotations.SerializedName;
import java.util.Map;
public class JAssets {
public boolean map_to_resources;
@SerializedName("map_to_resources") public boolean mapToResources;
public Map<String, JAssetInfo> objects;
}

View File

@@ -1,10 +1,9 @@
package net.kdt.pojavlaunch;
import android.graphics.*;
import android.annotation.SuppressLint;
import android.os.*;
import android.util.*;
import android.view.*;
import android.view.View.*;
import android.widget.*;
import java.io.*;
@@ -23,169 +22,121 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
private static final int MSG_LEFT_MOUSE_BUTTON_CHECK = 1028;
private AWTCanvasView mTextureView;
private LoggerView loggerView;
private LoggerView mLoggerView;
private LinearLayout touchPad;
private ImageView mousePointer;
private LinearLayout mTouchPad;
private ImageView mMousePointerImageView;
private GestureDetector gestureDetector;
private boolean mSkipDetectMod, mIsVirtualMouseEnabled;
private int mScaleFactor;
private int[] mScaleFactors = initScaleFactors();
private final Object mDialogLock = new Object();
private boolean mSkipDetectMod, isVirtualMouseEnabled;
private int scaleFactor;
private int[] scaleFactors = initScaleFactors();
private final int fingerStillThreshold = 8;
private int initialX;
private int initialY;
private static boolean triggeredLeftMouseButton = false;
private Handler theHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_LEFT_MOUSE_BUTTON_CHECK: {
float x = CallbackBridge.mouseX;
float y = CallbackBridge.mouseY;
if (CallbackBridge.isGrabbing() &&
Math.abs(initialX - x) < fingerStillThreshold &&
Math.abs(initialY - y) < fingerStillThreshold) {
triggeredLeftMouseButton = true;
AWTInputBridge.sendMousePress(AWTInputEvent.BUTTON1_DOWN_MASK, true);
}
} break;
}
}
};
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.install_mod);
setContentView(R.layout.activity_java_gui_launcher);
Tools.updateWindowSize(this);
Logger.getInstance().reset();
mTouchPad = findViewById(R.id.main_touchpad);
mLoggerView = findViewById(R.id.launcherLoggerView);
mMousePointerImageView = findViewById(R.id.main_mouse_pointer);
mTextureView = findViewById(R.id.installmod_surfaceview);
gestureDetector = new GestureDetector(this, new SingleTapConfirm());
mTouchPad.setFocusable(false);
mTouchPad.setVisibility(View.GONE);
findViewById(R.id.installmod_mouse_pri).setOnTouchListener(this);
findViewById(R.id.installmod_mouse_sec).setOnTouchListener(this);
mMousePointerImageView.post(() -> {
ViewGroup.LayoutParams params = mMousePointerImageView.getLayoutParams();
params.width = (int) (36 / 100f * LauncherPreferences.PREF_MOUSESCALE);
params.height = (int) (54 / 100f * LauncherPreferences.PREF_MOUSESCALE);
});
mTouchPad.setOnTouchListener((v, event) -> {
// MotionEvent reports input details from the touch screen
// and other input controls. In this case, you are only
// interested in events where the touch position changed.
// int index = event.getActionIndex();
int action = event.getActionMasked();
float x = event.getX();
float y = event.getY();
float prevX, prevY, mouseX, mouseY;
if(event.getHistorySize() > 0) {
prevX = event.getHistoricalX(0);
prevY = event.getHistoricalY(0);
}else{
prevX = x;
prevY = y;
}
mouseX = mMousePointerImageView.getX();
mouseY = mMousePointerImageView.getY();
if (gestureDetector.onTouchEvent(event)) {
sendScaledMousePosition(mouseX,mouseY);
AWTInputBridge.sendMousePress(AWTInputEvent.BUTTON1_DOWN_MASK);
} else {
if (action == MotionEvent.ACTION_MOVE) { // 2
mouseX = Math.max(0, Math.min(CallbackBridge.physicalWidth, mouseX + x - prevX));
mouseY = Math.max(0, Math.min(CallbackBridge.physicalHeight, mouseY + y - prevY));
placeMouseAt(mouseX, mouseY);
sendScaledMousePosition(mouseX, mouseY);
}
}
// debugText.setText(CallbackBridge.DEBUG_STRING.toString());
CallbackBridge.DEBUG_STRING.setLength(0);
return true;
});
mTextureView.setOnTouchListener((v, event) -> {
float x = event.getX();
float y = event.getY();
if (gestureDetector.onTouchEvent(event)) {
sendScaledMousePosition(x, y);
AWTInputBridge.sendMousePress(AWTInputEvent.BUTTON1_DOWN_MASK);
return true;
}
switch (event.getActionMasked()) {
case MotionEvent.ACTION_UP: // 1
case MotionEvent.ACTION_CANCEL: // 3
case MotionEvent.ACTION_POINTER_UP: // 6
break;
case MotionEvent.ACTION_MOVE: // 2
sendScaledMousePosition(x, y);
break;
}
return true;
});
try {
JREUtils.jreReleaseList = JREUtils.readJREReleaseProperties(LauncherPreferences.PREF_DEFAULT_RUNTIME);
if (JREUtils.jreReleaseList.get("JAVA_VERSION").equals("1.8.0")) {
MultiRTUtils.setRuntimeNamed(this,LauncherPreferences.PREF_DEFAULT_RUNTIME);
} else {
MultiRTUtils.setRuntimeNamed(this,MultiRTUtils.getExactJREName(8));
MultiRTUtils.setRuntimeNamed(this,MultiRTUtils.getExactJreName(8));
JREUtils.jreReleaseList = JREUtils.readJREReleaseProperties();
}
loggerView = findViewById(R.id.launcherLoggerView);
gestureDetector = new GestureDetector(this, new SingleTapConfirm());
findViewById(R.id.installmod_mouse_pri).setOnTouchListener(this);
findViewById(R.id.installmod_mouse_sec).setOnTouchListener(this);
this.touchPad = findViewById(R.id.main_touchpad);
touchPad.setFocusable(false);
touchPad.setVisibility(View.GONE);
this.mousePointer = findViewById(R.id.main_mouse_pointer);
this.mousePointer.post(() -> {
ViewGroup.LayoutParams params = mousePointer.getLayoutParams();
params.width = (int) (36 / 100f * LauncherPreferences.PREF_MOUSESCALE);
params.height = (int) (54 / 100f * LauncherPreferences.PREF_MOUSESCALE);
});
touchPad.setOnTouchListener(new OnTouchListener(){
private float prevX, prevY;
@Override
public boolean onTouch(View v, MotionEvent event) {
// MotionEvent reports input details from the touch screen
// and other input controls. In this case, you are only
// interested in events where the touch position changed.
// int index = event.getActionIndex();
int action = event.getActionMasked();
float x = event.getX();
float y = event.getY();
if(event.getHistorySize() > 0) {
prevX = event.getHistoricalX(0);
prevY = event.getHistoricalY(0);
}else{
prevX = x;
prevY = y;
}
float mouseX = mousePointer.getX();
float mouseY = mousePointer.getY();
if (gestureDetector.onTouchEvent(event)) {
sendScaledMousePosition(mouseX,mouseY);
AWTInputBridge.sendMousePress(AWTInputEvent.BUTTON1_DOWN_MASK);
} else {
switch (action) {
case MotionEvent.ACTION_UP: // 1
case MotionEvent.ACTION_CANCEL: // 3
case MotionEvent.ACTION_POINTER_UP: // 6
break;
case MotionEvent.ACTION_MOVE: // 2
mouseX = Math.max(0, Math.min(CallbackBridge.physicalWidth, mouseX + x - prevX));
mouseY = Math.max(0, Math.min(CallbackBridge.physicalHeight, mouseY + y - prevY));
placeMouseAt(mouseX, mouseY);
sendScaledMousePosition(mouseX,mouseY);
/*
if (!CallbackBridge.isGrabbing()) {
CallbackBridge.sendMouseKeycode(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, 0, isLeftMouseDown);
CallbackBridge.sendMouseKeycode(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, 0, isRightMouseDown);
}
*/
break;
}
}
// debugText.setText(CallbackBridge.DEBUG_STRING.toString());
CallbackBridge.DEBUG_STRING.setLength(0);
return true;
}
});
placeMouseAt(CallbackBridge.physicalWidth / 2, CallbackBridge.physicalHeight / 2);
// this.textLogBehindGL = (TextView) findViewById(R.id.main_log_behind_GL);
// this.textLogBehindGL.setTypeface(Typeface.MONOSPACE);
final File modFile = (File) getIntent().getExtras().getSerializable("modFile");
final String javaArgs = getIntent().getExtras().getString("javaArgs");
mTextureView = findViewById(R.id.installmod_surfaceview);
mTextureView.setOnTouchListener((v, event) -> {
float x = event.getX();
float y = event.getY();
if (gestureDetector.onTouchEvent(event)) {
sendScaledMousePosition(x, y);
AWTInputBridge.sendMousePress(AWTInputEvent.BUTTON1_DOWN_MASK);
return true;
}
switch (event.getActionMasked()) {
case MotionEvent.ACTION_UP: // 1
case MotionEvent.ACTION_CANCEL: // 3
case MotionEvent.ACTION_POINTER_UP: // 6
break;
case MotionEvent.ACTION_MOVE: // 2
sendScaledMousePosition(x, y);
break;
}
return true;
});
mSkipDetectMod = getIntent().getExtras().getBoolean("skipDetectMod", false);
if (mSkipDetectMod) {
new Thread(() -> launchJavaRuntime(modFile, javaArgs), "JREMainThread").start();
return;
}
// No skip detection
openLogOutput(null);
new Thread(() -> {
@@ -209,6 +160,14 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
}
}
@Override
public void onResume() {
super.onResume();
final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
final View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(uiOptions);
}
@Override
public boolean onTouch(View v, MotionEvent e) {
boolean isDown;
@@ -239,18 +198,18 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
}
public void placeMouseAdd(float x, float y) {
this.mousePointer.setX(mousePointer.getX() + x);
this.mousePointer.setY(mousePointer.getY() + y);
mMousePointerImageView.setX(mMousePointerImageView.getX() + x);
mMousePointerImageView.setY(mMousePointerImageView.getY() + y);
}
public void placeMouseAt(float x, float y) {
this.mousePointer.setX(x);
this.mousePointer.setY(y);
mMousePointerImageView.setX(x);
mMousePointerImageView.setY(y);
}
void sendScaledMousePosition(float x, float y){
AWTInputBridge.sendMousePos((int) map(x,0,CallbackBridge.physicalWidth, scaleFactors[0], scaleFactors[2]),
(int) map(y,0,CallbackBridge.physicalHeight, scaleFactors[1], scaleFactors[3]));
AWTInputBridge.sendMousePos((int) map(x,0,CallbackBridge.physicalWidth, mScaleFactors[0], mScaleFactors[2]),
(int) map(y,0,CallbackBridge.physicalHeight, mScaleFactors[1], mScaleFactors[3]));
}
public void forceClose(View v) {
@@ -258,32 +217,27 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
}
public void openLogOutput(View v) {
loggerView.setVisibility(View.VISIBLE);
mLoggerView.setVisibility(View.VISIBLE);
}
public void closeLogOutput(View view) {
if (mSkipDetectMod) {
loggerView.setVisibility(View.GONE);
mLoggerView.setVisibility(View.GONE);
} else {
forceClose(null);
}
}
public void toggleVirtualMouse(View v) {
isVirtualMouseEnabled = !isVirtualMouseEnabled;
touchPad.setVisibility(isVirtualMouseEnabled ? View.VISIBLE : View.GONE);
mIsVirtualMouseEnabled = !mIsVirtualMouseEnabled;
mTouchPad.setVisibility(mIsVirtualMouseEnabled ? View.VISIBLE : View.GONE);
Toast.makeText(this,
isVirtualMouseEnabled ? R.string.control_mouseon : R.string.control_mouseoff,
mIsVirtualMouseEnabled ? R.string.control_mouseon : R.string.control_mouseoff,
Toast.LENGTH_SHORT).show();
}
private int doCustomInstall(File modFile, String javaArgs) throws IOException {
mSkipDetectMod = true;
return launchJavaRuntime(modFile, javaArgs);
}
public int launchJavaRuntime(File modFile, String javaArgs) {
JREUtils.redirectAndPrintJRELog(this);
JREUtils.redirectAndPrintJRELog();
try {
List<String> javaArgList = new ArrayList<String>();
@@ -313,13 +267,7 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
}
}
@Override
public void onResume() {
super.onResume();
final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
final View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(uiOptions);
}
int[] initScaleFactors(){
return initScaleFactors(true);
@@ -330,37 +278,42 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
if(autoScale) { //Auto scale
int minDimension = Math.min(CallbackBridge.physicalHeight, CallbackBridge.physicalWidth);
scaleFactor = Math.max(((3 * minDimension) / 1080) - 1, 1);
mScaleFactor = Math.max(((3 * minDimension) / 1080) - 1, 1);
}
int[] scales = new int[4]; //Left, Top, Right, Bottom
scales[0] = (CallbackBridge.physicalWidth/2);
scales[0] -= scales[0]/scaleFactor;
scales[0] -= scales[0]/ mScaleFactor;
scales[1] = (CallbackBridge.physicalHeight/2);
scales[1] -= scales[1]/scaleFactor;
scales[1] -= scales[1]/ mScaleFactor;
scales[2] = (CallbackBridge.physicalWidth/2);
scales[2] += scales[2]/scaleFactor;
scales[2] += scales[2]/ mScaleFactor;
scales[3] = (CallbackBridge.physicalHeight/2);
scales[3] += scales[3]/scaleFactor;
scales[3] += scales[3]/ mScaleFactor;
return scales;
}
public void scaleDown(View view) {
scaleFactor = Math.max(scaleFactor - 1, 1);
scaleFactors = initScaleFactors(false);
mTextureView.initScaleFactors(scaleFactor);
sendScaledMousePosition(mousePointer.getX(),mousePointer.getY());
mScaleFactor = Math.max(mScaleFactor - 1, 1);
mScaleFactors = initScaleFactors(false);
mTextureView.initScaleFactors(mScaleFactor);
sendScaledMousePosition(mMousePointerImageView.getX(), mMousePointerImageView.getY());
}
public void scaleUp(View view) {
scaleFactor = Math.min(scaleFactor + 1, 6);
scaleFactors = initScaleFactors(false);
mTextureView.initScaleFactors(scaleFactor);
sendScaledMousePosition(mousePointer.getX(),mousePointer.getY());
mScaleFactor = Math.min(mScaleFactor + 1, 6);
mScaleFactors = initScaleFactors(false);
mTextureView.initScaleFactors(mScaleFactor);
sendScaledMousePosition(mMousePointerImageView.getX(), mMousePointerImageView.getY());
}
private int doCustomInstall(File modFile, String javaArgs) throws IOException {
mSkipDetectMod = true;
return launchJavaRuntime(modFile, javaArgs);
}
}

View File

@@ -12,12 +12,12 @@ import java.lang.ref.WeakReference;
*/
@Keep
public class Logger {
private static Logger loggerSingleton = null;
private static Logger sLoggerSingleton = null;
/* Instance variables */
private final File logFile;
private PrintStream logStream;
private WeakReference<eventLogListener> logListenerWeakReference = null;
private final File mLogFile;
private PrintStream mLogStream;
private WeakReference<eventLogListener> mLogListenerWeakReference = null;
/* No public construction */
private Logger(){
@@ -25,25 +25,25 @@ public class Logger {
}
private Logger(String fileName){
logFile = new File(Tools.DIR_GAME_HOME, fileName);
mLogFile = new File(Tools.DIR_GAME_HOME, fileName);
// Make a new instance of the log file
logFile.delete();
mLogFile.delete();
try {
logFile.createNewFile();
logStream = new PrintStream(logFile.getAbsolutePath());
mLogFile.createNewFile();
mLogStream = new PrintStream(mLogFile.getAbsolutePath());
}catch (IOException e){e.printStackTrace();}
}
public static Logger getInstance(){
if(loggerSingleton == null){
if(sLoggerSingleton == null){
synchronized(Logger.class){
if(loggerSingleton == null){
loggerSingleton = new Logger();
if(sLoggerSingleton == null){
sLoggerSingleton = new Logger();
}
}
}
return loggerSingleton;
return sLoggerSingleton;
}
@@ -55,22 +55,22 @@ public class Logger {
/** Print the text to the log file, no china censoring there */
public void appendToLogUnchecked(String text){
logStream.println(text);
mLogStream.println(text);
notifyLogListener(text);
}
/** Reset the log file, effectively erasing any previous logs */
public void reset(){
try{
logFile.delete();
logFile.createNewFile();
logStream = new PrintStream(logFile.getAbsolutePath());
mLogFile.delete();
mLogFile.createNewFile();
mLogStream = new PrintStream(mLogFile.getAbsolutePath());
}catch (IOException e){ e.printStackTrace();}
}
/** Disables the printing */
public void shutdown(){
logStream.close();
mLogStream.close();
}
/**
@@ -91,15 +91,15 @@ public class Logger {
/** Link a log listener to the logger */
public void setLogListener(eventLogListener logListener){
this.logListenerWeakReference = new WeakReference<>(logListener);
this.mLogListenerWeakReference = new WeakReference<>(logListener);
}
/** Notifies the event listener, if it exists */
private void notifyLogListener(String text){
if(logListenerWeakReference == null) return;
eventLogListener logListener = logListenerWeakReference.get();
if(mLogListenerWeakReference == null) return;
eventLogListener logListener = mLogListenerWeakReference.get();
if(logListener == null){
logListenerWeakReference = null;
mLogListenerWeakReference = null;
return;
}
logListener.onEventLogged(text);

View File

@@ -30,8 +30,7 @@
package net.kdt.pojavlaunch;
public class LWJGLGLFWKeycode
{
public class LwjglGlfwKeycode {
/** The unknown key. */
public static final short GLFW_KEY_UNKNOWN = 0; // should be -1
@@ -195,5 +194,8 @@ public class LWJGLGLFWKeycode
GLFW_MOUSE_BUTTON_LEFT = GLFW_MOUSE_BUTTON_1,
GLFW_MOUSE_BUTTON_RIGHT = GLFW_MOUSE_BUTTON_2,
GLFW_MOUSE_BUTTON_MIDDLE = GLFW_MOUSE_BUTTON_3;
public static final int
GLFW_VISIBLE = 0x20004,
GLFW_HOVERED = 0x2000B;
}

View File

@@ -5,8 +5,6 @@ import android.content.Intent;
import android.os.*;
import androidx.annotation.Nullable;
import net.kdt.pojavlaunch.customcontrols.*;
import net.kdt.pojavlaunch.prefs.*;
import net.kdt.pojavlaunch.utils.MCOptionUtils;
@@ -15,7 +13,6 @@ import java.io.*;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.DEFAULT_PREF;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_SUSTAINED_PERFORMANCE;
import static net.kdt.pojavlaunch.utils.MCOptionUtils.getMcScale;
public class MainActivity extends BaseMainActivity {
public static ControlLayout mControlLayout;
@@ -25,7 +22,7 @@ public class MainActivity extends BaseMainActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initLayout(R.layout.main_with_customctrl);
initLayout(R.layout.activity_basemain);
// Set the sustained performance mode for available APIs
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)

View File

@@ -11,20 +11,17 @@ import static org.lwjgl.glfw.CallbackBridge.windowWidth;
import android.app.Activity;
import android.content.*;
import android.graphics.SurfaceTexture;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.*;
import android.view.*;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import com.google.android.material.math.MathUtils;
import net.kdt.pojavlaunch.customcontrols.TouchCharInput;
import net.kdt.pojavlaunch.customcontrols.gamepad.Gamepad;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.utils.JREUtils;
@@ -36,44 +33,6 @@ import org.lwjgl.glfw.CallbackBridge;
* Class dealing with showing minecraft surface and taking inputs to dispatch them to minecraft
*/
public class MinecraftGLView extends TextureView {
/* Gamepad object for gamepad inputs, instantiated on need */
private Gamepad gamepad = null;
/* Pointer Debug textview, used to show info about the pointer state */
private TextView pointerDebugText;
/* Resolution scaler option, allow downsizing a window */
private final float scaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
/* Display properties, such as resolution and DPI */
private final DisplayMetrics displayMetrics = Tools.getDisplayMetrics((Activity) getContext());
/* Sensitivity, adjusted according to screen size */
private final double sensitivityFactor = (1.4 * (1080f/ displayMetrics.heightPixels));
/* Use to detect simple and double taps */
private final TapDetector singleTapDetector = new TapDetector(1, TapDetector.DETECTION_METHOD_BOTH);
private final TapDetector doubleTapDetector = new TapDetector(2, TapDetector.DETECTION_METHOD_DOWN);
/* MC GUI scale, listened by MCOptionUtils */
private int GUIScale = getMcScale();
private MCOptionUtils.MCOptionListener GUIScaleListener = () -> GUIScale = getMcScale();
/* Surface ready listener, used by the activity to launch minecraft */
SurfaceReadyListener surfaceReadyListener = null;
/* List of hotbarKeys, used when clicking on the hotbar */
private static final int[] hotbarKeys = {
LWJGLGLFWKeycode.GLFW_KEY_1, LWJGLGLFWKeycode.GLFW_KEY_2, LWJGLGLFWKeycode.GLFW_KEY_3,
LWJGLGLFWKeycode.GLFW_KEY_4, LWJGLGLFWKeycode.GLFW_KEY_5, LWJGLGLFWKeycode.GLFW_KEY_6,
LWJGLGLFWKeycode.GLFW_KEY_7, LWJGLGLFWKeycode.GLFW_KEY_8, LWJGLGLFWKeycode.GLFW_KEY_9};
/* Last hotbar button (0-9) registered */
private int lastHotbarKey = -1;
/* Events can start with only a move instead of an pointerDown due to mouse passthrough */
private boolean shouldBeDown = false;
/* When fingers are really near to each other, it tends to either swap or remove a pointer ! */
private int lastPointerCount = 0;
/* Previous MotionEvent position, not scale */
private float prevX, prevY;
/* PointerID used for the moving camera */
private int currentPointerID = -1000;
/* Initial first pointer positions non-scaled, used to test touch sloppiness */
private float initialX, initialY;
/* Last first pointer positions non-scaled, used to scroll distance */
private float scrollLastInitialX, scrollLastInitialY;
/* How much distance a finger has to go for touch sloppiness to be disabled */
public static final int FINGER_STILL_THRESHOLD = (int) Tools.dpToPx(9);
/* How much distance a finger has to go to scroll */
@@ -81,6 +40,46 @@ public class MinecraftGLView extends TextureView {
/* Handle hotbar throw button and mouse mining button */
public static final int MSG_LEFT_MOUSE_BUTTON_CHECK = 1028;
public static final int MSG_DROP_ITEM_BUTTON_CHECK = 1029;
/* Gamepad object for gamepad inputs, instantiated on need */
private Gamepad mGamepad = null;
/* Pointer Debug textview, used to show info about the pointer state */
private TextView mPointerDebugTextView;
/* Resolution scaler option, allow downsizing a window */
private final float mScaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
/* Display properties, such as resolution and DPI */
private final DisplayMetrics mDisplayMetrics = Tools.getDisplayMetrics((Activity) getContext());
/* Sensitivity, adjusted according to screen size */
private final double mSensitivityFactor = (1.4 * (1080f/ mDisplayMetrics.heightPixels));
/* Use to detect simple and double taps */
private final TapDetector mSingleTapDetector = new TapDetector(1, TapDetector.DETECTION_METHOD_BOTH);
private final TapDetector mDoubleTapDetector = new TapDetector(2, TapDetector.DETECTION_METHOD_DOWN);
/* MC GUI scale, listened by MCOptionUtils */
private int mGuiScale = getMcScale();
private MCOptionUtils.MCOptionListener mGuiScaleListener = () -> mGuiScale = getMcScale();
/* Surface ready listener, used by the activity to launch minecraft */
SurfaceReadyListener mSurfaceReadyListener = null;
/* List of hotbarKeys, used when clicking on the hotbar */
private static final int[] sHotbarKeys = {
LwjglGlfwKeycode.GLFW_KEY_1, LwjglGlfwKeycode.GLFW_KEY_2, LwjglGlfwKeycode.GLFW_KEY_3,
LwjglGlfwKeycode.GLFW_KEY_4, LwjglGlfwKeycode.GLFW_KEY_5, LwjglGlfwKeycode.GLFW_KEY_6,
LwjglGlfwKeycode.GLFW_KEY_7, LwjglGlfwKeycode.GLFW_KEY_8, LwjglGlfwKeycode.GLFW_KEY_9};
/* Last hotbar button (0-9) registered */
private int mLastHotbarKey = -1;
/* Events can start with only a move instead of an pointerDown due to mouse passthrough */
private boolean mShouldBeDown = false;
/* When fingers are really near to each other, it tends to either swap or remove a pointer ! */
private int mLastPointerCount = 0;
/* Previous MotionEvent position, not scale */
private float mPrevX, mPrevY;
/* PointerID used for the moving camera */
private int mCurrentPointerID = -1000;
/* Initial first pointer positions non-scaled, used to test touch sloppiness */
private float mInitialX, mInitialY;
/* Last first pointer positions non-scaled, used to scroll distance */
private float mScrollLastInitialX, mScrollLastInitialY;
/* Handle hotbar throw button and mouse mining button */
private final Handler theHandler = new Handler(Looper.getMainLooper()) {
public void handleMessage(Message msg) {
if(msg.what == MSG_LEFT_MOUSE_BUTTON_CHECK) {
@@ -88,15 +87,15 @@ public class MinecraftGLView extends TextureView {
float x = CallbackBridge.mouseX;
float y = CallbackBridge.mouseY;
if (CallbackBridge.isGrabbing() &&
MathUtils.dist(x, y, initialX, initialY) < FINGER_STILL_THRESHOLD) {
triggeredLeftMouseButton = true;
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, true);
MathUtils.dist(x, y, mInitialX, mInitialY) < FINGER_STILL_THRESHOLD) {
mTriggeredLeftMouseButton = true;
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, true);
}
return;
}
if(msg.what == MSG_DROP_ITEM_BUTTON_CHECK) {
if(CallbackBridge.isGrabbing()){
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_Q);
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_Q);
theHandler.sendEmptyMessageDelayed(MSG_DROP_ITEM_BUTTON_CHECK, 600);
}
return;
@@ -105,7 +104,9 @@ public class MinecraftGLView extends TextureView {
}
};
/* Whether the button was triggered, used by the handler */
private static boolean triggeredLeftMouseButton = false;
private boolean mTriggeredLeftMouseButton = false;
/* Whether the pointer debug has failed at some point */
private boolean debugErrored = false;
public MinecraftGLView(Context context) {
@@ -119,68 +120,7 @@ public class MinecraftGLView extends TextureView {
setOpaque(false);
setFocusable(true);
MCOptionUtils.addMCOptionListener(GUIScaleListener);
}
/** Initialize the view and all its settings */
public void start(){
// Add the pointer debug textview
pointerDebugText = new TextView(getContext());
pointerDebugText.setX(0);
pointerDebugText.setY(0);
pointerDebugText.setVisibility(GONE);
((ViewGroup)getParent()).addView(pointerDebugText);
setSurfaceTextureListener(new SurfaceTextureListener() {
private boolean isCalled = false;
@Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
windowWidth = Tools.getDisplayFriendlyRes(width, scaleFactor);
windowHeight = Tools.getDisplayFriendlyRes(height, scaleFactor);
texture.setDefaultBufferSize(windowWidth, windowHeight);
//Load Minecraft options:
MCOptionUtils.load();
MCOptionUtils.set("overrideWidth", String.valueOf(windowWidth));
MCOptionUtils.set("overrideHeight", String.valueOf(windowHeight));
MCOptionUtils.save();
getMcScale();
// Should we do that?
if(isCalled) return;
isCalled = true;
JREUtils.setupBridgeWindow(new Surface(texture));
new Thread(() -> {
try {
Thread.sleep(200);
if(surfaceReadyListener != null){
surfaceReadyListener.isReady();
}
} catch (Throwable e) {
Tools.showError(getContext(), e, true);
}
}, "JVM Main thread").start();
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
return true;
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
windowWidth = Tools.getDisplayFriendlyRes(width, scaleFactor);
windowHeight = Tools.getDisplayFriendlyRes(height, scaleFactor);
CallbackBridge.sendUpdateWindowSize(windowWidth, windowHeight);
getMcScale();
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
texture.setDefaultBufferSize(windowWidth, windowHeight);
}
});
MCOptionUtils.addMCOptionListener(mGuiScaleListener);
}
@@ -196,7 +136,7 @@ public class MinecraftGLView extends TextureView {
// Mouse found
if(CallbackBridge.isGrabbing()) return false;
CallbackBridge.sendCursorPos( e.getX(i) * scaleFactor, e.getY(i) * scaleFactor);
CallbackBridge.sendCursorPos( e.getX(i) * mScaleFactor, e.getY(i) * mScaleFactor);
return true; //mouse event handled successfully
}
@@ -205,17 +145,17 @@ public class MinecraftGLView extends TextureView {
//Getting scaled position from the event
/* Tells if a double tap happened [MOUSE GRAB ONLY]. Doesn't tell where though. */
if(!CallbackBridge.isGrabbing()) {
CallbackBridge.mouseX = (e.getX() * scaleFactor);
CallbackBridge.mouseY = (e.getY() * scaleFactor);
CallbackBridge.mouseX = (e.getX() * mScaleFactor);
CallbackBridge.mouseY = (e.getY() * mScaleFactor);
//One android click = one MC click
if(singleTapDetector.onTouchEvent(e)){
CallbackBridge.putMouseEventWithCoords(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, CallbackBridge.mouseX, CallbackBridge.mouseY);
if(mSingleTapDetector.onTouchEvent(e)){
CallbackBridge.putMouseEventWithCoords(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, CallbackBridge.mouseX, CallbackBridge.mouseY);
return true;
}
}
// Check double tap state, used for the hotbar
boolean hasDoubleTapped = doubleTapDetector.onTouchEvent(e);
boolean hasDoubleTapped = mDoubleTapDetector.onTouchEvent(e);
switch (e.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
@@ -227,46 +167,46 @@ public class MinecraftGLView extends TextureView {
// Touch hover
if(pointerCount == 1){
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
prevX = e.getX();
prevY = e.getY();
mPrevX = e.getX();
mPrevY = e.getY();
break;
}
// Scrolling feature
if(LauncherPreferences.PREF_DISABLE_GESTURES) break;
// The pointer count can never be 0, and it is not 1, therefore it is >= 2
int hScroll = ((int) (e.getX() - scrollLastInitialX)) / FINGER_SCROLL_THRESHOLD;
int vScroll = ((int) (e.getY() - scrollLastInitialY)) / FINGER_SCROLL_THRESHOLD;
int hScroll = ((int) (e.getX() - mScrollLastInitialX)) / FINGER_SCROLL_THRESHOLD;
int vScroll = ((int) (e.getY() - mScrollLastInitialY)) / FINGER_SCROLL_THRESHOLD;
if(vScroll != 0 || hScroll != 0){
CallbackBridge.sendScroll(hScroll, vScroll);
scrollLastInitialX = e.getX();
scrollLastInitialY = e.getY();
mScrollLastInitialX = e.getX();
mScrollLastInitialY = e.getY();
}
break;
}
// Camera movement
int pointerIndex = e.findPointerIndex(currentPointerID);
int pointerIndex = e.findPointerIndex(mCurrentPointerID);
int hudKeyHandled = handleGuiBar((int)e.getX(), (int) e.getY());
// Start movement, due to new pointer or loss of pointer
if (pointerIndex == -1 || lastPointerCount != pointerCount || !shouldBeDown) {
if (pointerIndex == -1 || mLastPointerCount != pointerCount || !mShouldBeDown) {
if(hudKeyHandled != -1) break; //No pointer attribution on hotbar
shouldBeDown = true;
currentPointerID = e.getPointerId(0);
prevX = e.getX();
prevY = e.getY();
mShouldBeDown = true;
mCurrentPointerID = e.getPointerId(0);
mPrevX = e.getX();
mPrevY = e.getY();
break;
}
// Continue movement as usual
if(hudKeyHandled == -1){ //No camera on hotbar
CallbackBridge.mouseX += (e.getX(pointerIndex) - prevX) * sensitivityFactor;
CallbackBridge.mouseY += (e.getY(pointerIndex) - prevY) * sensitivityFactor;
CallbackBridge.mouseX += (e.getX(pointerIndex) - mPrevX) * mSensitivityFactor;
CallbackBridge.mouseY += (e.getY(pointerIndex) - mPrevY) * mSensitivityFactor;
}
prevX = e.getX(pointerIndex);
prevY = e.getY(pointerIndex);
mPrevX = e.getX(pointerIndex);
mPrevY = e.getY(pointerIndex);
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
break;
@@ -278,35 +218,35 @@ public class MinecraftGLView extends TextureView {
boolean isTouchInHotbar = hudKeyHandled != -1;
if (isTouchInHotbar) {
sendKeyPress(hudKeyHandled);
if(hasDoubleTapped && hudKeyHandled == lastHotbarKey){
if(hasDoubleTapped && hudKeyHandled == mLastHotbarKey){
//Prevent double tapping Event on two different slots
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_F);
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_F);
}
theHandler.sendEmptyMessageDelayed(MSG_DROP_ITEM_BUTTON_CHECK, 350);
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
lastHotbarKey = hudKeyHandled;
mLastHotbarKey = hudKeyHandled;
break;
}
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
prevX = e.getX();
prevY = e.getY();
mPrevX = e.getX();
mPrevY = e.getY();
if (CallbackBridge.isGrabbing()) {
currentPointerID = e.getPointerId(0);
mCurrentPointerID = e.getPointerId(0);
// It cause hold left mouse while moving camera
initialX = CallbackBridge.mouseX;
initialY = CallbackBridge.mouseY;
mInitialX = CallbackBridge.mouseX;
mInitialY = CallbackBridge.mouseY;
theHandler.sendEmptyMessageDelayed(MSG_LEFT_MOUSE_BUTTON_CHECK, LauncherPreferences.PREF_LONGPRESS_TRIGGER);
}
lastHotbarKey = hudKeyHandled;
mLastHotbarKey = hudKeyHandled;
break;
case MotionEvent.ACTION_UP: // 1
case MotionEvent.ACTION_CANCEL: // 3
shouldBeDown = false;
currentPointerID = -1;
mShouldBeDown = false;
mCurrentPointerID = -1;
hudKeyHandled = handleGuiBar((int)e.getX(), (int) e.getY());
isTouchInHotbar = hudKeyHandled != -1;
@@ -315,49 +255,49 @@ public class MinecraftGLView extends TextureView {
// Stop the dropping of items
if (isTouchInHotbar) {
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_Q, 0, false);
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_Q, 0, false);
theHandler.removeMessages(MSG_DROP_ITEM_BUTTON_CHECK);
break;
}
// Remove the mouse left button
if(triggeredLeftMouseButton){
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, false);
triggeredLeftMouseButton = false;
if(mTriggeredLeftMouseButton){
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, false);
mTriggeredLeftMouseButton = false;
break;
}
theHandler.removeMessages(MSG_LEFT_MOUSE_BUTTON_CHECK);
// In case of a short click, just send a quick right click
if(!LauncherPreferences.PREF_DISABLE_GESTURES &&
MathUtils.dist(initialX, initialY, CallbackBridge.mouseX, CallbackBridge.mouseY) < FINGER_STILL_THRESHOLD){
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, true);
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, false);
MathUtils.dist(mInitialX, mInitialY, CallbackBridge.mouseX, CallbackBridge.mouseY) < FINGER_STILL_THRESHOLD){
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, true);
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, false);
}
break;
case MotionEvent.ACTION_POINTER_DOWN: // 5
//TODO Hey we could have some sort of middle click detection ?
scrollLastInitialX = e.getX();
scrollLastInitialY = e.getY();
mScrollLastInitialX = e.getX();
mScrollLastInitialY = 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){
sendKeyPress(hudKeyHandled);
if(hasDoubleTapped && hudKeyHandled == lastHotbarKey){
if(hasDoubleTapped && hudKeyHandled == mLastHotbarKey){
//Prevent double tapping Event on two different slots
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_F);
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_F);
}
}
lastHotbarKey = hudKeyHandled;
mLastHotbarKey = hudKeyHandled;
break;
}
// Actualise the pointer count
lastPointerCount = e.getPointerCount();
mLastPointerCount = e.getPointerCount();
//debugText.setText(CallbackBridge.DEBUG_STRING.toString());
CallbackBridge.DEBUG_STRING.setLength(0);
@@ -374,11 +314,11 @@ public class MinecraftGLView extends TextureView {
int mouseCursorIndex = -1;
if(Gamepad.isGamepadEvent(event)){
if(gamepad == null){
gamepad = new Gamepad(this, event.getDevice());
if(mGamepad == null){
mGamepad = new Gamepad(this, event.getDevice());
}
gamepad.update(event);
mGamepad.update(event);
return true;
}
@@ -397,8 +337,8 @@ public class MinecraftGLView extends TextureView {
}
switch(event.getActionMasked()) {
case MotionEvent.ACTION_HOVER_MOVE:
CallbackBridge.mouseX = (event.getX(mouseCursorIndex) * scaleFactor);
CallbackBridge.mouseY = (event.getY(mouseCursorIndex) * scaleFactor);
CallbackBridge.mouseX = (event.getX(mouseCursorIndex) * mScaleFactor);
CallbackBridge.mouseY = (event.getY(mouseCursorIndex) * mScaleFactor);
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
//debugText.setText(CallbackBridge.DEBUG_STRING.toString());
CallbackBridge.DEBUG_STRING.setLength(0);
@@ -415,20 +355,20 @@ public class MinecraftGLView extends TextureView {
}
}
//TODO MOVE THIS SOMEWHERE ELSE
private boolean debugErrored = false;
/** The input event for mouse with a captured pointer */
@RequiresApi(26)
@Override
public boolean dispatchCapturedPointerEvent(MotionEvent e) {
CallbackBridge.mouseX += (e.getX()*scaleFactor);
CallbackBridge.mouseY += (e.getY()*scaleFactor);
CallbackBridge.mouseX += (e.getX()* mScaleFactor);
CallbackBridge.mouseY += (e.getY()* mScaleFactor);
if(!CallbackBridge.isGrabbing()){
releasePointerCapture();
clearFocus();
}
if (pointerDebugText.getVisibility() == View.VISIBLE && !debugErrored) {
if (mPointerDebugTextView.getVisibility() == View.VISIBLE && !debugErrored) {
StringBuilder builder = new StringBuilder();
try {
builder.append("PointerCapture debug\n");
@@ -448,12 +388,12 @@ public class MinecraftGLView extends TextureView {
debugErrored = true;
builder.append("Error getting debug. The debug will be stopped!\n").append(Log.getStackTraceString(th));
} finally {
pointerDebugText.setText(builder.toString());
mPointerDebugTextView.setText(builder.toString());
builder.setLength(0);
}
}
pointerDebugText.setText(CallbackBridge.DEBUG_STRING.toString());
mPointerDebugTextView.setText(CallbackBridge.DEBUG_STRING.toString());
CallbackBridge.DEBUG_STRING.setLength(0);
switch (e.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
@@ -506,7 +446,7 @@ public class MinecraftGLView extends TextureView {
if(eventKeycode == KeyEvent.KEYCODE_BACK){
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, event.getAction() == KeyEvent.ACTION_DOWN);
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, event.getAction() == KeyEvent.ACTION_DOWN);
return true;
}
}
@@ -514,11 +454,11 @@ public class MinecraftGLView extends TextureView {
if(Gamepad.isGamepadEvent(event)){
if(gamepad == null){
gamepad = new Gamepad(this, event.getDevice());
if(mGamepad == null){
mGamepad = new Gamepad(this, event.getDevice());
}
gamepad.update(event);
mGamepad.update(event);
return true;
}
@@ -532,11 +472,66 @@ public class MinecraftGLView extends TextureView {
return false;
}
/** Get the mouse direction as a string */
private String getMoving(float pos, boolean xOrY) {
if (pos == 0) return "STOPPED";
if (pos > 0) return xOrY ? "RIGHT" : "DOWN";
return xOrY ? "LEFT" : "UP";
/** Initialize the view and all its settings */
public void start(){
// Add the pointer debug textview
mPointerDebugTextView = new TextView(getContext());
mPointerDebugTextView.setX(0);
mPointerDebugTextView.setY(0);
mPointerDebugTextView.setVisibility(GONE);
((ViewGroup)getParent()).addView(mPointerDebugTextView);
setSurfaceTextureListener(new SurfaceTextureListener() {
private boolean isCalled = false;
@Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
windowWidth = Tools.getDisplayFriendlyRes(width, mScaleFactor);
windowHeight = Tools.getDisplayFriendlyRes(height, mScaleFactor);
texture.setDefaultBufferSize(windowWidth, windowHeight);
//Load Minecraft options:
MCOptionUtils.load();
MCOptionUtils.set("overrideWidth", String.valueOf(windowWidth));
MCOptionUtils.set("overrideHeight", String.valueOf(windowHeight));
MCOptionUtils.save();
getMcScale();
// Should we do that?
if(isCalled) return;
isCalled = true;
JREUtils.setupBridgeWindow(new Surface(texture));
new Thread(() -> {
try {
Thread.sleep(200);
if(mSurfaceReadyListener != null){
mSurfaceReadyListener.isReady();
}
} catch (Throwable e) {
Tools.showError(getContext(), e, true);
}
}, "JVM Main thread").start();
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
return true;
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
windowWidth = Tools.getDisplayFriendlyRes(width, mScaleFactor);
windowHeight = Tools.getDisplayFriendlyRes(height, mScaleFactor);
CallbackBridge.sendUpdateWindowSize(windowWidth, windowHeight);
getMcScale();
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
texture.setDefaultBufferSize(windowWidth, windowHeight);
}
});
}
/** Convert the mouse button, then send it
@@ -546,13 +541,13 @@ public class MinecraftGLView extends TextureView {
int glfwButton = -256;
switch (button) {
case MotionEvent.BUTTON_PRIMARY:
glfwButton = LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT;
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT;
break;
case MotionEvent.BUTTON_TERTIARY:
glfwButton = LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_MIDDLE;
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_MIDDLE;
break;
case MotionEvent.BUTTON_SECONDARY:
glfwButton = LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT;
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT;
break;
}
if(glfwButton == -256) return false;
@@ -560,8 +555,6 @@ public class MinecraftGLView extends TextureView {
return true;
}
/** @return the hotbar key, given the position. -1 if no key are pressed */
public int handleGuiBar(int x, int y) {
if (!CallbackBridge.isGrabbing()) return -1;
@@ -574,17 +567,12 @@ public class MinecraftGLView extends TextureView {
int barX = (CallbackBridge.physicalWidth / 2) - (barWidth / 2);
if(x < barX || x >= barX + barWidth) return -1;
return hotbarKeys[(int) net.kdt.pojavlaunch.utils.MathUtils.map(x, barX, barX + barWidth, 0, 9)];
}
/** Return the size, given the UI scale size */
private int mcscale(int input) {
return (int)((GUIScale * input)/scaleFactor);
return sHotbarKeys[(int) net.kdt.pojavlaunch.utils.MathUtils.map(x, barX, barX + barWidth, 0, 9)];
}
/** Toggle the pointerDebugText visibility state */
public void togglepointerDebugging() {
pointerDebugText.setVisibility(pointerDebugText.getVisibility() == View.GONE ? View.VISIBLE : View.GONE);
mPointerDebugTextView.setVisibility(mPointerDebugTextView.getVisibility() == View.GONE ? View.VISIBLE : View.GONE);
}
/** A small interface called when the listener is ready for the first time */
@@ -593,6 +581,19 @@ public class MinecraftGLView extends TextureView {
}
public void setSurfaceReadyListener(SurfaceReadyListener listener){
surfaceReadyListener = listener;
mSurfaceReadyListener = listener;
}
/** Return the size, given the UI scale size */
private int mcscale(int input) {
return (int)((mGuiScale * input)/ mScaleFactor);
}
/** Get the mouse direction as a string */
private String getMoving(float pos, boolean xOrY) {
if (pos == 0) return "STOPPED";
if (pos > 0) return xOrY ? "RIGHT" : "DOWN";
return xOrY ? "LEFT" : "UP";
}
}

View File

@@ -0,0 +1,604 @@
package net.kdt.pojavlaunch;
import static net.kdt.pojavlaunch.BaseMainActivity.touchCharInput;
import static net.kdt.pojavlaunch.utils.MCOptionUtils.getMcScale;
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
import static org.lwjgl.glfw.CallbackBridge.sendMouseButton;
import static org.lwjgl.glfw.CallbackBridge.windowHeight;
import static org.lwjgl.glfw.CallbackBridge.windowWidth;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import com.google.android.material.math.MathUtils;
import net.kdt.pojavlaunch.customcontrols.gamepad.Gamepad;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.utils.JREUtils;
import net.kdt.pojavlaunch.utils.MCOptionUtils;
import org.lwjgl.glfw.CallbackBridge;
/**
* Class dealing with showing minecraft surface and taking inputs to dispatch them to minecraft
*/
public class MinecraftLEGLView extends SurfaceView {
/* Gamepad object for gamepad inputs, instantiated on need */
private Gamepad gamepad = null;
/* Pointer Debug textview, used to show info about the pointer state */
private TextView pointerDebugText;
/* Resolution scaler option, allow downsizing a window */
private final float scaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
/* Display properties, such as resolution and DPI */
private final DisplayMetrics displayMetrics = Tools.getDisplayMetrics((Activity) getContext());
/* Sensitivity, adjusted according to screen size */
private final double sensitivityFactor = (1.4 * (1080f/ displayMetrics.heightPixels));
/* Use to detect simple and double taps */
private final TapDetector singleTapDetector = new TapDetector(1, TapDetector.DETECTION_METHOD_BOTH);
private final TapDetector doubleTapDetector = new TapDetector(2, TapDetector.DETECTION_METHOD_DOWN);
/* MC GUI scale, listened by MCOptionUtils */
private int GUIScale = getMcScale();
private MCOptionUtils.MCOptionListener GUIScaleListener = () -> GUIScale = getMcScale();
/* Surface ready listener, used by the activity to launch minecraft */
SurfaceReadyListener surfaceReadyListener = null;
/* List of hotbarKeys, used when clicking on the hotbar */
private static final int[] hotbarKeys = {
LwjglGlfwKeycode.GLFW_KEY_1, LwjglGlfwKeycode.GLFW_KEY_2, LwjglGlfwKeycode.GLFW_KEY_3,
LwjglGlfwKeycode.GLFW_KEY_4, LwjglGlfwKeycode.GLFW_KEY_5, LwjglGlfwKeycode.GLFW_KEY_6,
LwjglGlfwKeycode.GLFW_KEY_7, LwjglGlfwKeycode.GLFW_KEY_8, LwjglGlfwKeycode.GLFW_KEY_9};
/* Last hotbar button (0-9) registered */
private int lastHotbarKey = -1;
/* Events can start with only a move instead of an pointerDown due to mouse passthrough */
private boolean shouldBeDown = false;
/* When fingers are really near to each other, it tends to either swap or remove a pointer ! */
private int lastPointerCount = 0;
/* Previous MotionEvent position, not scale */
private float prevX, prevY;
/* PointerID used for the moving camera */
private int currentPointerID = -1000;
/* Initial first pointer positions non-scaled, used to test touch sloppiness */
private float initialX, initialY;
/* Last first pointer positions non-scaled, used to scroll distance */
private float scrollLastInitialX, scrollLastInitialY;
/* How much distance a finger has to go for touch sloppiness to be disabled */
public static final int FINGER_STILL_THRESHOLD = (int) Tools.dpToPx(9);
/* How much distance a finger has to go to scroll */
public static final int FINGER_SCROLL_THRESHOLD = (int) Tools.dpToPx(6);
/* Handle hotbar throw button and mouse mining button */
public static final int MSG_LEFT_MOUSE_BUTTON_CHECK = 1028;
public static final int MSG_DROP_ITEM_BUTTON_CHECK = 1029;
private final Handler theHandler = new Handler(Looper.getMainLooper()) {
public void handleMessage(Message msg) {
if(msg.what == MSG_LEFT_MOUSE_BUTTON_CHECK) {
if (LauncherPreferences.PREF_DISABLE_GESTURES) return;
float x = CallbackBridge.mouseX;
float y = CallbackBridge.mouseY;
if (CallbackBridge.isGrabbing() &&
MathUtils.dist(x, y, initialX, initialY) < FINGER_STILL_THRESHOLD) {
triggeredLeftMouseButton = true;
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, true);
}
return;
}
if(msg.what == MSG_DROP_ITEM_BUTTON_CHECK) {
if(CallbackBridge.isGrabbing()){
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_Q);
theHandler.sendEmptyMessageDelayed(MSG_DROP_ITEM_BUTTON_CHECK, 600);
}
return;
}
}
};
/* Whether the button was triggered, used by the handler */
private static boolean triggeredLeftMouseButton = false;
public MinecraftLEGLView(Context context) {
this(context, null);
}
public MinecraftLEGLView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
//Fixes freeform and dex mode having transparent glass,
//since it forces android to used the background color of the view/layout behind it.
//setOpaque(false);
setFocusable(true);
MCOptionUtils.addMCOptionListener(GUIScaleListener);
}
/** Initialize the view and all its settings */
public void start(){
// Add the pointer debug textview
pointerDebugText = new TextView(getContext());
pointerDebugText.setX(0);
pointerDebugText.setY(0);
pointerDebugText.setVisibility(GONE);
((ViewGroup)getParent()).addView(pointerDebugText);
getHolder().addCallback(new SurfaceHolder.Callback() {
private boolean isCalled = false;
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
//Load Minecraft options:
MCOptionUtils.load();
MCOptionUtils.set("overrideWidth", String.valueOf(windowWidth));
MCOptionUtils.set("overrideHeight", String.valueOf(windowHeight));
MCOptionUtils.save();
getMcScale();
// Should we do that?
if(isCalled) return;
isCalled = true;
getHolder().setFixedSize(windowWidth, windowHeight);
JREUtils.setupBridgeWindow(getHolder().getSurface());
new Thread(() -> {
try {
Thread.sleep(200);
if(surfaceReadyListener != null){
surfaceReadyListener.isReady();
}
} catch (Throwable e) {
Tools.showError(getContext(), e, true);
}
}, "JVM Main thread").start();
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
windowWidth = Tools.getDisplayFriendlyRes(displayMetrics.widthPixels, scaleFactor);
windowHeight = Tools.getDisplayFriendlyRes(displayMetrics.heightPixels, scaleFactor);
CallbackBridge.sendUpdateWindowSize(windowWidth, windowHeight);
getMcScale();
Toast.makeText(getContext(), "width: " + width, Toast.LENGTH_SHORT).show();
Toast.makeText(getContext(), "height: " + height, Toast.LENGTH_SHORT).show();
getHolder().setFixedSize(windowWidth, windowHeight);
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
}
});
}
/**
* The touch event for both grabbed an non-grabbed mouse state on the touch screen
* Does not cover the virtual mouse touchpad
*/
@Override
public boolean onTouchEvent(MotionEvent e) {
// Looking for a mouse to handle, won't have an effect if no mouse exists.
for (int i = 0; i < e.getPointerCount(); i++) {
if (e.getToolType(i) != MotionEvent.TOOL_TYPE_MOUSE) continue;
// Mouse found
if(CallbackBridge.isGrabbing()) return false;
CallbackBridge.sendCursorPos( e.getX(i) * scaleFactor, e.getY(i) * scaleFactor);
return true; //mouse event handled successfully
}
// System.out.println("Pre touch, isTouchInHotbar=" + Boolean.toString(isTouchInHotbar) + ", action=" + MotionEvent.actionToString(e.getActionMasked()));
//Getting scaled position from the event
/* Tells if a double tap happened [MOUSE GRAB ONLY]. Doesn't tell where though. */
if(!CallbackBridge.isGrabbing()) {
CallbackBridge.mouseX = (e.getX() * scaleFactor);
CallbackBridge.mouseY = (e.getY() * scaleFactor);
//One android click = one MC click
if(singleTapDetector.onTouchEvent(e)){
CallbackBridge.putMouseEventWithCoords(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, CallbackBridge.mouseX, CallbackBridge.mouseY);
return true;
}
}
// Check double tap state, used for the hotbar
boolean hasDoubleTapped = doubleTapDetector.onTouchEvent(e);
switch (e.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
int pointerCount = e.getPointerCount();
// In-menu interactions
if(!CallbackBridge.isGrabbing()){
// Touch hover
if(pointerCount == 1){
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
prevX = e.getX();
prevY = e.getY();
break;
}
// Scrolling feature
if(LauncherPreferences.PREF_DISABLE_GESTURES) break;
// The pointer count can never be 0, and it is not 1, therefore it is >= 2
int hScroll = ((int) (e.getX() - scrollLastInitialX)) / FINGER_SCROLL_THRESHOLD;
int vScroll = ((int) (e.getY() - scrollLastInitialY)) / FINGER_SCROLL_THRESHOLD;
if(vScroll != 0 || hScroll != 0){
CallbackBridge.sendScroll(hScroll, vScroll);
scrollLastInitialX = e.getX();
scrollLastInitialY = e.getY();
}
break;
}
// Camera movement
int pointerIndex = e.findPointerIndex(currentPointerID);
int hudKeyHandled = handleGuiBar((int)e.getX(), (int) e.getY());
// Start movement, due to new pointer or loss of pointer
if (pointerIndex == -1 || lastPointerCount != pointerCount || !shouldBeDown) {
if(hudKeyHandled != -1) break; //No pointer attribution on hotbar
shouldBeDown = true;
currentPointerID = e.getPointerId(0);
prevX = e.getX();
prevY = e.getY();
break;
}
// Continue movement as usual
if(hudKeyHandled == -1){ //No camera on hotbar
CallbackBridge.mouseX += (e.getX(pointerIndex) - prevX) * sensitivityFactor;
CallbackBridge.mouseY += (e.getY(pointerIndex) - prevY) * sensitivityFactor;
}
prevX = e.getX(pointerIndex);
prevY = e.getY(pointerIndex);
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
break;
case MotionEvent.ACTION_DOWN: // 0
CallbackBridge.sendPrepareGrabInitialPos();
hudKeyHandled = handleGuiBar((int)e.getX(), (int) e.getY());
boolean isTouchInHotbar = hudKeyHandled != -1;
if (isTouchInHotbar) {
sendKeyPress(hudKeyHandled);
if(hasDoubleTapped && hudKeyHandled == lastHotbarKey){
//Prevent double tapping Event on two different slots
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_F);
}
theHandler.sendEmptyMessageDelayed(MSG_DROP_ITEM_BUTTON_CHECK, 350);
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
lastHotbarKey = hudKeyHandled;
break;
}
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
prevX = e.getX();
prevY = e.getY();
if (CallbackBridge.isGrabbing()) {
currentPointerID = e.getPointerId(0);
// It cause hold left mouse while moving camera
initialX = CallbackBridge.mouseX;
initialY = CallbackBridge.mouseY;
theHandler.sendEmptyMessageDelayed(MSG_LEFT_MOUSE_BUTTON_CHECK, LauncherPreferences.PREF_LONGPRESS_TRIGGER);
}
lastHotbarKey = hudKeyHandled;
break;
case MotionEvent.ACTION_UP: // 1
case MotionEvent.ACTION_CANCEL: // 3
shouldBeDown = false;
currentPointerID = -1;
hudKeyHandled = handleGuiBar((int)e.getX(), (int) e.getY());
isTouchInHotbar = hudKeyHandled != -1;
// We only treat in world events
if (!CallbackBridge.isGrabbing()) break;
// Stop the dropping of items
if (isTouchInHotbar) {
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_Q, 0, false);
theHandler.removeMessages(MSG_DROP_ITEM_BUTTON_CHECK);
break;
}
// Remove the mouse left button
if(triggeredLeftMouseButton){
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, false);
triggeredLeftMouseButton = false;
break;
}
theHandler.removeMessages(MSG_LEFT_MOUSE_BUTTON_CHECK);
// In case of a short click, just send a quick right click
if(!LauncherPreferences.PREF_DISABLE_GESTURES &&
MathUtils.dist(initialX, initialY, CallbackBridge.mouseX, CallbackBridge.mouseY) < FINGER_STILL_THRESHOLD){
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, true);
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, false);
}
break;
case MotionEvent.ACTION_POINTER_DOWN: // 5
//TODO Hey we could have some sort of middle click detection ?
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){
sendKeyPress(hudKeyHandled);
if(hasDoubleTapped && hudKeyHandled == lastHotbarKey){
//Prevent double tapping Event on two different slots
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_F);
}
}
lastHotbarKey = hudKeyHandled;
break;
}
// Actualise the pointer count
lastPointerCount = e.getPointerCount();
//debugText.setText(CallbackBridge.DEBUG_STRING.toString());
CallbackBridge.DEBUG_STRING.setLength(0);
return true;
}
/**
* The event for mouse/joystick movements
* We don't do the gamepad right now.
*/
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
int mouseCursorIndex = -1;
if(Gamepad.isGamepadEvent(event)){
if(gamepad == null){
gamepad = new Gamepad(this, event.getDevice());
}
gamepad.update(event);
return true;
}
for(int i = 0; i < event.getPointerCount(); i++) {
if(event.getToolType(i) != MotionEvent.TOOL_TYPE_MOUSE) continue;
// Mouse found
mouseCursorIndex = i;
break;
}
if(mouseCursorIndex == -1) return false; // we cant consoom that, theres no mice!
if(CallbackBridge.isGrabbing()) {
if(BaseMainActivity.isAndroid8OrHigher()){
requestFocus();
requestPointerCapture();
}
}
switch(event.getActionMasked()) {
case MotionEvent.ACTION_HOVER_MOVE:
CallbackBridge.mouseX = (event.getX(mouseCursorIndex) * scaleFactor);
CallbackBridge.mouseY = (event.getY(mouseCursorIndex) * scaleFactor);
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
//debugText.setText(CallbackBridge.DEBUG_STRING.toString());
CallbackBridge.DEBUG_STRING.setLength(0);
return true;
case MotionEvent.ACTION_SCROLL:
CallbackBridge.sendScroll((double) event.getAxisValue(MotionEvent.AXIS_VSCROLL), (double) event.getAxisValue(MotionEvent.AXIS_HSCROLL));
return true;
case MotionEvent.ACTION_BUTTON_PRESS:
return sendMouseButtonUnconverted(event.getActionButton(),true);
case MotionEvent.ACTION_BUTTON_RELEASE:
return sendMouseButtonUnconverted(event.getActionButton(),false);
default:
return false;
}
}
//TODO MOVE THIS SOMEWHERE ELSE
private boolean debugErrored = false;
/** The input event for mouse with a captured pointer */
@RequiresApi(26)
@Override
public boolean dispatchCapturedPointerEvent(MotionEvent e) {
CallbackBridge.mouseX += (e.getX()*scaleFactor);
CallbackBridge.mouseY += (e.getY()*scaleFactor);
if(!CallbackBridge.isGrabbing()){
releasePointerCapture();
clearFocus();
}
if (pointerDebugText.getVisibility() == View.VISIBLE && !debugErrored) {
StringBuilder builder = new StringBuilder();
try {
builder.append("PointerCapture debug\n");
builder.append("MotionEvent=").append(e.getActionMasked()).append("\n");
builder.append("PressingBtn=").append(MotionEvent.class.getDeclaredMethod("buttonStateToString").invoke(null, e.getButtonState())).append("\n\n");
builder.append("PointerX=").append(e.getX()).append("\n");
builder.append("PointerY=").append(e.getY()).append("\n");
builder.append("RawX=").append(e.getRawX()).append("\n");
builder.append("RawY=").append(e.getRawY()).append("\n\n");
builder.append("XPos=").append(CallbackBridge.mouseX).append("\n");
builder.append("YPos=").append(CallbackBridge.mouseY).append("\n\n");
builder.append("MovingX=").append(getMoving(e.getX(), true)).append("\n");
builder.append("MovingY=").append(getMoving(e.getY(), false)).append("\n");
} catch (Throwable th) {
debugErrored = true;
builder.append("Error getting debug. The debug will be stopped!\n").append(Log.getStackTraceString(th));
} finally {
pointerDebugText.setText(builder.toString());
builder.setLength(0);
}
}
pointerDebugText.setText(CallbackBridge.DEBUG_STRING.toString());
CallbackBridge.DEBUG_STRING.setLength(0);
switch (e.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
return true;
case MotionEvent.ACTION_BUTTON_PRESS:
return sendMouseButtonUnconverted(e.getActionButton(), true);
case MotionEvent.ACTION_BUTTON_RELEASE:
return sendMouseButtonUnconverted(e.getActionButton(), false);
case MotionEvent.ACTION_SCROLL:
CallbackBridge.sendScroll(e.getAxisValue(MotionEvent.AXIS_HSCROLL), e.getAxisValue(MotionEvent.AXIS_VSCROLL));
return true;
default:
return false;
}
}
/** The event for keyboard/ gamepad button inputs */
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
//Toast.makeText(this, event.toString(),Toast.LENGTH_SHORT).show();
//Toast.makeText(this, event.getDevice().toString(), Toast.LENGTH_SHORT).show();
//Filtering useless events by order of probability
if((event.getFlags() & KeyEvent.FLAG_FALLBACK) == KeyEvent.FLAG_FALLBACK) return true;
int eventKeycode = event.getKeyCode();
if(eventKeycode == KeyEvent.KEYCODE_UNKNOWN) return true;
if(eventKeycode == KeyEvent.KEYCODE_VOLUME_DOWN) return false;
if(eventKeycode == KeyEvent.KEYCODE_VOLUME_UP) return false;
if(event.getRepeatCount() != 0) return true;
if(event.getAction() == KeyEvent.ACTION_MULTIPLE) return true;
//Toast.makeText(this, "FIRST VERIF PASSED", Toast.LENGTH_SHORT).show();
//Sometimes, key events comes from SOME keys of the software keyboard
//Even weirder, is is unknown why a key or another is selected to trigger a keyEvent
if((event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) == KeyEvent.FLAG_SOFT_KEYBOARD){
if(eventKeycode == KeyEvent.KEYCODE_ENTER) return true; //We already listen to it.
touchCharInput.dispatchKeyEvent(event);
return true;
}
//Toast.makeText(this, "SECOND VERIF PASSED", Toast.LENGTH_SHORT).show();
//Sometimes, key events may come from the mouse
if(event.getDevice() != null
&& ( (event.getSource() & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE
|| (event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) ){
//Toast.makeText(this, "THE EVENT COMES FROM A MOUSE", Toast.LENGTH_SHORT).show();
if(eventKeycode == KeyEvent.KEYCODE_BACK){
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, event.getAction() == KeyEvent.ACTION_DOWN);
return true;
}
}
System.out.println(event);
if(Gamepad.isGamepadEvent(event)){
if(gamepad == null){
gamepad = new Gamepad(this, event.getDevice());
}
gamepad.update(event);
return true;
}
int index = EfficientAndroidLWJGLKeycode.getIndexByKey(eventKeycode);
if(index >= 0) {
//Toast.makeText(this,"THIS IS A KEYBOARD EVENT !", Toast.LENGTH_SHORT).show();
EfficientAndroidLWJGLKeycode.execKey(event, index);
return true;
}
return false;
}
/** Get the mouse direction as a string */
private String getMoving(float pos, boolean xOrY) {
if (pos == 0) return "STOPPED";
if (pos > 0) return xOrY ? "RIGHT" : "DOWN";
return xOrY ? "LEFT" : "UP";
}
/** Convert the mouse button, then send it
* @return Whether the event was processed
*/
public static boolean sendMouseButtonUnconverted(int button, boolean status) {
int glfwButton = -256;
switch (button) {
case MotionEvent.BUTTON_PRIMARY:
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT;
break;
case MotionEvent.BUTTON_TERTIARY:
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_MIDDLE;
break;
case MotionEvent.BUTTON_SECONDARY:
glfwButton = LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT;
break;
}
if(glfwButton == -256) return false;
sendMouseButton(glfwButton, status);
return true;
}
/** @return the hotbar key, given the position. -1 if no key are pressed */
public int handleGuiBar(int x, int y) {
if (!CallbackBridge.isGrabbing()) return -1;
int barHeight = mcscale(20);
int barY = CallbackBridge.physicalHeight - barHeight;
if(y < barY) return -1;
int barWidth = mcscale(180);
int barX = (CallbackBridge.physicalWidth / 2) - (barWidth / 2);
if(x < barX || x >= barX + barWidth) return -1;
return hotbarKeys[(int) net.kdt.pojavlaunch.utils.MathUtils.map(x, barX, barX + barWidth, 0, 9)];
}
/** Return the size, given the UI scale size */
private int mcscale(int input) {
return (int)((GUIScale * input)/scaleFactor);
}
/** Toggle the pointerDebugText visibility state */
public void togglepointerDebugging() {
pointerDebugText.setVisibility(pointerDebugText.getVisibility() == View.GONE ? View.VISIBLE : View.GONE);
}
/** A small interface called when the listener is ready for the first time */
public interface SurfaceReadyListener {
void isReady();
}
public void setSurfaceReadyListener(SurfaceReadyListener listener){
surfaceReadyListener = listener;
}
}

View File

@@ -14,40 +14,37 @@ import java.util.*;
import net.kdt.pojavlaunch.utils.*;
public class PojavApplication extends Application
{
public class PojavApplication extends Application {
public static String CRASH_REPORT_TAG = "PojavCrashReport";
@Override
public void onCreate() {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler(){
@Override
public void uncaughtException(Thread thread, Throwable th) {
boolean storagePermAllowed = Build.VERSION.SDK_INT < 23 || ActivityCompat.checkSelfPermission(PojavApplication.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
File crashFile = new File(storagePermAllowed ? Tools.DIR_GAME_HOME : Tools.DIR_DATA, "latestcrash.txt");
try {
// Write to file, since some devices may not able to show error
crashFile.getParentFile().mkdirs();
crashFile.createNewFile();
PrintStream crashStream = new PrintStream(crashFile);
crashStream.append("PojavLauncher crash report\n");
crashStream.append(" - Time: " + DateFormat.getDateTimeInstance().format(new Date()) + "\n");
crashStream.append(" - Device: " + Build.PRODUCT + " " + Build.MODEL + "\n");
crashStream.append(" - Android version: " + Build.VERSION.RELEASE + "\n");
crashStream.append(" - Crash stack trace:\n");
crashStream.append(" - Launcher version: " + BuildConfig.VERSION_NAME + "\n");
crashStream.append(Log.getStackTraceString(th));
crashStream.close();
} catch (Throwable th2) {
Log.e(CRASH_REPORT_TAG, " - Exception attempt saving crash stack trace:", th2);
Log.e(CRASH_REPORT_TAG, " - The crash stack trace was:", th);
}
FatalErrorActivity.showError(PojavApplication.this, crashFile.getAbsolutePath(), storagePermAllowed, th);
// android.os.Process.killProcess(android.os.Process.myPid());
BaseMainActivity.fullyExit();
Thread.setDefaultUncaughtExceptionHandler((thread, th) -> {
boolean storagePermAllowed = Build.VERSION.SDK_INT < 23 ||
ActivityCompat.checkSelfPermission(PojavApplication.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
File crashFile = new File(storagePermAllowed ? Tools.DIR_GAME_HOME : Tools.DIR_DATA, "latestcrash.txt");
try {
// Write to file, since some devices may not able to show error
crashFile.getParentFile().mkdirs();
crashFile.createNewFile();
PrintStream crashStream = new PrintStream(crashFile);
crashStream.append("PojavLauncher crash report\n");
crashStream.append(" - Time: " + DateFormat.getDateTimeInstance().format(new Date()) + "\n");
crashStream.append(" - Device: " + Build.PRODUCT + " " + Build.MODEL + "\n");
crashStream.append(" - Android version: " + Build.VERSION.RELEASE + "\n");
crashStream.append(" - Crash stack trace:\n");
crashStream.append(" - Launcher version: " + BuildConfig.VERSION_NAME + "\n");
crashStream.append(Log.getStackTraceString(th));
crashStream.close();
} catch (Throwable throwable) {
Log.e(CRASH_REPORT_TAG, " - Exception attempt saving crash stack trace:", throwable);
Log.e(CRASH_REPORT_TAG, " - The crash stack trace was:", th);
}
FatalErrorActivity.showError(PojavApplication.this, crashFile.getAbsolutePath(), storagePermAllowed, th);
// android.os.Process.killProcess(android.os.Process.myPid());
BaseMainActivity.fullyExit();
});
try {
@@ -70,10 +67,9 @@ public class PojavApplication extends Application
.concat("/x86");
}
} catch (Throwable th) {
} catch (Throwable throwable) {
Intent ferrorIntent = new Intent(this, FatalErrorActivity.class);
ferrorIntent.putExtra("throwable", th);
ferrorIntent.putExtra("throwable", throwable);
startActivity(ferrorIntent);
}
}

View File

@@ -98,7 +98,7 @@ public class PojavLauncherActivity extends BaseLauncherActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.launcher_main_v4);
setContentView(R.layout.activity_pojav_launcher);
//Boilerplate linking/initialisation
viewPager = findViewById(R.id.launchermainTabPager);
@@ -288,7 +288,7 @@ public class PojavLauncherActivity extends BaseLauncherActivity
accountFaceImageView.setImageBitmap(mProfile.getSkinFace());
//TODO FULL BACKGROUND LOGIN
tvConnectStatus.setText(mProfile.accessToken.equals("0") ? R.string.mcl_account_offline : R.string.mcl_account_connected);
tvConnectStatus.setText(mProfile.accessToken.equals("0") ? R.string.mcl_account_local : R.string.mcl_account_connected);
} catch(Exception e) {
mProfile = new MinecraftAccount();
Tools.showError(this, e, true);

View File

@@ -10,10 +10,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Build;
@@ -22,7 +19,6 @@ import android.text.Html;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.StyleSpan;
import android.util.Base64;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -48,8 +44,6 @@ import androidx.core.content.ContextCompat;
import net.kdt.pojavlaunch.authenticator.microsoft.MicrosoftAuthTask;
import net.kdt.pojavlaunch.authenticator.microsoft.ui.MicrosoftLoginGUIActivity;
import net.kdt.pojavlaunch.authenticator.mojang.InvalidateTokenTask;
import net.kdt.pojavlaunch.authenticator.mojang.LoginListener;
import net.kdt.pojavlaunch.authenticator.mojang.LoginTask;
import net.kdt.pojavlaunch.authenticator.mojang.RefreshListener;
import net.kdt.pojavlaunch.customcontrols.CustomControls;
import net.kdt.pojavlaunch.multirt.MultiRTConfigDialog;
@@ -69,15 +63,13 @@ import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Locale;
public class PojavLoginActivity extends BaseActivity
// MineActivity
{
public class PojavLoginActivity extends BaseActivity {
private final Object mLockStoragePerm = new Object();
private final Object mLockSelectJRE = new Object();
private EditText edit2, edit3;
private EditText edit2;
private final int REQUEST_STORAGE_REQUEST_CODE = 1;
private CheckBox sRemember, sOffline;
private CheckBox sRemember;
private TextView startupTextView;
private SharedPreferences firstLaunchPrefs;
private MinecraftAccount mProfile = null;
@@ -173,7 +165,7 @@ public class PojavLoginActivity extends BaseActivity
}
}
private void uiInit() {
setContentView(R.layout.launcher_login_v3);
setContentView(R.layout.activity_pojav_login);
Spinner spinnerChgLang = findViewById(R.id.login_spinner_language);
@@ -243,15 +235,8 @@ public class PojavLoginActivity extends BaseActivity
});
edit2 = (EditText) findViewById(R.id.login_edit_email);
edit3 = (EditText) findViewById(R.id.login_edit_password);
sRemember = findViewById(R.id.login_switch_remember);
sOffline = findViewById(R.id.login_switch_offline);
sOffline.setOnCheckedChangeListener((p1, p2) -> {
// May delete later
edit3.setEnabled(!p2);
});
isSkipInit = true;
}
@@ -496,14 +481,14 @@ public class PojavLoginActivity extends BaseActivity
final Dialog accountDialog = new Dialog(PojavLoginActivity.this);
accountDialog.setContentView(R.layout.simple_account_list_holder);
accountDialog.setContentView(R.layout.dialog_select_account);
LinearLayout accountListLayout = accountDialog.findViewById(R.id.accountListLayout);
LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
for (int accountIndex = 0; accountIndex < accountArr.length; accountIndex++) {
String s = accountArr[accountIndex];
View child = inflater.inflate(R.layout.simple_account_list_item, accountListLayout,false);
View child = inflater.inflate(R.layout.item_minecraft_account, accountListLayout,false);
TextView accountName = child.findViewById(R.id.accountitem_text_name);
ImageButton removeButton = child.findViewById(R.id.accountitem_button_remove);
ImageView imageView = child.findViewById(R.id.account_head);
@@ -535,11 +520,9 @@ public class PojavLoginActivity extends BaseActivity
};
MinecraftAccount acc = MinecraftAccount.load(selectedAccName);
if (acc.isMicrosoft){
if (acc.accessToken.length() >= 5){
new MicrosoftAuthTask(PojavLoginActivity.this, authListener)
.execute("true", acc.msaRefreshToken);
} else if (acc.accessToken.length() >= 5) {
PojavProfile.updateTokens(PojavLoginActivity.this, selectedAccName, authListener);
} else {
accountDialog.dismiss();
PojavProfile.launch(PojavLoginActivity.this, selectedAccName);
@@ -580,7 +563,7 @@ public class PojavLoginActivity extends BaseActivity
accountDialog.show();
}
private MinecraftAccount loginOffline() {
private MinecraftAccount loginLocal() {
new File(Tools.DIR_ACCOUNT_OLD).mkdir();
String text = edit2.getText().toString();
@@ -590,8 +573,6 @@ public class PojavLoginActivity extends BaseActivity
edit2.setError(getString(R.string.login_error_invalid_username));
} else if (new File(Tools.DIR_ACCOUNT_NEW + "/" + text + ".json").exists()) {
edit2.setError(getString(R.string.login_error_exist_username));
} else if (!edit3.getText().toString().isEmpty()) {
edit3.setError(getString(R.string.login_error_offline_password));
} else {
MinecraftAccount builder = new MinecraftAccount();
builder.isMicrosoft = false;
@@ -605,43 +586,8 @@ public class PojavLoginActivity extends BaseActivity
public void loginMC(final View v)
{
if (sOffline.isChecked()) {
mProfile = loginOffline();
playProfile(false);
} else {
ProgressBar prb = findViewById(R.id.launcherAccProgress);
new LoginTask().setLoginListener(new LoginListener(){
@Override
public void onBeforeLogin() {
v.setEnabled(false);
prb.setVisibility(View.VISIBLE);
}
@Override
public void onLoginDone(String[] result) {
if(result[0].equals("ERROR")){
Tools.dialogOnUiThread(PojavLoginActivity.this,
getResources().getString(R.string.global_error), strArrToString(result));
} else{
MinecraftAccount builder = new MinecraftAccount();
builder.accessToken = result[1];
builder.clientToken = result[2];
builder.profileId = result[3];
builder.username = result[4];
builder.updateSkinFace();
mProfile = builder;
}
runOnUiThread(() -> {
v.setEnabled(true);
prb.setVisibility(View.GONE);
playProfile(false);
});
}
}).execute(edit2.getText().toString(), edit3.getText().toString());
}
mProfile = loginLocal();
playProfile(false);
}
private void playProfile(boolean notOnLogin) {

View File

@@ -6,8 +6,7 @@ import net.kdt.pojavlaunch.value.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
public class PojavMigrator
{
public class PojavMigrator {
public static void migrateAccountData(Context ctx) {
File oldAccDir = new File(Tools.DIR_ACCOUNT_OLD);
if (oldAccDir.exists() && oldAccDir.isDirectory()) {

View File

@@ -8,14 +8,11 @@ import android.util.Log;
import com.google.gson.JsonSyntaxException;
import java.io.File;
import java.io.IOException;
import net.kdt.pojavlaunch.authenticator.mojang.RefreshListener;
import net.kdt.pojavlaunch.authenticator.mojang.RefreshTokenTask;
import net.kdt.pojavlaunch.value.MinecraftAccount;
public class PojavProfile
{
private static String PROFILE_PREF = "pojav_profile";
private static String PROFILE_PREF_FILE = "file";
public class PojavProfile {
private static final String PROFILE_PREF = "pojav_profile";
private static final String PROFILE_PREF_FILE = "file";
public static String PROFILE_PREF_TEMP_CONTENT = "tempContent";
public static SharedPreferences getPrefs(Context ctx) {
@@ -33,26 +30,26 @@ public class PojavProfile
public static MinecraftAccount getTempProfileContent() {
try {
MinecraftAccount acc = MinecraftAccount.parse(Tools.read(Tools.DIR_DATA+"/cache/tempacc.json"));
if (acc.accessToken == null) {
acc.accessToken = "0";
MinecraftAccount account = MinecraftAccount.parse(Tools.read(Tools.DIR_DATA+"/cache/tempacc.json"));
if (account.accessToken == null) {
account.accessToken = "0";
}
if (acc.clientToken == null) {
acc.clientToken = "0";
if (account.clientToken == null) {
account.clientToken = "0";
}
if (acc.profileId == null) {
acc.profileId = "00000000-0000-0000-0000-000000000000";
if (account.profileId == null) {
account.profileId = "00000000-0000-0000-0000-000000000000";
}
if (acc.username == null) {
acc.username = "0";
if (account.username == null) {
account.username = "0";
}
if (acc.selectedVersion == null) {
acc.selectedVersion = "1.7.10";
if (account.selectedVersion == null) {
account.selectedVersion = "1.7.10";
}
if (acc.msaRefreshToken == null) {
acc.msaRefreshToken = "0";
if (account.msaRefreshToken == null) {
account.msaRefreshToken = "0";
}
return acc;
return account;
}catch (IOException e) {
Log.e(MinecraftAccount.class.getName(), "Caught an exception while loading the temporary profile",e);
return null;
@@ -104,8 +101,4 @@ public class PojavProfile
Intent intent = new Intent(ctx, PojavLauncherActivity.class); //MCLauncherActivity.class);
ctx.startActivity(intent);
}
public static void updateTokens(final Activity ctx, final String name, RefreshListener listen) throws Exception {
new RefreshTokenTask(ctx, listen).execute(name);
}
}

View File

@@ -3,8 +3,7 @@ package net.kdt.pojavlaunch;
import android.view.*;
import android.view.GestureDetector.*;
public class SingleTapConfirm extends SimpleOnGestureListener
{
public class SingleTapConfirm extends SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent event) {
return true;

View File

@@ -22,10 +22,10 @@ public class TapDetector {
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 mTapNumberToDetect;
private int mCurrentTapNumber = 0;
private final int detectionMethod;
private final int mDetectionMethod;
private long mLastEventTime = 0;
private float mLastX = 9999;
@@ -36,9 +36,9 @@ public class TapDetector {
* @param detectionMethod Method used to detect touches. See DETECTION_METHOD constants above.
*/
public TapDetector(int tapNumberToDetect, int detectionMethod){
this.detectionMethod = detectionMethod;
this.mDetectionMethod = detectionMethod;
//We expect both ACTION_DOWN and ACTION_UP for the DETECTION_METHOD_BOTH
this.tapNumberToDetect = detectBothTouch() ? 2*tapNumberToDetect : tapNumberToDetect;
this.mTapNumberToDetect = detectBothTouch() ? 2*tapNumberToDetect : tapNumberToDetect;
}
/**
@@ -78,17 +78,17 @@ public class TapDetector {
mLastY = eventY;
//Check for high enough speed and precision
if(currentTapNumber > 0){
if(mCurrentTapNumber > 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;
mCurrentTapNumber = 0;
}
}
//A worthy tap happened
currentTapNumber += 1;
if(currentTapNumber >= tapNumberToDetect){
mCurrentTapNumber += 1;
if(mCurrentTapNumber >= mTapNumberToDetect){
resetTapDetectionState();
return true;
}
@@ -101,22 +101,21 @@ public class TapDetector {
* Reset the double tap values.
*/
private void resetTapDetectionState(){
currentTapNumber = 0;
mCurrentTapNumber = 0;
mLastEventTime = 0;
mLastX = 9999;
mLastY = 9999;
}
private boolean detectDownTouch(){
return (detectionMethod & DETECTION_METHOD_DOWN) == DETECTION_METHOD_DOWN;
return (mDetectionMethod & DETECTION_METHOD_DOWN) == DETECTION_METHOD_DOWN;
}
private boolean detectUpTouch(){
return (detectionMethod & DETECTION_METHOD_UP) == DETECTION_METHOD_UP;
return (mDetectionMethod & DETECTION_METHOD_UP) == DETECTION_METHOD_UP;
}
private boolean detectBothTouch(){
return detectionMethod == DETECTION_METHOD_BOTH;
return mDetectionMethod == DETECTION_METHOD_BOTH;
}
}

View File

@@ -211,7 +211,7 @@ public final class Tools {
versionName = versionInfo.inheritsFrom;
}
String userType = "mojang";
String userType = "msa";
File gameDir = new File(strGameDir);
gameDir.mkdirs();
@@ -449,42 +449,37 @@ public final class Tools {
private static void showError(final Context ctx, final int titleId, final Throwable e, final boolean exitIfOk, final boolean showMore) {
e.printStackTrace();
Runnable runnable = new Runnable(){
@Override
public void run()
{
final String errMsg = showMore ? Log.getStackTraceString(e): e.getMessage();
AlertDialog.Builder builder = new AlertDialog.Builder((Context) ctx)
.setTitle(titleId)
.setMessage(errMsg)
.setPositiveButton(android.R.string.ok, (DialogInterface.OnClickListener) (p1, p2) -> {
if(exitIfOk) {
if (ctx instanceof BaseMainActivity) {
BaseMainActivity.fullyExit();
} else if (ctx instanceof Activity) {
((Activity) ctx).finish();
}
Runnable runnable = () -> {
final String errMsg = showMore ? Log.getStackTraceString(e): e.getMessage();
AlertDialog.Builder builder = new AlertDialog.Builder((Context) ctx)
.setTitle(titleId)
.setMessage(errMsg)
.setPositiveButton(android.R.string.ok, (DialogInterface.OnClickListener) (p1, p2) -> {
if(exitIfOk) {
if (ctx instanceof BaseMainActivity) {
BaseMainActivity.fullyExit();
} else if (ctx instanceof Activity) {
((Activity) ctx).finish();
}
})
.setNegativeButton(showMore ? R.string.error_show_less : R.string.error_show_more, (DialogInterface.OnClickListener) (p1, p2) -> showError(ctx, titleId, e, exitIfOk, !showMore))
.setNeutralButton(android.R.string.copy, (DialogInterface.OnClickListener) (p1, p2) -> {
ClipboardManager mgr = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE);
mgr.setPrimaryClip(ClipData.newPlainText("error", Log.getStackTraceString(e)));
if(exitIfOk) {
if (ctx instanceof BaseMainActivity) {
BaseMainActivity.fullyExit();
} else {
((Activity) ctx).finish();
}
}
})
.setNegativeButton(showMore ? R.string.error_show_less : R.string.error_show_more, (DialogInterface.OnClickListener) (p1, p2) -> showError(ctx, titleId, e, exitIfOk, !showMore))
.setNeutralButton(android.R.string.copy, (DialogInterface.OnClickListener) (p1, p2) -> {
ClipboardManager mgr = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE);
mgr.setPrimaryClip(ClipData.newPlainText("error", Log.getStackTraceString(e)));
if(exitIfOk) {
if (ctx instanceof BaseMainActivity) {
BaseMainActivity.fullyExit();
} else {
((Activity) ctx).finish();
}
})
.setCancelable(!exitIfOk);
try {
builder.show();
} catch (Throwable th) {
th.printStackTrace();
}
}
})
.setCancelable(!exitIfOk);
try {
builder.show();
} catch (Throwable th) {
th.printStackTrace();
}
};
@@ -495,8 +490,8 @@ public final class Tools {
}
}
public static void dialogOnUiThread(final Activity ctx, final CharSequence title, final CharSequence message) {
ctx.runOnUiThread(() -> new AlertDialog.Builder(ctx)
public static void dialogOnUiThread(final Activity activity, final CharSequence title, final CharSequence message) {
activity.runOnUiThread(() -> new AlertDialog.Builder(activity)
.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.ok, null)
@@ -568,7 +563,7 @@ public final class Tools {
}catch(IOException e) {
throw new RuntimeException("Can't find the source version for "+ versionName +" (req version="+customVer.inheritsFrom+")");
}
inheritsVer.inheritsFrom = inheritsVer.id;
//inheritsVer.inheritsFrom = inheritsVer.id;
insertSafety(inheritsVer, customVer,
"assetIndex", "assets", "id",
"mainClass", "minecraftArguments",
@@ -664,23 +659,19 @@ public final class Tools {
}
public static String convertStream(InputStream inputStream, Charset charset) throws IOException {
String out = "";
StringBuilder out = new StringBuilder();
int len;
byte[] buf = new byte[512];
while((len = inputStream.read(buf))!=-1) {
out += new String(buf,0,len,charset);
out.append(new String(buf, 0, len, charset));
}
return out;
return out.toString();
}
public static File lastFileModified(String dir) {
File fl = new File(dir);
File[] files = fl.listFiles(new FileFilter() {
public boolean accept(File file) {
return file.isFile();
}
});
File[] files = fl.listFiles(File::isFile);
long lastMod = Long.MIN_VALUE;
File choice = null;
@@ -696,13 +687,13 @@ public final class Tools {
public static String read(InputStream is) throws IOException {
String out = "";
StringBuilder out = new StringBuilder();
int len;
byte[] buf = new byte[512];
while((len = is.read(buf))!=-1) {
out += new String(buf,0,len);
out.append(new String(buf, 0, len));
}
return out;
return out.toString();
}
public static String read(String path) throws IOException {
@@ -748,6 +739,7 @@ public final class Tools {
public abstract static class DownloaderFeedback {
public abstract void updateProgress(int curr, int max);
}
public static void downloadFileMonitored(String urlInput,String nameOutput, DownloaderFeedback monitor) throws IOException {
File nameOutputFile = new File(nameOutput);
if (!nameOutputFile.exists()) {
@@ -784,75 +776,6 @@ public final class Tools {
return true;
}
}
public static class ZipTool
{
private ZipTool(){}
public static void zip(List<File> files, File zipFile) throws IOException {
final int BUFFER_SIZE = 2048;
BufferedInputStream origin = null;
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
try {
byte data[] = new byte[BUFFER_SIZE];
for (File file : files) {
FileInputStream fileInputStream = new FileInputStream( file );
origin = new BufferedInputStream(fileInputStream, BUFFER_SIZE);
try {
ZipEntry entry = new ZipEntry(file.getName());
out.putNextEntry(entry);
int count;
while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) {
out.write(data, 0, count);
}
}
finally {
origin.close();
}
}
} finally {
out.close();
}
}
public static void unzip(File zipFile, File targetDirectory) throws IOException {
final int BUFFER_SIZE = 1024;
ZipInputStream zis = new ZipInputStream(
new BufferedInputStream(new FileInputStream(zipFile)));
try {
ZipEntry ze;
int count;
byte[] buffer = new byte[BUFFER_SIZE];
while ((ze = zis.getNextEntry()) != null) {
File file = new File(targetDirectory, ze.getName());
File dir = ze.isDirectory() ? file : file.getParentFile();
if (!dir.isDirectory() && !dir.mkdirs())
throw new FileNotFoundException("Failed to ensure directory: " +
dir.getAbsolutePath());
if (ze.isDirectory())
continue;
FileOutputStream fout = new FileOutputStream(file);
try {
while ((count = zis.read(buffer)) != -1)
fout.write(buffer, 0, count);
} finally {
fout.close();
}
/* if time should be restored as well
long time = ze.getTime();
if (time > 0)
file.setLastModified(time);
*/
}
} finally {
zis.close();
}
}
}
public static void ignoreNotch(boolean shouldIgnore, Activity ctx){
if (SDK_INT >= P) {

View File

@@ -27,19 +27,19 @@ import org.lwjgl.glfw.CallbackBridge;
*/
public class Touchpad extends FrameLayout {
/* Whether the Touchpad should be displayed */
private boolean displayState;
private boolean mDisplayState;
/* Mouse pointer icon used by the touchpad */
private final ImageView mousePointer = new ImageView(getContext());
private final ImageView mMousePointerImageView = new ImageView(getContext());
/* Detect a classic android Tap */
private final GestureDetector singleTapDetector = new GestureDetector(getContext(), new SingleTapConfirm());
private final GestureDetector mSingleTapDetector = new GestureDetector(getContext(), new SingleTapConfirm());
/* Resolution scaler option, allow downsizing a window */
private final float scaleFactor = DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
private final float mScaleFactor = DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
/* Current pointer ID to move the mouse */
private int currentPointerID = -1000;
private int mCurrentPointerID = -1000;
/* Previous MotionEvent position, not scale */
private float prevX, prevY;
private float mPrevX, mPrevY;
/* Last first pointer positions non-scaled, used to scroll distance */
private float scrollLastInitialX, scrollLastInitialY;
private float mScrollLastInitialX, mScrollLastInitialY;
public Touchpad(@NonNull Context context) {
this(context, null);
@@ -50,56 +50,6 @@ public class Touchpad extends FrameLayout {
init();
}
private void init(){
// Setup mouse pointer
mousePointer.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.mouse_pointer, getContext().getTheme()));
mousePointer.post(() -> {
ViewGroup.LayoutParams params = mousePointer.getLayoutParams();
params.width = (int) (36 / 100f * LauncherPreferences.PREF_MOUSESCALE);
params.height = (int) (54 / 100f * LauncherPreferences.PREF_MOUSESCALE);
});
addView(mousePointer);
setFocusable(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setDefaultFocusHighlightEnabled(false);
}
// When the game is grabbing, we should not display the mouse
disable();
displayState = false;
Thread virtualMouseGrabThread = new Thread(() -> {
while (true) {
if (!CallbackBridge.isGrabbing() && displayState && getVisibility() != VISIBLE) {
post(this::enable);
}else{
if ((CallbackBridge.isGrabbing() && getVisibility() != View.GONE) || !displayState && getVisibility() == VISIBLE) {
post(this::disable);
}
}
}
}, "VirtualMouseGrabThread");
virtualMouseGrabThread.setPriority(Thread.MIN_PRIORITY);
virtualMouseGrabThread.start();
}
/** Enable the touchpad */
public void enable(){
setVisibility(VISIBLE);
placeMouseAt(currentDisplayMetrics.widthPixels / 2, currentDisplayMetrics.heightPixels / 2);
}
/** Disable the touchpad and hides the mouse */
public void disable(){
setVisibility(GONE);
}
/** @return The new state, enabled or disabled */
public boolean switchState(){
displayState = !displayState;
return displayState;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// MotionEvent reports input details from the touch screen
@@ -114,77 +64,126 @@ public class Touchpad extends FrameLayout {
float x = event.getX();
float y = event.getY();
float mouseX = mousePointer.getX();
float mouseY = mousePointer.getY();
float mouseX = mMousePointerImageView.getX();
float mouseY = mMousePointerImageView.getY();
if (singleTapDetector.onTouchEvent(event)) {
CallbackBridge.mouseX = (mouseX * scaleFactor);
CallbackBridge.mouseY = (mouseY * scaleFactor);
if (mSingleTapDetector.onTouchEvent(event)) {
CallbackBridge.mouseX = (mouseX * mScaleFactor);
CallbackBridge.mouseY = (mouseY * mScaleFactor);
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
CallbackBridge.sendMouseKeycode(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT);
CallbackBridge.sendMouseKeycode(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT);
return true;
}
switch (action) {
case MotionEvent.ACTION_POINTER_DOWN: // 5
scrollLastInitialX = event.getX();
scrollLastInitialY = event.getY();
mScrollLastInitialX = event.getX();
mScrollLastInitialY = event.getY();
break;
case MotionEvent.ACTION_DOWN:
prevX = x;
prevY = y;
currentPointerID = event.getPointerId(0);
mPrevX = x;
mPrevY = y;
mCurrentPointerID = event.getPointerId(0);
break;
case MotionEvent.ACTION_MOVE: // 2
//Scrolling feature
if (!LauncherPreferences.PREF_DISABLE_GESTURES && !CallbackBridge.isGrabbing() && event.getPointerCount() >= 2) {
int hScroll = ((int) (event.getX() - scrollLastInitialX)) / FINGER_SCROLL_THRESHOLD;
int vScroll = ((int) (event.getY() - scrollLastInitialY)) / FINGER_SCROLL_THRESHOLD;
int hScroll = ((int) (event.getX() - mScrollLastInitialX)) / FINGER_SCROLL_THRESHOLD;
int vScroll = ((int) (event.getY() - mScrollLastInitialY)) / FINGER_SCROLL_THRESHOLD;
if(vScroll != 0 || hScroll != 0){
CallbackBridge.sendScroll(hScroll, vScroll);
scrollLastInitialX = event.getX();
scrollLastInitialY = event.getY();
mScrollLastInitialX = event.getX();
mScrollLastInitialY = event.getY();
}
break;
}
// Mouse movement
if(currentPointerID == event.getPointerId(0)) {
mouseX = Math.max(0, Math.min(currentDisplayMetrics.widthPixels, mouseX + (x - prevX) * LauncherPreferences.PREF_MOUSESPEED));
mouseY = Math.max(0, Math.min(currentDisplayMetrics.heightPixels, mouseY + (y - prevY) * LauncherPreferences.PREF_MOUSESPEED));
if(mCurrentPointerID == event.getPointerId(0)) {
mouseX = Math.max(0, Math.min(currentDisplayMetrics.widthPixels, mouseX + (x - mPrevX) * LauncherPreferences.PREF_MOUSESPEED));
mouseY = Math.max(0, Math.min(currentDisplayMetrics.heightPixels, mouseY + (y - mPrevY) * LauncherPreferences.PREF_MOUSESPEED));
placeMouseAt(mouseX, mouseY);
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
}else currentPointerID = event.getPointerId(0);
}else mCurrentPointerID = event.getPointerId(0);
prevX = x;
prevY = y;
mPrevX = x;
mPrevY = y;
break;
case MotionEvent.ACTION_UP:
prevX = x;
prevY = y;
currentPointerID = -1000;
mPrevX = x;
mPrevY = y;
mCurrentPointerID = -1000;
break;
}
//debugText.setText(CallbackBridge.DEBUG_STRING.toString());
CallbackBridge.DEBUG_STRING.setLength(0);
return true;
}
/** Enable the touchpad */
public void enable(){
setVisibility(VISIBLE);
placeMouseAt(currentDisplayMetrics.widthPixels / 2, currentDisplayMetrics.heightPixels / 2);
}
/** Disable the touchpad and hides the mouse */
public void disable(){
setVisibility(GONE);
}
/** @return The new state, enabled or disabled */
public boolean switchState(){
mDisplayState = !mDisplayState;
return mDisplayState;
}
public void placeMouseAt(float x, float y) {
mousePointer.setX(x);
mousePointer.setY(y);
CallbackBridge.mouseX = (x * scaleFactor);
CallbackBridge.mouseY = (y * scaleFactor);
mMousePointerImageView.setX(x);
mMousePointerImageView.setY(y);
CallbackBridge.mouseX = (x * mScaleFactor);
CallbackBridge.mouseY = (y * mScaleFactor);
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
}
private void init(){
// Setup mouse pointer
mMousePointerImageView.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_mouse_pointer, getContext().getTheme()));
mMousePointerImageView.post(() -> {
ViewGroup.LayoutParams params = mMousePointerImageView.getLayoutParams();
params.width = (int) (36 / 100f * LauncherPreferences.PREF_MOUSESCALE);
params.height = (int) (54 / 100f * LauncherPreferences.PREF_MOUSESCALE);
});
addView(mMousePointerImageView);
setFocusable(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setDefaultFocusHighlightEnabled(false);
}
// When the game is grabbing, we should not display the mouse
disable();
mDisplayState = false;
Thread virtualMouseGrabThread = new Thread(() -> {
while (true) {
if (!CallbackBridge.isGrabbing() && mDisplayState && getVisibility() != VISIBLE) {
post(this::enable);
}else{
if ((CallbackBridge.isGrabbing() && getVisibility() != View.GONE) || !mDisplayState && getVisibility() == VISIBLE) {
post(this::disable);
}
}
}
}, "VirtualMouseGrabThread");
virtualMouseGrabThread.setPriority(Thread.MIN_PRIORITY);
virtualMouseGrabThread.start();
}
}

View File

@@ -8,6 +8,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.ViewGroup;
import android.webkit.CookieManager;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
@@ -24,6 +25,7 @@ public class MicrosoftLoginGUIActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CookieManager.getInstance().removeAllCookie();
waitDialog = new ProgressDialog(this);
waitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
waitDialog.setIndeterminate(true);

View File

@@ -1,7 +0,0 @@
package net.kdt.pojavlaunch.authenticator.mojang;
public interface LoginListener
{
public void onBeforeLogin();
public void onLoginDone(String[] result);
}

View File

@@ -1,71 +0,0 @@
package net.kdt.pojavlaunch.authenticator.mojang;
import android.os.*;
import net.kdt.pojavlaunch.authenticator.mojang.yggdrasil.*;
import java.io.*;
import java.util.*;
import net.kdt.pojavlaunch.*;
public class LoginTask extends AsyncTask<String, Void, Void>
{
private YggdrasilAuthenticator authenticator = new YggdrasilAuthenticator();
//private String TAG = "MojangAuth-login";
private LoginListener listener;
public LoginTask setLoginListener(LoginListener listener) {
this.listener = listener;
return this;
}
private UUID getRandomUUID() {
return UUID.randomUUID();
}
@Override
protected void onPreExecute() {
listener.onBeforeLogin();
super.onPreExecute();
}
@Override
protected Void doInBackground(String[] args) {
ArrayList<String> str = new ArrayList<String>();
str.add("ERROR");
try{
try{
AuthenticateResponse response = authenticator.authenticate(args[0], args[1], getRandomUUID());
if (response.selectedProfile == null) {
str.add("Can't login a demo account!\n");
} else {
if (new File(Tools.DIR_ACCOUNT_NEW + "/" + response.selectedProfile.name + ".json").exists()) {
str.add("This account already exist!\n");
} else {
str.add(response.accessToken); // Access token
str.add(response.clientToken.toString()); // Client token
str.add(response.selectedProfile.id); // Profile ID
str.add(response.selectedProfile.name); // Username
str.set(0, "NORMAL");
}
}
}
//MainActivity.updateStatus(804);
catch(Throwable e){
str.add(e.getMessage());
}
}
catch(Exception e){
str.add(e.getMessage());
}
listener.onLoginDone(str.toArray(new String[0]));
return null;
}
@Override
protected void onPostExecute(Void result) {
// listener.onLoginDone(result);
super.onPostExecute(result);
}
}

View File

@@ -1,79 +0,0 @@
package net.kdt.pojavlaunch.authenticator.mojang;
import android.content.*;
import android.os.*;
import com.google.gson.*;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.*;
import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.authenticator.mojang.yggdrasil.*;
import android.app.*;
import net.kdt.pojavlaunch.value.*;
public class RefreshTokenTask extends AsyncTask<String, Void, Throwable> {
private YggdrasilAuthenticator authenticator = new YggdrasilAuthenticator();
//private Gson gson = new Gson();
private RefreshListener listener;
private MinecraftAccount profilePath;
private final WeakReference<Context> ctx;
private ProgressDialog build;
public RefreshTokenTask(Context ctx, RefreshListener listener) {
this.ctx = new WeakReference<>(ctx);
this.listener = listener;
}
@Override
public void onPreExecute() {
build = new ProgressDialog(ctx.get());
build.setMessage(ctx.get().getString(R.string.global_waiting));
build.setProgressStyle(ProgressDialog.STYLE_SPINNER);
build.setCancelable(false);
build.show();
}
@Override
public Throwable doInBackground(String... args) {
try {
this.profilePath = MinecraftAccount.load(args[0]);
int responseCode = 400;
try {
responseCode = this.authenticator.validate(profilePath.accessToken).statusCode;
}catch(RuntimeException e) {}
if (responseCode == 403) {
RefreshResponse response = this.authenticator.refresh(profilePath.accessToken, UUID.fromString(profilePath.clientToken));
if (response == null) {
// Refresh when offline?
return null;
} else if (response.selectedProfile == null) {
throw new IllegalArgumentException("Can't refresh a demo account!");
}
profilePath.clientToken = response.clientToken.toString();
profilePath.accessToken = response.accessToken;
profilePath.username = response.selectedProfile.name;
profilePath.profileId = response.selectedProfile.id;
}
profilePath.updateSkinFace();
profilePath.save();
return null;
} catch (Throwable e) {
return e;
}
}
@Override
public void onPostExecute(Throwable result) {
build.dismiss();
if (result == null) {
listener.onSuccess(profilePath);
} else {
listener.onFailed(result);
}
}
}

View File

@@ -1,24 +0,0 @@
package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil;
import java.util.UUID;
public class AuthenticateRequest {
public AgentInfo agent = new AgentInfo();
public UUID clientToken;
public String password;
public String username;
public static class AgentInfo {
public String name;
public int version;
}
public AuthenticateRequest(String username, String password, UUID clientToken, String clientName, int clientVersion) {
this.username = username;
this.password = password;
this.clientToken = clientToken;
this.agent.name = clientName;
this.agent.version = clientVersion;
}
}

View File

@@ -1,11 +0,0 @@
package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil;
import java.util.UUID;
public class AuthenticateResponse {
public String accessToken;
public Profile[] availableProfiles;
public UUID clientToken;
public Profile selectedProfile;
}

View File

@@ -1,10 +0,0 @@
package net.kdt.pojavlaunch.authenticator.mojang.yggdrasil;
import java.util.UUID;
public class RefreshResponse {
public String accessToken;
public UUID clientToken;
public Profile selectedProfile;
}

View File

@@ -90,31 +90,6 @@ public class YggdrasilAuthenticator {
}
}
public AuthenticateResponse authenticate(String username, String password, UUID clientId) throws IOException, Throwable {
NetworkResponse obj = makeRequest("authenticate", new AuthenticateRequest(username, password, clientId, this.clientName, this.clientVersion), AuthenticateResponse.class);
/*
if (obj.statusCode != 200) {
throw new RuntimeException("Invalid username or password, status code: " + obj.statusCode);
}
*/
obj.throwExceptionIfNeed();
return (AuthenticateResponse) obj.response;
}
public RefreshResponse refresh(String authToken, UUID clientId) throws IOException, Throwable {
NetworkResponse obj = makeRequest("refresh", new RefreshRequest(authToken, clientId), RefreshResponse.class);
if (obj == null) {
return null;
} else {
obj.throwExceptionIfNeed(); // "Invalid username or password, status code: " + obj.statusCode);
return (RefreshResponse) obj.response;
}
}
public NetworkResponse validate(String authToken) throws Throwable {
return makeRequest("validate", new RefreshRequest(authToken, null), null);
}
public NetworkResponse invalidate(String authToken, UUID clientId) throws Throwable {
return makeRequest("invalidate", new RefreshRequest(authToken, clientId), null);
}

View File

@@ -14,13 +14,11 @@ import net.objecthunter.exp4j.function.Function;
import org.lwjgl.glfw.*;
import static net.kdt.pojavlaunch.LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN;
import static net.kdt.pojavlaunch.LwjglGlfwKeycode.GLFW_KEY_UNKNOWN;
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
import androidx.annotation.Keep;
import com.google.gson.annotations.SerializedName;
@Keep
public class ControlData {

View File

@@ -16,8 +16,7 @@ import net.kdt.pojavlaunch.customcontrols.buttons.ControlSubButton;
import net.kdt.pojavlaunch.customcontrols.handleview.HandleView;
import net.kdt.pojavlaunch.prefs.*;
public class ControlLayout extends FrameLayout
{
public class ControlLayout extends FrameLayout {
protected CustomControls mLayout;
private boolean mModifiable;
private CustomControlsActivity mActivity;

View File

@@ -3,12 +3,9 @@ import android.content.*;
import androidx.annotation.Keep;
import com.google.gson.*;
import java.io.IOException;
import java.util.*;
import net.kdt.pojavlaunch.*;
import org.lwjgl.glfw.*;
@Keep
public class CustomControls {
@@ -37,22 +34,22 @@ public class CustomControls {
this.mControlDataList.add(new ControlData(ControlData.getSpecialButtons()[3])); // Secondary Mouse mControlDataList
this.mControlDataList.add(new ControlData(ControlData.getSpecialButtons()[4])); // Virtual mouse toggle
this.mControlDataList.add(new ControlData(ctx, R.string.control_debug, new int[]{LWJGLGLFWKeycode.GLFW_KEY_F3}, "${margin}", "${margin}", false));
this.mControlDataList.add(new ControlData(ctx, R.string.control_chat, new int[]{LWJGLGLFWKeycode.GLFW_KEY_T}, "${margin} * 2 + ${width}", "${margin}", false));
this.mControlDataList.add(new ControlData(ctx, R.string.control_listplayers, new int[]{LWJGLGLFWKeycode.GLFW_KEY_TAB}, "${margin} * 4 + ${width} * 3", "${margin}", false));
this.mControlDataList.add(new ControlData(ctx, R.string.control_thirdperson, new int[]{LWJGLGLFWKeycode.GLFW_KEY_F5}, "${margin}", "${height} + ${margin}", false));
this.mControlDataList.add(new ControlData(ctx, R.string.control_debug, new int[]{LwjglGlfwKeycode.GLFW_KEY_F3}, "${margin}", "${margin}", false));
this.mControlDataList.add(new ControlData(ctx, R.string.control_chat, new int[]{LwjglGlfwKeycode.GLFW_KEY_T}, "${margin} * 2 + ${width}", "${margin}", false));
this.mControlDataList.add(new ControlData(ctx, R.string.control_listplayers, new int[]{LwjglGlfwKeycode.GLFW_KEY_TAB}, "${margin} * 4 + ${width} * 3", "${margin}", false));
this.mControlDataList.add(new ControlData(ctx, R.string.control_thirdperson, new int[]{LwjglGlfwKeycode.GLFW_KEY_F5}, "${margin}", "${height} + ${margin}", false));
this.mControlDataList.add(new ControlData(ctx, R.string.control_up, new int[]{LWJGLGLFWKeycode.GLFW_KEY_W}, "${margin} * 2 + ${width}", "${bottom} - ${margin} * 3 - ${height} * 2", true));
this.mControlDataList.add(new ControlData(ctx, R.string.control_left, new int[]{LWJGLGLFWKeycode.GLFW_KEY_A}, "${margin}", "${bottom} - ${margin} * 2 - ${height}", true));
this.mControlDataList.add(new ControlData(ctx, R.string.control_down, new int[]{LWJGLGLFWKeycode.GLFW_KEY_S}, "${margin} * 2 + ${width}", "${bottom} - ${margin}", true));
this.mControlDataList.add(new ControlData(ctx, R.string.control_right, new int[]{LWJGLGLFWKeycode.GLFW_KEY_D}, "${margin} * 3 + ${width} * 2", "${bottom} - ${margin} * 2 - ${height}", true));
this.mControlDataList.add(new ControlData(ctx, R.string.control_up, new int[]{LwjglGlfwKeycode.GLFW_KEY_W}, "${margin} * 2 + ${width}", "${bottom} - ${margin} * 3 - ${height} * 2", true));
this.mControlDataList.add(new ControlData(ctx, R.string.control_left, new int[]{LwjglGlfwKeycode.GLFW_KEY_A}, "${margin}", "${bottom} - ${margin} * 2 - ${height}", true));
this.mControlDataList.add(new ControlData(ctx, R.string.control_down, new int[]{LwjglGlfwKeycode.GLFW_KEY_S}, "${margin} * 2 + ${width}", "${bottom} - ${margin}", true));
this.mControlDataList.add(new ControlData(ctx, R.string.control_right, new int[]{LwjglGlfwKeycode.GLFW_KEY_D}, "${margin} * 3 + ${width} * 2", "${bottom} - ${margin} * 2 - ${height}", true));
this.mControlDataList.add(new ControlData(ctx, R.string.control_inventory, new int[]{LWJGLGLFWKeycode.GLFW_KEY_E}, "${margin} * 3 + ${width} * 2", "${bottom} - ${margin}", true));
this.mControlDataList.add(new ControlData(ctx, R.string.control_inventory, new int[]{LwjglGlfwKeycode.GLFW_KEY_E}, "${margin} * 3 + ${width} * 2", "${bottom} - ${margin}", true));
ControlData shiftData = new ControlData(ctx, R.string.control_shift, new int[]{LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT}, "${margin} * 2 + ${width}", "${screen_height} - ${margin} * 2 - ${height} * 2", true);
ControlData shiftData = new ControlData(ctx, R.string.control_shift, new int[]{LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT}, "${margin} * 2 + ${width}", "${screen_height} - ${margin} * 2 - ${height} * 2", true);
shiftData.isToggle = true;
this.mControlDataList.add(shiftData);
this.mControlDataList.add(new ControlData(ctx, R.string.control_jump, new int[]{LWJGLGLFWKeycode.GLFW_KEY_SPACE}, "${right} - ${margin} * 2 - ${width}", "${bottom} - ${margin} * 2 - ${height}", true));
this.mControlDataList.add(new ControlData(ctx, R.string.control_jump, new int[]{LwjglGlfwKeycode.GLFW_KEY_SPACE}, "${right} - ${margin} * 2 - ${width}", "${bottom} - ${margin} * 2 - ${height}", true));
//The default controls are conform to the V2
version = 4;
@@ -60,7 +57,7 @@ public class CustomControls {
public void save(String path) throws IOException {
//Current version is the V2.4 so the version as to be marked as 4 !
//Current version is the V2.5 so the version as to be marked as 4 !
version = 4;
Tools.write(path, Tools.GLOBAL_GSON.toJson(this));

View File

@@ -2,7 +2,7 @@ package net.kdt.pojavlaunch.customcontrols;
import com.google.gson.JsonSyntaxException;
import net.kdt.pojavlaunch.LWJGLGLFWKeycode;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.Tools;
import org.json.JSONArray;
@@ -83,10 +83,10 @@ public class LayoutConverter {
for(int i = 0; i < layoutMainArray.length(); i++) {
JSONObject button = layoutMainArray.getJSONObject(i);
ControlData n_button = new ControlData();
int[] keycodes = new int[] {LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN,
LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN,
LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN,
LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN};
int[] keycodes = new int[] {LwjglGlfwKeycode.GLFW_KEY_UNKNOWN,
LwjglGlfwKeycode.GLFW_KEY_UNKNOWN,
LwjglGlfwKeycode.GLFW_KEY_UNKNOWN,
LwjglGlfwKeycode.GLFW_KEY_UNKNOWN};
n_button.isDynamicBtn = button.getBoolean("isDynamicBtn");
n_button.dynamicX = button.getString("dynamicX");
n_button.dynamicY = button.getString("dynamicY");
@@ -116,9 +116,9 @@ public class LayoutConverter {
}
if(button.getBoolean("isRound")) { n_button.cornerRadius = 35f; }
int next_idx = 0;
if(button.getBoolean("holdShift")) { keycodes[next_idx] = LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT; next_idx++; }
if(button.getBoolean("holdCtrl")) { keycodes[next_idx] = LWJGLGLFWKeycode.GLFW_KEY_LEFT_CONTROL; next_idx++; }
if(button.getBoolean("holdAlt")) { keycodes[next_idx] = LWJGLGLFWKeycode.GLFW_KEY_LEFT_ALT; next_idx++; }
if(button.getBoolean("holdShift")) { keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT; next_idx++; }
if(button.getBoolean("holdCtrl")) { keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL; next_idx++; }
if(button.getBoolean("holdAlt")) { keycodes[next_idx] = LwjglGlfwKeycode.GLFW_KEY_LEFT_ALT; next_idx++; }
keycodes[next_idx] = button.getInt("keycode");
n_button.keycodes = keycodes;
empty.mControlDataList.add(n_button);

View File

@@ -11,13 +11,11 @@ import android.content.res.Configuration;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.kdt.pojavlaunch.BaseMainActivity;
import net.kdt.pojavlaunch.LWJGLGLFWKeycode;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.R;
import org.lwjgl.glfw.CallbackBridge;
@@ -38,7 +36,7 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
}
private boolean isDoingInternalChanges = false;
private boolean mIsDoingInternalChanges = false;
/**
* We take the new chars, and send them to the game.
@@ -48,10 +46,10 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
if(isDoingInternalChanges)return;
if(mIsDoingInternalChanges)return;
for(int i=0; i< lengthBefore; ++i){
CallbackBridge.sendKeycode(LWJGLGLFWKeycode.GLFW_KEY_BACKSPACE, '\u0008', 0, 0, true);
for(int i=0; i < lengthBefore; ++i){
CallbackBridge.sendKeycode(LwjglGlfwKeycode.GLFW_KEY_BACKSPACE, '\u0008', 0, 0, true);
}
for(int i=start, count = 0; count < lengthAfter; ++i){
CallbackBridge.sendChar(text.charAt(i), 0);
@@ -115,20 +113,12 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
*/
@SuppressLint("SetTextI18n")
public void clear(){
isDoingInternalChanges = true;
mIsDoingInternalChanges = true;
//Braille space, doesn't trigger keyboard auto-complete
//replacing directly the text without though setText avoids notifying changes
setText(" ");
setSelection(getText().length());
isDoingInternalChanges = false;
}
/**
* Send the enter key.
*/
private void sendEnter(){
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_ENTER);
clear();
mIsDoingInternalChanges = false;
}
/**
@@ -152,6 +142,13 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
setEnabled(false);
}
/**
* Send the enter key.
*/
private void sendEnter(){
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_ENTER);
clear();
}
/**
* This function deals with anything that has to be executed when the constructor is called

View File

@@ -16,11 +16,10 @@ import net.kdt.pojavlaunch.customcontrols.ControlData;
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
import net.kdt.pojavlaunch.customcontrols.handleview.*;
import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import org.lwjgl.glfw.*;
import static net.kdt.pojavlaunch.LWJGLGLFWKeycode.GLFW_KEY_UNKNOWN;
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;
@@ -30,19 +29,15 @@ import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
import static org.lwjgl.glfw.CallbackBridge.sendMouseButton;
@SuppressLint("ViewConstructor")
public class ControlButton extends androidx.appcompat.widget.AppCompatButton implements OnLongClickListener
{
private final Paint mRectPaint = new Paint();;
public class ControlButton extends androidx.appcompat.widget.AppCompatButton implements OnLongClickListener {
private final Paint mRectPaint = new Paint();
protected GestureDetector mGestureDetector;
protected ControlData mProperties;
protected SelectionEndHandleView mHandleView;
protected boolean mModifiable = false;
protected boolean mCanTriggerLongClick = true;
protected boolean isToggled = false;
protected boolean isPointerOutOfBounds = false;
protected boolean mIsToggled = false;
protected boolean mIsPointerOutOfBounds = false;
public ControlButton(ControlLayout layout, ControlData properties) {
super(layout.getContext());
@@ -259,7 +254,7 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isToggled || (!mProperties.isToggle && isActivated()))
if (mIsToggled || (!mProperties.isToggle && isActivated()))
canvas.drawRoundRect(0, 0, getWidth(), getHeight(), mProperties.cornerRadius, mProperties.cornerRadius, mRectPaint);
}
@@ -304,26 +299,26 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
//If out of bounds
if(event.getX() < getLeft() || event.getX() > getRight() ||
event.getY() < getTop() || event.getY() > getBottom()){
if(mProperties.isSwipeable && !isPointerOutOfBounds){
if(mProperties.isSwipeable && !mIsPointerOutOfBounds){
//Remove keys
if(!triggerToggle()) {
sendKeyPresses(false);
}
}
isPointerOutOfBounds = true;
mIsPointerOutOfBounds = true;
((ControlLayout) getParent()).onTouch(this, event);
break;
}
//Else if we now are in bounds
if(isPointerOutOfBounds) {
if(mIsPointerOutOfBounds) {
((ControlLayout) getParent()).onTouch(this, event);
//RE-press the button
if(mProperties.isSwipeable && !mProperties.isToggle){
sendKeyPresses(true);
}
}
isPointerOutOfBounds = false;
mIsPointerOutOfBounds = false;
break;
case MotionEvent.ACTION_DOWN: // 0
@@ -340,8 +335,8 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
MinecraftGLView v = ((ControlLayout) this.getParent()).findViewById(R.id.main_game_render_view);
if (v != null) v.dispatchTouchEvent(event);
}
if(isPointerOutOfBounds) ((ControlLayout) getParent()).onTouch(this, event);
isPointerOutOfBounds = false;
if(mIsPointerOutOfBounds) ((ControlLayout) getParent()).onTouch(this, event);
mIsPointerOutOfBounds = false;
if(!triggerToggle()) {
sendKeyPresses(false);
@@ -501,9 +496,9 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
public boolean triggerToggle(){
//returns true a the toggle system is triggered
if(mProperties.isToggle){
isToggled = !isToggled;
mIsToggled = !mIsToggled;
invalidate();
sendKeyPresses(isToggled);
sendKeyPresses(mIsToggled);
return true;
}
return false;
@@ -536,15 +531,15 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
break;
case ControlData.SPECIALBTN_MOUSEPRI:
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, isDown);
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, isDown);
break;
case ControlData.SPECIALBTN_MOUSEMID:
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_MIDDLE, isDown);
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_MIDDLE, isDown);
break;
case ControlData.SPECIALBTN_MOUSESEC:
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown);
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown);
break;
case ControlData.SPECIALBTN_SCROLLDOWN:

View File

@@ -2,7 +2,6 @@ package net.kdt.pojavlaunch.customcontrols.buttons;
import android.annotation.SuppressLint;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import net.kdt.pojavlaunch.Tools;
@@ -20,7 +19,7 @@ public class ControlDrawer extends ControlButton {
public ArrayList<ControlSubButton> buttons;
public ControlDrawerData drawerData;
public ControlLayout mLayout;
public ControlLayout layout;
public boolean areButtonsVisible;
@@ -28,14 +27,14 @@ public class ControlDrawer extends ControlButton {
super(layout, drawerData.properties);
buttons = new ArrayList<>(drawerData.buttonProperties.size());
mLayout = layout;
this.layout = layout;
this.drawerData = drawerData;
areButtonsVisible = layout.getModifiable();
}
public void addButton(ControlData properties){
addButton(new ControlSubButton(mLayout, properties, this));
addButton(new ControlSubButton(layout, properties, this));
}
public void addButton(ControlSubButton button){

View File

@@ -15,7 +15,7 @@ import android.widget.Toast;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.math.MathUtils;
import net.kdt.pojavlaunch.LWJGLGLFWKeycode;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.utils.MCOptionUtils;
@@ -40,60 +40,60 @@ import static org.lwjgl.glfw.CallbackBridge.sendMouseButton;
public class Gamepad {
/* Resolution scaler option, allow downsizing a window */
private final float scaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
private final float mScaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
/* Mouse positions, scaled by the scaleFactor */
private float mouse_x, mouse_y;
private float mMouse_x, mMouse_y;
/* Sensitivity, adjusted according to screen size */
private final double sensitivityFactor = (1.4 * (1080f/ currentDisplayMetrics.heightPixels));
private final double mSensitivityFactor = (1.4 * (1080f/ currentDisplayMetrics.heightPixels));
private final ImageView pointerView;
private final ImageView mPointerImageView;
private final GamepadDpad gamepadDpad = new GamepadDpad();
private final GamepadDpad mGamepadDpad = new GamepadDpad();
private final GamepadJoystick leftJoystick;
private int currentJoystickDirection = DIRECTION_NONE;
private final GamepadJoystick mLeftJoystick;
private int mCurrentJoystickDirection = DIRECTION_NONE;
private final GamepadJoystick rightJoystick;
private float lastHorizontalValue = 0.0f;
private float lastVerticalValue = 0.0f;
private final GamepadJoystick mRightJoystick;
private float mLastHorizontalValue = 0.0f;
private float mLastVerticalValue = 0.0f;
private final double mouseMaxAcceleration = 2f;
private final double MOUSE_MAX_ACCELERATION = 2f;
private double mouseMagnitude;
private double mouseAngle;
private double mouseSensitivity = 19;
private double mMouseMagnitude;
private double mMouseAngle;
private double mMouseSensitivity = 19;
private final GamepadMap gameMap = GamepadMap.getDefaultGameMap();
private final GamepadMap menuMap = GamepadMap.getDefaultMenuMap();
private GamepadMap currentMap = gameMap;
private final GamepadMap mGameMap = GamepadMap.getDefaultGameMap();
private final GamepadMap mMenuMap = GamepadMap.getDefaultMenuMap();
private GamepadMap mCurrentMap = mGameMap;
private boolean lastGrabbingState = true;
private boolean mLastGrabbingState = true;
//private final boolean mModifierDigitalTriggers;
private final boolean mModifierAnalogTriggers;
private boolean mModifierSwappedAxis = true; //Triggers and right stick axis are swapped.
/* Choreographer with time to compute delta on ticking */
private final Choreographer screenChoreographer;
private long lastFrameTime;
private final Choreographer mScreenChoreographer;
private long mLastFrameTime;
/* Listen for change in gui scale */
private MCOptionUtils.MCOptionListener GUIScaleListener = () -> notifyGUISizeChange(getMcScale());
private MCOptionUtils.MCOptionListener mGuiScaleListener = () -> notifyGUISizeChange(getMcScale());
public Gamepad(View contextView, InputDevice inputDevice){
screenChoreographer = Choreographer.getInstance();
mScreenChoreographer = Choreographer.getInstance();
Choreographer.FrameCallback frameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
updateGrabbingState();
tick(frameTimeNanos);
screenChoreographer.postFrameCallback(this);
mScreenChoreographer.postFrameCallback(this);
}
};
screenChoreographer.postFrameCallback(frameCallback);
lastFrameTime = System.nanoTime();
mScreenChoreographer.postFrameCallback(frameCallback);
mLastFrameTime = System.nanoTime();
/* Add the listener for the cross hair */
MCOptionUtils.addMCOptionListener(GUIScaleListener);
MCOptionUtils.addMCOptionListener(mGuiScaleListener);
Toast.makeText(contextView.getContext(),"GAMEPAD CREATED", Toast.LENGTH_LONG).show();
for(InputDevice.MotionRange range : inputDevice.getMotionRanges()){
@@ -106,98 +106,31 @@ public class Gamepad {
}
}
leftJoystick = new GamepadJoystick(MotionEvent.AXIS_X, MotionEvent.AXIS_Y, inputDevice);
mLeftJoystick = new GamepadJoystick(MotionEvent.AXIS_X, MotionEvent.AXIS_Y, inputDevice);
if(!mModifierSwappedAxis)
rightJoystick = new GamepadJoystick(MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ, inputDevice);
mRightJoystick = new GamepadJoystick(MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ, inputDevice);
else
rightJoystick = new GamepadJoystick(MotionEvent.AXIS_RX, MotionEvent.AXIS_RY, inputDevice);
mRightJoystick = new GamepadJoystick(MotionEvent.AXIS_RX, MotionEvent.AXIS_RY, inputDevice);
//mModifierDigitalTriggers = inputDevice.hasKeys(KeyEvent.KEYCODE_BUTTON_R2)[0];
mModifierAnalogTriggers = supportAnalogTriggers(inputDevice);
Context ctx = contextView.getContext();
pointerView = new ImageView(contextView.getContext());
pointerView.setImageDrawable(ResourcesCompat.getDrawable(ctx.getResources(), R.drawable.pointer, ctx.getTheme()));
pointerView.getDrawable().setFilterBitmap(false);
mPointerImageView = new ImageView(contextView.getContext());
mPointerImageView.setImageDrawable(ResourcesCompat.getDrawable(ctx.getResources(), R.drawable.ic_gamepad_pointer, ctx.getTheme()));
mPointerImageView.getDrawable().setFilterBitmap(false);
int size = (int) ((22 * getMcScale()) / scaleFactor);
pointerView.setLayoutParams(new FrameLayout.LayoutParams(size, size));
int size = (int) ((22 * getMcScale()) / mScaleFactor);
mPointerImageView.setLayoutParams(new FrameLayout.LayoutParams(size, size));
mouse_x = CallbackBridge.windowWidth/2;
mouse_y = CallbackBridge.windowHeight/2;
CallbackBridge.sendCursorPos(mouse_x, mouse_y);
mMouse_x = CallbackBridge.windowWidth/2;
mMouse_y = CallbackBridge.windowHeight/2;
CallbackBridge.sendCursorPos(mMouse_x, mMouse_y);
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
((ViewGroup)contextView.getParent()).addView(pointerView);
((ViewGroup)contextView.getParent()).addView(mPointerImageView);
}
/**
* Send the new mouse position, computing the delta
* @param frameTimeNanos The time to render the frame, used to compute mouse delta
*/
public void tick(long frameTimeNanos){
//update mouse position
if(lastHorizontalValue != 0 || lastVerticalValue != 0){
GamepadJoystick currentJoystick = lastGrabbingState ? leftJoystick : rightJoystick;
double acceleration = (mouseMagnitude - currentJoystick.getDeadzone()) / (1 - currentJoystick.getDeadzone());
acceleration = Math.pow(acceleration, mouseMaxAcceleration);
if(acceleration > 1) acceleration = 1;
// 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);
CallbackBridge.mouseY = MathUtils.clamp(CallbackBridge.mouseY, 0, CallbackBridge.windowHeight);
placePointerView((int) (CallbackBridge.mouseX / scaleFactor), (int) (CallbackBridge.mouseY/ scaleFactor));
}
mouse_x = CallbackBridge.mouseX;
mouse_y = CallbackBridge.mouseY;
//Send the mouse to the game
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) 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
mouse_x = CallbackBridge.windowWidth/2;
mouse_y = CallbackBridge.windowHeight/2;
CallbackBridge.sendCursorPos(mouse_x, mouse_y);
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
pointerView.setVisibility(View.VISIBLE);
// Sensitivity in menu is MC and HARDWARE resolution dependent
mouseSensitivity = 19 * scaleFactor / sensitivityFactor;
}
public void update(KeyEvent event){
sendButton(event);
@@ -208,125 +141,17 @@ public class Gamepad {
updateMouseJoystick(event);
updateAnalogTriggers(event);
int[] dpadEvent = gamepadDpad.convertEvent(event);
int[] dpadEvent = mGamepadDpad.convertEvent(event);
sendButton(dpadEvent[0], dpadEvent[1]);
}
private void updateMouseJoystick(MotionEvent event){
GamepadJoystick currentJoystick = lastGrabbingState ? rightJoystick : leftJoystick;
float horizontalValue = currentJoystick.getHorizontalAxis(event);
float verticalValue = currentJoystick.getVerticalAxis(event);
if(horizontalValue != lastHorizontalValue || verticalValue != lastVerticalValue){
lastHorizontalValue = horizontalValue;
lastVerticalValue = verticalValue;
mouseMagnitude = currentJoystick.getMagnitude(event);
mouseAngle = currentJoystick.getAngleRadian(event);
tick(System.nanoTime());
return;
}
lastHorizontalValue = horizontalValue;
lastVerticalValue = verticalValue;
mouseMagnitude = currentJoystick.getMagnitude(event);
mouseAngle = currentJoystick.getAngleRadian(event);
}
private void updateDirectionalJoystick(MotionEvent event){
GamepadJoystick currentJoystick = lastGrabbingState ? leftJoystick : rightJoystick;
int lastJoystickDirection = currentJoystickDirection;
currentJoystickDirection = currentJoystick.getHeightDirection(event);
if(currentJoystickDirection == lastJoystickDirection) return;
sendDirectionalKeycode(lastJoystickDirection, false, getCurrentMap());
sendDirectionalKeycode(currentJoystickDirection, true, getCurrentMap());
}
private void updateAnalogTriggers(MotionEvent event){
if(mModifierAnalogTriggers){
getCurrentMap().TRIGGER_LEFT.update(
(event.getAxisValue(MotionEvent.AXIS_LTRIGGER) > 0.5)
|| (event.getAxisValue(MotionEvent.AXIS_BRAKE) > 0.5)
|| (mModifierSwappedAxis &&(event.getAxisValue(MotionEvent.AXIS_Z) > 0.5)) );
getCurrentMap().TRIGGER_RIGHT.update(
(event.getAxisValue( MotionEvent.AXIS_RTRIGGER) > 0.5)
|| (event.getAxisValue(MotionEvent.AXIS_GAS) > 0.5)
|| (mModifierSwappedAxis && event.getAxisValue(MotionEvent.AXIS_RZ) > 0.5) );
}
}
public void notifyGUISizeChange(int newSize){
//Change the pointer size to match UI
int size = (int) ((22 * newSize) / scaleFactor);
pointerView.post(() -> pointerView.setLayoutParams(new FrameLayout.LayoutParams(size, size)));
int size = (int) ((22 * newSize) / mScaleFactor);
mPointerImageView.post(() -> mPointerImageView.setLayoutParams(new FrameLayout.LayoutParams(size, size)));
}
/**
* Detect if a gamepad supports analog triggers
* @param inputDevice The input device with all the MotionRange
* @return Whether the gamepad supports analog triggers
*/
private boolean supportAnalogTriggers(InputDevice inputDevice){
for(InputDevice.MotionRange motionRange : inputDevice.getMotionRanges()){
int axis = motionRange.getAxis();
if( axis == MotionEvent.AXIS_BRAKE || axis == MotionEvent.AXIS_GAS ||
axis == MotionEvent.AXIS_LTRIGGER || axis == MotionEvent.AXIS_RTRIGGER ||
(mModifierSwappedAxis && axis == MotionEvent.AXIS_Z) ||
(mModifierSwappedAxis && axis == MotionEvent.AXIS_RZ)){
return true;
}
}
return false;
}
private GamepadMap getCurrentMap(){
return currentMap;
}
private static void sendDirectionalKeycode(int direction, boolean isDown, GamepadMap map){
switch (direction){
case DIRECTION_NORTH:
sendInput(map.DIRECTION_FORWARD, isDown);
break;
case DIRECTION_NORTH_EAST:
sendInput(map.DIRECTION_FORWARD, isDown);
sendInput(map.DIRECTION_RIGHT, isDown);
break;
case DIRECTION_EAST:
sendInput(map.DIRECTION_RIGHT, isDown);
break;
case DIRECTION_SOUTH_EAST:
sendInput(map.DIRECTION_RIGHT, isDown);
sendInput(map.DIRECTION_BACKWARD, isDown);
break;
case DIRECTION_SOUTH:
sendInput(map.DIRECTION_BACKWARD, isDown);
break;
case DIRECTION_SOUTH_WEST:
sendInput(map.DIRECTION_BACKWARD, isDown);
sendInput(map.DIRECTION_LEFT, isDown);
break;
case DIRECTION_WEST:
sendInput(map.DIRECTION_LEFT, isDown);
break;
case DIRECTION_NORTH_WEST:
sendInput(map.DIRECTION_FORWARD, isDown);
sendInput(map.DIRECTION_LEFT, isDown);
break;
}
}
private void placePointerView(int x, int y){
pointerView.setX(x - pointerView.getWidth()/2);
pointerView.setY(y - pointerView.getHeight()/2);
}
public void sendButton(KeyEvent event){
sendButton(event.getKeyCode(), event.getAction());
}
@@ -403,7 +228,7 @@ public class Gamepad {
default:
sendKeyPress(LWJGLGLFWKeycode.GLFW_KEY_SPACE, CallbackBridge.getCurrentMods(), isDown);
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_SPACE, CallbackBridge.getCurrentMods(), isDown);
break;
}
}
@@ -418,11 +243,11 @@ public class Gamepad {
if(isDown) CallbackBridge.sendScroll(0, 1);
break;
case LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT:
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown);
case LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT:
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT, isDown);
break;
case LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT:
sendMouseButton(LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT, isDown);
case LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT:
sendMouseButton(LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT, isDown);
break;
@@ -443,4 +268,180 @@ public class Gamepad {
return ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD
|| GamepadDpad.isDpadEvent(event) );
}
/**
* Send the new mouse position, computing the delta
* @param frameTimeNanos The time to render the frame, used to compute mouse delta
*/
private void tick(long frameTimeNanos){
//update mouse position
if(mLastHorizontalValue != 0 || mLastVerticalValue != 0){
GamepadJoystick currentJoystick = mLastGrabbingState ? mLeftJoystick : mRightJoystick;
double acceleration = (mMouseMagnitude - currentJoystick.getDeadzone()) / (1 - currentJoystick.getDeadzone());
acceleration = Math.pow(acceleration, MOUSE_MAX_ACCELERATION);
if(acceleration > 1) acceleration = 1;
// Compute delta since last tick time
float deltaX = (float) (Math.cos(mMouseAngle) * acceleration * mMouseSensitivity);
float deltaY = (float) (Math.sin(mMouseAngle) * acceleration * mMouseSensitivity);
float deltaTimeScale = ((frameTimeNanos - mLastFrameTime) / 16666666f); // Scale of 1 = 60Hz
deltaX *= deltaTimeScale;
deltaY *= deltaTimeScale;
CallbackBridge.mouseX += deltaX;
CallbackBridge.mouseY -= deltaY;
if(!mLastGrabbingState){
CallbackBridge.mouseX = MathUtils.clamp(CallbackBridge.mouseX, 0, CallbackBridge.windowWidth);
CallbackBridge.mouseY = MathUtils.clamp(CallbackBridge.mouseY, 0, CallbackBridge.windowHeight);
placePointerView((int) (CallbackBridge.mouseX / mScaleFactor), (int) (CallbackBridge.mouseY/ mScaleFactor));
}
mMouse_x = CallbackBridge.mouseX;
mMouse_y = CallbackBridge.mouseY;
//Send the mouse to the game
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
}
// Update last nano time
mLastFrameTime = frameTimeNanos;
}
/** Update the grabbing state, and change the currentMap, mouse position and sensibility */
private void updateGrabbingState() {
boolean lastGrabbingValue = mLastGrabbingState;
mLastGrabbingState = CallbackBridge.isGrabbing();
if(lastGrabbingValue == mLastGrabbingState) return;
// Switch grabbing state then
mCurrentMap.resetPressedState();
if(mLastGrabbingState){
mCurrentMap = mGameMap;
mPointerImageView.setVisibility(View.INVISIBLE);
mMouseSensitivity = 18;
return;
}
mCurrentMap = mMenuMap;
sendDirectionalKeycode(mCurrentJoystickDirection, false, mGameMap); // removing what we were doing
mMouse_x = CallbackBridge.windowWidth/2;
mMouse_y = CallbackBridge.windowHeight/2;
CallbackBridge.sendCursorPos(mMouse_x, mMouse_y);
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
mPointerImageView.setVisibility(View.VISIBLE);
// Sensitivity in menu is MC and HARDWARE resolution dependent
mMouseSensitivity = 19 * mScaleFactor / mSensitivityFactor;
}
private void updateMouseJoystick(MotionEvent event){
GamepadJoystick currentJoystick = mLastGrabbingState ? mRightJoystick : mLeftJoystick;
float horizontalValue = currentJoystick.getHorizontalAxis(event);
float verticalValue = currentJoystick.getVerticalAxis(event);
if(horizontalValue != mLastHorizontalValue || verticalValue != mLastVerticalValue){
mLastHorizontalValue = horizontalValue;
mLastVerticalValue = verticalValue;
mMouseMagnitude = currentJoystick.getMagnitude(event);
mMouseAngle = currentJoystick.getAngleRadian(event);
tick(System.nanoTime());
return;
}
mLastHorizontalValue = horizontalValue;
mLastVerticalValue = verticalValue;
mMouseMagnitude = currentJoystick.getMagnitude(event);
mMouseAngle = currentJoystick.getAngleRadian(event);
}
private void updateDirectionalJoystick(MotionEvent event){
GamepadJoystick currentJoystick = mLastGrabbingState ? mLeftJoystick : mRightJoystick;
int lastJoystickDirection = mCurrentJoystickDirection;
mCurrentJoystickDirection = currentJoystick.getHeightDirection(event);
if(mCurrentJoystickDirection == lastJoystickDirection) return;
sendDirectionalKeycode(lastJoystickDirection, false, getCurrentMap());
sendDirectionalKeycode(mCurrentJoystickDirection, true, getCurrentMap());
}
private void updateAnalogTriggers(MotionEvent event){
if(mModifierAnalogTriggers){
getCurrentMap().TRIGGER_LEFT.update(
(event.getAxisValue(MotionEvent.AXIS_LTRIGGER) > 0.5)
|| (event.getAxisValue(MotionEvent.AXIS_BRAKE) > 0.5)
|| (mModifierSwappedAxis &&(event.getAxisValue(MotionEvent.AXIS_Z) > 0.5)) );
getCurrentMap().TRIGGER_RIGHT.update(
(event.getAxisValue( MotionEvent.AXIS_RTRIGGER) > 0.5)
|| (event.getAxisValue(MotionEvent.AXIS_GAS) > 0.5)
|| (mModifierSwappedAxis && event.getAxisValue(MotionEvent.AXIS_RZ) > 0.5) );
}
}
/**
* Detect if a gamepad supports analog triggers
* @param inputDevice The input device with all the MotionRange
* @return Whether the gamepad supports analog triggers
*/
private boolean supportAnalogTriggers(InputDevice inputDevice){
for(InputDevice.MotionRange motionRange : inputDevice.getMotionRanges()){
int axis = motionRange.getAxis();
if( axis == MotionEvent.AXIS_BRAKE || axis == MotionEvent.AXIS_GAS ||
axis == MotionEvent.AXIS_LTRIGGER || axis == MotionEvent.AXIS_RTRIGGER ||
(mModifierSwappedAxis && axis == MotionEvent.AXIS_Z) ||
(mModifierSwappedAxis && axis == MotionEvent.AXIS_RZ)){
return true;
}
}
return false;
}
private GamepadMap getCurrentMap(){
return mCurrentMap;
}
private static void sendDirectionalKeycode(int direction, boolean isDown, GamepadMap map){
switch (direction){
case DIRECTION_NORTH:
sendInput(map.DIRECTION_FORWARD, isDown);
break;
case DIRECTION_NORTH_EAST:
sendInput(map.DIRECTION_FORWARD, isDown);
sendInput(map.DIRECTION_RIGHT, isDown);
break;
case DIRECTION_EAST:
sendInput(map.DIRECTION_RIGHT, isDown);
break;
case DIRECTION_SOUTH_EAST:
sendInput(map.DIRECTION_RIGHT, isDown);
sendInput(map.DIRECTION_BACKWARD, isDown);
break;
case DIRECTION_SOUTH:
sendInput(map.DIRECTION_BACKWARD, isDown);
break;
case DIRECTION_SOUTH_WEST:
sendInput(map.DIRECTION_BACKWARD, isDown);
sendInput(map.DIRECTION_LEFT, isDown);
break;
case DIRECTION_WEST:
sendInput(map.DIRECTION_LEFT, isDown);
break;
case DIRECTION_NORTH_WEST:
sendInput(map.DIRECTION_FORWARD, isDown);
sendInput(map.DIRECTION_LEFT, isDown);
break;
}
}
private void placePointerView(int x, int y){
mPointerImageView.setX(x - mPointerImageView.getWidth()/2);
mPointerImageView.setY(y - mPointerImageView.getHeight()/2);
}
}

View File

@@ -2,15 +2,15 @@ package net.kdt.pojavlaunch.customcontrols.gamepad;
import android.view.KeyEvent;
/**
* Simple button able to store its state and some properties
*/
public class GamepadButton {
/*
Just a simple button, that auto deal with the great habit from android to just SPAAAMS input events
*/
public int[] keycodes;
public boolean isToggleable = false;
private boolean isDown = false;
private boolean isToggled = false;
private boolean mIsDown = false;
private boolean mIsToggled = false;
public void update(KeyEvent event){
boolean isKeyDown = (event.getAction() == KeyEvent.ACTION_DOWN);
@@ -18,29 +18,29 @@ public class GamepadButton {
}
public void update(boolean isKeyDown){
if(isKeyDown != isDown){
isDown = isKeyDown;
if(isKeyDown != mIsDown){
mIsDown = isKeyDown;
if(isToggleable){
if(isKeyDown){
isToggled = !isToggled;
Gamepad.sendInput(keycodes, isToggled);
mIsToggled = !mIsToggled;
Gamepad.sendInput(keycodes, mIsToggled);
}
return;
}
Gamepad.sendInput(keycodes, isDown);
Gamepad.sendInput(keycodes, mIsDown);
}
}
public void resetButtonState(){
if(isDown || isToggled){
if(mIsDown || mIsToggled){
Gamepad.sendInput(keycodes, false);
}
isDown = false;
isToggled = false;
mIsDown = false;
mIsToggled = false;
}
public boolean isDown(){
return isToggleable ? isToggled : isDown;
return isToggleable ? mIsToggled : mIsDown;
}
}

View File

@@ -5,7 +5,6 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import static android.view.InputDevice.KEYBOARD_TYPE_NON_ALPHABETIC;
import static android.view.InputDevice.SOURCE_DPAD;
import static android.view.KeyEvent.KEYCODE_DPAD_CENTER;
import static android.view.KeyEvent.KEYCODE_DPAD_DOWN;
import static android.view.KeyEvent.KEYCODE_DPAD_LEFT;
@@ -14,7 +13,7 @@ import static android.view.KeyEvent.KEYCODE_DPAD_UP;
public class GamepadDpad {
private int lastKeycode = KEYCODE_DPAD_CENTER;
private int mLastKeycode = KEYCODE_DPAD_CENTER;
/**
* Convert the event to a 2 int array: keycode and keyAction, similar to a keyEvent
@@ -30,22 +29,22 @@ public class GamepadDpad {
// Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad
// LEFT and RIGHT direction accordingly.
if (Float.compare(xaxis, -1.0f) == 0) {
lastKeycode = KEYCODE_DPAD_LEFT;
mLastKeycode = KEYCODE_DPAD_LEFT;
} else if (Float.compare(xaxis, 1.0f) == 0) {
lastKeycode = KEYCODE_DPAD_RIGHT;
mLastKeycode = KEYCODE_DPAD_RIGHT;
}
// Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
// UP and DOWN direction accordingly.
else if (Float.compare(yaxis, -1.0f) == 0) {
lastKeycode = KEYCODE_DPAD_UP;
mLastKeycode = KEYCODE_DPAD_UP;
} else if (Float.compare(yaxis, 1.0f) == 0) {
lastKeycode = KEYCODE_DPAD_DOWN;
mLastKeycode = KEYCODE_DPAD_DOWN;
}else {
//No keycode change
action = KeyEvent.ACTION_UP;
}
return new int[]{lastKeycode, action};
return new int[]{mLastKeycode, action};
}

View File

@@ -20,17 +20,14 @@ public class GamepadJoystick {
public static final int DIRECTION_SOUTH = 6;
public static final int DIRECTION_SOUTH_EAST = 7;
private final InputDevice device;
private final int verticalAxis;
private final int horizontalAxis;
private final InputDevice mInputDevice;
private final int mVerticalAxis;
private final int mHorizontalAxis;
public GamepadJoystick(int horizontalAxis, int verticalAxis, InputDevice device){
this.verticalAxis = verticalAxis;
this.horizontalAxis = horizontalAxis;
this.device = device;
this.mVerticalAxis = verticalAxis;
this.mHorizontalAxis = horizontalAxis;
this.mInputDevice = device;
}
public double getAngleRadian(MotionEvent event){
@@ -48,29 +45,18 @@ public class GamepadJoystick {
}
public double getMagnitude(MotionEvent event){
float x = Math.abs(event.getAxisValue(horizontalAxis));
float y = Math.abs(event.getAxisValue(verticalAxis));
float x = Math.abs(event.getAxisValue(mHorizontalAxis));
float y = Math.abs(event.getAxisValue(mVerticalAxis));
return MathUtils.dist(0,0, x, y);
}
public float getVerticalAxis(MotionEvent event){
return applyDeadzone(event, verticalAxis);
return applyDeadzone(event, mVerticalAxis);
}
public float getHorizontalAxis(MotionEvent event){
return applyDeadzone(event, horizontalAxis);
}
private float applyDeadzone(MotionEvent event, int axis){
//This piece of code also modifies the value
//to make it seem like there was no deadzone in the first place
double magnitude = getMagnitude(event);
float deadzone = getDeadzone();
if (magnitude < deadzone) return 0;
return (float) ( (event.getAxisValue(axis) / magnitude) * ((magnitude - deadzone) / (1 - deadzone)) );
return applyDeadzone(event, mHorizontalAxis);
}
public static boolean isJoystickEvent(MotionEvent event){
@@ -91,9 +77,20 @@ public class GamepadJoystick {
*/
public float getDeadzone() {
try{
return Math.max(device.getMotionRange(horizontalAxis).getFlat() * 1.9f, 0.2f);
return Math.max(mInputDevice.getMotionRange(mHorizontalAxis).getFlat() * 1.9f, 0.2f);
}catch (Exception e){
return 0.2f;
}
}
private float applyDeadzone(MotionEvent event, int axis){
//This piece of code also modifies the value
//to make it seem like there was no deadzone in the first place
double magnitude = getMagnitude(event);
float deadzone = getDeadzone();
if (magnitude < deadzone) return 0;
return (float) ( (event.getAxisValue(axis) / magnitude) * ((magnitude - deadzone) / (1 - deadzone)) );
}
}

View File

@@ -1,6 +1,6 @@
package net.kdt.pojavlaunch.customcontrols.gamepad;
import net.kdt.pojavlaunch.LWJGLGLFWKeycode;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
public class GamepadMap {
@@ -76,33 +76,33 @@ public class GamepadMap {
public static GamepadMap getDefaultGameMap(){
GamepadMap gameMap = new GamepadMap();
gameMap.BUTTON_A.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_SPACE};
gameMap.BUTTON_B.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_Q};
gameMap.BUTTON_X.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_E};
gameMap.BUTTON_Y.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_F};
gameMap.BUTTON_A.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_SPACE};
gameMap.BUTTON_B.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_Q};
gameMap.BUTTON_X.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_E};
gameMap.BUTTON_Y.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_F};
gameMap.DIRECTION_FORWARD = new int[]{LWJGLGLFWKeycode.GLFW_KEY_W};
gameMap.DIRECTION_BACKWARD = new int[]{LWJGLGLFWKeycode.GLFW_KEY_S};
gameMap.DIRECTION_RIGHT = new int[]{LWJGLGLFWKeycode.GLFW_KEY_D};
gameMap.DIRECTION_LEFT = new int[]{LWJGLGLFWKeycode.GLFW_KEY_A};
gameMap.DIRECTION_FORWARD = new int[]{LwjglGlfwKeycode.GLFW_KEY_W};
gameMap.DIRECTION_BACKWARD = new int[]{LwjglGlfwKeycode.GLFW_KEY_S};
gameMap.DIRECTION_RIGHT = new int[]{LwjglGlfwKeycode.GLFW_KEY_D};
gameMap.DIRECTION_LEFT = new int[]{LwjglGlfwKeycode.GLFW_KEY_A};
gameMap.DPAD_UP.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT};
gameMap.DPAD_DOWN.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_O}; //For mods ?
gameMap.DPAD_RIGHT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_K}; //For mods ?
gameMap.DPAD_LEFT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_J}; //For mods ?
gameMap.DPAD_UP.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT};
gameMap.DPAD_DOWN.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_O}; //For mods ?
gameMap.DPAD_RIGHT.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_K}; //For mods ?
gameMap.DPAD_LEFT.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_J}; //For mods ?
gameMap.SHOULDER_LEFT.keycodes = new int[]{GamepadMap.MOUSE_SCROLL_UP};
gameMap.SHOULDER_RIGHT.keycodes = new int[]{GamepadMap.MOUSE_SCROLL_DOWN};
gameMap.TRIGGER_LEFT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT};
gameMap.TRIGGER_RIGHT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT};
gameMap.TRIGGER_LEFT.keycodes = new int[]{LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT};
gameMap.TRIGGER_RIGHT.keycodes = new int[]{LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT};
gameMap.THUMBSTICK_LEFT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_LEFT_CONTROL};
gameMap.THUMBSTICK_RIGHT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT};
gameMap.THUMBSTICK_LEFT.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL};
gameMap.THUMBSTICK_RIGHT.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT};
gameMap.THUMBSTICK_RIGHT.isToggleable = true;
gameMap.BUTTON_START.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_ESCAPE};
gameMap.BUTTON_SELECT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_TAB};
gameMap.BUTTON_START.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_ESCAPE};
gameMap.BUTTON_SELECT.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_TAB};
return gameMap;
}
@@ -113,10 +113,10 @@ public class GamepadMap {
public static GamepadMap getDefaultMenuMap(){
GamepadMap menuMap = new GamepadMap();
menuMap.BUTTON_A.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_LEFT};
menuMap.BUTTON_B.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_ESCAPE};
menuMap.BUTTON_X.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT};
menuMap.BUTTON_Y.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT, LWJGLGLFWKeycode.GLFW_MOUSE_BUTTON_RIGHT}; //Oops, doesn't work since left shift isn't properly applied.
menuMap.BUTTON_A.keycodes = new int[]{LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_LEFT};
menuMap.BUTTON_B.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_ESCAPE};
menuMap.BUTTON_X.keycodes = new int[]{LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT};
menuMap.BUTTON_Y.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT, LwjglGlfwKeycode.GLFW_MOUSE_BUTTON_RIGHT}; //Oops, doesn't work since left shift isn't properly applied.
menuMap.DIRECTION_FORWARD = new int[]{GamepadMap.MOUSE_SCROLL_UP, GamepadMap.MOUSE_SCROLL_UP, GamepadMap.MOUSE_SCROLL_UP, GamepadMap.MOUSE_SCROLL_UP, GamepadMap.MOUSE_SCROLL_UP};
menuMap.DIRECTION_BACKWARD = new int[]{GamepadMap.MOUSE_SCROLL_DOWN, GamepadMap.MOUSE_SCROLL_DOWN, GamepadMap.MOUSE_SCROLL_DOWN, GamepadMap.MOUSE_SCROLL_DOWN, GamepadMap.MOUSE_SCROLL_DOWN};
@@ -124,9 +124,9 @@ public class GamepadMap {
menuMap.DIRECTION_LEFT = new int[]{};
menuMap.DPAD_UP.keycodes = new int[]{};
menuMap.DPAD_DOWN.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_O}; //For mods ?
menuMap.DPAD_RIGHT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_K}; //For mods ?
menuMap.DPAD_LEFT.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_J}; //For mods ?
menuMap.DPAD_DOWN.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_O}; //For mods ?
menuMap.DPAD_RIGHT.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_K}; //For mods ?
menuMap.DPAD_LEFT.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_J}; //For mods ?
menuMap.SHOULDER_LEFT.keycodes = new int[]{GamepadMap.MOUSE_SCROLL_UP};
menuMap.SHOULDER_RIGHT.keycodes = new int[]{GamepadMap.MOUSE_SCROLL_DOWN};
@@ -137,7 +137,7 @@ public class GamepadMap {
menuMap.THUMBSTICK_LEFT.keycodes = new int[]{};
menuMap.THUMBSTICK_RIGHT.keycodes = new int[]{};
menuMap.BUTTON_START.keycodes = new int[]{LWJGLGLFWKeycode.GLFW_KEY_ESCAPE};
menuMap.BUTTON_START.keycodes = new int[]{LwjglGlfwKeycode.GLFW_KEY_ESCAPE};
menuMap.BUTTON_SELECT.keycodes = new int[]{};
return menuMap;

View File

@@ -43,11 +43,11 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe
private TextView mDeleteTextView;
private TextView mCloneTextView;
private final ControlButton editedButton;
private final ControlButton mEditedButton;
public ActionPopupWindow(HandleView handleView, ControlButton button){
super(handleView);
this.editedButton = button;
this.mEditedButton = button;
}
@Override
@@ -97,18 +97,18 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe
public void onClick(final View view) {
if (view == mEditTextView) {
if(editedButton instanceof ControlSubButton){
new EditControlSubButtonPopup((ControlSubButton) editedButton);
if(mEditedButton instanceof ControlSubButton){
new EditControlSubButtonPopup((ControlSubButton) mEditedButton);
return;
}
if(editedButton instanceof ControlDrawer){
new EditControlDrawerPopup((ControlDrawer) editedButton);
if(mEditedButton instanceof ControlDrawer){
new EditControlDrawerPopup((ControlDrawer) mEditedButton);
return;
}
if(editedButton instanceof ControlButton){
new EditControlButtonPopup((ControlButton) editedButton);
if(mEditedButton instanceof ControlButton){
new EditControlButtonPopup((ControlButton) mEditedButton);
return;
}
@@ -121,18 +121,18 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe
alertBuilder.setPositiveButton(R.string.global_remove, (p1, p2) -> {
ControlLayout layout = ((ControlLayout) mHandleView.mView.getParent());
if(editedButton instanceof ControlSubButton){
layout.removeControlSubButton((ControlSubButton) editedButton);
if(mEditedButton instanceof ControlSubButton){
layout.removeControlSubButton((ControlSubButton) mEditedButton);
return;
}
if(editedButton instanceof ControlDrawer){
layout.removeControlDrawer((ControlDrawer) editedButton);
if(mEditedButton instanceof ControlDrawer){
layout.removeControlDrawer((ControlDrawer) mEditedButton);
return;
}
if(editedButton instanceof ControlButton){
layout.removeControlButton((ControlButton) editedButton);
if(mEditedButton instanceof ControlButton){
layout.removeControlButton((ControlButton) mEditedButton);
}
layout.removeControlButton(mHandleView.mView);
@@ -140,18 +140,18 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe
alertBuilder.setNegativeButton(android.R.string.cancel, null);
alertBuilder.show();
}else if(view == mCloneTextView) {
if(editedButton instanceof ControlDrawer){
ControlDrawerData cloneData = new ControlDrawerData(((ControlDrawer)editedButton).getDrawerData());
if(mEditedButton instanceof ControlDrawer){
ControlDrawerData cloneData = new ControlDrawerData(((ControlDrawer) mEditedButton).getDrawerData());
cloneData.properties.dynamicX = "0.5 * ${screen_width}";
cloneData.properties.dynamicY = "0.5 * ${screen_height}";
((ControlLayout) mHandleView.mView.getParent()).addDrawer(cloneData);
}else if(editedButton instanceof ControlSubButton){
ControlData cloneData = new ControlData(editedButton.getProperties());
}else if(mEditedButton instanceof ControlSubButton){
ControlData cloneData = new ControlData(mEditedButton.getProperties());
cloneData.dynamicX = "0.5 * ${screen_width}";
cloneData.dynamicY = "0.5 * ${screen_height}";
((ControlLayout) mHandleView.mView.getParent()).addSubButton(((ControlSubButton) editedButton).parentDrawer, cloneData);
((ControlLayout) mHandleView.mView.getParent()).addSubButton(((ControlSubButton) mEditedButton).parentDrawer, cloneData);
}else{
ControlData cloneData = new ControlData(editedButton.getProperties());
ControlData cloneData = new ControlData(mEditedButton.getProperties());
cloneData.dynamicX = "0.5 * ${screen_width}";
cloneData.dynamicY = "0.5 * ${screen_height}";
((ControlLayout) mHandleView.mView.getParent()).addControlButton(cloneData);

View File

@@ -1,6 +1,5 @@
package net.kdt.pojavlaunch.customcontrols.handleview;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
@@ -8,7 +7,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.SeekBar;
@@ -29,103 +27,103 @@ import static net.kdt.pojavlaunch.customcontrols.handleview.ActionPopupWindow.se
public class EditControlButtonPopup {
protected AlertDialog dialog;
protected View v;
protected AlertDialog.Builder builder;
protected AlertDialog mDialog;
protected View mRootView;
protected AlertDialog.Builder mBuilder;
protected EditText editName;
protected Spinner[] spinnersKeycode;
protected EditText mNameEditText;
protected Spinner[] mKeycodeSpinners;
protected CheckBox checkToggle;
protected CheckBox checkPassThrough;
protected CheckBox checkBoxSwipeable;
protected CheckBox checkDynamicPosition;
protected CheckBox mToggleCheckbox;
protected CheckBox mPassthroughCheckbox;
protected CheckBox mSwipeableCheckbox;
protected CheckBox mDynamicPositionCheckbox;
protected EditText editWidth;
protected EditText editHeight;
protected EditText editDynamicX;
protected EditText editDynamicY;
protected EditText mWidthEditText;
protected EditText mHeightEditText;
protected EditText mDynamicXEditText;
protected EditText mDynamicYEditText;
protected SeekBar seekBarOpacity;
protected SeekBar seekBarCornerRadius;
protected SeekBar seekBarStrokeWidth;
protected SeekBar mOpacitySeekbar;
protected SeekBar mCornerRadiusSeekbar;
protected SeekBar mStrokeWidthSeekbar;
protected ImageButton buttonBackgroundColor;
protected ImageButton buttonStrokeColor;
protected ImageButton mBackgroundColorButton;
protected ImageButton mStrokeColorButton;
protected TextView textOpacity;
protected TextView textCornerRadius;
protected TextView textStrokeWidth;
protected TextView textStrokeColor;
protected TextView mOpacityTextView;
protected TextView mCornerRadiusTextView;
protected TextView mStrokeWidthTextView;
protected TextView mStrokeColorTextView;
protected final ControlButton button;
protected final ControlData properties;
protected final ControlButton mControlButton;
protected final ControlData mProperties;
protected ArrayAdapter<String> adapter;
protected String[] specialArr;
protected ArrayAdapter<String> mAdapter;
protected String[] mSpecialArray;
public EditControlButtonPopup(ControlButton button){
this.button = button;
this.properties = button.getProperties();
this.mControlButton = button;
this.mProperties = button.getProperties();
initializeEditDialog(button.getContext());
//Create the finalized dialog
dialog = builder.create();
dialog.setOnShowListener(dialogInterface -> setEditDialogValues());
mDialog = mBuilder.create();
mDialog.setOnShowListener(dialogInterface -> setEditDialogValues());
dialog.show();
mDialog.show();
}
protected void initializeEditDialog(Context ctx){
//Create the editing dialog
LayoutInflater layoutInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = layoutInflater.inflate(R.layout.control_button_setting,null);
mRootView = layoutInflater.inflate(R.layout.dialog_control_button_setting,null);
builder = new AlertDialog.Builder(ctx);
builder.setTitle(ctx.getResources().getString(R.string.customctrl_edit, properties.name));
builder.setView(v);
mBuilder = new AlertDialog.Builder(ctx);
mBuilder.setTitle(ctx.getResources().getString(R.string.customctrl_edit, mProperties.name));
mBuilder.setView(mRootView);
//Linking a lot of stuff
editName = v.findViewById(R.id.editName_editText);
mNameEditText = mRootView.findViewById(R.id.editName_editText);
spinnersKeycode = new Spinner[]{
v.findViewById(R.id.editMapping_spinner_1),
v.findViewById(R.id.editMapping_spinner_2),
v.findViewById(R.id.editMapping_spinner_3),
v.findViewById(R.id.editMapping_spinner_4)
mKeycodeSpinners = new Spinner[]{
mRootView.findViewById(R.id.editMapping_spinner_1),
mRootView.findViewById(R.id.editMapping_spinner_2),
mRootView.findViewById(R.id.editMapping_spinner_3),
mRootView.findViewById(R.id.editMapping_spinner_4)
};
checkToggle = v.findViewById(R.id.checkboxToggle);
checkPassThrough = v.findViewById(R.id.checkboxPassThrough);
checkBoxSwipeable = v.findViewById(R.id.checkboxSwipeable);
mToggleCheckbox = mRootView.findViewById(R.id.checkboxToggle);
mPassthroughCheckbox = mRootView.findViewById(R.id.checkboxPassThrough);
mSwipeableCheckbox = mRootView.findViewById(R.id.checkboxSwipeable);
editWidth = v.findViewById(R.id.editSize_editTextX);
editHeight = v.findViewById(R.id.editSize_editTextY);
mWidthEditText = mRootView.findViewById(R.id.editSize_editTextX);
mHeightEditText = mRootView.findViewById(R.id.editSize_editTextY);
editDynamicX = v.findViewById(R.id.editDynamicPositionX_editText);
editDynamicY = v.findViewById(R.id.editDynamicPositionY_editText);
mDynamicXEditText = mRootView.findViewById(R.id.editDynamicPositionX_editText);
mDynamicYEditText = mRootView.findViewById(R.id.editDynamicPositionY_editText);
seekBarOpacity = v.findViewById(R.id.editButtonOpacity_seekbar);
seekBarCornerRadius = v.findViewById(R.id.editCornerRadius_seekbar);
seekBarStrokeWidth = v.findViewById(R.id.editStrokeWidth_seekbar);
mOpacitySeekbar = mRootView.findViewById(R.id.editButtonOpacity_seekbar);
mCornerRadiusSeekbar = mRootView.findViewById(R.id.editCornerRadius_seekbar);
mStrokeWidthSeekbar = mRootView.findViewById(R.id.editStrokeWidth_seekbar);
SeekBar.OnSeekBarChangeListener changeListener = new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if(seekBar.equals(seekBarCornerRadius)) {
setPercentageText(textCornerRadius, i);
if(seekBar.equals(mCornerRadiusSeekbar)) {
setPercentageText(mCornerRadiusTextView, i);
return;
}
if(seekBar.equals(seekBarOpacity)) {
setPercentageText(textOpacity, i);
if(seekBar.equals(mOpacitySeekbar)) {
setPercentageText(mOpacityTextView, i);
return;
}
if(seekBar.equals(seekBarStrokeWidth)) {
setPercentageText(textStrokeWidth, i);
textStrokeColor.setVisibility(i == 0 ? View.GONE : View.VISIBLE);
if(seekBar.equals(mStrokeWidthSeekbar)) {
setPercentageText(mStrokeWidthTextView, i);
mStrokeColorTextView.setVisibility(i == 0 ? View.GONE : View.VISIBLE);
}
}
@@ -136,43 +134,43 @@ public class EditControlButtonPopup {
};
//Add listeners, too bad I don't need all the methods
seekBarOpacity.setOnSeekBarChangeListener(changeListener);
seekBarCornerRadius.setOnSeekBarChangeListener(changeListener);
seekBarStrokeWidth.setOnSeekBarChangeListener(changeListener);
mOpacitySeekbar.setOnSeekBarChangeListener(changeListener);
mCornerRadiusSeekbar.setOnSeekBarChangeListener(changeListener);
mStrokeWidthSeekbar.setOnSeekBarChangeListener(changeListener);
buttonBackgroundColor = v.findViewById(R.id.editBackgroundColor_imageButton);
buttonStrokeColor = v.findViewById(R.id.editStrokeColor_imageButton);
mBackgroundColorButton = mRootView.findViewById(R.id.editBackgroundColor_imageButton);
mStrokeColorButton = mRootView.findViewById(R.id.editStrokeColor_imageButton);
textOpacity = v.findViewById(R.id.editButtonOpacity_textView_percent);
textCornerRadius = v.findViewById(R.id.editCornerRadius_textView_percent);
textStrokeWidth = v.findViewById(R.id.editStrokeWidth_textView_percent);
textStrokeColor = v.findViewById(R.id.editStrokeColor_textView);
mOpacityTextView = mRootView.findViewById(R.id.editButtonOpacity_textView_percent);
mCornerRadiusTextView = mRootView.findViewById(R.id.editCornerRadius_textView_percent);
mStrokeWidthTextView = mRootView.findViewById(R.id.editStrokeWidth_textView_percent);
mStrokeColorTextView = mRootView.findViewById(R.id.editStrokeColor_textView);
checkDynamicPosition = v.findViewById(R.id.checkboxDynamicPosition);
checkDynamicPosition.setOnCheckedChangeListener((btn, checked) -> {
editDynamicX.setEnabled(checked);
editDynamicY.setEnabled(checked);
mDynamicPositionCheckbox = mRootView.findViewById(R.id.checkboxDynamicPosition);
mDynamicPositionCheckbox.setOnCheckedChangeListener((btn, checked) -> {
mDynamicXEditText.setEnabled(checked);
mDynamicYEditText.setEnabled(checked);
});
//Initialize adapter for keycodes
adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item);
mAdapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item);
String[] oldSpecialArr = ControlData.buildSpecialButtonArray();
specialArr = new String[oldSpecialArr.length];
for (int i = 0; i < specialArr.length; i++) {
specialArr[i] = "SPECIAL_" + oldSpecialArr[specialArr.length - i - 1];
mSpecialArray = new String[oldSpecialArr.length];
for (int i = 0; i < mSpecialArray.length; i++) {
mSpecialArray[i] = "SPECIAL_" + oldSpecialArr[mSpecialArray.length - i - 1];
}
adapter.addAll(specialArr);
adapter.addAll(EfficientAndroidLWJGLKeycode.generateKeyName());
adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
mAdapter.addAll(mSpecialArray);
mAdapter.addAll(EfficientAndroidLWJGLKeycode.generateKeyName());
mAdapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
for (Spinner spinner : spinnersKeycode) {
spinner.setAdapter(adapter);
for (Spinner spinner : mKeycodeSpinners) {
spinner.setAdapter(mAdapter);
}
//Set color imageButton behavior
buttonBackgroundColor.setOnClickListener(view -> ActionPopupWindow.showColorPicker(ctx, "Edit background color", true, buttonBackgroundColor));
buttonStrokeColor.setOnClickListener(view -> ActionPopupWindow.showColorPicker(ctx, "Edit stroke color", false, buttonStrokeColor));
mBackgroundColorButton.setOnClickListener(view -> ActionPopupWindow.showColorPicker(ctx, "Edit background color", true, mBackgroundColorButton));
mStrokeColorButton.setOnClickListener(view -> ActionPopupWindow.showColorPicker(ctx, "Edit stroke color", false, mStrokeColorButton));
//Set dialog buttons behavior
@@ -187,34 +185,34 @@ public class EditControlButtonPopup {
protected void setupDialogButtons(){
//Set dialog buttons behavior
builder.setPositiveButton(android.R.string.ok, (dialogInterface1, i) -> {
if(!hasPropertiesErrors(dialog.getContext())){
mBuilder.setPositiveButton(android.R.string.ok, (dialogInterface1, i) -> {
if(!hasPropertiesErrors(mDialog.getContext())){
saveProperties();
}
});
builder.setNegativeButton(android.R.string.cancel, null);
mBuilder.setNegativeButton(android.R.string.cancel, null);
}
protected void hideUselessViews(){
(v.findViewById(R.id.editOrientation_textView)).setVisibility(View.GONE);
(mRootView.findViewById(R.id.editOrientation_textView)).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);
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
mDynamicXEditText.setVisibility(View.GONE);
mDynamicYEditText.setVisibility(View.GONE);
//Hide the color choice if the width is 0.
textStrokeColor.setVisibility(properties.strokeWidth == 0 ? View.GONE : View.VISIBLE);
mStrokeColorTextView.setVisibility(mProperties.strokeWidth == 0 ? View.GONE : View.VISIBLE);
}
protected void defineDynamicCheckChange(){
checkDynamicPosition.setOnCheckedChangeListener((compoundButton, b) -> {
mDynamicPositionCheckbox.setOnCheckedChangeListener((compoundButton, b) -> {
int visibility = b ? View.VISIBLE : View.GONE;
(v.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(visibility);
(v.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(visibility);
editDynamicX.setVisibility(visibility);
editDynamicY.setVisibility(visibility);
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(visibility);
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(visibility);
mDynamicXEditText.setVisibility(visibility);
mDynamicYEditText.setVisibility(visibility);
});
}
@@ -226,65 +224,65 @@ public class EditControlButtonPopup {
.size((int) Tools.dpToPx(20))
.build();
buttonBackgroundColor.setBackground(drawable);
buttonStrokeColor.setBackground(drawable);
mBackgroundColorButton.setBackground(drawable);
mStrokeColorButton.setBackground(drawable);
}
protected void setEditDialogValues(){
editName.setText(properties.name);
mNameEditText.setText(mProperties.name);
checkToggle.setChecked(properties.isToggle);
checkPassThrough.setChecked(properties.passThruEnabled);
checkBoxSwipeable.setChecked(properties.isSwipeable);
mToggleCheckbox.setChecked(mProperties.isToggle);
mPassthroughCheckbox.setChecked(mProperties.passThruEnabled);
mSwipeableCheckbox.setChecked(mProperties.isSwipeable);
editWidth.setText(Float.toString(properties.getWidth()));
editHeight.setText(Float.toString(properties.getHeight()));
mWidthEditText.setText(Float.toString(mProperties.getWidth()));
mHeightEditText.setText(Float.toString(mProperties.getHeight()));
editDynamicX.setEnabled(properties.isDynamicBtn);
editDynamicY.setEnabled(properties.isDynamicBtn);
editDynamicX.setText(properties.dynamicX);
mDynamicXEditText.setEnabled(mProperties.isDynamicBtn);
mDynamicYEditText.setEnabled(mProperties.isDynamicBtn);
mDynamicXEditText.setText(mProperties.dynamicX);
editDynamicY.setText(properties.dynamicY);
mDynamicYEditText.setText(mProperties.dynamicY);
seekBarOpacity.setProgress((int) (properties.opacity*100));
seekBarStrokeWidth.setProgress(properties.strokeWidth);
seekBarCornerRadius.setProgress((int)properties.cornerRadius);
mOpacitySeekbar.setProgress((int) (mProperties.opacity*100));
mStrokeWidthSeekbar.setProgress(mProperties.strokeWidth);
mCornerRadiusSeekbar.setProgress((int) mProperties.cornerRadius);
buttonBackgroundColor.setImageDrawable(new ColorDrawable(properties.bgColor));
buttonStrokeColor.setImageDrawable(new ColorDrawable(properties.strokeColor));
mBackgroundColorButton.setImageDrawable(new ColorDrawable(mProperties.bgColor));
mStrokeColorButton.setImageDrawable(new ColorDrawable(mProperties.strokeColor));
setPercentageText(textCornerRadius,seekBarCornerRadius.getProgress());
setPercentageText(textOpacity,seekBarOpacity.getProgress());
setPercentageText(textStrokeWidth,seekBarStrokeWidth.getProgress());
setPercentageText(mCornerRadiusTextView, mCornerRadiusSeekbar.getProgress());
setPercentageText(mOpacityTextView, mOpacitySeekbar.getProgress());
setPercentageText(mStrokeWidthTextView, mStrokeWidthSeekbar.getProgress());
checkDynamicPosition.setChecked(properties.isDynamicBtn);
mDynamicPositionCheckbox.setChecked(mProperties.isDynamicBtn);
for(int i=0; i< properties.keycodes.length; i++){
if (properties.keycodes[i] < 0) {
spinnersKeycode[i].setSelection(properties.keycodes[i] + specialArr.length);
for(int i = 0; i< mProperties.keycodes.length; i++){
if (mProperties.keycodes[i] < 0) {
mKeycodeSpinners[i].setSelection(mProperties.keycodes[i] + mSpecialArray.length);
} else {
spinnersKeycode[i].setSelection(EfficientAndroidLWJGLKeycode.getIndexByValue(properties.keycodes[i]) + specialArr.length);
mKeycodeSpinners[i].setSelection(EfficientAndroidLWJGLKeycode.getIndexByValue(mProperties.keycodes[i]) + mSpecialArray.length);
}
}
}
protected boolean hasPropertiesErrors(Context ctx){
if (editName.getText().toString().isEmpty()) {
editName.setError(ctx.getResources().getString(R.string.global_error_field_empty));
if (mNameEditText.getText().toString().isEmpty()) {
mNameEditText.setError(ctx.getResources().getString(R.string.global_error_field_empty));
return true;
}
if (properties.isDynamicBtn) {
if (mProperties.isDynamicBtn) {
int errorAt = 0;
try {
properties.insertDynamicPos(editDynamicX.getText().toString());
mProperties.insertDynamicPos(mDynamicXEditText.getText().toString());
errorAt = 1;
properties.insertDynamicPos(editDynamicY.getText().toString());
mProperties.insertDynamicPos(mDynamicYEditText.getText().toString());
} catch (Throwable th) {
(errorAt == 0 ? editDynamicX : editDynamicY).setError(th.getMessage());
(errorAt == 0 ? mDynamicXEditText : mDynamicYEditText).setError(th.getMessage());
return true;
}
@@ -295,36 +293,36 @@ public class EditControlButtonPopup {
protected void saveProperties(){
//This method assumes there are no error.
properties.name = editName.getText().toString();
mProperties.name = mNameEditText.getText().toString();
//Keycodes
for(int i=0; i<spinnersKeycode.length; ++i){
if (spinnersKeycode[i].getSelectedItemPosition() < specialArr.length) {
properties.keycodes[i] = spinnersKeycode[i].getSelectedItemPosition() - specialArr.length;
for(int i = 0; i< mKeycodeSpinners.length; ++i){
if (mKeycodeSpinners[i].getSelectedItemPosition() < mSpecialArray.length) {
mProperties.keycodes[i] = mKeycodeSpinners[i].getSelectedItemPosition() - mSpecialArray.length;
} else {
properties.keycodes[i] = EfficientAndroidLWJGLKeycode.getValueByIndex(spinnersKeycode[i].getSelectedItemPosition() - specialArr.length);
mProperties.keycodes[i] = EfficientAndroidLWJGLKeycode.getValueByIndex(mKeycodeSpinners[i].getSelectedItemPosition() - mSpecialArray.length);
}
}
properties.opacity = seekBarOpacity.getProgress()/100f;
properties.strokeWidth = seekBarStrokeWidth.getProgress();
properties.cornerRadius = seekBarCornerRadius.getProgress();
mProperties.opacity = mOpacitySeekbar.getProgress()/100f;
mProperties.strokeWidth = mStrokeWidthSeekbar.getProgress();
mProperties.cornerRadius = mCornerRadiusSeekbar.getProgress();
properties.bgColor = ((ColorDrawable)buttonBackgroundColor.getDrawable()).getColor();
properties.strokeColor = ((ColorDrawable) buttonStrokeColor.getDrawable()).getColor();
mProperties.bgColor = ((ColorDrawable) mBackgroundColorButton.getDrawable()).getColor();
mProperties.strokeColor = ((ColorDrawable) mStrokeColorButton.getDrawable()).getColor();
properties.isToggle = checkToggle.isChecked();
properties.passThruEnabled = checkPassThrough.isChecked();
properties.isSwipeable = checkBoxSwipeable.isChecked();
mProperties.isToggle = mToggleCheckbox.isChecked();
mProperties.passThruEnabled = mPassthroughCheckbox.isChecked();
mProperties.isSwipeable = mSwipeableCheckbox.isChecked();
properties.setWidth(Float.parseFloat(editWidth.getText().toString()));
properties.setHeight(Float.parseFloat(editHeight.getText().toString()));
mProperties.setWidth(Float.parseFloat(mWidthEditText.getText().toString()));
mProperties.setHeight(Float.parseFloat(mHeightEditText.getText().toString()));
properties.isDynamicBtn = checkDynamicPosition.isChecked();
if(!editDynamicX.getText().toString().isEmpty()) properties.dynamicX = editDynamicX.getText().toString();
if(!editDynamicY.getText().toString().isEmpty()) properties.dynamicY = editDynamicY.getText().toString();
mProperties.isDynamicBtn = mDynamicPositionCheckbox.isChecked();
if(!mDynamicXEditText.getText().toString().isEmpty()) mProperties.dynamicX = mDynamicXEditText.getText().toString();
if(!mDynamicYEditText.getText().toString().isEmpty()) mProperties.dynamicY = mDynamicYEditText.getText().toString();
button.updateProperties();
mControlButton.updateProperties();
}
}

View File

@@ -14,62 +14,62 @@ import net.kdt.pojavlaunch.customcontrols.ControlDrawerData;
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
public class EditControlDrawerPopup extends EditControlButtonPopup{
private Spinner spinnerOrientation;
private Spinner mOrientationSpinner;
private ControlDrawer drawer;
private ControlDrawerData drawerData;
private final ControlDrawer mDrawer;
private final ControlDrawerData mDrawerData;
public EditControlDrawerPopup(ControlDrawer editedButton) {
super(editedButton);
drawer = editedButton;
drawerData = editedButton.getDrawerData();
mDrawer = editedButton;
mDrawerData = editedButton.getDrawerData();
}
@Override
protected void hideUselessViews() {
(v.findViewById(R.id.editMapping_textView)).setVisibility(View.GONE);
checkPassThrough.setVisibility(View.GONE);
checkToggle.setVisibility(View.GONE);
checkBoxSwipeable.setVisibility(View.GONE);
(mRootView.findViewById(R.id.editMapping_textView)).setVisibility(View.GONE);
mPassthroughCheckbox.setVisibility(View.GONE);
mToggleCheckbox.setVisibility(View.GONE);
mSwipeableCheckbox.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);
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
mDynamicXEditText.setVisibility(View.GONE);
mDynamicYEditText.setVisibility(View.GONE);
}
@Override
protected void initializeEditDialog(Context ctx) {
super.initializeEditDialog(ctx);
spinnerOrientation = v.findViewById(R.id.editOrientation_spinner);
mOrientationSpinner = mRootView.findViewById(R.id.editOrientation_spinner);
ArrayAdapter<ControlDrawerData.Orientation> adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item);
adapter.addAll(ControlDrawerData.getOrientations());
adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
spinnerOrientation.setAdapter(adapter);
mOrientationSpinner.setAdapter(adapter);
}
@Override
protected void setEditDialogValues() {
super.setEditDialogValues();
spinnerOrientation.setSelection(ControlDrawerData.orientationToInt(drawerData.orientation));
mOrientationSpinner.setSelection(ControlDrawerData.orientationToInt(mDrawerData.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);
mDialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener(v -> {
ControlLayout layout = (ControlLayout) mDrawer.getParent();
ControlData controlData = new ControlData(mDrawerData.properties);
controlData.name = "new";
layout.addSubButton(drawer, controlData);
layout.addSubButton(mDrawer, controlData);
Context ctx = dialog.getContext();
Context ctx = mDialog.getContext();
Toast.makeText(ctx, ctx.getString(R.string.customctrl_add_subbutton_message,
drawer.getDrawerData().buttonProperties.size()), Toast.LENGTH_SHORT).show();
mDrawer.getDrawerData().buttonProperties.size()), Toast.LENGTH_SHORT).show();
});
}
@@ -78,13 +78,13 @@ public class EditControlDrawerPopup extends EditControlButtonPopup{
protected void setupDialogButtons() {
super.setupDialogButtons();
builder.setNeutralButton(v.getResources().getString(R.string.customctrl_addsubbutton), null);
mBuilder.setNeutralButton(mRootView.getResources().getString(R.string.customctrl_addsubbutton), null);
}
@Override
protected void saveProperties() {
drawerData.orientation = ControlDrawerData.intToOrientation(spinnerOrientation.getSelectedItemPosition());
mDrawerData.orientation = ControlDrawerData.intToOrientation(mOrientationSpinner.getSelectedItemPosition());
super.saveProperties();
}
}

View File

@@ -14,15 +14,15 @@ public class EditControlSubButtonPopup extends EditControlButtonPopup{
@Override
protected void hideUselessViews() {
(v.findViewById(R.id.editSize_textView)).setVisibility(View.GONE);
(v.findViewById(R.id.editOrientation_textView)).setVisibility(View.GONE);
(mRootView.findViewById(R.id.editSize_textView)).setVisibility(View.GONE);
(mRootView.findViewById(R.id.editOrientation_textView)).setVisibility(View.GONE);
checkDynamicPosition.setVisibility(View.GONE);
mDynamicPositionCheckbox.setVisibility(View.GONE);
(v.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
editDynamicX.setVisibility(View.GONE);
(mRootView.findViewById(R.id.editDynamicPositionX_textView)).setVisibility(View.GONE);
mDynamicXEditText.setVisibility(View.GONE);
(v.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
editDynamicY.setVisibility(View.GONE);
(mRootView.findViewById(R.id.editDynamicPositionY_textView)).setVisibility(View.GONE);
mDynamicYEditText.setVisibility(View.GONE);
}
}

View File

@@ -29,10 +29,8 @@ import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
public abstract class HandleView extends View implements ViewPositionListener, View.OnLongClickListener
{
public abstract class HandleView extends View implements ViewPositionListener, View.OnLongClickListener {
protected Drawable mDrawable;
protected Drawable mDrawableLtr;
protected Drawable mDrawableRtl;
private final PopupWindow mContainer;
// Position with respect to the parent TextView
@@ -65,12 +63,19 @@ public abstract class HandleView extends View implements ViewPositionListener, V
// int mWindowPosX, mWindowPosY;
private PositionListener mPositionListener;
public PositionListener getPositionListener() {
if (mPositionListener == null) {
mPositionListener = new PositionListener(mView);
}
return mPositionListener;
}
// Touch-up filter: number of previous positions remembered
private static final int HISTORY_SIZE = 5;
private static final int TOUCH_UP_FILTER_DELAY_AFTER = 150;
private static final int TOUCH_UP_FILTER_DELAY_BEFORE = 350;
private final long[] mPreviousOffsetsTimes = new long[HISTORY_SIZE];
private final int[] mPreviousOffsets = new int[HISTORY_SIZE];
private int mPreviousOffsetIndex = 0;
private int mNumberPreviousOffsets = 0;
// Addition
private float mDownX, mDownY;
public HandleView(ControlButton view) {
super(view.getContext());
@@ -86,8 +91,7 @@ public abstract class HandleView extends View implements ViewPositionListener, V
mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
mContainer.setContentView(this);
mDrawableLtr = view.getContext().getDrawable(R.drawable.text_select_handle_left_material);
mDrawableRtl = view.getContext().getDrawable(R.drawable.text_select_handle_right_material);
mDrawableRtl = view.getContext().getDrawable(R.drawable.ic_view_handle);
mMinSize = view.getContext().getResources().getDimensionPixelSize(R.dimen.text_handle_min_size);
setOnLongClickListener(this);
@@ -99,11 +103,103 @@ public abstract class HandleView extends View implements ViewPositionListener, V
mIdealVerticalOffset = 0.7f * handleHeight;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getPreferredWidth(), getPreferredHeight());
}
@Override
protected void onDraw(Canvas c) {
final int drawWidth = mDrawable.getIntrinsicWidth();
final int left = getHorizontalOffset();
mDrawable.setBounds(left, 0, left + drawWidth, mDrawable.getIntrinsicHeight());
mDrawable.draw(c);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
ViewGroup.LayoutParams params = mView.getLayoutParams();
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
startTouchUpFilter(getCurrentCursorOffset());
mTouchToWindowOffsetX = ev.getRawX() - mPositionX;
mTouchToWindowOffsetY = ev.getRawY() - mPositionY;
final PositionListener positionListener = getPositionListener();
mLastParentX = positionListener.getPositionX();
mLastParentY = positionListener.getPositionY();
mIsDragging = true;
// MOD: Addition
mDownX = ev.getRawX();
mDownY = ev.getRawY();
mDownWidth = params.width;
mDownHeight = params.height;
break;
}
case MotionEvent.ACTION_MOVE: {
final float rawX = ev.getRawX();
final float rawY = ev.getRawY();
// Vertical hysteresis: vertical down movement tends to snap to ideal offset
final float previousVerticalOffset = mTouchToWindowOffsetY - mLastParentY;
final float currentVerticalOffset = rawY - mPositionY - mLastParentY;
float newVerticalOffset;
if (previousVerticalOffset < mIdealVerticalOffset) {
newVerticalOffset = Math.min(currentVerticalOffset, mIdealVerticalOffset);
newVerticalOffset = Math.max(newVerticalOffset, previousVerticalOffset);
} else {
newVerticalOffset = Math.max(currentVerticalOffset, mIdealVerticalOffset);
newVerticalOffset = Math.min(newVerticalOffset, previousVerticalOffset);
}
mTouchToWindowOffsetY = newVerticalOffset + mLastParentY;
final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
final float newPosY = rawY - mTouchToWindowOffsetY + mTouchOffsetY;
int newWidth = (int) (mDownWidth + (rawX - mDownX));
int newHeight = (int) (mDownHeight + (rawY - mDownY));
// mDownX = rawX;
// mDownY = rawY;
params.width = Math.max(50, newWidth);
params.height = Math.max(50, newHeight);
mView.setLayoutParams(params);
updatePosition(newPosX, newPosY);
// break;
return true;
}
case MotionEvent.ACTION_UP:
filterOnTouchUp();
mIsDragging = false;
break;
case MotionEvent.ACTION_CANCEL:
mIsDragging = false;
break;
}
return true;
}
public PositionListener getPositionListener() {
if (mPositionListener == null) {
mPositionListener = new PositionListener(mView);
}
return mPositionListener;
}
protected void updateDrawable() {
// final int offset = getCurrentCursorOffset();
final boolean isRtlCharAtOffset = true; // mView.getLayout().isRtlCharAt(offset);
mDrawable = isRtlCharAtOffset ? mDrawableRtl : mDrawableLtr;
mDrawable = mDrawableRtl; //isRtlCharAtOffset ? mDrawableRtl : mDrawableLtr;
mHotspotX = getHotspotX(mDrawable, isRtlCharAtOffset);
mHorizontalGravity = getHorizontalGravity(isRtlCharAtOffset);
}
@@ -111,14 +207,7 @@ public abstract class HandleView extends View implements ViewPositionListener, V
protected abstract int getHotspotX(Drawable drawable, boolean isRtlRun);
protected abstract int getHorizontalGravity(boolean isRtlRun);
// Touch-up filter: number of previous positions remembered
private static final int HISTORY_SIZE = 5;
private static final int TOUCH_UP_FILTER_DELAY_AFTER = 150;
private static final int TOUCH_UP_FILTER_DELAY_BEFORE = 350;
private final long[] mPreviousOffsetsTimes = new long[HISTORY_SIZE];
private final int[] mPreviousOffsets = new int[HISTORY_SIZE];
private int mPreviousOffsetIndex = 0;
private int mNumberPreviousOffsets = 0;
private void startTouchUpFilter(int offset) {
mNumberPreviousOffsets = 0;
@@ -152,11 +241,6 @@ public abstract class HandleView extends View implements ViewPositionListener, V
return mNumberPreviousOffsets > 1;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getPreferredWidth(), getPreferredHeight());
}
private int getPreferredWidth() {
return Math.max(mDrawable.getIntrinsicWidth(), mMinSize);
}
@@ -283,15 +367,6 @@ public abstract class HandleView extends View implements ViewPositionListener, V
}
}
@Override
protected void onDraw(Canvas c) {
final int drawWidth = mDrawable.getIntrinsicWidth();
final int left = getHorizontalOffset();
mDrawable.setBounds(left, 0, left + drawWidth, mDrawable.getIntrinsicHeight());
mDrawable.draw(c);
}
private int getHorizontalOffset() {
final int width = getPreferredWidth();
final int drawWidth = mDrawable.getIntrinsicWidth();
@@ -315,81 +390,6 @@ public abstract class HandleView extends View implements ViewPositionListener, V
return 0;
}
// Addition
private float mDownX, mDownY;
@Override
public boolean onTouchEvent(MotionEvent ev) {
ViewGroup.LayoutParams params = mView.getLayoutParams();
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
startTouchUpFilter(getCurrentCursorOffset());
mTouchToWindowOffsetX = ev.getRawX() - mPositionX;
mTouchToWindowOffsetY = ev.getRawY() - mPositionY;
final PositionListener positionListener = getPositionListener();
mLastParentX = positionListener.getPositionX();
mLastParentY = positionListener.getPositionY();
mIsDragging = true;
// MOD: Addition
mDownX = ev.getRawX();
mDownY = ev.getRawY();
mDownWidth = params.width;
mDownHeight = params.height;
break;
}
case MotionEvent.ACTION_MOVE: {
final float rawX = ev.getRawX();
final float rawY = ev.getRawY();
// Vertical hysteresis: vertical down movement tends to snap to ideal offset
final float previousVerticalOffset = mTouchToWindowOffsetY - mLastParentY;
final float currentVerticalOffset = rawY - mPositionY - mLastParentY;
float newVerticalOffset;
if (previousVerticalOffset < mIdealVerticalOffset) {
newVerticalOffset = Math.min(currentVerticalOffset, mIdealVerticalOffset);
newVerticalOffset = Math.max(newVerticalOffset, previousVerticalOffset);
} else {
newVerticalOffset = Math.max(currentVerticalOffset, mIdealVerticalOffset);
newVerticalOffset = Math.min(newVerticalOffset, previousVerticalOffset);
}
mTouchToWindowOffsetY = newVerticalOffset + mLastParentY;
final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
final float newPosY = rawY - mTouchToWindowOffsetY + mTouchOffsetY;
int newWidth = (int) (mDownWidth + (rawX - mDownX));
int newHeight = (int) (mDownHeight + (rawY - mDownY));
// mDownX = rawX;
// mDownY = rawY;
params.width = Math.max(50, newWidth);
params.height = Math.max(50, newHeight);
mView.setLayoutParams(params);
updatePosition(newPosX, newPosY);
// break;
return true;
}
case MotionEvent.ACTION_UP:
filterOnTouchUp();
mIsDragging = false;
break;
case MotionEvent.ACTION_CANCEL:
mIsDragging = false;
break;
}
return true;
}
public boolean isDragging() {
return mIsDragging;
}

View File

@@ -25,8 +25,7 @@ import android.view.*;
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
public class SelectionEndHandleView extends HandleView
{
public class SelectionEndHandleView extends HandleView {
public SelectionEndHandleView(ControlButton view) {
super(view);
}

View File

@@ -20,5 +20,5 @@
package net.kdt.pojavlaunch.customcontrols.handleview;
public interface ViewPositionListener {
public void updatePosition(int parentPositionX, int parentPositionY, boolean parentPositionChanged, boolean parentScrolled);
void updatePosition(int parentPositionX, int parentPositionY, boolean parentPositionChanged, boolean parentScrolled);
}

View File

@@ -17,24 +17,24 @@ public final class ExtraCore {
private ExtraCore(){}
// Singleton instance
private static ExtraCore extraCoreSingleton = null;
private static ExtraCore sExtraCoreSingleton = null;
// Store the key-value pair
private final Map<String, Object> valueMap = new ConcurrentHashMap<>();
private final Map<String, Object> mValueMap = new ConcurrentHashMap<>();
// Store what each ExtraListener listen to
private final Map<String, ConcurrentLinkedQueue<WeakReference<ExtraListener>>> listenerMap = new ConcurrentHashMap<>();
private final Map<String, ConcurrentLinkedQueue<WeakReference<ExtraListener>>> mListenerMap = new ConcurrentHashMap<>();
// All public methods will pass through this one
private static ExtraCore getInstance(){
if(extraCoreSingleton == null){
if(sExtraCoreSingleton == null){
synchronized(ExtraCore.class){
if(extraCoreSingleton == null){
extraCoreSingleton = new ExtraCore();
if(sExtraCoreSingleton == null){
sExtraCoreSingleton = new ExtraCore();
}
}
}
return extraCoreSingleton;
return sExtraCoreSingleton;
}
/**
@@ -45,8 +45,8 @@ public final class ExtraCore {
public static void setValue(String key, Object value){
if(value == null || key == null) return; // null values create an NPE on insertion
getInstance().valueMap.put(key, value);
ConcurrentLinkedQueue<WeakReference<ExtraListener>> extraListenerList = getInstance().listenerMap.get(key);
getInstance().mValueMap.put(key, value);
ConcurrentLinkedQueue<WeakReference<ExtraListener>> extraListenerList = getInstance().mListenerMap.get(key);
if(extraListenerList == null) return; //No listeners
for(WeakReference<ExtraListener> listener : extraListenerList){
if(listener.get() == null){
@@ -63,17 +63,17 @@ public final class ExtraCore {
/** @return The value behind the key */
public static Object getValue(String key){
return getInstance().valueMap.get(key);
return getInstance().mValueMap.get(key);
}
/** Remove the key and its value from the valueMap */
public static void removeValue(String key){
getInstance().valueMap.remove(key);
getInstance().mValueMap.remove(key);
}
/** Remove all values */
public static void removeAllValues(){
getInstance().valueMap.clear();
getInstance().mValueMap.clear();
}
/**
@@ -82,11 +82,11 @@ public final class ExtraCore {
* @param listener The ExtraListener to link
*/
public static void addExtraListener(String key, ExtraListener listener){
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().listenerMap.get(key);
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().mListenerMap.get(key);
// Look for new sets
if(listenerList == null){
listenerList = new ConcurrentLinkedQueue<>();
getInstance().listenerMap.put(key, listenerList);
getInstance().mListenerMap.put(key, listenerList);
}
// This is kinda naive, I should look for duplicates
@@ -100,11 +100,11 @@ public final class ExtraCore {
* @param listener The ExtraListener to unlink
*/
public static void removeExtraListenerFromValue(String key, ExtraListener listener){
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().listenerMap.get(key);
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().mListenerMap.get(key);
// Look for new sets
if(listenerList == null){
listenerList = new ConcurrentLinkedQueue<>();
getInstance().listenerMap.put(key, listenerList);
getInstance().mListenerMap.put(key, listenerList);
}
// Removes all occurrences of ExtraListener and all null references
@@ -122,11 +122,11 @@ public final class ExtraCore {
* @param key The key to which ExtraListener are linked
*/
public static void removeAllExtraListenersFromValue(String key){
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().listenerMap.get(key);
ConcurrentLinkedQueue<WeakReference<ExtraListener>> listenerList = getInstance().mListenerMap.get(key);
// Look for new sets
if(listenerList == null){
listenerList = new ConcurrentLinkedQueue<>();
getInstance().listenerMap.put(key, listenerList);
getInstance().mListenerMap.put(key, listenerList);
}
listenerList.clear();
@@ -136,7 +136,7 @@ public final class ExtraCore {
* Remove all ExtraListeners from listening to any value
*/
public static void removeAllExtraListeners(){
getInstance().listenerMap.clear();
getInstance().mListenerMap.clear();
}
}

View File

@@ -2,6 +2,7 @@ package net.kdt.pojavlaunch.fragments;
import android.os.*;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.*;
import android.widget.*;
@@ -12,34 +13,33 @@ import android.graphics.*;
import androidx.fragment.app.Fragment;
public class ConsoleFragment extends Fragment
{
public TextView consoleView;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.lmaintab_consolelog, container, false);
public class ConsoleFragment extends Fragment {
public TextView mConsoleView;
consoleView = (TextView) view.findViewById(R.id.lmaintabconsoleLogTextView);
consoleView.setTypeface(Typeface.MONOSPACE);
consoleView.setHint(this.getText(R.string.main_nolog));
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_console_log, container, false);
mConsoleView = (TextView) view.findViewById(R.id.lmaintabconsoleLogTextView);
mConsoleView.setTypeface(Typeface.MONOSPACE);
mConsoleView.setHint(this.getText(R.string.main_nolog));
return view;
}
@Override
public void onResume()
{
public void onResume() {
super.onResume();
consoleView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogTextView);
mConsoleView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogTextView);
}
public void putLog(String str) {
if (consoleView == null) {
consoleView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogTextView);
if (mConsoleView == null) {
mConsoleView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogTextView);
}
consoleView.append(str);
mConsoleView.append(str);
}
}

View File

@@ -2,7 +2,10 @@ package net.kdt.pojavlaunch.fragments;
import android.os.*;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.Log;
import android.view.*;
import android.widget.*;
import java.io.*;
@@ -11,80 +14,76 @@ import net.kdt.pojavlaunch.*;
import android.graphics.*;
import androidx.fragment.app.Fragment;
public class CrashFragment extends Fragment
{
public static String lastCrashFile = Tools.DIR_DATA + "/lastcrash.txt";
private String crashContent;
private TextView crashView;
public boolean resetCrashLog = false;
public static boolean isNewCrash(File crashLog) throws Exception {
String content = Tools.read(crashLog.getAbsolutePath());
return crashLog != null && content.startsWith("---- Minecraft Crash Report ----");
}
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.lmaintab_crashlog, container, false);
public class CrashFragment extends Fragment {
public static String LAST_CRASH_FILE = Tools.DIR_DATA + "/lastcrash.txt";
return view;
}
@Override
public void onActivityCreated(Bundle b)
{
super.onActivityCreated(b);
crashView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogCrashTextView);
crashView.setTypeface(Typeface.MONOSPACE);
crashView.setHint(this.getText(R.string.main_nocrash));
private TextView mCrashView;
public boolean mResetCrashLog = false;
}
@Override
public void onResume()
{
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
return inflater.inflate(R.layout.fragment_crash_log, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mCrashView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogCrashTextView);
mCrashView.setTypeface(Typeface.MONOSPACE);
mCrashView.setHint(this.getText(R.string.main_nocrash));
}
@Override
public void onResume(){
super.onResume();
refreshCrashFile();
}
public void refreshCrashFile()
{
private void refreshCrashFile() {
// Default text
mCrashView.setText("");
setLastCrash("");
if(mResetCrashLog) return;
File crashLog = Tools.lastFileModified(Tools.DIR_HOME_CRASH);
String lastCrash = getLastCrash();
String crashContent;
try {
if(!resetCrashLog){
File crashLog = Tools.lastFileModified(Tools.DIR_HOME_CRASH);
String lastCrash = getLastCrash();
if (isNewCrash(crashLog)) {
crashContent = Tools.read(crashLog.getAbsolutePath());
Tools.write(crashLog.getAbsolutePath(), "\n" + crashContent);
setLastCrash(crashLog.getAbsolutePath());
crashView.setText(crashContent);
} else if(!lastCrash.isEmpty()) {
crashContent = Tools.read(lastCrash);
crashView.setText(crashContent);
} else throw new Exception();
} else throw new Exception();
} catch (Exception e) {
// Can't find crash or no NEW crashes
crashView.setText(""/*Log.getStackTraceString(e)*/);
setLastCrash("");
if (isNewCrash(crashLog)) {
crashContent = Tools.read(crashLog.getAbsolutePath());
Tools.write(crashLog.getAbsolutePath(), "\n" + crashContent);
setLastCrash(crashLog.getAbsolutePath());
mCrashView.setText(crashContent);
} else if(!lastCrash.isEmpty()) {
crashContent = Tools.read(lastCrash);
mCrashView.setText(crashContent);
}
}catch (IOException ioException){
Log.e("CrashFragment", ioException.toString());
}
}
public void setLastCrash(String newValue) {
private static boolean isNewCrash(File crashLog) throws IOException {
String content = Tools.read(crashLog.getAbsolutePath());
return crashLog != null && content.startsWith("---- Minecraft Crash Report ----");
}
private void setLastCrash(String newValue) {
try {
Tools.write(lastCrashFile, newValue);
} catch (Throwable th) {
throw new RuntimeException(th);
Tools.write(LAST_CRASH_FILE, newValue);
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
public String getLastCrash() {
private String getLastCrash() {
try {
return Tools.read(lastCrashFile);
} catch (Throwable th) {
return Tools.read(LAST_CRASH_FILE);
} catch (IOException ioException) {
return "";
}
}

View File

@@ -4,12 +4,12 @@ import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -25,74 +25,45 @@ import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Locale;
import java.util.Objects;
public class LauncherFragment extends Fragment
{
private WebView webNews;
private View view;
private Thread validUrlSelectorThread;
private String validChangelog = "/changelog.html";
private Handler mainHandler = new Handler(Looper.getMainLooper());
private boolean interruptLoad = false;
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
view = inflater.inflate(R.layout.lmaintab_news, container, false);
return view;
}
public void selectValidUrl() {
String lang = LauncherPreferences.PREF_LANGUAGE;
if(lang.equals("default")) lang = Locale.getDefault().getLanguage();
final String localizedUrl = "/changelog-"+lang+".html";
if(!tryUrl(Tools.URL_HOME+localizedUrl)) return;
else {
mainHandler.post(()->{
interruptLoad = true;
validChangelog = localizedUrl;
webNews.loadUrl(Tools.URL_HOME+validChangelog);
});
}
}
public boolean tryUrl(String url) {
Log.i("ChangelogLocale","Trying localized url: "+url);
try {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.connect();
Log.i("ChangelogLocale","Code: "+conn.getResponseCode());
return ("" + conn.getResponseCode()).startsWith("2");
}catch (IOException e) {
e.printStackTrace();
return false;
}
}
public class LauncherFragment extends Fragment {
private WebView mNewsWebview;
private View mRootView;
private Thread mValidUrlSelectorThread;
private String mValidChangelog = "/changelog.html";
private boolean mInterruptLoad = false;
@Override
public void onActivityCreated(Bundle p1)
{
super.onActivityCreated(p1);
mainHandler = new Handler(Looper.myLooper());
webNews = (WebView) getView().findViewById(R.id.lmaintabnewsNewsView);
webNews.setWebViewClient(new WebViewClient(){
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
mRootView = inflater.inflate(R.layout.fragment_news, container, false);
return mRootView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
mNewsWebview = (WebView) getView().findViewById(R.id.lmaintabnewsNewsView);
mNewsWebview.setWebViewClient(new WebViewClient(){
// API < 23
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Log.i("WebNews",failingUrl + ": "+description);
if(webNews != null){
if(validUrlSelectorThread.isAlive()) validUrlSelectorThread.interrupt();
removeWebView();
//Change the background to match the other pages.
//We change it only when the webView is removed to avoid huge overdraw.
LauncherFragment.this.view.setBackgroundColor(Color.parseColor("#44000000"));
}
if(mNewsWebview == null) return;
if(mValidUrlSelectorThread.isAlive()) mValidUrlSelectorThread.interrupt();
removeWebView();
//Change the background to match the other pages.
//We change it only when the webView is removed to avoid huge overdraw.
LauncherFragment.this.mRootView.setBackgroundColor(Color.parseColor("#44000000"));
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if(!url.equals(Tools.URL_HOME + validChangelog)){
if(!url.equals(Tools.URL_HOME + mValidChangelog)){
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(i);
return true;
@@ -104,17 +75,17 @@ public class LauncherFragment extends Fragment
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
Log.i("WebNews",error.getDescription()+"");
if(webNews != null){
if(validUrlSelectorThread.isAlive()) validUrlSelectorThread.interrupt();
removeWebView();
LauncherFragment.this.view.setBackgroundColor(Color.parseColor("#44000000"));
}
if(mNewsWebview == null) return;
if(mValidUrlSelectorThread.isAlive()) mValidUrlSelectorThread.interrupt();
removeWebView();
LauncherFragment.this.mRootView.setBackgroundColor(Color.parseColor("#44000000"));
}
@RequiresApi(23)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
if(!request.getUrl().toString().equals(Tools.URL_HOME + validChangelog)){
if(!request.getUrl().toString().equals(Tools.URL_HOME + mValidChangelog)){
Intent i = new Intent(Intent.ACTION_VIEW, request.getUrl());
startActivity(i);
return true;
@@ -122,36 +93,64 @@ public class LauncherFragment extends Fragment
return false;
}
});
webNews.clearCache(true);
webNews.getSettings().setJavaScriptEnabled(true);
validUrlSelectorThread = new Thread(this::selectValidUrl);
validUrlSelectorThread.start();
if(!interruptLoad)webNews.loadUrl(Tools.URL_HOME + validChangelog);
mNewsWebview.clearCache(true);
mNewsWebview.getSettings().setJavaScriptEnabled(true);
mValidUrlSelectorThread = new Thread(this::selectValidUrl);
mValidUrlSelectorThread.start();
if(!mInterruptLoad) mNewsWebview.loadUrl(Tools.URL_HOME + mValidChangelog);
}
private void selectValidUrl() {
String lang = LauncherPreferences.PREF_LANGUAGE;
if(lang.equals("default")) lang = Locale.getDefault().getLanguage();
final String localizedUrl = "/changelog-" + lang + ".html";
if(!tryUrl(Tools.URL_HOME+localizedUrl)) return;
requireActivity().runOnUiThread(() -> {
mInterruptLoad = true;
mValidChangelog = localizedUrl;
mNewsWebview.loadUrl(Tools.URL_HOME + mValidChangelog);
});
}
private boolean tryUrl(String url) {
Log.i("ChangelogLocale","Trying localized url: "+url);
try {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.connect();
Log.i("ChangelogLocale","Code: "+conn.getResponseCode());
return ("" + conn.getResponseCode()).startsWith("2");
}catch (IOException e) {
e.printStackTrace();
return false;
}
}
private void removeWebView() {
//Removing the parent which contain the webView crashes the viewPager.
//So I just try to "minimize" its impact on memory instead
webNews.clearHistory();
webNews.clearCache(true);
mNewsWebview.clearHistory();
mNewsWebview.clearCache(true);
// Loading a blank page is optional, but will ensure that the WebView isn't doing anything when you destroy it.
webNews.loadUrl("about:blank");
mNewsWebview.loadUrl("about:blank");
webNews.onPause();
webNews.removeAllViews();
webNews.destroyDrawingCache();
mNewsWebview.onPause();
mNewsWebview.removeAllViews();
mNewsWebview.destroyDrawingCache();
// make sure to call webNews.resumeTimers().
webNews.pauseTimers();
mNewsWebview.pauseTimers();
webNews.setVisibility(View.GONE);
mNewsWebview.setVisibility(View.GONE);
webNews.destroy();
mNewsWebview.destroy();
// Null out the reference so that you don't end up re-using it.
webNews = null;
mNewsWebview = null;
}

View File

@@ -14,31 +14,33 @@ import net.kdt.pojavlaunch.R;
public class MultiRTConfigDialog {
public static final int MULTIRT_PICK_RUNTIME = 2048;
public static final int MULTIRT_PICK_RUNTIME_STARTUP = 2049;
public AlertDialog dialog;
public RecyclerView dialogView;
public void prepare(BaseLauncherActivity ctx) {
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
public AlertDialog mDialog;
public RecyclerView mDialogView;
public void prepare(BaseLauncherActivity activity) {
mDialogView = new RecyclerView(activity);
mDialogView.setLayoutManager(new LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false));
mDialogView.setAdapter(new RTRecyclerViewAdapter(this));
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.multirt_config_title);
dialogView = new RecyclerView(ctx);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ctx);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
dialogView.setLayoutManager(linearLayoutManager);
dialogView.setAdapter(new RTRecyclerViewAdapter(this));
builder.setView(dialogView);
builder.setPositiveButton(R.string.multirt_config_add, (dialog, which) -> openRuntimeSelector(ctx,MULTIRT_PICK_RUNTIME));
builder.setView(mDialogView);
builder.setPositiveButton(R.string.multirt_config_add, (dialog, which) -> openRuntimeSelector(activity,MULTIRT_PICK_RUNTIME));
builder.setNegativeButton(R.string.mcn_exit_call, (dialog, which) -> dialog.cancel());
dialog = builder.create();
mDialog = builder.create();
}
public void refresh() {
RecyclerView.Adapter adapter = dialogView.getAdapter();
if(adapter != null)dialogView.getAdapter().notifyDataSetChanged();
RecyclerView.Adapter adapter = mDialogView.getAdapter();
if(adapter != null) mDialogView.getAdapter().notifyDataSetChanged();
}
public static void openRuntimeSelector(Activity ctx, int code) {
public static void openRuntimeSelector(Activity activity, int code) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("xz");
if(mimeType == null) mimeType = "*/*";
intent.setType(mimeType);
ctx.startActivityForResult(intent,code);
activity.startActivityForResult(intent,code);
}
}

View File

@@ -2,6 +2,7 @@ package net.kdt.pojavlaunch.multirt;
import android.content.Context;
import android.system.Os;
import android.util.Log;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
@@ -22,135 +23,102 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
public class MultiRTUtils {
public static HashMap<String,Runtime> cache = new HashMap<>();
public static class Runtime {
public Runtime(String name) {
this.name = name;
}
public String name;
public String versionString;
public String arch;
public int javaVersion;
public interface RuntimeProgressReporter {
void reportStringProgress(int resId, Object ... stuff);
}
private static final HashMap<String,Runtime> sCache = new HashMap<>();
private static final File RUNTIME_FOLDER = new File(Tools.MULTIRT_HOME);
private static final String JAVA_VERSION_STR = "JAVA_VERSION=\"";
private static final String OS_ARCH_STR = "OS_ARCH=\"";
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Runtime runtime = (Runtime) o;
return name.equals(runtime.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
public static interface ProgressReporterThingy {
void reportStringProgress(int resid, Object ... stuff);
}
private static final File runtimeFolder = new File(Tools.MULTIRT_HOME);
private static final String JAVA_VERSION_str = "JAVA_VERSION=\"";
private static final String OS_ARCH_str = "OS_ARCH=\"";
public static List<Runtime> getRuntimes() {
if(!runtimeFolder.exists()) runtimeFolder.mkdirs();
ArrayList<Runtime> ret = new ArrayList<>();
if(!RUNTIME_FOLDER.exists()) RUNTIME_FOLDER.mkdirs();
ArrayList<Runtime> runtimes = new ArrayList<>();
System.out.println("Fetch runtime list");
for(File f : runtimeFolder.listFiles()) {
ret.add(read(f.getName()));
for(File f : RUNTIME_FOLDER.listFiles()) {
runtimes.add(read(f.getName()));
}
return ret;
return runtimes;
}
public static String getExactJREName(int majorVersion) {
public static String getExactJreName(int majorVersion) {
List<Runtime> runtimes = getRuntimes();
for(Runtime r : runtimes) {
if(r.javaVersion == majorVersion) {
return r.name;
}
}
for(Runtime r : runtimes)
if(r.javaVersion == majorVersion)return r.name;
return null;
}
public static String getNearestJREName(int majorVersion) {
public static String getNearestJreName(int majorVersion) {
List<Runtime> runtimes = getRuntimes();
int diff_factor = Integer.MAX_VALUE;
String result = null;
for(Runtime r : runtimes) {
if(r.javaVersion >= majorVersion) { // lower - not useful
int currentFactor = r.javaVersion - majorVersion;
if(diff_factor > currentFactor) {
result = r.name;
diff_factor = currentFactor;
}
if(r.javaVersion < majorVersion) continue; // lower - not useful
int currentFactor = r.javaVersion - majorVersion;
if(diff_factor > currentFactor) {
result = r.name;
diff_factor = currentFactor;
}
}
return result;
}
public static void installRuntimeNamed(InputStream runtimeInputStream, String name, ProgressReporterThingy thingy) throws IOException {
File dest = new File(runtimeFolder,"/"+name);
public static void installRuntimeNamed(InputStream runtimeInputStream, String name, RuntimeProgressReporter progressReporter) throws IOException {
File dest = new File(RUNTIME_FOLDER,"/"+name);
File tmp = new File(dest,"temporary");
if(dest.exists()) FileUtils.deleteDirectory(dest);
dest.mkdirs();
FileOutputStream fos = new FileOutputStream(tmp);
thingy.reportStringProgress(R.string.multirt_progress_caching);
progressReporter.reportStringProgress(R.string.multirt_progress_caching);
IOUtils.copy(runtimeInputStream,fos);
fos.close();
runtimeInputStream.close();
uncompressTarXZ(tmp,dest,thingy);
uncompressTarXZ(tmp,dest,progressReporter);
tmp.delete();
read(name);
}
private static void __installRuntimeNamed__NoRM(InputStream runtimeInputStream, File dest, ProgressReporterThingy thingy) throws IOException {
File tmp = new File(dest,"temporary");
FileOutputStream fos = new FileOutputStream(tmp);
thingy.reportStringProgress(R.string.multirt_progress_caching);
IOUtils.copy(runtimeInputStream,fos);
fos.close();
runtimeInputStream.close();
uncompressTarXZ(tmp,dest,thingy);
tmp.delete();
}
public static void postPrepare(Context ctx, String name) throws IOException {
File dest = new File(runtimeFolder,"/"+name);
File dest = new File(RUNTIME_FOLDER,"/" + name);
if(!dest.exists()) return;
Runtime r = read(name);
Runtime runtime = read(name);
String libFolder = "lib";
if(new File(dest,libFolder+"/"+r.arch).exists()) libFolder = libFolder+"/"+r.arch;
File ftIn = new File(dest, libFolder+ "/libfreetype.so.6");
if(new File(dest,libFolder + "/" + runtime.arch).exists()) libFolder = libFolder + "/" + runtime.arch;
File ftIn = new File(dest, libFolder + "/libfreetype.so.6");
File ftOut = new File(dest, libFolder + "/libfreetype.so");
if (ftIn.exists() && (!ftOut.exists() || ftIn.length() != ftOut.length())) {
ftIn.renameTo(ftOut);
}
// Refresh libraries
copyDummyNativeLib(ctx,"libawt_xawt.so",dest,libFolder);
copyDummyNativeLib(ctx,"libawt_xawt.so", dest, libFolder);
}
private static void copyDummyNativeLib(Context ctx, String name, File dest, String libFolder) throws IOException {
File fileLib = new File(dest, "/"+libFolder + "/" + name);
fileLib.delete();
FileInputStream is = new FileInputStream(new File(ctx.getApplicationInfo().nativeLibraryDir, name));
FileOutputStream os = new FileOutputStream(fileLib);
IOUtils.copy(is, os);
is.close();
os.close();
}
public static Runtime installRuntimeNamedBinpack(InputStream universalFileInputStream, InputStream platformBinsInputStream, String name, String binpackVersion, ProgressReporterThingy thingy) throws IOException {
File dest = new File(runtimeFolder,"/"+name);
public static Runtime installRuntimeNamedBinpack(InputStream universalFileInputStream, InputStream platformBinsInputStream, String name, String binpackVersion, RuntimeProgressReporter thingy) throws IOException {
File dest = new File(RUNTIME_FOLDER,"/"+name);
if(dest.exists()) FileUtils.deleteDirectory(dest);
dest.mkdirs();
__installRuntimeNamed__NoRM(universalFileInputStream,dest,thingy);
__installRuntimeNamed__NoRM(platformBinsInputStream,dest,thingy);
File binpack_verfile = new File(runtimeFolder,"/"+name+"/pojav_version");
installRuntimeNamedNoRemove(universalFileInputStream,dest,thingy);
installRuntimeNamedNoRemove(platformBinsInputStream,dest,thingy);
File binpack_verfile = new File(RUNTIME_FOLDER,"/"+name+"/pojav_version");
FileOutputStream fos = new FileOutputStream(binpack_verfile);
fos.write(binpackVersion.getBytes());
fos.close();
cache.remove(name); // Force reread
sCache.remove(name); // Force reread
return read(name);
}
public static String __internal__readBinpackVersion(String name) {
File binpack_verfile = new File(runtimeFolder,"/"+name+"/pojav_version");
File binpack_verfile = new File(RUNTIME_FOLDER,"/"+name+"/pojav_version");
try {
if (binpack_verfile.exists()) {
return Tools.read(binpack_verfile.getAbsolutePath());
@@ -162,38 +130,42 @@ public class MultiRTUtils {
return null;
}
}
public static void removeRuntimeNamed(String name) throws IOException {
File dest = new File(runtimeFolder,"/"+name);
File dest = new File(RUNTIME_FOLDER,"/"+name);
if(dest.exists()) {
FileUtils.deleteDirectory(dest);
cache.remove(name);
sCache.remove(name);
}
}
public static void setRuntimeNamed(Context ctx, String name) throws IOException {
File dest = new File(runtimeFolder,"/"+name);
File dest = new File(RUNTIME_FOLDER,"/"+name);
if((!dest.exists()) || MultiRTUtils.forceReread(name).versionString == null) throw new RuntimeException("Selected runtime is broken!");
Tools.DIR_HOME_JRE = dest.getAbsolutePath();
JREUtils.relocateLibPath(ctx);
}
public static Runtime forceReread(String name) {
cache.remove(name);
sCache.remove(name);
return read(name);
}
public static Runtime read(String name) {
if(cache.containsKey(name)) return cache.get(name);
Runtime retur;
File release = new File(runtimeFolder,"/"+name+"/release");
if(sCache.containsKey(name)) return sCache.get(name);
Runtime returnRuntime;
File release = new File(RUNTIME_FOLDER,"/"+name+"/release");
if(!release.exists()) {
return new Runtime(name);
}
try {
String content = Tools.read(release.getAbsolutePath());
int _JAVA_VERSION_index = content.indexOf(JAVA_VERSION_str);
int _OS_ARCH_index = content.indexOf(OS_ARCH_str);
if(_JAVA_VERSION_index != -1 && _OS_ARCH_index != -1) {
_JAVA_VERSION_index += JAVA_VERSION_str.length();
_OS_ARCH_index += OS_ARCH_str.length();
String javaVersion = content.substring(_JAVA_VERSION_index,content.indexOf('"',_JAVA_VERSION_index));
int javaVersionIndex = content.indexOf(JAVA_VERSION_STR);
int osArchIndex = content.indexOf(OS_ARCH_STR);
if(javaVersionIndex != -1 && osArchIndex != -1) {
javaVersionIndex += JAVA_VERSION_STR.length();
osArchIndex += OS_ARCH_STR.length();
String javaVersion = content.substring(javaVersionIndex,content.indexOf('"', javaVersionIndex));
String[] javaVersionSplit = javaVersion.split("\\.");
int javaVersionInt;
if (javaVersionSplit[0].equals("1")) {
@@ -201,25 +173,46 @@ public class MultiRTUtils {
} else {
javaVersionInt = Integer.parseInt(javaVersionSplit[0]);
}
Runtime r = new Runtime(name);
r.arch = content.substring(_OS_ARCH_index,content.indexOf('"',_OS_ARCH_index));
r.javaVersion = javaVersionInt;
r.versionString = javaVersion;
retur = r;
Runtime runtime = new Runtime(name);
runtime.arch = content.substring(osArchIndex,content.indexOf('"', osArchIndex));
runtime.javaVersion = javaVersionInt;
runtime.versionString = javaVersion;
returnRuntime = runtime;
}else{
retur = new Runtime(name);
returnRuntime = new Runtime(name);
}
}catch(IOException e) {
retur = new Runtime(name);
returnRuntime = new Runtime(name);
}
cache.put(name,retur);
return retur;
sCache.put(name, returnRuntime);
return returnRuntime;
}
private static void uncompressTarXZ(final File tarFile, final File dest, final ProgressReporterThingy thingy) throws IOException {
dest.mkdirs();
TarArchiveInputStream tarIn = null;
tarIn = new TarArchiveInputStream(
private static void copyDummyNativeLib(Context ctx, String name, File dest, String libFolder) throws IOException {
File fileLib = new File(dest, "/"+libFolder + "/" + name);
fileLib.delete();
FileInputStream is = new FileInputStream(new File(ctx.getApplicationInfo().nativeLibraryDir, name));
FileOutputStream os = new FileOutputStream(fileLib);
IOUtils.copy(is, os);
is.close();
os.close();
}
private static void installRuntimeNamedNoRemove(InputStream runtimeInputStream, File dest, RuntimeProgressReporter progressReporter) throws IOException {
File tmp = new File(dest,"temporary");
FileOutputStream fos = new FileOutputStream(tmp);
progressReporter.reportStringProgress(R.string.multirt_progress_caching);
IOUtils.copy(runtimeInputStream,fos);
fos.close();
runtimeInputStream.close();
uncompressTarXZ(tmp,dest,progressReporter);
tmp.delete();
}
private static void uncompressTarXZ(final File tarFile, final File dest, final RuntimeProgressReporter thingy) throws IOException {
dest.mkdirs();
TarArchiveInputStream tarIn = new TarArchiveInputStream(
new XZCompressorInputStream(
new BufferedInputStream(
new FileInputStream(tarFile)
@@ -251,7 +244,7 @@ public class MultiRTUtils {
// Libcore one support all Android versions
Os.symlink(tarEntry.getName(), tarEntry.getLinkName());
} catch (Throwable e) {
e.printStackTrace();
Log.e("MultiRT", e.toString());
}
} else if (tarEntry.isDirectory()) {

View File

@@ -23,115 +23,126 @@ import java.io.IOException;
import java.util.List;
public class RTRecyclerViewAdapter extends RecyclerView.Adapter<RTRecyclerViewAdapter.RTViewHolder> {
MultiRTConfigDialog dialog;
MultiRTConfigDialog mConfigDialog;
public RTRecyclerViewAdapter(MultiRTConfigDialog dialog) {
this.dialog = dialog;
this.mConfigDialog = dialog;
}
@NonNull
@Override
public RTViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View recyclableView = LayoutInflater.from(parent.getContext()).inflate(R.layout.multirt_recyclable_view,parent,false);
View recyclableView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_multirt_runtime,parent,false);
return new RTViewHolder(recyclableView);
}
@Override
public void onBindViewHolder(@NonNull RTViewHolder holder, int position) {
final List<MultiRTUtils.Runtime> runtimes = MultiRTUtils.getRuntimes();
final List<Runtime> runtimes = MultiRTUtils.getRuntimes();
holder.bindRuntime(runtimes.get(position),position);
}
public boolean isDefaultRuntime(MultiRTUtils.Runtime rt) {
return LauncherPreferences.PREF_DEFAULT_RUNTIME.equals(rt.name);
}
public void setDefault(MultiRTUtils.Runtime rt){
LauncherPreferences.PREF_DEFAULT_RUNTIME = rt.name;
LauncherPreferences.DEFAULT_PREF.edit().putString("defaultRuntime",LauncherPreferences.PREF_DEFAULT_RUNTIME).apply();
RTRecyclerViewAdapter.this.notifyDataSetChanged();
}
@Override
public int getItemCount() {
return MultiRTUtils.getRuntimes().size();
}
public boolean isDefaultRuntime(Runtime rt) {
return LauncherPreferences.PREF_DEFAULT_RUNTIME.equals(rt.name);
}
public void setDefault(Runtime rt){
LauncherPreferences.PREF_DEFAULT_RUNTIME = rt.name;
LauncherPreferences.DEFAULT_PREF.edit().putString("defaultRuntime",LauncherPreferences.PREF_DEFAULT_RUNTIME).apply();
RTRecyclerViewAdapter.this.notifyDataSetChanged();
}
public class RTViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
final TextView javaVersionView;
final TextView fullJavaVersionView;
final ColorStateList defaultColors;
final Button setDefaultButton;
final Context ctx;
MultiRTUtils.Runtime currentRuntime;
int currentPosition;
final TextView mJavaVersionTextView;
final TextView mFullJavaVersionTextView;
final ColorStateList mDefaultColors;
final Button mSetDefaultButton;
final Context mContext;
Runtime mCurrentRuntime;
int mCurrentPosition;
public RTViewHolder(View itemView) {
super(itemView);
javaVersionView = itemView.findViewById(R.id.multirt_view_java_version);
fullJavaVersionView = itemView.findViewById(R.id.multirt_view_java_version_full);
mJavaVersionTextView = itemView.findViewById(R.id.multirt_view_java_version);
mFullJavaVersionTextView = itemView.findViewById(R.id.multirt_view_java_version_full);
mSetDefaultButton = itemView.findViewById(R.id.multirt_view_setdefaultbtn);
mSetDefaultButton.setOnClickListener(this);
mDefaultColors = mFullJavaVersionTextView.getTextColors();
mContext = itemView.getContext();
itemView.findViewById(R.id.multirt_view_removebtn).setOnClickListener(this);
setDefaultButton = itemView.findViewById(R.id.multirt_view_setdefaultbtn);
setDefaultButton.setOnClickListener(this);
defaultColors = fullJavaVersionView.getTextColors();
ctx = itemView.getContext();
}
public void bindRuntime(MultiRTUtils.Runtime rt, int pos) {
currentRuntime = rt;
currentPosition = pos;
if(rt.versionString != null && Tools.DEVICE_ARCHITECTURE == Architecture.archAsInt(rt.arch)) {
javaVersionView.setText(ctx.getString(R.string.multirt_java_ver, rt.name, rt.javaVersion));
fullJavaVersionView.setText(rt.versionString);
fullJavaVersionView.setTextColor(defaultColors);
setDefaultButton.setVisibility(View.VISIBLE);
boolean default_ = isDefaultRuntime(rt);
setDefaultButton.setEnabled(!default_);
setDefaultButton.setText(default_?R.string.multirt_config_setdefault_already:R.string.multirt_config_setdefault);
}else{
if(rt.versionString == null){
fullJavaVersionView.setText(R.string.multirt_runtime_corrupt);
}else{
fullJavaVersionView.setText(ctx.getString(R.string.multirt_runtime_incompatiblearch, rt.arch));
}
javaVersionView.setText(rt.name);
fullJavaVersionView.setTextColor(Color.RED);
setDefaultButton.setVisibility(View.GONE);
}
}
@Override
public void onClick(View v) {
if(v.getId() == R.id.multirt_view_removebtn) {
if (currentRuntime != null) {
if(MultiRTUtils.getRuntimes().size() < 2 && setDefaultButton.isShown()) {
AlertDialog.Builder bldr = new AlertDialog.Builder(ctx);
bldr.setTitle(R.string.global_error);
bldr.setMessage(R.string.multirt_config_removeerror_last);
bldr.setPositiveButton(android.R.string.ok,(adapter, which)->adapter.dismiss());
bldr.show();
return;
}
public void onClick(View view) {
if(view.getId() == R.id.multirt_view_removebtn) {
if (mCurrentRuntime == null) return;
final ProgressDialog barrier = new ProgressDialog(ctx);
barrier.setMessage(ctx.getString(R.string.global_waiting));
barrier.setProgressStyle(ProgressDialog.STYLE_SPINNER);
barrier.setCancelable(false);
barrier.show();
Thread t = new Thread(() -> {
try {
MultiRTUtils.removeRuntimeNamed(currentRuntime.name);
} catch (IOException e) {
Tools.showError(itemView.getContext(), e);
}
v.post(() -> {
if(isDefaultRuntime(currentRuntime)) setDefault(MultiRTUtils.getRuntimes().get(0));
barrier.dismiss();
RTRecyclerViewAdapter.this.notifyDataSetChanged();
dialog.dialog.show();
});
});
t.start();
if(MultiRTUtils.getRuntimes().size() < 2 && mSetDefaultButton.isShown()) {
AlertDialog.Builder bldr = new AlertDialog.Builder(mContext);
bldr.setTitle(R.string.global_error);
bldr.setMessage(R.string.multirt_config_removeerror_last);
bldr.setPositiveButton(android.R.string.ok,(adapter, which)->adapter.dismiss());
bldr.show();
return;
}
}else if(v.getId() == R.id.multirt_view_setdefaultbtn) {
if(currentRuntime != null) {
setDefault(currentRuntime);
final ProgressDialog barrier = new ProgressDialog(mContext);
barrier.setMessage(mContext.getString(R.string.global_waiting));
barrier.setProgressStyle(ProgressDialog.STYLE_SPINNER);
barrier.setCancelable(false);
barrier.show();
Thread t = new Thread(() -> {
try {
MultiRTUtils.removeRuntimeNamed(mCurrentRuntime.name);
} catch (IOException e) {
Tools.showError(itemView.getContext(), e);
}
view.post(() -> {
if(isDefaultRuntime(mCurrentRuntime)) setDefault(MultiRTUtils.getRuntimes().get(0));
barrier.dismiss();
RTRecyclerViewAdapter.this.notifyDataSetChanged();
mConfigDialog.mDialog.show();
});
});
t.start();
}else if(view.getId() == R.id.multirt_view_setdefaultbtn) {
if(mCurrentRuntime != null) {
setDefault(mCurrentRuntime);
RTRecyclerViewAdapter.this.notifyDataSetChanged();
}
}
}
public void bindRuntime(Runtime runtime, int pos) {
mCurrentRuntime = runtime;
mCurrentPosition = pos;
if(runtime.versionString != null && Tools.DEVICE_ARCHITECTURE == Architecture.archAsInt(runtime.arch)) {
mJavaVersionTextView.setText(mContext.getString(R.string.multirt_java_ver, runtime.name, runtime.javaVersion));
mFullJavaVersionTextView.setText(runtime.versionString);
mFullJavaVersionTextView.setTextColor(mDefaultColors);
mSetDefaultButton.setVisibility(View.VISIBLE);
boolean defaultRuntime = isDefaultRuntime(runtime);
mSetDefaultButton.setEnabled(!defaultRuntime);
mSetDefaultButton.setText(defaultRuntime ? R.string.multirt_config_setdefault_already:R.string.multirt_config_setdefault);
return;
}
// Problematic runtime moment
if(runtime.versionString == null){
mFullJavaVersionTextView.setText(R.string.multirt_runtime_corrupt);
}else{
mFullJavaVersionTextView.setText(mContext.getString(R.string.multirt_runtime_incompatiblearch, runtime.arch));
}
mJavaVersionTextView.setText(runtime.name);
mFullJavaVersionTextView.setTextColor(Color.RED);
mSetDefaultButton.setVisibility(View.GONE);
}
}
}

View File

@@ -16,39 +16,39 @@ import net.kdt.pojavlaunch.R;
import java.util.List;
public class RTSpinnerAdapter implements SpinnerAdapter {
final Context ctx;
List<MultiRTUtils.Runtime> runtimes;
public RTSpinnerAdapter(@NonNull Context context, List<MultiRTUtils.Runtime> runtimes) {
this.runtimes = runtimes;
MultiRTUtils.Runtime runtime = new MultiRTUtils.Runtime("<Default>");
final Context mContext;
List<Runtime> mRuntimes;
public RTSpinnerAdapter(@NonNull Context context, List<Runtime> runtimes) {
mRuntimes = runtimes;
Runtime runtime = new Runtime("<Default>");
runtime.versionString = "";
this.runtimes.add(runtime);
ctx = context;
mRuntimes.add(runtime);
mContext = context;
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
//STUB
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
//STUB
}
@Override
public int getCount() {
return runtimes.size();
return mRuntimes.size();
}
@Override
public Object getItem(int position) {
return runtimes.get(position);
return mRuntimes.get(position);
}
@Override
public long getItemId(int position) {
return runtimes.get(position).name.hashCode();
return mRuntimes.get(position).name.hashCode();
}
@Override
@@ -59,25 +59,25 @@ public class RTSpinnerAdapter implements SpinnerAdapter {
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View v = convertView!=null?
View view = convertView != null?
convertView:
LayoutInflater.from(ctx).inflate(R.layout.multirt_recyclable_view,parent,false);
LayoutInflater.from(mContext).inflate(R.layout.item_multirt_runtime,parent,false);
MultiRTUtils.Runtime rt = runtimes.get(position);
Runtime runtime = mRuntimes.get(position);
final TextView javaVersionView = v.findViewById(R.id.multirt_view_java_version);
final TextView fullJavaVersionView = v.findViewById(R.id.multirt_view_java_version_full);
v.findViewById(R.id.multirt_view_removebtn).setVisibility(View.GONE);
v.findViewById(R.id.multirt_view_setdefaultbtn).setVisibility(View.GONE);
final TextView javaVersionView = view.findViewById(R.id.multirt_view_java_version);
final TextView fullJavaVersionView = view.findViewById(R.id.multirt_view_java_version_full);
view.findViewById(R.id.multirt_view_removebtn).setVisibility(View.GONE);
view.findViewById(R.id.multirt_view_setdefaultbtn).setVisibility(View.GONE);
if(rt.versionString != null) {
javaVersionView.setText(ctx.getString(R.string.multirt_java_ver, rt.name, rt.javaVersion));
fullJavaVersionView.setText(rt.versionString);
if(runtime.versionString != null) {
javaVersionView.setText(mContext.getString(R.string.multirt_java_ver, runtime.name, runtime.javaVersion));
fullJavaVersionView.setText(runtime.versionString);
}else{
javaVersionView.setText(rt.name);
javaVersionView.setText(runtime.name);
fullJavaVersionView.setText(R.string.multirt_runtime_corrupt);
}
return v;
return view;
}
@Override
@@ -92,7 +92,7 @@ public class RTSpinnerAdapter implements SpinnerAdapter {
@Override
public boolean isEmpty() {
return runtimes.isEmpty();
return mRuntimes.isEmpty();
}
@Override

View File

@@ -0,0 +1,26 @@
package net.kdt.pojavlaunch.multirt;
import java.util.Objects;
public class Runtime {
public Runtime(String name) {
this.name = name;
}
public String name;
public String versionString;
public String arch;
public int javaVersion;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Runtime runtime = (Runtime) o;
return name.equals(runtime.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}

View File

@@ -20,9 +20,7 @@ import net.kdt.pojavlaunch.R;
/** Custom preference class displaying a dialog */
public class ControlOffsetPreference extends Preference {
private AlertDialog preferenceDialog;
private AlertDialog mPreferenceDialog;
public ControlOffsetPreference(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -34,43 +32,19 @@ public class ControlOffsetPreference extends Preference {
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();
mPreferenceDialog.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);
SeekBar topOffsetSeekbar = mPreferenceDialog.findViewById(R.id.control_offset_top_seekbar);
SeekBar rightOffsetSeekbar = mPreferenceDialog.findViewById(R.id.control_offset_right_seekbar);
SeekBar bottomOffsetSeekbar = mPreferenceDialog.findViewById(R.id.control_offset_bottom_seekbar);
SeekBar leftOffsetSeekbar = mPreferenceDialog.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);
TextView topOffsetTextView = mPreferenceDialog.findViewById(R.id.control_offset_top_textview);
TextView rightOffsetTextView = mPreferenceDialog.findViewById(R.id.control_offset_right_textview);
TextView bottomOffsetTextView = mPreferenceDialog.findViewById(R.id.control_offset_bottom_textview);
TextView leftOffsetTextView = mPreferenceDialog.findViewById(R.id.control_offset_left_textview);
SeekBar.OnSeekBarChangeListener seekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
@Override
@@ -118,15 +92,36 @@ public class ControlOffsetPreference extends Preference {
seekBarChangeListener.onProgressChanged(leftOffsetSeekbar, PREF_CONTROL_LEFT_OFFSET, false);
// Custom writing to preferences
preferenceDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(view -> {
mPreferenceDialog.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();
mPreferenceDialog.dismiss();
});
}
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.dialog_control_offset_preference);
dialogBuilder.setTitle(getContext().getString(R.string.control_offset_title));
dialogBuilder.setPositiveButton(android.R.string.ok, null);
dialogBuilder.setNegativeButton(android.R.string.cancel, null);
mPreferenceDialog = dialogBuilder.create();
}
}

View File

@@ -16,11 +16,11 @@ import net.kdt.pojavlaunch.R;
public class CustomSeekBarPreference extends SeekBarPreference {
/** The suffix displayed */
private String suffix = "";
private String mSuffix = "";
/** 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;
private TextView mTextView;
public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
@@ -37,7 +37,6 @@ public class CustomSeekBarPreference extends SeekBarPreference {
public CustomSeekBarPreference(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.seekBarPreferenceStyle);
}
public CustomSeekBarPreference(Context context) {
@@ -58,8 +57,8 @@ public class CustomSeekBarPreference extends SeekBarPreference {
TextView titleTextView = (TextView) view.findViewById(android.R.id.title);
titleTextView.setTextColor(Color.WHITE);
textView = (TextView) view.findViewById(R.id.seekbar_value);
textView.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
mTextView = (TextView) view.findViewById(R.id.seekbar_value);
mTextView.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
SeekBar seekBar = (SeekBar) view.findViewById(R.id.seekbar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@@ -71,7 +70,7 @@ public class CustomSeekBarPreference extends SeekBarPreference {
progress = progress * getSeekBarIncrement();
progress -= mMin;
textView.setText(String.valueOf(progress + mMin));
mTextView.setText(String.valueOf(progress + mMin));
updateTextViewWithSuffix();
}
@@ -94,20 +93,12 @@ public class CustomSeekBarPreference extends SeekBarPreference {
updateTextViewWithSuffix();
}
private void updateTextViewWithSuffix(){
if(!textView.getText().toString().endsWith(suffix)){
textView.setText(String.format("%s%s", textView.getText(), suffix));
}
}
/**
* Set a suffix to be appended on the TextView associated to the value
* @param suffix The suffix to append as a String
*/
public void setSuffix(String suffix) {
this.suffix = suffix;
this.mSuffix = suffix;
}
/**
@@ -119,4 +110,11 @@ public class CustomSeekBarPreference extends SeekBarPreference {
setMin(min);
setMax(max);
}
private void updateTextViewWithSuffix(){
if(!mTextView.getText().toString().endsWith(mSuffix)){
mTextView.setText(String.format("%s%s", mTextView.getText(), mSuffix));
}
}
}

View File

@@ -13,108 +13,112 @@ import androidx.appcompat.app.AlertDialog;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.multirt.RTSpinnerAdapter;
import net.kdt.pojavlaunch.tasks.RefreshVersionListTask;
import net.kdt.pojavlaunch.multirt.Runtime;
import net.kdt.pojavlaunch.value.PerVersionConfig;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class PerVersionConfigDialog{
final Context ctx;
final AlertDialog dialog;
final View v;
List<MultiRTUtils.Runtime> runtimes;
final Spinner javaVMSpinner;
final Spinner rendererSpinner;
final EditText customDirText;
final EditText jvmArgsEditText;
final List<String> renderNames;
String selectedGameVersion = null;
public PerVersionConfigDialog(Context _ctx) {
ctx = _ctx;
v = LayoutInflater.from(ctx).inflate(R.layout.pvc_popup,null);
javaVMSpinner = v.findViewById(R.id.pvc_javaVm);
rendererSpinner = v.findViewById(R.id.pvc_renderer);
{
List<String> renderList = new ArrayList<>();
Collections.addAll(renderList, ctx.getResources().getStringArray(R.array.renderer));
renderList.add("Default");
renderNames = Arrays.asList(ctx.getResources().getStringArray(R.array.renderer_values));
rendererSpinner.setAdapter(new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_dropdown_item,renderList));
}
customDirText = v.findViewById(R.id.pvc_customDir);
jvmArgsEditText = v.findViewById(R.id.pvc_jvmArgs);
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setView(v);
final Context mContext;
final AlertDialog mDialog;
final View mRootView;
List<Runtime> mRuntimes;
final Spinner mJvmSpinner;
final Spinner mRendererSpinner;
final EditText mCustomDirEditText;
final EditText mJvmArgsEditText;
final List<String> mRendererNames;
String mSelectedGameVersion = null;
public PerVersionConfigDialog(Context ctx) {
mContext = ctx;
mRootView = LayoutInflater.from(mContext).inflate(R.layout.dialog_per_version_control,null);
mJvmSpinner = mRootView.findViewById(R.id.pvc_javaVm);
mRendererSpinner = mRootView.findViewById(R.id.pvc_renderer);
ArrayList<String> renderList = new ArrayList<>(5);
Collections.addAll(renderList, mContext.getResources().getStringArray(R.array.renderer));
renderList.add("Default");
mRendererNames = Arrays.asList(mContext.getResources().getStringArray(R.array.renderer_values));
mRendererSpinner.setAdapter(new ArrayAdapter<>(mContext, android.R.layout.simple_spinner_dropdown_item, renderList));
mCustomDirEditText = mRootView.findViewById(R.id.pvc_customDir);
mJvmArgsEditText = mRootView.findViewById(R.id.pvc_jvmArgs);
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setView(mRootView);
builder.setTitle(R.string.pvc_title);
builder.setNegativeButton(android.R.string.cancel,(dialogInterface,i)->dialogInterface.dismiss());
builder.setPositiveButton(android.R.string.ok,this::save);
dialog = builder.create();
builder.setNegativeButton(android.R.string.cancel, null);
builder.setPositiveButton(android.R.string.ok, this::save);
mDialog = builder.create();
}
public void refreshRuntimes() {
if(runtimes!=null)runtimes.clear();
runtimes = MultiRTUtils.getRuntimes();
//runtimes.add(new MultiRTUtils.Runtime("<Default>"));
if(mRuntimes !=null) mRuntimes.clear();
mRuntimes = MultiRTUtils.getRuntimes();
//runtimes.add(new Runtime("<Default>"));
}
private void save(DialogInterface i, int which) {
if(selectedGameVersion == null) {
i.dismiss();
private void save(DialogInterface dialogInterface, int which) {
if(mSelectedGameVersion == null) {
dialogInterface.dismiss();
return;
}
PerVersionConfig.VersionConfig conf1 = PerVersionConfig.configMap.get(selectedGameVersion);
if(conf1==null){
conf1=new PerVersionConfig.VersionConfig();
PerVersionConfig.VersionConfig versionConfig = PerVersionConfig.configMap.get(mSelectedGameVersion);
if(versionConfig == null){
versionConfig = new PerVersionConfig.VersionConfig();
}
conf1.jvmArgs=jvmArgsEditText.getText().toString();
conf1.gamePath=customDirText.getText().toString();
versionConfig.jvmArgs= mJvmArgsEditText.getText().toString();
versionConfig.gamePath= mCustomDirEditText.getText().toString();
if(rendererSpinner.getSelectedItemPosition() == renderNames.size()) conf1.renderer = null;
else conf1.renderer = renderNames.get(rendererSpinner.getSelectedItemPosition());
if(mRendererSpinner.getSelectedItemPosition() == mRendererNames.size()) versionConfig.renderer = null;
else versionConfig.renderer = mRendererNames.get(mRendererSpinner.getSelectedItemPosition());
String runtime=((MultiRTUtils.Runtime)javaVMSpinner.getSelectedItem()).name;;
if(!runtime.equals("<Default>"))conf1.selectedRuntime=runtime;
else conf1.selectedRuntime=null;
String runtime=((Runtime) mJvmSpinner.getSelectedItem()).name;;
if(!runtime.equals("<Default>"))versionConfig.selectedRuntime=runtime;
else versionConfig.selectedRuntime = null;
PerVersionConfig.configMap.put(selectedGameVersion,conf1);
PerVersionConfig.configMap.put(mSelectedGameVersion, versionConfig);
try{
PerVersionConfig.update();
}catch(IOException e){
e.printStackTrace();
}
}
public boolean openConfig(String selectedVersion) {
selectedGameVersion = selectedVersion;
mSelectedGameVersion = selectedVersion;
try{
PerVersionConfig.update();
}catch(IOException e){
e.printStackTrace();
}
PerVersionConfig.VersionConfig conf=PerVersionConfig.configMap.get(selectedGameVersion);
PerVersionConfig.VersionConfig versionConfig = PerVersionConfig.configMap.get(mSelectedGameVersion);
refreshRuntimes();
javaVMSpinner.setAdapter(new RTSpinnerAdapter(ctx,runtimes));
{
int jvm_index = runtimes.indexOf(new MultiRTUtils.Runtime("<Default>"));
int rnd_index = rendererSpinner.getAdapter().getCount()-1;
if (conf != null) {
customDirText.setText(conf.gamePath);
jvmArgsEditText.setText(conf.jvmArgs);
if (conf.selectedRuntime != null) {
int nindex = runtimes.indexOf(new MultiRTUtils.Runtime(conf.selectedRuntime));
if (nindex != -1) jvm_index = nindex;
}
if(conf.renderer != null) {
int nindex = renderNames.indexOf(conf.renderer);
if (nindex != -1) rnd_index = nindex;
}
mJvmSpinner.setAdapter(new RTSpinnerAdapter(mContext, mRuntimes));
int jvmIndex = mRuntimes.indexOf(new Runtime("<Default>"));
int rendererIndex = mRendererSpinner.getAdapter().getCount()-1;
if (versionConfig != null) {
mCustomDirEditText.setText(versionConfig.gamePath);
mJvmArgsEditText.setText(versionConfig.jvmArgs);
if (versionConfig.selectedRuntime != null) {
int nIndex = mRuntimes.indexOf(new Runtime(versionConfig.selectedRuntime));
if (nIndex != -1) jvmIndex = nIndex;
}
if(versionConfig.renderer != null) {
int nIndex = mRendererNames.indexOf(versionConfig.renderer);
if (nIndex != -1) rendererIndex = nIndex;
}
javaVMSpinner.setSelection(jvm_index);
rendererSpinner.setSelection(rnd_index);
}
dialog.show();
mJvmSpinner.setSelection(jvmIndex);
mRendererSpinner.setSelection(rendererIndex);
mDialog.show();
return true;
}
}
}

View File

@@ -6,7 +6,6 @@ import android.util.AttributeSet;
import androidx.preference.Preference;
import net.kdt.pojavlaunch.BaseLauncherActivity;
import net.kdt.pojavlaunch.multirt.MultiRTConfigDialog;
public class RuntimeManagerPreference extends Preference{
public RuntimeManagerPreference(Context ctx) {
@@ -17,9 +16,10 @@ public class RuntimeManagerPreference extends Preference{
super(ctx, attrs);
setPersistent(false);
}
@Override
protected void onClick() {
super.onClick();
((BaseLauncherActivity)this.getContext()).mRuntimeConfigDialog.dialog.show();
((BaseLauncherActivity)this.getContext()).mRuntimeConfigDialog.mDialog.show();
}
}

View File

@@ -23,7 +23,7 @@ import java.util.Collections;
import java.util.LinkedList;
public class GameFolderProvider extends DocumentsProvider {
static File baseDir = new File(Tools.DIR_GAME_HOME);
static File sBaseDir = new File(Tools.DIR_GAME_HOME);
private static final String[] DEFAULT_ROOT_PROJECTION = new String[]{
Root.COLUMN_ROOT_ID,
Root.COLUMN_MIME_TYPES,
@@ -47,13 +47,13 @@ public class GameFolderProvider extends DocumentsProvider {
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
final MatrixCursor.RowBuilder row = result.newRow();
row.add(Root.COLUMN_ROOT_ID, baseDir.getAbsolutePath());
row.add(Root.COLUMN_DOCUMENT_ID, baseDir.getAbsolutePath());
row.add(Root.COLUMN_ROOT_ID, sBaseDir.getAbsolutePath());
row.add(Root.COLUMN_DOCUMENT_ID, sBaseDir.getAbsolutePath());
row.add(Root.COLUMN_SUMMARY, null);
row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_RECENTS | Root.FLAG_SUPPORTS_SEARCH);
row.add(Root.COLUMN_TITLE, getContext().getString(R.string.app_name));
row.add(Root.COLUMN_MIME_TYPES, "*/*");
row.add(Root.COLUMN_AVAILABLE_BYTES, baseDir.getFreeSpace());
row.add(Root.COLUMN_AVAILABLE_BYTES, sBaseDir.getFreeSpace());
row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
return result;
}
@@ -112,7 +112,7 @@ public class GameFolderProvider extends DocumentsProvider {
final File file = pending.removeFirst();
boolean isInsideGameDir;
try {
isInsideGameDir = file.getCanonicalPath().startsWith(baseDir.getCanonicalPath());
isInsideGameDir = file.getCanonicalPath().startsWith(sBaseDir.getCanonicalPath());
} catch (IOException e) {
isInsideGameDir = true;
}

View File

@@ -2,16 +2,15 @@ package net.kdt.pojavlaunch.tasks;
import android.app.*;
import android.content.*;
import android.content.res.AssetManager;
import android.graphics.*;
import android.os.*;
import android.util.*;
import com.google.gson.*;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.multirt.Runtime;
import net.kdt.pojavlaunch.prefs.*;
import net.kdt.pojavlaunch.utils.*;
import net.kdt.pojavlaunch.value.*;
@@ -280,7 +279,7 @@ public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable
setMax(assets.objects.size());
zeroProgress();
try {
downloadAssets(assets, verInfo.assets, assets.map_to_resources ? new File(Tools.OBSOLETE_RESOURCES_PATH) : new File(Tools.ASSETS_PATH));
downloadAssets(assets, verInfo.assets, assets.mapToResources ? new File(Tools.OBSOLETE_RESOURCES_PATH) : new File(Tools.ASSETS_PATH));
} catch (Exception e) {
e.printStackTrace();
@@ -382,7 +381,7 @@ public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable
}
@Override
protected void onPostExecute(Throwable p1)
public void onPostExecute(Throwable p1)
{
mActivity.mPlayButton.setText("Play");
mActivity.mPlayButton.setEnabled(true);
@@ -466,7 +465,7 @@ public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable
JAssetInfo asset = assetsObjects.get(assetKey);
assetsSizeBytes+=asset.size;
String assetPath = asset.hash.substring(0, 2) + "/" + asset.hash;
File outFile = assets.map_to_resources?new File(objectsDir,"/"+assetKey):new File(objectsDir, assetPath);
File outFile = assets.mapToResources ?new File(objectsDir,"/"+assetKey):new File(objectsDir, assetPath);
boolean skip = outFile.exists();// skip if the file exists
if(LauncherPreferences.PREF_CHECK_LIBRARY_SHA) //if sha checking is enabled
if(skip) skip = Tools.compareSHA1(outFile, asset.hash); //check hash
@@ -476,7 +475,7 @@ public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable
if(outFile.exists()) publishProgress("0",mActivity.getString(R.string.dl_library_sha_fail,assetKey));
executor.execute(()->{
try {
if (!assets.map_to_resources) {
if (!assets.mapToResources) {
downloadAsset(asset, objectsDir, downloadedSize);
} else {
downloadAssetMapped(asset, assetKey, outputDir, downloadedSize);

View File

@@ -1,7 +1,6 @@
package net.kdt.pojavlaunch.utils;
import static net.kdt.pojavlaunch.Architecture.ARCH_X86;
import static net.kdt.pojavlaunch.Architecture.archAsString;
import static net.kdt.pojavlaunch.Architecture.is64BitsDevice;
import static net.kdt.pojavlaunch.Tools.LOCAL_RENDERER;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_GLES_SHRINK_HACK;
@@ -15,7 +14,6 @@ import android.system.*;
import android.util.*;
import android.widget.Toast;
import com.kdt.LoggerView;
import com.oracle.dalvik.*;
import java.io.*;
import java.util.*;
@@ -32,21 +30,20 @@ public class JREUtils {
private JREUtils() {}
public static String LD_LIBRARY_PATH;
private static String nativeLibDir;
public static Map<String, String> jreReleaseList;
public static String jvmLibraryPath;
private static String sNativeLibDir;
public static String findInLdLibPath(String libName) {
if(Os.getenv("LD_LIBRARY_PATH")==null) {
try {
if (LD_LIBRARY_PATH != null) {
Os.setenv("LD_LIBRARY_PATH", LD_LIBRARY_PATH, true);
}else{
return libName;
}
}catch (ErrnoException e) {
e.printStackTrace();
return libName;
}
return libName;
}
for (String libPath : Os.getenv("LD_LIBRARY_PATH").split(":")) {
File f = new File(libPath, libName);
@@ -56,18 +53,22 @@ public class JREUtils {
}
return libName;
}
public static ArrayList<File> locateLibs(File path) {
ArrayList<File> ret = new ArrayList<>();
ArrayList<File> returnValue = new ArrayList<>();
File[] list = path.listFiles();
if(list != null) {for(File f : list) {
if(f.isFile() && f.getName().endsWith(".so")) {
ret.add(f);
}else if(f.isDirectory()) {
ret.addAll(locateLibs(f));
if(list != null) {
for(File f : list) {
if(f.isFile() && f.getName().endsWith(".so")) {
returnValue.add(f);
}else if(f.isDirectory()) {
returnValue.addAll(locateLibs(f));
}
}
}}
return ret;
}
return returnValue;
}
public static void initJavaRuntime() {
dlopen(findInLdLibPath("libjli.so"));
if(!dlopen("libjvm.so")){
@@ -86,13 +87,13 @@ public class JREUtils {
for(File f : locateLibs(new File(Tools.DIR_HOME_JRE + "/" + Tools.DIRNAME_HOME_JRE))) {
dlopen(f.getAbsolutePath());
}
dlopen(nativeLibDir + "/libopenal.so");
dlopen(sNativeLibDir + "/libopenal.so");
}
public static Map<String, String> readJREReleaseProperties() throws IOException {
return readJREReleaseProperties(Tools.DIR_HOME_JRE);
}
public static Map<String, String> readJREReleaseProperties(String name) throws IOException {
Map<String, String> jreReleaseMap = new ArrayMap<>();
if (!name.contains("/")) {
@@ -109,11 +110,11 @@ public class JREUtils {
jreReleaseReader.close();
return jreReleaseMap;
}
public static String jvmLibraryPath;
public static void redirectAndPrintJRELog(final Context ctx) {
public static void redirectAndPrintJRELog() {
Log.v("jrelog","Log starts here");
JREUtils.logToLogger(Logger.getInstance());
Thread t = new Thread(new Runnable(){
new Thread(new Runnable(){
int failTime = 0;
ProcessBuilder logcatPb;
@Override
@@ -128,16 +129,6 @@ public class JREUtils {
Log.i("jrelog-logcat","Starting logcat");
java.lang.Process p = logcatPb.start();
// idk which better, both have a bug that printf(\n) in a single line
/*
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
act.appendlnToLog(line);
}
reader.close();
*/
byte[] buf = new byte[1024];
int len;
while ((len = p.getInputStream().read(buf)) != -1) {
@@ -161,8 +152,7 @@ public class JREUtils {
Logger.getInstance().appendToLog("Exception on logging thread:\n" + Log.getStackTraceString(e));
}
}
});
t.start();
}).start();
Log.i("jrelog-logcat","Logcat thread started");
}
@@ -172,7 +162,7 @@ public class JREUtils {
JRE_ARCHITECTURE = "i386/i486/i586";
}
nativeLibDir = ctx.getApplicationInfo().nativeLibraryDir;
sNativeLibDir = ctx.getApplicationInfo().nativeLibraryDir;
for (String arch : JRE_ARCHITECTURE.split("/")) {
File f = new File(Tools.DIR_HOME_JRE, "lib/" + arch);
@@ -191,7 +181,7 @@ public class JREUtils {
"/system/" + libName + ":" +
"/vendor/" + libName + ":" +
"/vendor/" + libName + "/hw:" +
nativeLibDir
sNativeLibDir
);
LD_LIBRARY_PATH = ldLibraryPath.toString();
}
@@ -461,7 +451,7 @@ public class JREUtils {
Log.e("RENDER_LIBRARY","Failed to load renderer " + renderLibrary + ". Falling back to GL4ES 1.1.4");
LOCAL_RENDERER = "opengles2";
renderLibrary = "libgl4es_114.so";
dlopen(nativeLibDir + "/libgl4es_114.so");
dlopen(sNativeLibDir + "/libgl4es_114.so");
}
return renderLibrary;
}

View File

@@ -20,22 +20,21 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
public class MCOptionUtils
{
private static final HashMap<String,String> parameterMap = new HashMap<>();
private static final ArrayList<WeakReference<MCOptionListener>> optionListeners = new ArrayList<>();
private static FileObserver fileObserver;
public class MCOptionUtils {
private static final HashMap<String,String> sParameterMap = new HashMap<>();
private static final ArrayList<WeakReference<MCOptionListener>> sOptionListeners = new ArrayList<>();
private static FileObserver sFileObserver;
public interface MCOptionListener {
/** Called when an option is changed. Don't know which one though */
void onOptionChanged();
}
public static void load() {
if(fileObserver == null){
if(sFileObserver == null){
setupFileObserver();
}
parameterMap.clear();
sParameterMap.clear();
try {
BufferedReader reader = new BufferedReader(new FileReader(Tools.DIR_GAME_NEW + "/options.txt"));
@@ -46,7 +45,7 @@ public class MCOptionUtils
Log.w(Tools.APP_NAME, "No colon on line \""+line+"\", skipping");
continue;
}
parameterMap.put(line.substring(0,firstColonIndex), line.substring(firstColonIndex+1));
sParameterMap.put(line.substring(0,firstColonIndex), line.substring(firstColonIndex+1));
}
reader.close();
} catch (IOException e) {
@@ -55,16 +54,16 @@ public class MCOptionUtils
}
public static void set(String key, String value) {
parameterMap.put(key,value);
sParameterMap.put(key,value);
}
/** Set an array of String, instead of a simple value. Not supported on all options */
public static void set(String key, List<String> values){
parameterMap.put(key, values.toString());
sParameterMap.put(key, values.toString());
}
public static String get(String key){
return parameterMap.get(key);
return sParameterMap.get(key);
}
/** @return A list of values from an array stored as a string */
@@ -83,10 +82,10 @@ public class MCOptionUtils
public static void save() {
StringBuilder result = new StringBuilder();
for(String key : parameterMap.keySet())
for(String key : sParameterMap.keySet())
result.append(key)
.append(':')
.append(parameterMap.get(key))
.append(sParameterMap.get(key))
.append('\n');
try {
@@ -114,7 +113,7 @@ public class MCOptionUtils
* Listeners get notified of the change */
private static void setupFileObserver(){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
fileObserver = new FileObserver(new File(Tools.DIR_GAME_NEW + "/options.txt"), FileObserver.MODIFY) {
sFileObserver = new FileObserver(new File(Tools.DIR_GAME_NEW + "/options.txt"), FileObserver.MODIFY) {
@Override
public void onEvent(int i, @Nullable String s) {
MCOptionUtils.load();
@@ -122,7 +121,7 @@ public class MCOptionUtils
}
};
}else{
fileObserver = new FileObserver(Tools.DIR_GAME_NEW + "/options.txt", FileObserver.MODIFY) {
sFileObserver = new FileObserver(Tools.DIR_GAME_NEW + "/options.txt", FileObserver.MODIFY) {
@Override
public void onEvent(int i, @Nullable String s) {
MCOptionUtils.load();
@@ -131,12 +130,12 @@ public class MCOptionUtils
};
}
fileObserver.startWatching();
sFileObserver.startWatching();
}
/** Notify the option listeners */
public static void notifyListeners(){
for(WeakReference<MCOptionListener> weakReference : optionListeners){
for(WeakReference<MCOptionListener> weakReference : sOptionListeners){
MCOptionListener optionListener = weakReference.get();
if(optionListener == null) continue;
@@ -146,16 +145,16 @@ public class MCOptionUtils
/** Add an option listener, notice how we don't have a reference to it */
public static void addMCOptionListener(MCOptionListener listener){
optionListeners.add(new WeakReference<>(listener));
sOptionListeners.add(new WeakReference<>(listener));
}
/** Remove a listener from existence, or at least, its reference here */
public static void removeMCOptionListener(MCOptionListener listener){
for(WeakReference<MCOptionListener> weakReference : optionListeners){
for(WeakReference<MCOptionListener> weakReference : sOptionListeners){
MCOptionListener optionListener = weakReference.get();
if(optionListener == null) continue;
if(optionListener == listener){
optionListeners.remove(weakReference);
sOptionListeners.remove(weakReference);
return;
}
}

View File

@@ -95,15 +95,17 @@ public class V117CompatUtil {
Log.i("V117CompatDebug",rawList);
return new ArrayList<>(Arrays.asList(rawList.split(",")));
}
private static String regenPackList(List<String> packs) {
if(packs.size()==0) return "[]";
String ret = "["+packs.get(0);
StringBuilder ret = new StringBuilder("[" + packs.get(0));
for(int i = 1; i < packs.size(); i++) {
ret += ","+packs.get(i);
ret.append(",").append(packs.get(i));
}
ret += "]";
return ret;
ret.append("]");
return ret.toString();
}
public static void runCheck(String version, Activity ctx) throws Exception{
@@ -132,25 +134,25 @@ public class V117CompatUtil {
Object lock = new Object();
AtomicInteger proceed = new AtomicInteger(0);
ctx.runOnUiThread(() -> {
AlertDialog.Builder bldr = new AlertDialog.Builder(ctx);
bldr.setTitle(R.string.global_warinng);
bldr.setMessage(R.string.compat_117_message);
bldr.setPositiveButton(android.R.string.ok, (dialog, which) -> {
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setTitle(R.string.global_warinng);
builder.setMessage(R.string.compat_117_message);
builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
proceed.set(1);
synchronized (lock) { lock.notifyAll(); }
dialog.dismiss();
});
bldr.setNegativeButton(android.R.string.cancel, (dialog, which) -> {
builder.setNegativeButton(android.R.string.cancel, (dialog, which) -> {
synchronized (lock) { lock.notifyAll(); }
dialog.dismiss();
});
bldr.setNeutralButton(R.string.compat_11x_playanyway, (dialog, which) -> {
builder.setNeutralButton(R.string.compat_11x_playanyway, (dialog, which) -> {
proceed.set(2);
synchronized (lock) { lock.notifyAll(); }
dialog.dismiss();
});
bldr.setCancelable(false);
bldr.show();
builder.setCancelable(false);
builder.show();
});
synchronized (lock) {
@@ -182,6 +184,7 @@ public class V117CompatUtil {
throw new MinecraftDownloaderTask.SilentException();
}
}
public static void copyResourcePack(String gameDir, AssetManager am) throws IOException {
File resourcepacksDir = new File(gameDir,"resourcepacks");
if(!resourcepacksDir.exists()) resourcepacksDir.mkdirs();

View File

@@ -1,12 +1,8 @@
package org.lwjgl.glfw;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.*;
import android.os.Handler;
import android.os.Looper;
import android.widget.*;
import net.kdt.pojavlaunch.*;
import android.content.*;
@@ -20,6 +16,9 @@ public class CallbackBridge {
public static volatile int physicalWidth, physicalHeight;
public static float mouseX, mouseY;
public static StringBuilder DEBUG_STRING = new StringBuilder();
private static boolean threadAttached;
public volatile static boolean holdingAlt, holdingCapslock, holdingCtrl,
holdingNumlock, holdingShift;
public static void putMouseEventWithCoords(int button, float x, float y) {
@@ -34,7 +33,7 @@ public class CallbackBridge {
sendMouseKeycode(button, CallbackBridge.getCurrentMods(), isDown);
}
private static boolean threadAttached;
public static void sendCursorPos(float x, float y) {
if (!threadAttached) {
threadAttached = CallbackBridge.nativeAttachThreadToOther(true, BaseMainActivity.isInputStackCall);
@@ -158,43 +157,42 @@ public class CallbackBridge {
private static native void nativeSendData(boolean isAndroid, int type, String data);
*/
public volatile static boolean holdingAlt, holdingCapslock, holdingCtrl,
holdingNumlock, holdingShift;
public static int getCurrentMods() {
int currMods = 0;
if (holdingAlt) {
currMods |= LWJGLGLFWKeycode.GLFW_MOD_ALT;
currMods |= LwjglGlfwKeycode.GLFW_MOD_ALT;
} if (holdingCapslock) {
currMods |= LWJGLGLFWKeycode.GLFW_MOD_CAPS_LOCK;
currMods |= LwjglGlfwKeycode.GLFW_MOD_CAPS_LOCK;
} if (holdingCtrl) {
currMods |= LWJGLGLFWKeycode.GLFW_MOD_CONTROL;
currMods |= LwjglGlfwKeycode.GLFW_MOD_CONTROL;
} if (holdingNumlock) {
currMods |= LWJGLGLFWKeycode.GLFW_MOD_NUM_LOCK;
currMods |= LwjglGlfwKeycode.GLFW_MOD_NUM_LOCK;
} if (holdingShift) {
currMods |= LWJGLGLFWKeycode.GLFW_MOD_SHIFT;
currMods |= LwjglGlfwKeycode.GLFW_MOD_SHIFT;
}
return currMods;
}
public static void setModifiers(int keyCode, boolean isDown){
switch (keyCode){
case LWJGLGLFWKeycode.GLFW_KEY_LEFT_SHIFT:
case LwjglGlfwKeycode.GLFW_KEY_LEFT_SHIFT:
CallbackBridge.holdingShift = isDown;
return;
case LWJGLGLFWKeycode.GLFW_KEY_LEFT_CONTROL:
case LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL:
CallbackBridge.holdingCtrl = isDown;
return;
case LWJGLGLFWKeycode.GLFW_KEY_LEFT_ALT:
case LwjglGlfwKeycode.GLFW_KEY_LEFT_ALT:
CallbackBridge.holdingAlt = isDown;
return;
case LWJGLGLFWKeycode.GLFW_KEY_CAPS_LOCK:
case LwjglGlfwKeycode.GLFW_KEY_CAPS_LOCK:
CallbackBridge.holdingCapslock = isDown;
return;
case LWJGLGLFWKeycode.GLFW_KEY_NUM_LOCK:
case LwjglGlfwKeycode.GLFW_KEY_NUM_LOCK:
CallbackBridge.holdingNumlock = isDown;
return;
}
@@ -211,7 +209,8 @@ public class CallbackBridge {
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);
public static native void nativeSetWindowAttrib(int attrib, int value);
public static native boolean nativeIsGrabbing();
static {
System.loadLibrary("pojavexec");

View File

@@ -363,3 +363,21 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSendScroll(JNIEn
JNIEXPORT void JNICALL Java_org_lwjgl_glfw_GLFW_nglfwSetShowingWindow(JNIEnv* env, jclass clazz, jlong window) {
showingWindow = (long) window;
}
JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetWindowAttrib(JNIEnv* env, jclass clazz, jint attrib, jint value) {
if (!showingWindow) {
return; // nothing to do yet
}
jclass glfwClazz = (*runtimeJNIEnvPtr_ANDROID)->FindClass(runtimeJNIEnvPtr_ANDROID, "org/lwjgl/glfw/GLFW");
assert(glfwClazz != NULL);
jmethodID glfwMethod = (*runtimeJNIEnvPtr_ANDROID)->GetStaticMethodID(runtimeJNIEnvPtr_ANDROID, glfwMethod, "glfwSetWindowAttrib", "(JII)V");
assert(glfwMethod != NULL);
(*runtimeJNIEnvPtr_ANDROID)->CallStaticVoidMethod(
runtimeJNIEnvPtr_ANDROID,
glfwClazz, glfwMethod,
(jlong) showingWindow, attrib, value
);
}

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromXDelta="100%"
android:toXDelta="0%"/>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Some files were not shown because too many files have changed in this diff Show More