From 2919e1899fff80106084e8ba10264733c546ba0d Mon Sep 17 00:00:00 2001
From: Holden Ramsey <[EMAIL REDACTED]>
Date: Sat, 27 Jun 2026 13:53:46 -0400
Subject: [PATCH] Android: decouple JNI setup from unused subsystems
Query the natively compiled-in subsystems at runtime so the Java side
only registers and initializes the managers that exist, fixing
UnsatisfiedLinkError when SDL is built with a subsystem disabled
(e.g. -DSDL_AUDIO_DISABLED).
- Add SDL.setupJNI(int subsystems) plus SDL_INIT_* Java constants;
SDLActivity passes an overridable getInitSubsystems() mask so custom
activities can skip Java-side setup for unused subsystems.
- Distinguish compiled from requested subsystems: JNI registration
follows nativeGetCompiledSubsystems(), while manager initialization
and surface/layout creation follow the requested-and-compiled mask.
- Gate HIDDeviceManager.acquire() (USB/BLE device scanning) on a new
nativeIsHIDAPIEnabled() query so HIDAPI-less builds never touch it.
- Gate SDLControllerManager.initializeDeviceListener() and the
joystick key-event path on the controller subsystem; gate the
clipboard handler on video, mirroring the native guards.
- Guard the SDLControllerManager JNI bindings with
SDL_ANDROID_NEED_CONTROLLER_MANAGER (joystick or haptic enabled).
- Skip layout updates in ShowTextInputTask when no layout exists
(video disabled).
- Reorganize SDL_android.h/.c into guarded per-subsystem groups with
matching ordering.
---
.../app/src/main/java/org/libsdl/app/SDL.java | 36 +-
.../main/java/org/libsdl/app/SDLActivity.java | 92 +-
.../org/libsdl/app/SDLControllerManager.java | 36 +-
src/core/android/SDL_android.c | 2579 +++++++++--------
src/core/android/SDL_android.h | 92 +-
src/joystick/android/SDL_sysjoystick.c | 4 +
6 files changed, 1503 insertions(+), 1336 deletions(-)
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDL.java b/android-project/app/src/main/java/org/libsdl/app/SDL.java
index 097eb8cc873cc..a04f2c996c198 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDL.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDL.java
@@ -22,23 +22,29 @@ public class SDL {
public static final int SDL_INIT_EVERYTHING = SDL_INIT_AUDIO | SDL_INIT_VIDEO |
SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMEPAD | SDL_INIT_SENSOR | SDL_INIT_CAMERA;
+ // SDLControllerManager backs all three of these, so it is set up when any are present.
+ private static final int SDL_INIT_CONTROLLER = SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC;
+
private static int mInitializedSubsystems = SDL_INIT_EVERYTHING;
+ private static int mCompiledSubsystems = SDL_INIT_EVERYTHING;
static public void setupJNI() {
setupJNI(SDL_INIT_EVERYTHING);
}
- // Mask must match the native build's SDL_*_DISABLED flags: dropping SDL_INIT_AUDIO when the lib was built with audio stalls checkJNIReady() and SDL_SetMainReady() never fires.
static public void setupJNI(int subsystems) {
- mInitializedSubsystems = subsystems;
-
SDLActivity.nativeSetupJNI();
- if ((subsystems & SDL_INIT_AUDIO) != 0) {
+ mCompiledSubsystems = SDLActivity.nativeGetCompiledSubsystems();
+ mInitializedSubsystems = (subsystems & mCompiledSubsystems);
+
+ if (isSubsystemCompiled(SDL_INIT_AUDIO)) {
SDLAudioManager.nativeSetupJNI();
}
- SDLControllerManager.nativeSetupJNI();
+ if (isSubsystemCompiled(SDL_INIT_CONTROLLER)) {
+ SDLControllerManager.nativeSetupJNI();
+ }
}
static public void initialize() {
@@ -50,16 +56,30 @@ static public void initialize(int subsystems) {
SDLActivity.initialize();
- if ((subsystems & SDL_INIT_AUDIO) != 0) {
+ if (isSubsystemCompiled(SDL_INIT_AUDIO)) {
SDLAudioManager.initialize();
}
- SDLControllerManager.initialize();
+ if (isSubsystemCompiled(SDL_INIT_CONTROLLER)) {
+ SDLControllerManager.initialize();
+ }
+ }
+
+ static boolean isSubsystemInitialized(int subsystem) {
+ return (mInitializedSubsystems & subsystem) != 0;
+ }
+
+ static boolean isSubsystemCompiled(int subsystem) {
+ return (mCompiledSubsystems & subsystem) != 0;
+ }
+
+ static boolean isControllerManagerReady() {
+ return isSubsystemInitialized(SDL_INIT_CONTROLLER);
}
// This function stores the current activity (SDL or not)
static public void setContext(Activity context) {
- if ((mInitializedSubsystems & SDL_INIT_AUDIO) != 0) {
+ if (isSubsystemCompiled(SDL_INIT_AUDIO)) {
SDLAudioManager.setContext(context);
}
mContext = context;
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
index 00df5f0864add..31c3b267c28e4 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
@@ -337,6 +337,20 @@ protected String[] getArguments() {
return new String[0];
}
+ /**
+ * This method returns the SDL_INIT_* subsystems this activity should set up on the Java side.
+ * It can be overridden to skip the surface/layout creation, device listener and input event
+ * routing for unused subsystems. Manager JNI setup always follows the subsystems compiled
+ * into the native library, regardless of this mask. The native app must not SDL_Init() a
+ * subsystem excluded here: it would initialize without Java-side events (no window surface,
+ * no controller hotplug or input). Called from onCreate(); overrides must not depend on
+ * state the subclass assigns after super.onCreate().
+ * @return mask of SDL.SDL_INIT_* values.
+ */
+ protected int getInitSubsystems() {
+ return SDL.SDL_INIT_EVERYTHING;
+ }
+
public static void initialize() {
// The static nature of the singleton and Android quirkyness force us to initialize everything here
// Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values
@@ -458,7 +472,7 @@ public void onClick(DialogInterface dialog,int id) {
}
// Set up JNI
- SDL.setupJNI();
+ SDL.setupJNI(getInitSubsystems());
// Initialize state
SDL.initialize();
@@ -467,22 +481,30 @@ public void onClick(DialogInterface dialog,int id) {
mSingleton = this;
SDL.setContext(this);
- SDLControllerManager.initializeDeviceListener();
+ if (SDL.isControllerManagerReady()) {
+ SDLControllerManager.initializeDeviceListener();
+ }
- mClipboardHandler = new SDLClipboardHandler();
+ if (SDL.isSubsystemCompiled(SDL.SDL_INIT_VIDEO)) {
+ mClipboardHandler = new SDLClipboardHandler();
+ }
- mHIDDeviceManager = HIDDeviceManager.acquire(this);
+ if (nativeIsHIDAPIEnabled()) {
+ mHIDDeviceManager = HIDDeviceManager.acquire(this);
+ }
// Set up the surface
- mSurface = createSDLSurface(this);
+ if (SDL.isSubsystemInitialized(SDL.SDL_INIT_VIDEO)) {
+ mSurface = createSDLSurface(this);
- mLayout = new RelativeLayout(this);
- mLayout.addView(mSurface);
+ mLayout = new RelativeLayout(this);
+ mLayout.addView(mSurface);
- // Get our current screen orientation and pass it down.
- SDLActivity.nativeSetNaturalOrientation(SDLActivity.getNaturalOrientation());
- mCurrentRotation = SDLActivity.getCurrentRotation();
- SDLActivity.onNativeRotationChanged(mCurrentRotation);
+ // Get our current screen orientation and pass it down.
+ SDLActivity.nativeSetNaturalOrientation(SDLActivity.getNaturalOrientation());
+ mCurrentRotation = SDLActivity.getCurrentRotation();
+ SDLActivity.onNativeRotationChanged(mCurrentRotation);
+ }
try {
if (Build.VERSION.SDK_INT < 24 /* Android 7.0 (N) */) {
@@ -502,19 +524,22 @@ public void onClick(DialogInterface dialog,int id) {
break;
}
- setContentView(mLayout);
-
- setWindowStyle(false);
+ if (mLayout != null) {
+ setContentView(mLayout);
+ setWindowStyle(false);
+ }
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this);
// Get filename from "Open with" of another application
- Intent intent = getIntent();
- if (intent != null && intent.getData() != null) {
- String filename = intent.getData().getPath();
- if (filename != null) {
- Log.v(TAG, "Got filename: " + filename);
- SDLActivity.onNativeDropFile(filename);
+ if (SDL.isSubsystemInitialized(SDL.SDL_INIT_VIDEO)) {
+ Intent intent = getIntent();
+ if (intent != null && intent.getData() != null) {
+ String filename = intent.getData().getPath();
+ if (filename != null) {
+ Log.v(TAG, "Got filename: " + filename);
+ SDLActivity.onNativeDropFile(filename);
+ }
}
}
}
@@ -886,21 +911,27 @@ public static void handleNativeState() {
// Try a transition to resumed state
if (mNextNativeState == NativeState.RESUMED) {
- if (mSurface.mIsSurfaceReady && (mHasFocus || mHasMultiWindow) && mIsResumedCalled) {
+ boolean readyToRun = (mSurface == null) ? mIsResumedCalled
+ : (mSurface.mIsSurfaceReady && (mHasFocus || mHasMultiWindow) && mIsResumedCalled);
+ if (readyToRun) {
if (mSDLThread == null) {
// This is the entry point to the C app.
// Start up the C app thread and enable sensor input for the first time
// FIXME: Why aren't we enabling sensor input at start?
mSDLThread = new Thread(new SDLMain(), "SDLThread");
- mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
+ if (mSurface != null) {
+ mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
+ }
mSDLThread.start();
// No nativeResume(), don't signal Android_ResumeSem
} else {
nativeResume();
}
- mSurface.handleResume();
+ if (mSurface != null) {
+ mSurface.handleResume();
+ }
mCurrentNativeState = mNextNativeState;
}
@@ -1058,7 +1089,8 @@ protected boolean sendCommand(int command, Object data) {
DisplayMetrics realMetrics = new DisplayMetrics();
display.getRealMetrics(realMetrics);
- boolean bFullscreenLayout = ((realMetrics.widthPixels == mSurface.getWidth()) &&
+ boolean bFullscreenLayout = (mSurface != null) &&
+ ((realMetrics.widthPixels == mSurface.getWidth()) &&
(realMetrics.heightPixels == mSurface.getHeight()));
if ((Integer) data == 1) {
@@ -1102,6 +1134,8 @@ protected boolean sendCommand(int command, Object data) {
// C functions we call
public static native String nativeGetVersion();
public static native void nativeSetupJNI();
+ public static native int nativeGetCompiledSubsystems();
+ public static native boolean nativeIsHIDAPIEnabled();
public static native void nativeInitMainThread();
public static native void nativeCleanupMainThread();
public static native int nativeRunMain(String library, String function, Object arguments);
@@ -1486,6 +1520,10 @@ public ShowTextInputTask(int input_type, int x, int y, int w, int h) {
@Override
public void run() {
+ if (mLayout == null) {
+ return;
+ }
+
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(w, h + HEIGHT_PADDING);
params.leftMargin = x;
params.topMargin = y;
@@ -1515,6 +1553,10 @@ public void run() {
* This method is called by SDL using JNI.
*/
public static boolean showTextInput(int input_type, int x, int y, int w, int h) {
+ if (mLayout == null) {
+ return false;
+ }
+
// Transfer the task to the main thread as a Runnable
return mSingleton.commandHandler.post(new ShowTextInputTask(input_type, x, y, w, h));
}
@@ -1553,7 +1595,7 @@ public static boolean handleKeyEvent(View v, int keyCode, KeyEvent event, InputC
// Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
// SOURCE_JOYSTICK, while its key events arrive from the keyboard source
// So, retrieve the device itself and check all of its sources
- if (SDLControllerManager.isDeviceSDLJoystick(device)) {
+ if (SDL.isControllerManagerReady() && SDLControllerManager.isDeviceSDLJoystick(device)) {
// Note that we process events with specific key codes here
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (SDLControllerManager.onNativePadDown(deviceId, keyCode, event.getScanCode())) {
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
index 0e6c20494584b..e5b0b864606aa 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
@@ -60,7 +60,7 @@ static void initialize() {
mJoystickHandler = new SDLJoystickHandler();
}
- if (mHapticHandler == null) {
+ if (mHapticHandler == null && SDL.isSubsystemCompiled(SDL.SDL_INIT_HAPTIC)) {
if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
mHapticHandler = new SDLHapticHandler_API31();
} else if (Build.VERSION.SDK_INT >= 26 /* Android 8.0 (O) */) {
@@ -90,7 +90,7 @@ static public void shutdownDeviceListener() {
// Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
static public boolean handleJoystickMotionEvent(MotionEvent event) {
- return mJoystickHandler.handleMotionEvent(event);
+ return mJoystickHandler != null && mJoystickHandler.handleMotionEvent(event);
}
/**
@@ -118,21 +118,27 @@ static void joystickSetSensorsEnabled(int device_id, boolean enabled) {
* This method is called by SDL using JNI.
*/
static void detectHapticDevices() {
- mHapticHandler.detectHapticDevices();
+ if (mHapticHandler != null) {
+ mHapticHandler.detectHapticDevices();
+ }
}
/**
* This method is called by SDL using JNI.
*/
static void hapticRun(int device_id, float intensity, int length) {
- mHapticHandler.run(device_id, intensity, length);
+ if (mHapticHandler != null) {
+ mHapticHandler.run(device_id, intensity, length);
+ }
}
/**
* This method is called by SDL using JNI.
*/
static void hapticRumble(int device_id, float low_frequency_intensity, float high_frequency_intensity, int length) {
- mHapticHandler.rumble(device_id, low_frequency_intensity, high_frequency_intensity, length);
+ if (mHapticHandler != null) {
+ mHapticHandler.rumble(device_id, low_frequency_intensity, high_frequency_intensity, length);
+ }
}
/**
@@ -140,7 +146,9 @@ static void hapticRumble(int device_id, float low_frequency_intensity, float hig
*/
static void hapticStop(int device_id)
{
- mHapticHandler.stop(device_id);
+ if (mHapticHandler != null) {
+ mHapticHandler.stop(device_id);
+ }
}
// Check if a given device is considered a possible SDL joystick
@@ -977,10 +985,13 @@ boolean setRelativeMouseEnabled(boolean enabled) {
}
if (!SDLActivity.isDeXMode() || Build.VERSION.SDK_INT >= 27 /* Android 8.1 (O_MR1) */) {
- if (enabled) {
- SDLActivity.getContentView().requestPointerCapture();
- } else {
- SDLActivity.getContentView().releasePointerCapture();
+ View contentView = SDLActivity.getContentView();
+ if (contentView != null) {
+ if (enabled) {
+ contentView.requestPointerCapture();
+ } else {
+ contentView.releasePointerCapture();
+ }
}
mRelativeModeEnabled = enabled;
return true;
@@ -998,7 +1009,10 @@ void reclaimRelativeMouseModeIfNeeded() {
}
if (mRelativeModeEnabled && !SDLActivity.isDeXMode()) {
- SDLActivity.getContentView().requestPointerCapture();
+ View contentView = SDLActivity.getContentView();
+ if (contentView != null) {
+ contentView.requestPointerCapture();
+ }
}
}
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index fd95400d15b74..16322a7012dac 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -61,6 +61,116 @@
#define ENCODING_PCM_16BIT 2
#define ENCODING_PCM_FLOAT 4
+// The SDLControllerManager Java class backs both the joystick and haptic subsystems.
+// Haptic requires joystick (enforced in CMake), so gating on joystick covers both.
+#ifndef SDL_JOYSTICK_DISABLED
+#define SDL_ANDROID_NEED_CONTROLLER_MANAGER
+#endif
+
+static void checkJNIReady(void);
+
+/*******************************************************************************
+ This file links the Java side of Android with libsdl
+*******************************************************************************/
+#include <jni.h>
+
+/*******************************************************************************
+ Globals
+*******************************************************************************/
+static pthread_key_t mThreadKey;
+static pthread_once_t key_once = PTHREAD_ONCE_INIT;
+static JavaVM *mJavaVM = NULL;
+
+// Main activity
+static jclass mActivityClass;
+
+static jmethodID midGetContext;
+static jmethodID midGetDeviceFormFactor;
+static jmethodID midGetManifestEnvironmentVariables;
+static jmethodID midIsAndroidTV;
+static jmethodID midIsChromebook;
+static jmethodID midIsDeXMode;
+static jmethodID midIsTablet;
+static jmethodID midOpenURL;
+static jmethodID midRequestPermission;
+static jmethodID midShowToast;
+static jmethodID midSendMessage;
+static jmethodID midOpenFileDescriptor;
+static jmethodID midManualBackButton;
+#ifndef SDL_DIALOG_DISABLED
+static jmethodID midShowFileDialog;
+#endif // !SDL_DIALOG_DISABLED
+static jmethodID midGetPreferredLocales;
+
+#ifndef SDL_VIDEO_DISABLED
+// Video/surface method signatures
+static jmethodID midClipboardGetText;
+static jmethodID midClipboardHasText;
+static jmethodID midClipboardSetText;
+static jmethodID midCreateCustomCursor;
+static jmethodID midDestroyCustomCursor;
+static jmethodID midGetNativeSurface;
+static jmethodID midInitTouch;
+static jmethodID midMinimizeWindow;
+static jmethodID midSetActivityTitle;
+static jmethodID midSetCustomCursor;
+static jmethodID midSetOrientation;
+static jmethodID midSetRelativeMouseEnabled;
+static jmethodID midSetSystemCursor;
+static jmethodID midSetWindowStyle;
+static jmethodID midShouldMinimizeOnFocusLoss;
+static jmethodID midShowTextInput;
+static jmethodID midSupportsRelativeMouse;
+#endif // !SDL_VIDEO_DISABLED
+
+#ifndef SDL_AUDIO_DISABLED
+// audio manager
+static jclass mAudioManagerClass;
+
+// method signatures
+static jmethodID midRegisterAudioDeviceCallback;
+static jmethodID midUnregisterAudioDeviceCallback;
+static jmethodID midAudioSetThreadPriority;
+#endif // !SDL_AUDIO_DISABLED
+
+// controller manager
+#ifdef SDL_ANDROID_NEED_CONTROLLER_MANAGER
+static jclass mControllerManagerClass;
+
+// method signatures
+static jmethodID midDetectDevices;
+static jmethodID midJoystickSetLED;
+static jmethodID midJoystickSetSensorsEnabled;
+#endif // SDL_ANDROID_NEED_CONTROLLER_MANAGER
+
+#ifndef SDL_HAPTIC_DISABLED
+static jmethodID midDetectHapticDevices;
+static jmethodID midHapticRun;
+static jmethodID midHapticRumble;
+static jmethodID midHapticStop;
+#endif // !SDL_HAPTIC_DISABLED
+
+#ifndef SDL_VIDEO_DISABLED
+// display orientation
+static SDL_DisplayOrientation displayNaturalOrientation;
+static SDL_DisplayOrientation displayCurrentOrientation;
+#endif // !SDL_VIDEO_DISABLED
+
+static bool bHasEnvironmentVariables;
+
+// Android AssetManager
+static void Internal_Android_Create_AssetManager(void);
+static void Internal_Android_Destroy_AssetManager(void);
+static AAssetManager *asset_manager = NULL;
+static jobject javaAssetManagerRef = 0;
+
+static SDL_Mutex *Android_ActivityMutex = NULL;
+static int Android_ActivityMutexCount = 0;
+static SDL_Mutex *Android_LifecycleMutex = NULL;
+static SDL_Semaphore *Android_LifecycleEventSem = NULL;
+static SDL_AndroidLifecycleEvent Android_LifecycleEvents[SDL_NUM_ANDROID_LIFECYCLE_EVENTS];
+static int Android_NumLifecycleEvents;
+
// Java class SDLActivity
JNIEXPORT jstring JNICALL SDL_JAVA_INTERFACE(nativeGetVersion)(
JNIEnv *env, jclass cls);
@@ -68,6 +178,12 @@ JNIEXPORT jstring JNICALL SDL_JAVA_INTERFACE(nativeGetVersion)(
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(
JNIEnv *env, jclass cls);
+JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeGetCompiledSubsystems)(
+ JNIEnv *env, jclass jcls);
+
+JNIEXPORT jboolean JNICALL SDL_JAVA_INTERFACE(nativeIsHIDAPIEnabled)(
+ JNIEnv *env, jclass jcls);
+
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeInitMainThread)(
JNIEnv *env, jclass cls);
@@ -91,6 +207,22 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetScreenResolution)(
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeResize)(
JNIEnv *env, jclass cls);
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetNaturalOrientation)(
+ JNIEnv *env, jclass cls,
+ jint orientation);
+
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeRotationChanged)(
+ JNIEnv *env, jclass cls,
+ jint rotation);
+
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeInsetsChanged)(
+ JNIEnv *env, jclass cls,
+ jint left, jint right, jint top, jint bottom);
+
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)(
+ JNIEnv *env, jclass cls,
+ jint touchId, jstring name);
+
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceCreated)(
JNIEnv *env, jclass jcls);
@@ -147,6 +279,20 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePen)(
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeClipboardChanged)(
JNIEnv *env, jclass jcls);
+
+// Java class SDLInputConnection
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText)(
+ JNIEnv *env, jclass cls,
+ jstring text, jint newCursorPosition);
+
+JNIEXPORT void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeGenerateScancodeForUnichar)(
+ JNIEnv *env, jclass cls,
+ jchar chUnicode);
+
+static JNINativeMethod SDLInputConnection_tab[] = {
+ { "nativeCommitText", "(Ljava/lang/String;I)V", SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText) },
+ { "nativeGenerateScancodeForUnichar", "(C)V", SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeGenerateScancodeForUnichar) }
+};
#endif // !SDL_VIDEO_DISABLED
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeLowMemory)(
@@ -185,24 +331,6 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetenv)(
JNIEnv *env, jclass cls,
jstring name, jstring value);
-#ifndef SDL_VIDEO_DISABLED
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetNaturalOrientation)(
- JNIEnv *env, jclass cls,
- jint orientation);
-
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeRotationChanged)(
- JNIEnv *env, jclass cls,
- jint rotation);
-
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeInsetsChanged)(
- JNIEnv *env, jclass cls,
- jint left, jint right, jint top, jint bottom);
-
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)(
- JNIEnv *env, jclass cls,
- jint touchId, jstring name);
-#endif // !SDL_VIDEO_DISABLED
-
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePermissionResult)(
JNIEnv *env, jclass cls,
jint requestCode, jboolean result);
@@ -213,13 +341,17 @@ JNIEXPORT jboolean JNICALL SDL_JAVA_INTERFACE(nativeAllowRecreateActivity)(
JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter)(
JNIEnv *env, jclass jcls);
+#ifndef SDL_DIALOG_DISABLED
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeFileDialog)(
JNIEnv *env, jclass jcls,
jint requestCode, jobjectArray fileList, jint filter);
+#endif // !SDL_DIALOG_DISABLED
static JNINativeMethod SDLActivity_tab[] = {
{ "nativeGetVersion", "()Ljava/lang/String;", SDL_JAVA_INTERFACE(nativeGetVersion) },
{ "nativeSetupJNI", "()V", SDL_JAVA_INTERFACE(nativeSetupJNI) },
+ { "nativeGetCompiledSubsystems", "()I", SDL_JAVA_INTERFACE(nativeGetCompiledSubsystems) },
+ { "nativeIsHIDAPIEnabled", "()Z", SDL_JAVA_INTERFACE(nativeIsHIDAPIEnabled) },
{ "nativeInitMainThread", "()V", SDL_JAVA_INTERFACE(nativeInitMainThread) },
{ "nativeCleanupMainThread", "()V", SDL_JAVA_INTERFACE(nativeCleanupMainThread) },
{ "nativeRunMain", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)I", SDL_JAVA_INTERFACE(nativeRunMain) },
@@ -237,12 +369,18 @@ static JNINativeMethod SDLActivity_tab[] = {
{ "nativePermissionResult", "(IZ)V", SDL_JAVA_INTERFACE(nativePermissionResult) },
{ "nativeAllowRecreateActivity", "()Z", SDL_JAVA_INTERFACE(nativeAllowRecreateActivity) },
{ "nativeCheckSDLThreadCounter", "()I", SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter) },
+#ifndef SDL_DIALOG_DISABLED
{ "onNativeFileDialog", "(I[Ljava/lang/String;I)V", SDL_JAVA_INTERFACE(onNativeFileDialog) },
+#endif // !SDL_DIALOG_DISABLED
#ifndef SDL_VIDEO_DISABLED
// Video/input methods, registered only when the video subsystem is enabled
{ "onNativeDropFile", "(Ljava/lang/String;)V", SDL_JAVA_INTERFACE(onNativeDropFile) },
{ "nativeSetScreenResolution", "(IIIIFF)V", SDL_JAVA_INTERFACE(nativeSetScreenResolution) },
{ "onNativeResize", "()V", SDL_JAVA_INTERFACE(onNativeResize) },
+ { "nativeSetNaturalOrientation", "(I)V", SDL_JAVA_INTERFACE(nativeSetNaturalOrientation) },
+ { "onNativeRotationChanged", "(I)V", SDL_JAVA_INTERFACE(onNativeRotationChanged) },
+ { "onNativeInsetsChanged", "(IIII)V", SDL_JAVA_INTERFACE(onNativeInsetsChanged) },
+ { "nativeAddTouch", "(ILjava/lang/String;)V", SDL_JAVA_INTERFACE(nativeAddTouch) },
{ "onNativeSurfaceCreated", "()V", SDL_JAVA_INTERFACE(onNativeSurfaceCreated) },
{ "onNativeSurfaceChanged", "()V", SDL_JAVA_INTERFACE(onNativeSurfaceChanged) },
{ "onNativeSurfaceDestroyed", "()V", SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed) },
@@ -258,30 +396,10 @@ static JNINativeMethod SDLActivity_tab[] = {
{ "onNativePinchEnd", "(FFFF)V", SDL_JAVA_INTERFACE(onNativePinchEnd) },
{ "onNativeMouse", "(IIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) },
{ "onNativePen", "(IIIIFFF)V", SDL_JAVA_INTERFACE(onNativePen) },
- { "onNativeClipboardChanged", "()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) },
- { "nativeSetNaturalOrientation", "(I)V", SDL_JAVA_INTERFACE(nativeSetNaturalOrientation) },
- { "onNativeRotationChanged", "(I)V", SDL_JAVA_INTERFACE(onNativeRotationChanged) },
- { "onNativeInsetsChanged", "(IIII)V", SDL_JAVA_INTERFACE(onNativeInsetsChanged) },
- { "nativeAddTouch", "(ILjava/lang/String;)V", SDL_JAVA_INTERFACE(nativeAddTouch) }
+ { "onNativeClipboardChanged", "()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) }
#endif // !SDL_VIDEO_DISABLED
};
-#ifndef SDL_VIDEO_DISABLED
-// Java class SDLInputConnection
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText)(
- JNIEnv *env, jclass cls,
- jstring text, jint newCursorPosition);
-
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeGenerateScancodeForUnichar)(
- JNIEnv *env, jclass cls,
- jchar chUnicode);
-
-static JNINativeMethod SDLInputConnection_tab[] = {
- { "nativeCommitText", "(Ljava/lang/String;I)V", SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText) },
- { "nativeGenerateScancodeForUnichar", "(C)V", SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeGenerateScancodeForUnichar) }
-};
-#endif // !SDL_VIDEO_DISABLED
-
#ifndef SDL_AUDIO_DISABLED
// Java class SDLAudioManager
JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(
@@ -303,6 +421,7 @@ static JNINativeMethod SDLAudioManager_tab[] = {
#endif // !SDL_AUDIO_DISABLED
// Java class SDLControllerManager
+#ifdef SDL_ANDROID_NEED_CONTROLLER_MANAGER
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(
JNIEnv *env, jclass jcls);
@@ -335,7 +454,9 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
JNIEnv *env, jclass jcls,
jint device_id);
+#endif // SDL_ANDROID_NEED_CONTROLLER_MANAGER
+#ifndef SDL_HAPTIC_DISABLED
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic)(
JNIEnv *env, jclass jcls,
jint device_id, jstring device_name);
@@ -343,7 +464,9 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic)(
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic)(
JNIEnv *env, jclass jcls,
jint device_id);
+#endif // !SDL_HAPTIC_DISABLED
+#ifdef SDL_ANDROID_NEED_CONTROLLER_MANAGER
static JNINativeMethod SDLControllerManager_tab[] = {
{ "nativeSetupJNI", "()V", SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI) },
{ "onNativePadDown", "(III)Z", SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown) },
@@ -353,204 +476,54 @@ static JNINativeMethod SDLControllerManager_tab[] = {
{ "onNativeJoySensor", "(IIJFFF)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoySensor) },
{ "nativeAddJoystick", "(ILjava/lang/String;Ljava/lang/String;IIIIIIZZZZ)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick) },
{ "nativeRemoveJoystick", "(I)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick) },
+#ifndef SDL_HAPTIC_DISABLED
{ "nativeAddHaptic", "(ILjava/lang/String;)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic) },
{ "nativeRemoveHaptic", "(I)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic) }
+#endif // !SDL_HAPTIC_DISABLED
};
+#endif // SDL_ANDROID_NEED_CONTROLLER_MANAGER
// Uncomment this to log messages entering and exiting methods in this file
// #define DEBUG_JNI
-static void checkJNIReady(void);
-
-/*******************************************************************************
- This file links the Java side of Android with libsdl
-*******************************************************************************/
-#include <jni.h>
/*******************************************************************************
- Globals
+ Functions called by JNI
*******************************************************************************/
-static pthread_key_t mThre
(Patch may be truncated, please check the link at the top of this post.)