The TouchCharInput class can now use key sending strategies.

W.I.P: AWT key sender for the mod installer
Add ability to choose the either the TexturView ro SurfaceView
1:1 mapping of the touchpad in the mod installer
This commit is contained in:
SerpentSpirale 2022-03-23 22:39:12 +01:00 committed by Boulay Mathias
parent 146cc46121
commit 46ee7b33bc
15 changed files with 264 additions and 119 deletions

View file

@ -26,6 +26,8 @@ import java.io.*;
import java.util.*;
import net.kdt.pojavlaunch.customcontrols.*;
import net.kdt.pojavlaunch.customcontrols.keyboard.LwjglCharSender;
import net.kdt.pojavlaunch.customcontrols.keyboard.TouchCharInput;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.prefs.*;
@ -47,7 +49,7 @@ public class BaseMainActivity extends BaseActivity {
private boolean mIsResuming = false;
ControlLayout mControlLayout;
private MinecraftGLSurfaceView minecraftGLView;
private MinecraftGLSurface minecraftGLView;
private static Touchpad touchpad;
private LoggerView loggerView;
@ -71,6 +73,7 @@ public class BaseMainActivity extends BaseActivity {
// FIXME: is it safe fot multi thread?
GLOBAL_CLIPBOARD = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
touchCharInput = findViewById(R.id.mainTouchCharInput);
touchCharInput.setCharacterSender(new LwjglCharSender());
loggerView = findViewById(R.id.mainLoggerView);
mControlLayout = findViewById(R.id.main_control_layout);

View file

@ -9,6 +9,8 @@ import android.widget.*;
import java.io.*;
import java.util.*;
import net.kdt.pojavlaunch.customcontrols.keyboard.AwtCharSender;
import net.kdt.pojavlaunch.customcontrols.keyboard.TouchCharInput;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.prefs.*;
import net.kdt.pojavlaunch.utils.*;
@ -21,6 +23,7 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
private AWTCanvasView mTextureView;
private LoggerView mLoggerView;
private TouchCharInput mTouchCharInput;
private LinearLayout mTouchPad;
private ImageView mMousePointerImageView;
@ -35,6 +38,8 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
setContentView(R.layout.activity_java_gui_launcher);
Logger.getInstance().reset();
mTouchCharInput = findViewById(R.id.awt_touch_char);
mTouchCharInput.setCharacterSender(new AwtCharSender());
mTouchPad = findViewById(R.id.main_touchpad);
mLoggerView = findViewById(R.id.launcherLoggerView);
@ -53,7 +58,10 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
params.height = (int) (54 / 100f * LauncherPreferences.PREF_MOUSESCALE);
});
mTouchPad.setOnTouchListener((v, event) -> {
mTouchPad.setOnTouchListener(new View.OnTouchListener() {
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.
@ -62,14 +70,7 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
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;
}
float mouseX, mouseY;
mouseX = mMousePointerImageView.getX();
mouseY = mMousePointerImageView.getY();
@ -88,7 +89,10 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
// debugText.setText(CallbackBridge.DEBUG_STRING.toString());
CallbackBridge.DEBUG_STRING.setLength(0);
prevY = y;
prevX = x;
return true;
}
});
mTextureView.setOnTouchListener((v, event) -> {
@ -203,7 +207,7 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
}
void sendScaledMousePosition(float x, float y){
// Clamp positions, then scale them
// Clamp positions to the borders of the usable view, then scale them
x = androidx.core.math.MathUtils.clamp(x, mTextureView.getX(), mTextureView.getX() + mTextureView.getWidth());
y = androidx.core.math.MathUtils.clamp(y, mTextureView.getY(), mTextureView.getY() + mTextureView.getHeight());
@ -274,4 +278,8 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
mSkipDetectMod = true;
return launchJavaRuntime(modFile, javaArgs);
}
public void toggleKeyboard(View view) {
mTouchCharInput.switchKeyboardState();
}
}

View file

@ -9,21 +9,22 @@ import static org.lwjgl.glfw.CallbackBridge.windowWidth;
import android.app.Activity;
import android.content.Context;
import android.graphics.SurfaceTexture;
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.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
@ -40,13 +41,13 @@ import org.lwjgl.glfw.CallbackBridge;
/**
* Class dealing with showing minecraft surface and taking inputs to dispatch them to minecraft
*/
public class MinecraftGLSurfaceView extends SurfaceView {
public class MinecraftGLSurface extends View {
/* 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;
private final float mScaleFactor = LauncherPreferences.PREF_SCALE_FACTOR/100f;
/* Sensitivity, adjusted according to screen size */
private final double mSensitivityFactor = (1.4 * (1080f/ Tools.getDisplayMetrics((Activity) getContext()).heightPixels));
/* Use to detect simple and double taps */
@ -57,6 +58,8 @@ public class MinecraftGLSurfaceView extends SurfaceView {
private final MCOptionUtils.MCOptionListener mGuiScaleListener = () -> mGuiScale = getMcScale();
/* Surface ready listener, used by the activity to launch minecraft */
SurfaceReadyListener mSurfaceReadyListener = null;
/* View holding the surface, either a SurfaceView or a TextureView */
View mSurface;
/* List of hotbarKeys, used when clicking on the hotbar */
private static final int[] HOTBAR_KEYS = {
@ -112,11 +115,11 @@ public class MinecraftGLSurfaceView extends SurfaceView {
public MinecraftGLSurfaceView(Context context) {
public MinecraftGLSurface(Context context) {
this(context, null);
}
public MinecraftGLSurfaceView(Context context, AttributeSet attributeSet) {
public MinecraftGLSurface(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
setFocusable(true);
@ -132,41 +135,18 @@ public class MinecraftGLSurfaceView extends SurfaceView {
mPointerDebugTextView.setVisibility(GONE);
((ViewGroup)getParent()).addView(mPointerDebugTextView);
if(LauncherPreferences.PREF_USE_ALTERNATE_SURFACE){
SurfaceView surfaceView = new SurfaceView(getContext());
mSurface = surfaceView;
getHolder().addCallback(new SurfaceHolder.Callback() {
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
private boolean isCalled = false;
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
//Load Minecraft options:
MCOptionUtils.load();
MCOptionUtils.set("fullscreen", "off");
MCOptionUtils.set("overrideWidth", String.valueOf(windowWidth));
MCOptionUtils.set("overrideHeight", String.valueOf(windowHeight));
MCOptionUtils.save();
getMcScale();
// Resize stuff
if(isCalled){
//getHolder().setFixedSize(windowWidth, windowHeight);
//JREUtils.setupBridgeWindow(getHolder().getSurface());
return;
}
if(isCalled) return;
isCalled = true;
refreshSize();
JREUtils.setupBridgeWindow(getHolder().getSurface());
new Thread(() -> {
try {
Thread.sleep(200);
if(mSurfaceReadyListener != null){
mSurfaceReadyListener.isReady();
}
} catch (Throwable e) {
Tools.showError(getContext(), e, true);
}
}, "JVM Main thread").start();
realStart(surfaceView.getHolder().getSurface());
}
@Override
@ -179,9 +159,42 @@ public class MinecraftGLSurfaceView extends SurfaceView {
JREUtils.releaseBridgeWindow();
}
});
((ViewGroup)getParent()).addView(surfaceView);
}else{
TextureView textureView = new TextureView(getContext());
mSurface = textureView;
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
private boolean isCalled = false;
@Override
public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
if(isCalled) return;
isCalled = true;
realStart(new Surface(textureView.getSurfaceTexture()));
}
@Override
public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
refreshSize();
}
@Override
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
JREUtils.releaseBridgeWindow();
return true;
}
@Override
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {}
});
((ViewGroup)getParent()).addView(textureView);
}
}
/**
@ -588,22 +601,45 @@ public class MinecraftGLSurfaceView extends SurfaceView {
public void refreshSize(){
windowWidth = Tools.getDisplayFriendlyRes(Tools.currentDisplayMetrics.widthPixels, mScaleFactor);
windowHeight = Tools.getDisplayFriendlyRes(Tools.currentDisplayMetrics.heightPixels, mScaleFactor);
getHolder().setFixedSize(windowWidth, windowHeight);
// Set the new frame size
MCOptionUtils.load();
MCOptionUtils.set("overrideWidth", String.valueOf(windowWidth));
MCOptionUtils.set("overrideHeight", String.valueOf(windowHeight));
MCOptionUtils.save();
if(LauncherPreferences.PREF_USE_ALTERNATE_SURFACE){
((SurfaceView)mSurface).getHolder().setFixedSize(windowWidth, windowHeight);
}else{
((TextureView)mSurface).getSurfaceTexture().setDefaultBufferSize(windowWidth, windowHeight);
}
CallbackBridge.sendUpdateWindowSize(windowWidth, windowHeight);
getMcScale();
//getMcScale();
//Toast.makeText(getContext(), "width: " + width, Toast.LENGTH_SHORT).show();
//Toast.makeText(getContext(), "height: " + height, Toast.LENGTH_SHORT).show();
}
private void realStart(Surface surface){
// Initial size set
refreshSize();
//Load Minecraft options:
MCOptionUtils.load();
MCOptionUtils.set("fullscreen", "off");
MCOptionUtils.set("overrideWidth", String.valueOf(windowWidth));
MCOptionUtils.set("overrideHeight", String.valueOf(windowHeight));
MCOptionUtils.save();
getMcScale();
JREUtils.setupBridgeWindow(surface);
new Thread(() -> {
try {
Thread.sleep(200);
if(mSurfaceReadyListener != null){
mSurfaceReadyListener.isReady();
}
} catch (Throwable e) {
Tools.showError(getContext(), e, true);
}
}, "JVM Main thread").start();
}
/** A small interface called when the listener is ready for the first time */
public interface SurfaceReadyListener {
void isReady();

View file

@ -1,6 +1,6 @@
package net.kdt.pojavlaunch;
import static net.kdt.pojavlaunch.MinecraftGLSurfaceView.FINGER_SCROLL_THRESHOLD;
import static net.kdt.pojavlaunch.MinecraftGLSurface.FINGER_SCROLL_THRESHOLD;
import static net.kdt.pojavlaunch.Tools.currentDisplayMetrics;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.DEFAULT_PREF;

View file

@ -292,7 +292,7 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
case MotionEvent.ACTION_MOVE:
//Send the event to be taken as a mouse action
if(mProperties.passThruEnabled && CallbackBridge.isGrabbing()){
MinecraftGLSurfaceView v = ((ControlLayout) this.getParent()).findViewById(R.id.main_game_render_view);
MinecraftGLSurface v = ((ControlLayout) this.getParent()).findViewById(R.id.main_game_render_view);
if (v != null) v.dispatchTouchEvent(event);
}
@ -332,7 +332,7 @@ public class ControlButton extends androidx.appcompat.widget.AppCompatButton imp
case MotionEvent.ACTION_CANCEL: // 3
case MotionEvent.ACTION_POINTER_UP: // 6
if(mProperties.passThruEnabled){
MinecraftGLSurfaceView v = ((ControlLayout) this.getParent()).findViewById(R.id.main_game_render_view);
MinecraftGLSurface v = ((ControlLayout) this.getParent()).findViewById(R.id.main_game_render_view);
if (v != null) v.dispatchTouchEvent(event);
}
if(mIsPointerOutOfBounds) ((ControlLayout) getParent()).onTouch(this, event);

View file

@ -0,0 +1,22 @@
package net.kdt.pojavlaunch.customcontrols.keyboard;
import net.kdt.pojavlaunch.AWTInputBridge;
import net.kdt.pojavlaunch.AWTInputEvent;
/** Send chars via the AWT Bridgee */
public class AwtCharSender implements CharacterSenderStrategy {
@Override
public void sendBackspace() {
AWTInputBridge.sendKey(' ', AWTInputEvent.VK_BACK_SPACE);
}
@Override
public void sendEnter() {
AWTInputBridge.sendKey(' ', AWTInputEvent.VK_ENTER);
}
@Override
public void sendChar(char character) {
AWTInputBridge.sendKey(character, character);
}
}

View file

@ -0,0 +1,14 @@
package net.kdt.pojavlaunch.customcontrols.keyboard;
/** Simple interface for sending chars through whatever bridge will be necessary */
public interface CharacterSenderStrategy {
/** Called when there is a character to delete, may be called multiple times in a row */
void sendBackspace();
/** Called when we want to send enter specifically */
void sendEnter();
/** Called when there is a character to send, may be called multiple times in a row */
void sendChar(char character);
}

View file

@ -0,0 +1,25 @@
package net.kdt.pojavlaunch.customcontrols.keyboard;
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import org.lwjgl.glfw.CallbackBridge;
/** Sends keys via the CallBackBridge */
public class LwjglCharSender implements CharacterSenderStrategy {
@Override
public void sendBackspace() {
CallbackBridge.sendKeycode(LwjglGlfwKeycode.GLFW_KEY_BACKSPACE, '\u0008', 0, 0, true);
}
@Override
public void sendEnter() {
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_ENTER);
}
@Override
public void sendChar(char character) {
CallbackBridge.sendChar(character, 0);
}
}

View file

@ -1,4 +1,4 @@
package net.kdt.pojavlaunch.customcontrols;
package net.kdt.pojavlaunch.customcontrols.keyboard;
import static android.content.Context.INPUT_METHOD_SERVICE;
@ -37,6 +37,7 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
private boolean mIsDoingInternalChanges = false;
private CharacterSenderStrategy mCharacterSender;
/**
* We take the new chars, and send them to the game.
@ -47,14 +48,16 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
if(mIsDoingInternalChanges)return;
if(mCharacterSender != null){
for(int i=0; i < lengthBefore; ++i){
CallbackBridge.sendKeycode(LwjglGlfwKeycode.GLFW_KEY_BACKSPACE, '\u0008', 0, 0, true);
mCharacterSender.sendBackspace();
}
for(int i=start, count = 0; count < lengthAfter; ++i){
CallbackBridge.sendChar(text.charAt(i), 0);
mCharacterSender.sendChar(text.charAt(i));
++count;
}
}
//Reset the keyboard state
if(text.length() < 1) clear();
@ -121,9 +124,7 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
mIsDoingInternalChanges = false;
}
/**
* Regain ability to exist, take focus and have some text being input
*/
/** Regain ability to exist, take focus and have some text being input */
public void enable(){
setEnabled(true);
setFocusable(true);
@ -132,9 +133,7 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
}
/**
* Lose ability to exist, take focus and have some text being input
*/
/** Lose ability to exist, take focus and have some text being input */
public void disable(){
clear();
setVisibility(GONE);
@ -142,17 +141,18 @@ public class TouchCharInput extends androidx.appcompat.widget.AppCompatEditText
setEnabled(false);
}
/**
* Send the enter key.
*/
/** Send the enter key. */
private void sendEnter(){
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_ENTER);
mCharacterSender.sendEnter();
clear();
}
/**
* This function deals with anything that has to be executed when the constructor is called
*/
/** Just sets the char sender that should be used. */
public void setCharacterSender(CharacterSenderStrategy characterSender){
mCharacterSender = characterSender;
}
/** This function deals with anything that has to be executed when the constructor is called */
private void setup(){
setOnEditorActionListener((textView, i, keyEvent) -> {
sendEnter();

View file

@ -5,8 +5,7 @@ import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.utils.JREUtils;
public class LauncherPreferences
{
public class LauncherPreferences {
public static SharedPreferences DEFAULT_PREF;
public static String PREF_RENDERER = "opengles2";
@ -39,6 +38,8 @@ public class LauncherPreferences
public static boolean PREF_VIRTUAL_MOUSE_START = false;
public static boolean PREF_OPENGL_VERSION_HACK = false;
public static boolean PREF_ARC_CAPES = false;
public static boolean PREF_USE_ALTERNATE_SURFACE = true;
public static int PREF_SCALE_FACTOR = 100;
public static void loadPreferences(Context ctx) {
@ -73,6 +74,8 @@ public class LauncherPreferences
PREF_VIRTUAL_MOUSE_START = DEFAULT_PREF.getBoolean("mouse_start", false);
PREF_OPENGL_VERSION_HACK = DEFAULT_PREF.getBoolean("gles_version_hack", false);
PREF_ARC_CAPES = DEFAULT_PREF.getBoolean("arc_capes",false);
PREF_USE_ALTERNATE_SURFACE = DEFAULT_PREF.getBoolean("alternate_surface", false);
PREF_SCALE_FACTOR = DEFAULT_PREF.getInt("resolutionRatio", 100);
/*
if (PREF_CUSTOM_JAVA_ARGS.isEmpty()) {

View file

@ -3,6 +3,8 @@ package net.kdt.pojavlaunch.utils;
import static net.kdt.pojavlaunch.Architecture.ARCH_X86;
import static net.kdt.pojavlaunch.Architecture.is64BitsDevice;
import static net.kdt.pojavlaunch.Tools.LOCAL_RENDERER;
import static net.kdt.pojavlaunch.Tools.currentDisplayMetrics;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_BUTTONSIZE;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_GLES_SHRINK_HACK;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_OPENGL_VERSION_HACK;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_VBO_DISABLE_HACK;
@ -349,8 +351,8 @@ public class JREUtils {
//"-Dorg.lwjgl.util.DebugFunctions=true",
//"-Dorg.lwjgl.util.DebugLoader=true",
// GLFW Stub width height
"-Dglfwstub.windowWidth=" + CallbackBridge.windowWidth,
"-Dglfwstub.windowHeight=" + CallbackBridge.windowHeight,
"-Dglfwstub.windowWidth=" + Tools.getDisplayFriendlyRes(currentDisplayMetrics.widthPixels, LauncherPreferences.PREF_SCALE_FACTOR/100F),
"-Dglfwstub.windowHeight=" + Tools.getDisplayFriendlyRes(currentDisplayMetrics.heightPixels, LauncherPreferences.PREF_SCALE_FACTOR/100F),
"-Dglfwstub.initEgl=false",
"-Dext.net.resolvPath=" +resolvFile,
"-Dlog4j2.formatMsgNoLookups=true", //Log4j RCE mitigation

View file

@ -20,7 +20,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<net.kdt.pojavlaunch.MinecraftGLSurfaceView
<net.kdt.pojavlaunch.MinecraftGLSurface
android:id="@+id/main_game_render_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
@ -30,10 +30,11 @@
android:layout_width="match_parent"
android:orientation="vertical"
android:id="@+id/main_touchpad"
android:elevation="1dp"
android:visibility="gone"/>
<net.kdt.pojavlaunch.customcontrols.TouchCharInput
<net.kdt.pojavlaunch.customcontrols.keyboard.TouchCharInput
android:id="@+id/mainTouchCharInput"
android:layout_width="1dp"
android:layout_height="1dp"

View file

@ -11,6 +11,17 @@
android:layout_height="match_parent"
android:background="#000000">
<net.kdt.pojavlaunch.customcontrols.keyboard.TouchCharInput
android:id="@+id/awt_touch_char"
android:layout_width="1dp"
android:layout_height="1dp"
android:background="@android:color/darker_gray"
android:ems="10"
android:imeOptions="flagNoFullscreen|flagNoExtractUi|flagNoPersonalizedLearning|actionDone"
android:inputType="textFilter|textImeMultiLine|textAutoComplete|textAutoCorrect"
tools:ignore="TouchTargetSizeCheck"
/>
<net.kdt.pojavlaunch.AWTCanvasView
android:id="@+id/installmod_surfaceview"
android:layout_width="match_parent"
@ -74,6 +85,16 @@
app:layout_constraintRight_toLeftOf="@id/installmod_btn3"
app:layout_constraintTop_toBottomOf="@+id/installmod_btn3" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:background="@drawable/control_button"
android:text="Keyboard"
android:onClick="toggleKeyboard"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button2" />
<Button
android:id="@+id/installmod_mouse_pri"
android:layout_width="wrap_content"

View file

@ -71,6 +71,9 @@
<string name="mcl_option_settings">Settings</string>
<string name="mcl_option_about">About</string>
<string name="mcl_setting_title_use_surface_view">Use alternate surface rendering</string>
<string name="mcl_setting_subtitle_use_surface_view">May help performance in gpu bound scenarios</string>
<string name="mcl_setting_title_uninstalljre">Uninstall Java Runtime</string>
<string name="mcl_setting_subtitle_uninstalljre">[Launcher restart required] This let you re-install Java Runtime</string>
<string name="mcl_setting_title_freeform">Launch Minecraft in Freeform mode</string>

View file

@ -28,5 +28,12 @@
app2:selectable="false"
app2:seekBarIncrement="5"
app2:icon="@drawable/ic_setting_resolution_scaler"/>
<androidx.preference.SwitchPreferenceCompat
android:defaultValue="false"
android:key="alternate_surface"
android:summary="@string/mcl_setting_subtitle_use_surface_view"
android:title="@string/mcl_setting_title_use_surface_view"
/>
</PreferenceCategory>
</PreferenceScreen>