From f536fbea7162d939689e1d9899d082896dd67c4a Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 16 Mar 2018 11:08:53 -0700 Subject: [PATCH] Reimplemented Android cursor API support using reflection so it builds with older SDKs --- .../main/java/org/libsdl/app/SDLActivity.java | 98 ++++++++++--------- src/core/android/SDL_android.c | 32 +++--- src/core/android/SDL_android.h | 4 +- src/video/android/SDL_androidmouse.c | 12 ++- 4 files changed, 78 insertions(+), 68 deletions(-) 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 e665c4139f885..3ea99da9b67f0 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 @@ -77,10 +77,8 @@ public enum NativeState { protected static boolean mScreenKeyboardShown; protected static ViewGroup mLayout; protected static SDLClipboardHandler mClipboardHandler; - //#CURSORIMPLEENTATION - //protected static Hashtable mCursors; - //protected static int mLastCursorID; - //protected static PointerIcon mActiveCursor; + protected static Hashtable mCursors; + protected static int mLastCursorID; // This is what SDL runs in. It invokes SDL_main(), eventually @@ -153,10 +151,8 @@ public static void initialize() { mTextEdit = null; mLayout = null; mClipboardHandler = null; - //#CURSORIMPLEENTATION - //mCursors = new Hashtable(); - //mLastCursorID = 0; - //mActiveCursor = null; + mCursors = new Hashtable(); + mLastCursorID = 0; mSDLThread = null; mExitCalledFromJava = false; mBrokenLibraries = false; @@ -1093,69 +1089,91 @@ public static void clipboardSetText(String string) { /** * This method is called by SDL using JNI. */ - /** - * #CURSORIMPLEENTATION - * The cursor implementation requires API 24 or above - * public static int createCustomCursor(int[] colors, int width, int height, int hotSpotX, int hotSpotY) { Bitmap bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888); ++mLastCursorID; - mCursors.put(mLastCursorID, PointerIcon.create(bitmap, hotSpotX, hotSpotY)); + // This requires API 24, so use reflection to implement this + try { + Class PointerIconClass = Class.forName("android.view.PointerIcon"); + Class[] arg_types = new Class[] { Bitmap.class, float.class, float.class }; + Method create = PointerIconClass.getMethod("create", arg_types); + mCursors.put(mLastCursorID, create.invoke(null, bitmap, hotSpotX, hotSpotY)); + } catch (Exception e) { + return 0; + } return mLastCursorID; } - public static void setCustomCursor(int cursorID) { - mActiveCursor = mCursors.get(cursorID); + /** + * This method is called by SDL using JNI. + */ + public static boolean setCustomCursor(int cursorID) { + // This requires API 24, so use reflection to implement this + try { + Class PointerIconClass = Class.forName("android.view.PointerIcon"); + Method setPointerIcon = SDLSurface.class.getMethod("setPointerIcon", PointerIconClass); + setPointerIcon.invoke(mSurface, mCursors.get(cursorID)); + } catch (Exception e) { + return false; + } + return true; } - public static void setSystemCursor(int cursorID) { + /** + * This method is called by SDL using JNI. + */ + public static boolean setSystemCursor(int cursorID) { + int cursor_type = 0; //PointerIcon.TYPE_NULL; switch (cursorID) { - case SDL_SYSTEM_CURSOR_NONE: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_NULL); - break; case SDL_SYSTEM_CURSOR_ARROW: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_ARROW); + cursor_type = 1000; //PointerIcon.TYPE_ARROW; break; case SDL_SYSTEM_CURSOR_IBEAM: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_TEXT); + cursor_type = 1008; //PointerIcon.TYPE_TEXT; break; case SDL_SYSTEM_CURSOR_WAIT: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_WAIT); + cursor_type = 1004; //PointerIcon.TYPE_WAIT; break; case SDL_SYSTEM_CURSOR_CROSSHAIR: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_CROSSHAIR); + cursor_type = 1007; //PointerIcon.TYPE_CROSSHAIR; break; case SDL_SYSTEM_CURSOR_WAITARROW: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_WAIT); + cursor_type = 1004; //PointerIcon.TYPE_WAIT; break; case SDL_SYSTEM_CURSOR_SIZENWSE: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW); + cursor_type = 1017; //PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW; break; case SDL_SYSTEM_CURSOR_SIZENESW: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW); + cursor_type = 1016; //PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW; break; case SDL_SYSTEM_CURSOR_SIZEWE: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW); + cursor_type = 1014; //PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW; break; case SDL_SYSTEM_CURSOR_SIZENS: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW); + cursor_type = 1015; //PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW; break; case SDL_SYSTEM_CURSOR_SIZEALL: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_GRAB); + cursor_type = 1020; //PointerIcon.TYPE_GRAB; break; case SDL_SYSTEM_CURSOR_NO: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_NO_DROP); + cursor_type = 1012; //PointerIcon.TYPE_NO_DROP; break; case SDL_SYSTEM_CURSOR_HAND: - mActiveCursor = PointerIcon.getSystemIcon(SDL.getContext(), PointerIcon.TYPE_HAND); + cursor_type = 1002; //PointerIcon.TYPE_HAND; break; } + // This requires API 24, so use reflection to implement this + try { + Class PointerIconClass = Class.forName("android.view.PointerIcon"); + Class[] arg_types = new Class[] { Context.class, int.class }; + Method getSystemIcon = PointerIconClass.getMethod("getSystemIcon", arg_types); + Method setPointerIcon = SDLSurface.class.getMethod("setPointerIcon", PointerIconClass); + setPointerIcon.invoke(mSurface, getSystemIcon.invoke(null, SDL.getContext(), cursor_type)); + } catch (Exception e) { + return false; + } + return true; } - - public static PointerIcon getCursor() { - return mActiveCursor; - } - */ } /** @@ -1547,14 +1565,6 @@ public void onSensorChanged(SensorEvent event) { event.values[2] / SensorManager.GRAVITY_EARTH); } } - - /** - * #CURSORIMPLEENTATION - @Override - public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { - return SDLActivity.getCursor(); - } - */ } /* This is a fake invisible editor view that receives the input and defines the diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index dd7f1ba06ab80..c5bec9059f6d3 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -335,17 +335,16 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass c "getManifestEnvironmentVariables", "()Z"); midGetDisplayDPI = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "getDisplayDPI", "()Landroid/util/DisplayMetrics;"); - - /* Custom cursor implementation is only available on API 24 and above */ midCreateCustomCursor = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "createCustomCursor", "([IIIII)I"); - midSetCustomCursor = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "setCustomCursor", "(I)V"); - midSetSystemCursor = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "setSystemCursor", "(I)V"); + midSetCustomCursor = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "setCustomCursor", "(I)Z"); + midSetSystemCursor = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "setSystemCursor", "(I)Z"); if (!midGetNativeSurface || !midSetActivityTitle || !midSetWindowStyle || !midSetOrientation || !midGetContext || !midIsAndroidTV || !midInputGetInputDeviceIds || !midSendMessage || !midShowTextInput || !midIsScreenKeyboardShown || !midClipboardSetText || !midClipboardGetText || !midClipboardHasText || - !midOpenAPKExpansionInputStream || !midGetManifestEnvironmentVariables|| !midGetDisplayDPI) { + !midOpenAPKExpansionInputStream || !midGetManifestEnvironmentVariables || !midGetDisplayDPI || + !midCreateCustomCursor || !midSetCustomCursor || !midSetSystemCursor) { __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?"); } @@ -2178,34 +2177,29 @@ int Android_JNI_CreateCustomCursor(SDL_Surface *surface, int hot_x, int hot_y) { JNIEnv *mEnv = Android_JNI_GetEnv(); int custom_cursor = 0; - if (midCreateCustomCursor) { - jintArray pixels; - pixels = (*mEnv)->NewIntArray(mEnv, surface->w * surface->h); - if (!pixels) { - return 0; - } + jintArray pixels; + pixels = (*mEnv)->NewIntArray(mEnv, surface->w * surface->h); + if (pixels) { (*mEnv)->SetIntArrayRegion(mEnv, pixels, 0, surface->w * surface->h, (int *)surface->pixels); custom_cursor = (*mEnv)->CallStaticIntMethod(mEnv, mActivityClass, midCreateCustomCursor, pixels, surface->w, surface->h, hot_x, hot_y); (*mEnv)->DeleteLocalRef(mEnv, pixels); + } else { + SDL_OutOfMemory(); } return custom_cursor; } -void Android_JNI_SetCustomCursor(int cursorID) +SDL_bool Android_JNI_SetCustomCursor(int cursorID) { JNIEnv *mEnv = Android_JNI_GetEnv(); - if (midSetCustomCursor) { - (*mEnv)->CallStaticVoidMethod(mEnv, mActivityClass, midSetCustomCursor, cursorID); - } + return (*mEnv)->CallStaticBooleanMethod(mEnv, mActivityClass, midSetCustomCursor, cursorID); } -void Android_JNI_SetSystemCursor(int cursorID) +SDL_bool Android_JNI_SetSystemCursor(int cursorID) { JNIEnv *mEnv = Android_JNI_GetEnv(); - if (midSetSystemCursor) { - (*mEnv)->CallStaticVoidMethod(mEnv, mActivityClass, midSetSystemCursor, cursorID); - } + return (*mEnv)->CallStaticBooleanMethod(mEnv, mActivityClass, midSetSystemCursor, cursorID); } #endif /* __ANDROID__ */ diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h index b801092661143..5eb727d19ecc1 100644 --- a/src/core/android/SDL_android.h +++ b/src/core/android/SDL_android.h @@ -104,8 +104,8 @@ int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *bu /* Cursor support */ int Android_JNI_CreateCustomCursor(SDL_Surface *surface, int hot_x, int hot_y); -void Android_JNI_SetCustomCursor(int cursorID); -void Android_JNI_SetSystemCursor(int cursorID); +SDL_bool Android_JNI_SetCustomCursor(int cursorID); +SDL_bool Android_JNI_SetSystemCursor(int cursorID); /* Ends C function definitions when using C++ */ #ifdef __cplusplus diff --git a/src/video/android/SDL_androidmouse.c b/src/video/android/SDL_androidmouse.c index b84b6cefdb604..13c62718a2c3e 100644 --- a/src/video/android/SDL_androidmouse.c +++ b/src/video/android/SDL_androidmouse.c @@ -121,12 +121,18 @@ Android_ShowCursor(SDL_Cursor * cursor) if (cursor) { SDL_AndroidCursorData *data = (SDL_AndroidCursorData*)cursor->driverdata; if (data->custom_cursor) { - Android_JNI_SetCustomCursor(data->custom_cursor); + if (!Android_JNI_SetCustomCursor(data->custom_cursor)) { + return SDL_Unsupported(); + } } else { - Android_JNI_SetSystemCursor(data->system_cursor); + if (!Android_JNI_SetSystemCursor(data->system_cursor)) { + return SDL_Unsupported(); + } } } else { - Android_JNI_SetSystemCursor(-1); + if (!Android_JNI_SetSystemCursor(-1)) { + return SDL_Unsupported(); + } } return 0; }