From 7a6eed4ec89d51c640575ad5e50bb36ce5f3aa07 Mon Sep 17 00:00:00 2001
From: Holden Ramsey <[EMAIL REDACTED]>
Date: Thu, 12 Mar 2026 11:22:14 -0400
Subject: [PATCH] Android: decouple video/audio subsystems from JNI
initialization
Allow Android embedders to use SDL without the full video/audio Java
layer by gating subsystem-specific code behind SDL_VIDEO_DISABLED and
SDL_AUDIO_DISABLED preprocessor flags.
This enables applications that only need joystick/gamepad support
(e.g. Qt-based apps like QGroundControl) to build SDL without shipping
stub Java classes for unused subsystems.
Changes:
- Split SDLActivity JNI method table into core (lifecycle, hints,
permissions) and video (surface, input, clipboard, orientation)
- Gate SDLAudioManager and SDLInputConnection JNI registration
- Make checkJNIReady() subsystem-aware: no longer requires
mAudioManagerClass when SDL_AUDIO_DISABLED
- Group method ID resolution by subsystem in nativeSetupJNI()
- Guard all video/audio function implementations and declarations
- Keep display orientation accessors always available (needed by camera)
- Add subsystem-selective SDL.setupJNI(int)/initialize(int) to SDL.java
with backwards-compatible zero-arg overloads
- Guard SDL_VIDEO_DRIVER_ANDROID and related defines in
SDL_build_config_android.h
---
CMakeLists.txt | 10 +-
.../app/src/main/java/org/libsdl/app/SDL.java | 44 +++-
build-scripts/check_android_jni.py | 2 +
.../build_config/SDL_build_config_android.h | 2 +
src/core/android/SDL_android.c | 190 ++++++++++++------
src/core/android/SDL_android.h | 16 ++
src/video/android/SDL_androidevents.c | 23 +++
7 files changed, 219 insertions(+), 68 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cd77e752ae5f7..30575c0e3a305 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1499,6 +1499,9 @@ if(ANDROID)
"${SDL3_SOURCE_DIR}/src/core/android/*.h"
)
+ # Core Android code (asset I/O, logging, sensors) needs these regardless of the video subsystem.
+ sdl_link_dependency(android_core LIBS dl log android)
+
sdl_glob_sources(
"${SDL3_SOURCE_DIR}/src/misc/android/*.c"
"${SDL3_SOURCE_DIR}/src/misc/android/*.h"
@@ -1629,10 +1632,6 @@ if(ANDROID)
)
set(HAVE_SDL_VIDEO TRUE)
- # Core stuff
- # find_library(ANDROID_DL_LIBRARY dl)
- # FIXME failing dlopen https://github.com/android-ndk/ndk/issues/929
- sdl_link_dependency(android_video LIBS dl log android)
sdl_compile_definitions(PRIVATE "GL_GLEXT_PROTOTYPES")
#enable gles
@@ -1663,6 +1662,9 @@ if(ANDROID)
endif()
endif()
endif()
+ else()
+ # SDL_events.c pumps Android events even with video disabled; this TU supplies the stub implementations.
+ sdl_sources("${SDL3_SOURCE_DIR}/src/video/android/SDL_androidevents.c")
endif()
CheckPTHREAD()
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 d9650a72e4230..097eb8cc873cc 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
@@ -10,26 +10,58 @@
*/
public class SDL {
- // This function should be called first and sets up the native code
- // so it can call into the Java classes
+ // SDL_INIT_* values, mirrored so embedders can request a subset and skip stub classes for unused subsystems.
+ public static final int SDL_INIT_AUDIO = 0x00000010;
+ public static final int SDL_INIT_VIDEO = 0x00000020;
+ public static final int SDL_INIT_JOYSTICK = 0x00000200;
+ public static final int SDL_INIT_HAPTIC = 0x00001000;
+ public static final int SDL_INIT_GAMEPAD = 0x00002000;
+ public static final int SDL_INIT_SENSOR = 0x00008000;
+ public static final int SDL_INIT_CAMERA = 0x00010000;
+
+ 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;
+
+ private static int mInitializedSubsystems = 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();
- SDLAudioManager.nativeSetupJNI();
+
+ if ((subsystems & SDL_INIT_AUDIO) != 0) {
+ SDLAudioManager.nativeSetupJNI();
+ }
+
SDLControllerManager.nativeSetupJNI();
}
- // This function should be called each time the activity is started
static public void initialize() {
+ initialize(mInitializedSubsystems);
+ }
+
+ static public void initialize(int subsystems) {
setContext(null);
SDLActivity.initialize();
- SDLAudioManager.initialize();
+
+ if ((subsystems & SDL_INIT_AUDIO) != 0) {
+ SDLAudioManager.initialize();
+ }
+
SDLControllerManager.initialize();
}
// This function stores the current activity (SDL or not)
static public void setContext(Activity context) {
- SDLAudioManager.setContext(context);
+ if ((mInitializedSubsystems & SDL_INIT_AUDIO) != 0) {
+ SDLAudioManager.setContext(context);
+ }
mContext = context;
}
diff --git a/build-scripts/check_android_jni.py b/build-scripts/check_android_jni.py
index b0f6ee20e545f..f9a27e23d15bc 100755
--- a/build-scripts/check_android_jni.py
+++ b/build-scripts/check_android_jni.py
@@ -82,6 +82,8 @@ def collect_jni_bindings_from_c() -> dict[str, set[JniMethodBinding]]:
if re.match(r"\};", line):
in_struct = False
break
+ if re.match(r"\s*(#|//)", line):
+ continue
n = re.match(r"""\s*\{\s*"(?P<method>[a-zA-Z0-9_]+)"\s*,\s*"(?P<spec>[()A-Za-z0-9_/;[]+)"\s*,\s*(\(void\*\))?(HID|SDL)[_A-Z]*_JAVA_[_A-Z]*INTERFACE[_A-Z]*\((?P=method)\)\s*\},?""", line)
assert n, f"'{line}' does not match regex"
methods.add(JniMethodBinding(name=n["method"], spec=n["spec"]))
diff --git a/include/build_config/SDL_build_config_android.h b/include/build_config/SDL_build_config_android.h
index e709ec9ee04e4..966e3bae3d3af 100644
--- a/include/build_config/SDL_build_config_android.h
+++ b/include/build_config/SDL_build_config_android.h
@@ -178,6 +178,7 @@
#define SDL_TIMER_UNIX 1
/* Enable various video drivers */
+#ifndef SDL_VIDEO_DISABLED
#define SDL_VIDEO_DRIVER_ANDROID 1
/* Enable OpenGL ES */
@@ -196,6 +197,7 @@
#define HAVE_GPU_OPENXR 1
#define SDL_VIDEO_RENDER_GPU 1
#endif
+#endif /* SDL_VIDEO_DISABLED */
/* Enable system power support */
#define SDL_POWER_ANDROID 1
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index 1125719ed6bf2..fd95400d15b74 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -25,12 +25,14 @@
#include "SDL_android.h"
#include "../../events/SDL_events_c.h"
+#ifndef SDL_VIDEO_DISABLED
#include "../../video/android/SDL_androidkeyboard.h"
#include "../../video/android/SDL_androidmouse.h"
#include "../../video/android/SDL_androidtouch.h"
#include "../../video/android/SDL_androidpen.h"
#include "../../video/android/SDL_androidvideo.h"
#include "../../video/android/SDL_androidwindow.h"
+#endif
#include "../../joystick/android/SDL_sysjoystick_c.h"
#include "../../haptic/android/SDL_syshaptic_c.h"
#include "../../hidapi/android/hid.h"
@@ -76,6 +78,7 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(
JNIEnv *env, jclass cls,
jstring library, jstring function, jobject array);
+#ifndef SDL_VIDEO_DISABLED
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDropFile)(
JNIEnv *env, jclass jcls,
jstring filename);
@@ -144,6 +147,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativePen)(
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeClipboardChanged)(
JNIEnv *env, jclass jcls);
+#endif // !SDL_VIDEO_DISABLED
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeLowMemory)(
JNIEnv *env, jclass cls);
@@ -181,6 +185,7 @@ 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);
@@ -196,6 +201,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeInsetsChanged)(
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,
@@ -217,6 +223,23 @@ static JNINativeMethod SDLActivity_tab[] = {
{ "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) },
+ { "nativeLowMemory", "()V", SDL_JAVA_INTERFACE(nativeLowMemory) },
+ { "onNativeLocaleChanged", "()V", SDL_JAVA_INTERFACE(onNativeLocaleChanged) },
+ { "onNativeDarkModeChanged", "(Z)V", SDL_JAVA_INTERFACE(onNativeDarkModeChanged) },
+ { "nativeSendQuit", "()V", SDL_JAVA_INTERFACE(nativeSendQuit) },
+ { "nativeQuit", "()V", SDL_JAVA_INTERFACE(nativeQuit) },
+ { "nativePause", "()V", SDL_JAVA_INTERFACE(nativePause) },
+ { "nativeResume", "()V", SDL_JAVA_INTERFACE(nativeResume) },
+ { "nativeFocusChanged", "(Z)V", SDL_JAVA_INTERFACE(nativeFocusChanged) },
+ { "nativeGetHint", "(Ljava/lang/String;)Ljava/lang/String;", SDL_JAVA_INTERFACE(nativeGetHint) },
+ { "nativeGetHintBoolean", "(Ljava/lang/String;Z)Z", SDL_JAVA_INTERFACE(nativeGetHintBoolean) },
+ { "nativeSetenv", "(Ljava/lang/String;Ljava/lang/String;)V", SDL_JAVA_INTERFACE(nativeSetenv) },
+ { "nativePermissionResult", "(IZ)V", SDL_JAVA_INTERFACE(nativePermissionResult) },
+ { "nativeAllowRecreateActivity", "()Z", SDL_JAVA_INTERFACE(nativeAllowRecreateActivity) },
+ { "nativeCheckSDLThreadCounter", "()I", SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter) },
+ { "onNativeFileDialog", "(I[Ljava/lang/String;I)V", SDL_JAVA_INTERFACE(onNativeFileDialog) },
+#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) },
@@ -236,27 +259,14 @@ static JNINativeMethod SDLActivity_tab[] = {
{ "onNativeMouse", "(IIFFZ)V", SDL_JAVA_INTERFACE(onNativeMouse) },
{ "onNativePen", "(IIIIFFF)V", SDL_JAVA_INTERFACE(onNativePen) },
{ "onNativeClipboardChanged", "()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) },
- { "nativeLowMemory", "()V", SDL_JAVA_INTERFACE(nativeLowMemory) },
- { "onNativeLocaleChanged", "()V", SDL_JAVA_INTERFACE(onNativeLocaleChanged) },
- { "onNativeDarkModeChanged", "(Z)V", SDL_JAVA_INTERFACE(onNativeDarkModeChanged) },
- { "nativeSendQuit", "()V", SDL_JAVA_INTERFACE(nativeSendQuit) },
- { "nativeQuit", "()V", SDL_JAVA_INTERFACE(nativeQuit) },
- { "nativePause", "()V", SDL_JAVA_INTERFACE(nativePause) },
- { "nativeResume", "()V", SDL_JAVA_INTERFACE(nativeResume) },
- { "nativeFocusChanged", "(Z)V", SDL_JAVA_INTERFACE(nativeFocusChanged) },
- { "nativeGetHint", "(Ljava/lang/String;)Ljava/lang/String;", SDL_JAVA_INTERFACE(nativeGetHint) },
- { "nativeGetHintBoolean", "(Ljava/lang/String;Z)Z", SDL_JAVA_INTERFACE(nativeGetHintBoolean) },
- { "nativeSetenv", "(Ljava/lang/String;Ljava/lang/String;)V", SDL_JAVA_INTERFACE(nativeSetenv) },
{ "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) },
- { "nativePermissionResult", "(IZ)V", SDL_JAVA_INTERFACE(nativePermissionResult) },
- { "nativeAllowRecreateActivity", "()Z", SDL_JAVA_INTERFACE(nativeAllowRecreateActivity) },
- { "nativeCheckSDLThreadCounter", "()I", SDL_JAVA_INTERFACE(nativeCheckSDLThreadCounter) },
- { "onNativeFileDialog", "(I[Ljava/lang/String;I)V", SDL_JAVA_INTERFACE(onNativeFileDialog) }
+ { "nativeAddTouch", "(ILjava/lang/String;)V", SDL_JAVA_INTERFACE(nativeAddTouch) }
+#endif // !SDL_VIDEO_DISABLED
};
+#ifndef SDL_VIDEO_DISABLED
// Java class SDLInputConnection
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText)(
JNIEnv *env, jclass cls,
@@ -270,7 +280,9 @@ 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)(
JNIEnv *env, jclass jcls);
@@ -288,6 +300,7 @@ static JNINativeMethod SDLAudioManager_tab[] = {
{ "nativeAddAudioDevice", "(ZLjava/lang/String;I)V", SDL_JAVA_AUDIO_INTERFACE(nativeAddAudioDevice) },
{ "nativeRemoveAudioDevice", "(ZI)V", SDL_JAVA_AUDIO_INTERFACE(nativeRemoveAudioDevice) }
};
+#endif // !SDL_AUDIO_DISABLED
// Java class SDLControllerManager
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(
@@ -364,27 +377,32 @@ static JavaVM *mJavaVM = NULL;
// Main activity
static jclass mActivityClass;
-// method signatures
-static jmethodID midClipboardGetText;
-static jmethodID midClipboardHasText;
-static jmethodID midClipboardSetText;
-static jmethodID midCreateCustomCursor;
-static jmethodID midDestroyCustomCursor;
static jmethodID midGetContext;
static jmethodID midGetDeviceFormFactor;
static jmethodID midGetManifestEnvironmentVariables;
-static jmethodID midGetNativeSurface;
-static jmethodID midInitTouch;
static jmethodID midIsAndroidTV;
static jmethodID midIsChromebook;
static jmethodID midIsDeXMode;
static jmethodID midIsTablet;
-static jmethodID midManualBackButton;
-static jmethodID midMinimizeWindow;
static jmethodID midOpenURL;
static jmethodID midRequestPermission;
static jmethodID midShowToast;
static jmethodID midSendMessage;
+static jmethodID midOpenFileDescriptor;
+static jmethodID midShowFileDialog;
+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 midManualBackButton;
+static jmethodID midMinimizeWindow;
static jmethodID midSetActivityTitle;
static jmethodID midSetCustomCursor;
static jmethodID midSetOrientation;
@@ -394,10 +412,9 @@ static jmethodID midSetWindowStyle;
static jmethodID midShouldMinimizeOnFocusLoss;
static jmethodID midShowTextInput;
static jmethodID midSupportsRelativeMouse;
-static jmethodID midOpenFileDescriptor;
-static jmethodID midShowFileDialog;
-static jmethodID midGetPreferredLocales;
+#endif // !SDL_VIDEO_DISABLED
+#ifndef SDL_AUDIO_DISABLED
// audio manager
static jclass mAudioManagerClass;
@@ -405,6 +422,7 @@ static jclass mAudioManagerClass;
static jmethodID midRegisterAudioDeviceCallback;
static jmethodID midUnregisterAudioDeviceCallback;
static jmethodID midAudioSetThreadPriority;
+#endif // !SDL_AUDIO_DISABLED
// controller manager
static jclass mControllerManagerClass;
@@ -584,8 +602,12 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
}
register_methods(env, "org/libsdl/app/SDLActivity", SDLActivity_tab, SDL_arraysize(SDLActivity_tab));
+#ifndef SDL_VIDEO_DISABLED
register_methods(env, "org/libsdl/app/SDLInputConnection", SDLInputConnection_tab, SDL_arraysize(SDLInputConnection_tab));
+#endif
+#ifndef SDL_AUDIO_DISABLED
register_methods(env, "org/libsdl/app/SDLAudioManager", SDLAudioManager_tab, SDL_arraysize(SDLAudioManager_tab));
+#endif
register_methods(env, "org/libsdl/app/SDLControllerManager", SDLControllerManager_tab, SDL_arraysize(SDLControllerManager_tab));
register_methods(env, "org/libsdl/app/HIDDeviceManager", HIDDeviceManager_tab, SDL_arraysize(HIDDeviceManager_tab));
@@ -594,11 +616,17 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
void checkJNIReady(void)
{
- if (!mActivityClass || !mAudioManagerClass || !mControllerManagerClass) {
+ if (!mActivityClass || !mControllerManagerClass) {
// We aren't fully initialized, let's just return.
return;
}
+#ifndef SDL_AUDIO_DISABLED
+ if (!mAudioManagerClass) {
+ return;
+ }
+#endif
+
SDL_SetMainReady();
}
@@ -656,26 +684,48 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
mActivityClass = (jclass)((*env)->NewGlobalRef(env, cls));
- midClipboardGetText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardGetText", "()Ljava/lang/String;");
- midClipboardHasText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardHasText", "()Z");
- midClipboardSetText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardSetText", "(Ljava/lang/String;)V");
- midCreateCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "createCustomCursor", "([IIIII)I");
- midDestroyCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "destroyCustomCursor", "(I)V");
midGetContext = (*env)->GetStaticMethodID(env, mActivityClass, "getContext", "()Landroid/app/Activity;");
midGetDeviceFormFactor = (*env)->GetStaticMethodID(env, mActivityClass, "getDeviceFormFactor", "()Ljava/lang/String;");
midGetManifestEnvironmentVariables = (*env)->GetStaticMethodID(env, mActivityClass, "getManifestEnvironmentVariables", "()Z");
- midGetNativeSurface = (*env)->GetStaticMethodID(env, mActivityClass, "getNativeSurface", "()Landroid/view/Surface;");
- midInitTouch = (*env)->GetStaticMethodID(env, mActivityClass, "initTouch", "()V");
midIsAndroidTV = (*env)->GetStaticMethodID(env, mActivityClass, "isAndroidTV", "()Z");
midIsChromebook = (*env)->GetStaticMethodID(env, mActivityClass, "isChromebook", "()Z");
midIsDeXMode = (*env)->GetStaticMethodID(env, mActivityClass, "isDeXMode", "()Z");
midIsTablet = (*env)->GetStaticMethodID(env, mActivityClass, "isTablet", "()Z");
- midManualBackButton = (*env)->GetStaticMethodID(env, mActivityClass, "manualBackButton", "()V");
- midMinimizeWindow = (*env)->GetStaticMethodID(env, mActivityClass, "minimizeWindow", "()V");
midOpenURL = (*env)->GetStaticMethodID(env, mActivityClass, "openURL", "(Ljava/lang/String;)Z");
midRequestPermission = (*env)->GetStaticMethodID(env, mActivityClass, "requestPermission", "(Ljava/lang/String;I)V");
midShowToast = (*env)->GetStaticMethodID(env, mActivityClass, "showToast", "(Ljava/lang/String;IIII)Z");
midSendMessage = (*env)->GetStaticMethodID(env, mActivityClass, "sendMessage", "(II)Z");
+ midOpenFileDescriptor = (*env)->GetStaticMethodID(env, mActivityClass, "openFileDescriptor", "(Ljava/lang/String;Ljava/lang/String;)I");
+ midShowFileDialog = (*env)->GetStaticMethodID(env, mActivityClass, "showFileDialog", "([Ljava/lang/String;ZILjava/lang/String;I)Z");
+ midGetPreferredLocales = (*env)->GetStaticMethodID(env, mActivityClass, "getPreferredLocales", "()Ljava/lang/String;");
+
+ if (!midGetContext ||
+ !midGetDeviceFormFactor ||
+ !midGetManifestEnvironmentVariables ||
+ !midIsAndroidTV ||
+ !midIsChromebook ||
+ !midIsDeXMode ||
+ !midIsTablet ||
+ !midOpenURL ||
+ !midRequestPermission ||
+ !midShowToast ||
+ !midSendMessage ||
+ !midOpenFileDescriptor ||
+ !midShowFileDialog ||
+ !midGetPreferredLocales) {
+ __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some core Java callbacks, do you have the latest version of SDLActivity.java?");
+ }
+
+#ifndef SDL_VIDEO_DISABLED
+ midClipboardGetText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardGetText", "()Ljava/lang/String;");
+ midClipboardHasText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardHasText", "()Z");
+ midClipboardSetText = (*env)->GetStaticMethodID(env, mActivityClass, "clipboardSetText", "(Ljava/lang/String;)V");
+ midCreateCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "createCustomCursor", "([IIIII)I");
+ midDestroyCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "destroyCustomCursor", "(I)V");
+ midGetNativeSurface = (*env)->GetStaticMethodID(env, mActivityClass, "getNativeSurface", "()Landroid/view/Surface;");
+ midInitTouch = (*env)->GetStaticMethodID(env, mActivityClass, "initTouch", "()V");
+ midManualBackButton = (*env)->GetStaticMethodID(env, mActivityClass, "manualBackButton", "()V");
+ midMinimizeWindow = (*env)->GetStaticMethodID(env, mActivityClass, "minimizeWindow", "()V");
midSetActivityTitle = (*env)->GetStaticMethodID(env, mActivityClass, "setActivityTitle", "(Ljava/lang/String;)Z");
midSetCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "setCustomCursor", "(I)Z");
midSetOrientation = (*env)->GetStaticMethodID(env, mActivityClass, "setOrientation", "(IIZLjava/lang/String;)V");
@@ -685,30 +735,16 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
midShouldMinimizeOnFocusLoss = (*env)->GetStaticMethodID(env, mActivityClass, "shouldMinimizeOnFocusLoss", "()Z");
midShowTextInput = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIIII)Z");
midSupportsRelativeMouse = (*env)->GetStaticMethodID(env, mActivityClass, "supportsRelativeMouse", "()Z");
- midOpenFileDescriptor = (*env)->GetStaticMethodID(env, mActivityClass, "openFileDescriptor", "(Ljava/lang/String;Ljava/lang/String;)I");
- midShowFileDialog = (*env)->GetStaticMethodID(env, mActivityClass, "showFileDialog", "([Ljava/lang/String;ZILjava/lang/String;I)Z");
- midGetPreferredLocales = (*env)->GetStaticMethodID(env, mActivityClass, "getPreferredLocales", "()Ljava/lang/String;");
if (!midClipboardGetText ||
!midClipboardHasText ||
!midClipboardSetText ||
!midCreateCustomCursor ||
!midDestroyCustomCursor ||
- !midGetContext ||
- !midGetDeviceFormFactor ||
- !midGetManifestEnvironmentVariables ||
!midGetNativeSurface ||
!midInitTouch ||
- !midIsAndroidTV ||
- !midIsChromebook ||
- !midIsDeXMode ||
- !midIsTablet ||
!midManualBackButton ||
!midMinimizeWindow ||
- !midOpenURL ||
- !midRequestPermission ||
- !midShowToast ||
- !midSendMessage ||
!midSetActivityTitle ||
!midSetCustomCursor ||
!midSetOrientation ||
@@ -717,16 +753,15 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
!midSetWindowStyle ||
!midShouldMinimizeOnFocusLoss ||
!midShowTextInput ||
- !midSupportsRelativeMouse ||
- !midOpenFileDescriptor ||
- !midShowFileDialog ||
- !midGetPreferredLocales) {
- __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
+ !midSupportsRelativeMouse) {
+ __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some video Java callbacks, do you have the latest version of SDLActivity.java?");
}
+#endif // !SDL_VIDEO_DISABLED
checkJNIReady();
}
+#ifndef SDL_AUDIO_DISABLED
// Audio initialization -- called before SDL_main() to initialize JNI bindings
JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cls)
{
@@ -750,6 +785,7 @@ JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv *env, jcl
checkJNIReady();
}
+#endif // !SDL_AUDIO_DISABLED
// Controller initialization -- called before SDL_main() to initialize JNI bindings
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cls)
@@ -1043,6 +1079,7 @@ void Android_UnlockActivityMutex(void)
SDL_UnlockMutex(Android_ActivityMutex);
}
+#ifndef SDL_VIDEO_DISABLED
// Drop file
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDropFile)(
JNIEnv *env, jclass jcls,
@@ -1142,7 +1179,9 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)(
(*env)->ReleaseStringUTFChars(env, name, utfname);
}
+#endif // !SDL_VIDEO_DISABLED
+#ifndef SDL_AUDIO_DISABLED
JNIEXPORT void JNICALL
SDL_JAVA_AUDIO_INTERFACE(nativeAddAudioDevice)(JNIEnv *env, jclass jcls, jboolean recording,
jstring name, jint device_id)
@@ -1170,6 +1209,7 @@ SDL_JAVA_AUDIO_INTERFACE(nativeRemoveAudioDevice)(JNIEnv *env, jclass jcls, jboo
}
#endif
}
+#endif // !SDL_AUDIO_DISABLED
// Paddown
JNIEXPORT jboolean JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown)(
@@ -1273,6 +1313,7 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic)(
#endif
}
+#ifndef SDL_VIDEO_DISABLED
// Called from surfaceCreated()
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceCreated)(JNIEnv *env, jclass jcls)
{
@@ -1498,6 +1539,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeClipboardChanged)(
// TODO: compute new mime types
SDL_SendClipboardUpdate(false, NULL, 0);
}
+#endif // !SDL_VIDEO_DISABLED
// Low memory
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeLowMemory)(
@@ -1518,7 +1560,11 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeLocaleChanged)(
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDarkModeChanged)(
JNIEnv *env, jclass cls, jboolean enabled)
{
+#ifndef SDL_VIDEO_DISABLED
Android_SetDarkMode(enabled);
+#else
+ (void)enabled;
+#endif
}
// Send Quit event to "SDLThread" thread
@@ -1584,10 +1630,14 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeFocusChanged)(
{
SDL_LockMutex(Android_ActivityMutex);
+#ifndef SDL_VIDEO_DISABLED
if (Android_Window) {
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeFocusChanged()");
SDL_SendWindowEvent(Android_Window, (hasFocus ? SDL_EVENT_WINDOW_FOCUS_GAINED : SDL_EVENT_WINDOW_FOCUS_LOST), 0, 0);
}
+#else
+ (void)hasFocus;
+#endif
SDL_UnlockMutex(Android_ActivityMutex);
}
@@ -1705,6 +1755,7 @@ static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder)
}
}
+#ifndef SDL_VIDEO_DISABLED
ANativeWindow *Android_JNI_GetNativeWindow(void)
{
ANativeWindow *anw = NULL;
@@ -1744,6 +1795,9 @@ void Android_JNI_SetOrientation(int w, int h, int resizable, const char *hint)
(*env)->DeleteLocalRef(env, jhint);
}
+#endif // !SDL_VIDEO_DISABLED
+
+// Outside the video guard: the camera driver reads these cached values (only written by the video Java layer).
SDL_DisplayOrientation Android_JNI_GetDisplayNaturalOrientation(void)
{
return displayNaturalOrientation;
@@ -1754,6 +1808,7 @@ SDL_DisplayOrientation Android_JNI_GetDisplayCurrentOrientation(void)
return displayCurrentOrientation;
}
+#ifndef SDL_VIDEO_DISABLED
void Android_JNI_MinimizeWindow(void)
{
JNIEnv *env = Android_JNI_GetEnv();
@@ -1766,6 +1821,14 @@ bool Android_JNI_ShouldMinimizeOnFocusLoss(void)
return (*env)->CallStaticBooleanMethod(env, mActivityClass, midShouldMinimizeOnFocusLoss);
}
+#else
+bool Android_JNI_ShouldMinimizeOnFocusLoss(void)
+{
+ return false;
+}
+#endif // !SDL_VIDEO_DISABLED
+
+#ifndef SDL_AUDIO_DISABLED
/*
* Audio support
*/
@@ -1793,6 +1856,7 @@ void Android_AudioThreadInit(SDL_AudioDevice *device)
{
Android_JNI_AudioSetThreadPriority((int) device->recording, (int)device->instance_id);
}
+#endif // !SDL_AUDIO_DISABLED
// Test for an exception and call SDL_SetError with its detail if one occurs
// If the parameter silent is truthy then SDL_SetError() will not be called.
@@ -2500,6 +2564,7 @@ bool Android_JNI_GetAssetPathInfo(const char *path, SDL_PathInfo *info)
return true;
}
+#ifndef SDL_VIDEO_DISABLED
bool Android_JNI_SetClipboardText(const char *text)
{
JNIEnv *env = Android_JNI_GetEnv();
@@ -2533,6 +2598,7 @@ bool Android_JNI_HasClipboardText(void)
JNIEnv *env = Android_JNI_GetEnv();
return (*env)->CallStaticBooleanMethod(env, mActivityClass, midClipboardHasText);
}
+#endif // !SDL_VIDEO_DISABLED
/* returns 0 on success or -1 on error (others undefined then)
* returns truthy or falsy value in plugged, charged and battery
@@ -2654,12 +2720,14 @@ int Android_JNI_GetPowerInfo(int *plugged, int *charged, int *battery, int *seco
return 0;
}
+#ifndef SDL_VIDEO_DISABLED
// Add all touch devices
void Android_JNI_InitTouch(void)
{
JNIEnv *env = Android_JNI_GetEnv();
(*env)->CallStaticVoidMethod(env, mActivityClass, midInitTouch);
}
+#endif // !SDL_VIDEO_DISABLED
void Android_JNI_DetectDevices(void)
{
@@ -2726,6 +2794,7 @@ bool Android_JNI_SuspendScreenSaver(bool suspend)
return Android_JNI_SendMessage(COMMAND_SET_KEEP_SCREEN_ON, (suspend == false) ? 0 : 1);
}
+#ifndef SDL_VIDEO_DISABLED
void Android_JNI_ShowScreenKeyboard(int input_type, SDL_Rect *inputRect)
{
JNIEnv *env = Android_JNI_GetEnv();
@@ -2743,6 +2812,7 @@ void Android_JNI_HideScreenKeyboard(void)
const int COMMAND_TEXTEDIT_HIDE = 3;
Android_JNI_SendMessage(COMMAND_TEXTEDIT_HIDE, 0);
}
+#endif // !SDL_VIDEO_DISABLED
bool Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
{
@@ -2937,8 +3007,10 @@ bool SDL_IsDeXMode(void)
void SDL_SendAndroidBackButton(void)
{
+#ifndef SDL_VIDEO_DISABLED
JNIEnv *env = Android_JNI_GetEnv();
(*env)->CallStaticVoidMethod(env, mActivityClass, midManualBackButton);
+#endif
}
const char *SDL_GetAndroidInternalStoragePath(void)
@@ -3147,6 +3219,7 @@ void Android_JNI_GetManifestEnvironmentVariables(void)
}
}
+#ifndef SDL_VIDEO_DISABLED
int Android_JNI_CreateCustomCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
JNIEnv *env = Android_JNI_GetEnv();
@@ -3192,6 +3265,7 @@ bool Android_JNI_SetRelativeMouseEnabled(bool enabled)
JNIEnv *env = Android_JNI_GetEnv();
return (*env)->CallStaticBooleanMethod(env, mActivityClass, midSetRelativeMouseEnabled, (enabled == 1));
}
+#endif // !SDL_VIDEO_DISABLED
typedef struct NativePermissionRequestInfo
{
diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h
index b5faa2ff49348..caa098d32ae33 100644
--- a/src/core/android/SDL_android.h
+++ b/src/core/android/SDL_a
(Patch may be truncated, please check the link at the top of this post.)