From dbb0a2aa74d2dadd19256e67cc3cb98fd428099b Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 28 Aug 2017 14:34:15 -0700 Subject: [PATCH] Removed the need for libSDL2main.a on Android, and separated JNI initialization out for other integrations --- .../src/org/libsdl/app/SDLActivity.java | 126 ++++++++++-------- configure | 3 +- configure.in | 1 - include/SDL_main.h | 2 +- src/core/android/SDL_android.c | 98 +++++++++++++- src/main/android/SDL_android_main.c | 85 +----------- 6 files changed, 167 insertions(+), 148 deletions(-) diff --git a/android-project/src/org/libsdl/app/SDLActivity.java b/android-project/src/org/libsdl/app/SDLActivity.java index b1bbf1eccfe02..79a371d5d4856 100644 --- a/android-project/src/org/libsdl/app/SDLActivity.java +++ b/android-project/src/org/libsdl/app/SDLActivity.java @@ -136,10 +136,11 @@ public static void initialize() { protected void onCreate(Bundle savedInstanceState) { Log.v(TAG, "Device: " + android.os.Build.DEVICE); Log.v(TAG, "Model: " + android.os.Build.MODEL); - Log.v(TAG, "onCreate(): " + mSingleton); + Log.v(TAG, "onCreate()"); super.onCreate(savedInstanceState); SDLActivity.initialize(); + // So we can call stuff from static callbacks mSingleton = this; @@ -179,18 +180,16 @@ public void onClick(DialogInterface dialog,int id) { return; } - // Set up the surface - mSurface = new SDLSurface(getApplication()); - + // Set up JNI + SDLActivity.nativeSetupJNI(); - if(Build.VERSION.SDK_INT >= 16) { + if (Build.VERSION.SDK_INT >= 16) { mJoystickHandler = new SDLJoystickHandler_API16(); - } else if(Build.VERSION.SDK_INT >= 12) { + } else if (Build.VERSION.SDK_INT >= 12) { mJoystickHandler = new SDLJoystickHandler_API12(); } else { mJoystickHandler = new SDLJoystickHandler(); } - mHapticHandler = new SDLHapticHandler(); if (Build.VERSION.SDK_INT >= 11) { @@ -200,6 +199,9 @@ public void onClick(DialogInterface dialog,int id) { mClipboardHandler = new SDLClipboardHandler_Old(); } + // Set up the surface + mSurface = new SDLSurface(getApplication()); + mLayout = new RelativeLayout(this); mLayout.addView(mSurface); @@ -207,7 +209,6 @@ public void onClick(DialogInterface dialog,int id) { // 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) { @@ -309,6 +310,7 @@ protected void onDestroy() { } super.onDestroy(); + // Reset everything in case the user re opens the app SDLActivity.initialize(); } @@ -358,43 +360,42 @@ public static void handleNativeState() { // Try a transition to resumed state if (mNextNativeState == NativeState.RESUMED) { + if (mIsSurfaceReady && mHasFocus && mIsResumedCalled) { + 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? + + final Thread sdlThread = new Thread(new SDLMain(), "SDLThread"); + mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true); + sdlThread.start(); + + // Set up a listener thread to catch when the native thread ends + mSDLThread = new Thread(new Runnable() { + @Override + public void run() { + try { + sdlThread.join(); + } catch (Exception e) { + // Ignore any exception + } finally { + // Native thread has finished + if (!mExitCalledFromJava) { + handleNativeExit(); + } + } + } + }, "SDLThreadListener"); - if (mIsSurfaceReady && mHasFocus && mIsResumedCalled) { - - 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 - - final Thread sdlThread = new Thread(new SDLMain(), "SDLThread"); - mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true); - sdlThread.start(); - - // Set up a listener thread to catch when the native thread ends - mSDLThread = new Thread(new Runnable(){ - @Override - public void run(){ - try { - sdlThread.join(); - } - catch(Exception e){} - finally{ - // Native thread has finished - if (! mExitCalledFromJava) { - handleNativeExit(); - } - } - } - }, "SDLThreadListener"); - mSDLThread.start(); - } - + mSDLThread.start(); + } - nativeResume(); - mSurface.handleResume(); - mCurrentNativeState = mNextNativeState; - } - return; - } + nativeResume(); + mSurface.handleResume(); + mCurrentNativeState = mNextNativeState; + } + return; + } } /* The native thread has finished */ @@ -460,12 +461,14 @@ public void handleMessage(Message msg) { break; case COMMAND_SET_KEEP_SCREEN_ON: { - Window window = ((Activity) context).getWindow(); - if (window != null) { - if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) { - window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } else { - window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + if (context instanceof Activity) { + Window window = ((Activity) context).getWindow(); + if (window != null) { + if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) { + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } else { + window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } } } break; @@ -490,7 +493,8 @@ boolean sendCommand(int command, Object data) { } // C functions we call - public static native int nativeInit(Object arguments); + public static native int nativeSetupJNI(); + public static native int nativeRunMain(String library, String function, Object arguments); public static native void nativeLowMemory(); public static native void nativeQuit(); public static native void nativePause(); @@ -1208,15 +1212,25 @@ public static void clipboardSetText(String string) { } /** - Simple nativeInit() runnable + Simple runnable to start the SDL application */ class SDLMain implements Runnable { @Override public void run() { // Runs SDL_main() - SDLActivity.nativeInit(SDLActivity.mSingleton.getArguments()); + String library; + String[] libraries = SDLActivity.mSingleton.getLibraries(); + if (libraries.length > 0) { + library = "lib" + libraries[libraries.length - 1] + ".so"; + } else { + library = "libmain.so"; + } + String function = "SDL_main"; + + Log.v("SDL", "Running main function " + function + " from library " + library); + SDLActivity.nativeRunMain(library, function, SDLActivity.mSingleton.getArguments()); - //Log.v("SDL", "SDL thread terminated"); + Log.v("SDL", "Finished main function"); } } @@ -1251,7 +1265,7 @@ public SDLSurface(Context context) { mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); - if(Build.VERSION.SDK_INT >= 12) { + if (Build.VERSION.SDK_INT >= 12) { setOnGenericMotionListener(new SDLGenericMotionListener_API12()); } @@ -1964,8 +1978,8 @@ public void pollHapticDevices() { SDLHaptic haptic = getHaptic(deviceIds[i]); if (haptic == null) { InputDevice device = InputDevice.getDevice(deviceIds[i]); - Vibrator vib = device.getVibrator (); - if(vib.hasVibrator ()) { + Vibrator vib = device.getVibrator(); + if (vib.hasVibrator()) { haptic = new SDLHaptic(); haptic.device_id = deviceIds[i]; haptic.name = device.getName(); diff --git a/configure b/configure index 8011d5013b3a2..f15e2620531e2 100755 --- a/configure +++ b/configure @@ -1616,7 +1616,7 @@ Optional Features: include OpenGL ES 1.1 support [[default=yes]] --enable-video-opengles2 include OpenGL ES 2.0 support [[default=yes]] - --enable-video-vulkan include Vulkan surface support [[default=yes]] + --enable-video-vulkan include Vulkan support [[default=yes]] --enable-libudev enable libudev support [[default=yes]] --enable-dbus enable D-Bus support [[default=yes]] --enable-ime enable IME support [[default=yes]] @@ -23641,7 +23641,6 @@ case "$host" in ANDROID_CFLAGS="-DGL_GLEXT_PROTOTYPES" CFLAGS="$CFLAGS $ANDROID_CFLAGS" SDL_CFLAGS="$SDL_CFLAGS $ANDROID_CFLAGS" - SDL_LIBS="$SDL_LIBS -lSDL2main -Wl,-u,SDL_main_dummy" EXTRA_CFLAGS="$EXTRA_CFLAGS $ANDROID_CFLAGS" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ldl -lGLESv1_CM -lGLESv2 -llog -landroid" SDLMAIN_SOURCES="$srcdir/src/main/android/*.c" diff --git a/configure.in b/configure.in index ca3307eb3cc61..6e0c354ee3bd9 100644 --- a/configure.in +++ b/configure.in @@ -3201,7 +3201,6 @@ case "$host" in ANDROID_CFLAGS="-DGL_GLEXT_PROTOTYPES" CFLAGS="$CFLAGS $ANDROID_CFLAGS" SDL_CFLAGS="$SDL_CFLAGS $ANDROID_CFLAGS" - SDL_LIBS="$SDL_LIBS -lSDL2main -Wl,-u,SDL_main_dummy" EXTRA_CFLAGS="$EXTRA_CFLAGS $ANDROID_CFLAGS" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ldl -lGLESv1_CM -lGLESv2 -llog -landroid" SDLMAIN_SOURCES="$srcdir/src/main/android/*.c" diff --git a/include/SDL_main.h b/include/SDL_main.h index 24eef5e668d95..2af32360f7be8 100644 --- a/include/SDL_main.h +++ b/include/SDL_main.h @@ -107,7 +107,7 @@ /** * The prototype for the application's main() function */ -extern C_LINKAGE int SDL_main(int argc, char *argv[]); +extern C_LINKAGE DECLSPEC int SDL_main(int argc, char *argv[]); #include "begin_code.h" diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 926b68497b5d8..fabd8bfee3764 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -43,6 +43,7 @@ #include #include #include +#include /* #define LOG_TAG "SDL_android" */ /* #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) */ /* #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) */ @@ -58,6 +59,13 @@ /* Java class SDLActivity */ +JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)( + JNIEnv* mEnv, jclass cls); + +JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)( + JNIEnv* env, jclass cls, + jstring library, jstring function, jobject array); + JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDropFile)( JNIEnv* env, jclass jcls, jstring filename); @@ -237,9 +245,9 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) } /* Called before SDL_main() to initialize JNI bindings */ -JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls) +JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass cls) { - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init()"); + __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeSetupJNI()"); Android_JNI_SetupThread(); @@ -299,16 +307,95 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls) !midSetActivityTitle || !midSetOrientation || !midGetContext || !midInputGetInputDeviceIds || !midSendMessage || !midShowTextInput || !midIsScreenKeyboardShown || !midClipboardSetText || !midClipboardGetText || !midClipboardHasText) { - __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly"); + __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?"); } fidSeparateMouseAndTouch = (*mEnv)->GetStaticFieldID(mEnv, mActivityClass, "mSeparateMouseAndTouch", "Z"); if (!fidSeparateMouseAndTouch) { - __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java static fields, check that they're named and typed correctly"); + __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java static fields, do you have the latest version of SDLActivity.java?"); } - __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init() finished!"); + SDL_SetMainReady(); +} + +/* SDL main function prototype */ +typedef int (*SDL_main_func)(int argc, char *argv[]); + +/* Start up the SDL app */ +JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv* env, jclass cls, jstring library, jstring function, jobject array) +{ + int status = -1; + const char *library_file; + void *library_handle; + + library_file = (*env)->GetStringUTFChars(env, library, NULL); + library_handle = dlopen(library_file, RTLD_GLOBAL); + if (library_handle) { + const char *function_name; + SDL_main_func SDL_main; + + function_name = (*env)->GetStringUTFChars(env, function, NULL); + SDL_main = (SDL_main_func)dlsym(library_handle, function_name); + if (SDL_main) { + int i; + int argc; + int len; + char **argv; + + /* Prepare the arguments. */ + len = (*env)->GetArrayLength(env, array); + argv = SDL_stack_alloc(char*, 1 + len + 1); + argc = 0; + /* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works. + https://bitbucket.org/MartinFelis/love-android-sdl2/issue/23/release-build-crash-on-start + */ + argv[argc++] = SDL_strdup("app_process"); + for (i = 0; i < len; ++i) { + const char* utf; + char* arg = NULL; + jstring string = (*env)->GetObjectArrayElement(env, array, i); + if (string) { + utf = (*env)->GetStringUTFChars(env, string, 0); + if (utf) { + arg = SDL_strdup(utf); + (*env)->ReleaseStringUTFChars(env, string, utf); + } + (*env)->DeleteLocalRef(env, string); + } + if (!arg) { + arg = SDL_strdup(""); + } + argv[argc++] = arg; + } + argv[argc] = NULL; + + + /* Run the application. */ + status = SDL_main(argc, argv); + + /* Release the arguments. */ + for (i = 0; i < argc; ++i) { + SDL_free(argv[i]); + } + SDL_stack_free(argv); + + } else { + __android_log_print(ANDROID_LOG_ERROR, "SDL", "nativeRunMain(): Couldn't find function %s in library %s", function_name, library_file); + } + (*env)->ReleaseStringUTFChars(env, function, function_name); + + dlclose(library_handle); + + } else { + __android_log_print(ANDROID_LOG_ERROR, "SDL", "nativeRunMain(): Couldn't load library %s", library_file); + } + (*env)->ReleaseStringUTFChars(env, library, library_file); + + /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ + /* exit(status); */ + + return status; } /* Drop file */ @@ -548,6 +635,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePause)( JNIEnv* env, jclass cls) { __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativePause()"); + if (Android_Window) { SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0); SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0); diff --git a/src/main/android/SDL_android_main.c b/src/main/android/SDL_android_main.c index db6ae4fbb7d5b..054738a9aa57f 100644 --- a/src/main/android/SDL_android_main.c +++ b/src/main/android/SDL_android_main.c @@ -1,88 +1,7 @@ /* SDL_android_main.c, placed in the public domain by Sam Lantinga 3/13/14 -*/ - -#include "SDL_config.h" -#include "SDL.h" - -#ifdef __ANDROID__ - -/* Include the SDL main definition header */ -#include "SDL_main.h" - -/******************************************************************************* - Functions called by JNI -*******************************************************************************/ -#include - -/* Dummy symbol so '-u SDL_main_dummy' forces ld to link in libSDL2main.a */ -JNIEXPORT int SDL_main_dummy; - -/* Called before SDL_main() to initialize JNI bindings in SDL library */ -extern void SDL_Android_Init(JNIEnv* env, jclass cls); - -/* This prototype is needed to prevent a warning about the missing prototype for global function below */ -JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject array); - -/* Start up the SDL app */ -JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject array) -{ - int i; - int argc; - int status; - int len; - char** argv; - - /* This interface could expand with ABI negotiation, callbacks, etc. */ - SDL_Android_Init(env, cls); - SDL_SetMainReady(); - - /* Prepare the arguments. */ - - len = (*env)->GetArrayLength(env, array); - argv = SDL_stack_alloc(char*, 1 + len + 1); - argc = 0; - /* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works. - https://bitbucket.org/MartinFelis/love-android-sdl2/issue/23/release-build-crash-on-start - */ - argv[argc++] = SDL_strdup("app_process"); - for (i = 0; i < len; ++i) { - const char* utf; - char* arg = NULL; - jstring string = (*env)->GetObjectArrayElement(env, array, i); - if (string) { - utf = (*env)->GetStringUTFChars(env, string, 0); - if (utf) { - arg = SDL_strdup(utf); - (*env)->ReleaseStringUTFChars(env, string, utf); - } - (*env)->DeleteLocalRef(env, string); - } - if (!arg) { - arg = SDL_strdup(""); - } - argv[argc++] = arg; - } - argv[argc] = NULL; - - - /* Run the application. */ - - status = SDL_main(argc, argv); - - /* Release the arguments. */ - - for (i = 0; i < argc; ++i) { - SDL_free(argv[i]); - } - SDL_stack_free(argv); - /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ - /* exit(status); */ - - return status; -} - -#endif /* __ANDROID__ */ + As of SDL 2.0.6 this file is no longer necessary. +*/ /* vi: set ts=4 sw=4 expandtab: */