diff --git a/CMakeLists.txt b/CMakeLists.txt index cd77e752ae..30575c0e3a 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 d9650a72e4..097eb8cc87 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 @@ import java.lang.reflect.Method; */ 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 b0f6ee20e5..f9a27e23d1 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[a-zA-Z0-9_]+)"\s*,\s*"(?P[()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 e709ec9ee0..966e3bae3d 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 1125719ed6..fd95400d15 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 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 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 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 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)); + 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"); + 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"); + 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"); - 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"); 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 b5faa2ff49..caa098d32a 100644 --- a/src/core/android/SDL_android.h +++ b/src/core/android/SDL_android.h @@ -30,13 +30,17 @@ extern "C" { /* *INDENT-ON* */ #endif +#ifndef SDL_VIDEO_DISABLED #include #include +#endif +#ifndef SDL_AUDIO_DISABLED #include "../../audio/SDL_sysaudio.h" // this appears to be broken right now (on Android, not SDL, I think...?). #define ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES 0 +#endif // Life cycle typedef enum @@ -57,6 +61,7 @@ void Android_UnlockActivityMutex(void); void Android_SetAllowRecreateActivity(bool enabled); +#ifndef SDL_VIDEO_DISABLED // Interface from the SDL library into the Android Java activity extern void Android_JNI_SetActivityTitle(const char *title); extern void Android_JNI_SetWindowStyle(bool fullscreen); @@ -68,13 +73,18 @@ extern void Android_JNI_ShowScreenKeyboard(int input_type, SDL_Rect *inputRect); extern void Android_JNI_HideScreenKeyboard(void); extern ANativeWindow *Android_JNI_GetNativeWindow(void); +#endif // !SDL_VIDEO_DISABLED + +// Kept outside the video guard for the camera driver; stays SDL_ORIENTATION_UNKNOWN when video is disabled (only the video Java layer updates it). extern SDL_DisplayOrientation Android_JNI_GetDisplayNaturalOrientation(void); extern SDL_DisplayOrientation Android_JNI_GetDisplayCurrentOrientation(void); +#ifndef SDL_AUDIO_DISABLED // Audio support void Android_StartAudioHotplug(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording); void Android_StopAudioHotplug(void); extern void Android_AudioThreadInit(SDL_AudioDevice *device); +#endif // !SDL_AUDIO_DISABLED // Detecting device type extern bool Android_IsDeXMode(void); @@ -93,10 +103,12 @@ bool Android_JNI_GetAssetPathInfo(const char *path, SDL_PathInfo *info); void Android_JNI_GetManifestEnvironmentVariables(void); int Android_JNI_OpenFileDescriptor(const char *uri, const char *mode); +#ifndef SDL_VIDEO_DISABLED // Clipboard support bool Android_JNI_SetClipboardText(const char *text); char *Android_JNI_GetClipboardText(void); bool Android_JNI_HasClipboardText(void); +#endif // !SDL_VIDEO_DISABLED // Power support int Android_JNI_GetPowerInfo(int *plugged, int *charged, int *battery, int *seconds, int *percent); @@ -115,8 +127,10 @@ void Android_JNI_HapticStop(int device_id); // Video bool Android_JNI_SuspendScreenSaver(bool suspend); +#ifndef SDL_VIDEO_DISABLED // Touch support void Android_JNI_InitTouch(void); +#endif // !SDL_VIDEO_DISABLED // Threads #include @@ -132,6 +146,7 @@ bool Android_JNI_SendMessage(int command, int param); // MessageBox bool Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID); +#ifndef SDL_VIDEO_DISABLED // Cursor support int Android_JNI_CreateCustomCursor(SDL_Surface *surface, int hot_x, int hot_y); void Android_JNI_DestroyCustomCursor(int cursorID); @@ -141,6 +156,7 @@ bool Android_JNI_SetSystemCursor(int cursorID); // Relative mouse support bool Android_JNI_SupportsRelativeMouse(void); bool Android_JNI_SetRelativeMouseEnabled(bool enabled); +#endif // !SDL_VIDEO_DISABLED // Show toast notification bool Android_JNI_ShowToast(const char *message, int duration, int gravity, int xOffset, int yOffset); diff --git a/src/video/android/SDL_androidevents.c b/src/video/android/SDL_androidevents.c index 4bdd717e12..cddc1bff7e 100644 --- a/src/video/android/SDL_androidevents.c +++ b/src/video/android/SDL_androidevents.c @@ -264,4 +264,27 @@ void Android_QuitEvents(void) Android_EventsInitialized = false; } +#else + +#include "../../core/android/SDL_android.h" + +void Android_InitEvents(void) +{ +} + +void Android_PumpEvents(Sint64 timeoutNS) +{ + (void)timeoutNS; +} + +bool Android_WaitActiveAndLockActivity(void) +{ + Android_LockActivityMutex(); + return true; +} + +void Android_QuitEvents(void) +{ +} + #endif // SDL_VIDEO_DRIVER_ANDROID