From 11357b354f620d26828c3b8bf8578ffeb40cb102 Mon Sep 17 00:00:00 2001 From: Mario Liebisch Date: Thu, 4 Jun 2015 16:55:58 +0200 Subject: [PATCH] Android: Updated the JNI/event handling code * Local Java references are now freed after use. * SFML is now able to consider (Android) events as unhandled and pass them. * Hovering a pen over the screen no longer triggers movement events (untested). --- src/SFML/Window/Android/InputImpl.cpp | 10 +++ src/SFML/Window/Android/WindowImplAndroid.cpp | 73 +++++++++++-------- src/SFML/Window/Android/WindowImplAndroid.hpp | 8 +- 3 files changed, 55 insertions(+), 36 deletions(-) diff --git a/src/SFML/Window/Android/InputImpl.cpp b/src/SFML/Window/Android/InputImpl.cpp index 920587b2..8940b9e2 100644 --- a/src/SFML/Window/Android/InputImpl.cpp +++ b/src/SFML/Window/Android/InputImpl.cpp @@ -78,6 +78,7 @@ void InputImpl::setVirtualKeyboardVisible(bool visible) "INPUT_METHOD_SERVICE", "Ljava/lang/String;"); jobject INPUT_METHOD_SERVICE = lJNIEnv->GetStaticObjectField(ClassContext, FieldINPUT_METHOD_SERVICE); + lJNIEnv->DeleteLocalRef(ClassContext); // Runs getSystemService(Context.INPUT_METHOD_SERVICE) jclass ClassInputMethodManager = @@ -86,6 +87,7 @@ void InputImpl::setVirtualKeyboardVisible(bool visible) "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"); jobject lInputMethodManager = lJNIEnv->CallObjectMethod(lNativeActivity, MethodGetSystemService, INPUT_METHOD_SERVICE); + lJNIEnv->DeleteLocalRef(INPUT_METHOD_SERVICE); // Runs getWindow().getDecorView() jmethodID MethodGetWindow = lJNIEnv->GetMethodID(ClassNativeActivity, @@ -95,6 +97,8 @@ void InputImpl::setVirtualKeyboardVisible(bool visible) jmethodID MethodGetDecorView = lJNIEnv->GetMethodID(ClassWindow, "getDecorView", "()Landroid/view/View;"); jobject lDecorView = lJNIEnv->CallObjectMethod(lWindow, MethodGetDecorView); + lJNIEnv->DeleteLocalRef(lWindow); + lJNIEnv->DeleteLocalRef(ClassWindow); if (visible) { @@ -112,13 +116,19 @@ void InputImpl::setVirtualKeyboardVisible(bool visible) "getWindowToken", "()Landroid/os/IBinder;"); jobject lBinder = lJNIEnv->CallObjectMethod(lDecorView, MethodGetWindowToken); + lJNIEnv->DeleteLocalRef(ClassView); // lInputMethodManager.hideSoftInput(...) jmethodID MethodHideSoftInput = lJNIEnv->GetMethodID(ClassInputMethodManager, "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z"); jboolean lRes = lJNIEnv->CallBooleanMethod(lInputMethodManager, MethodHideSoftInput, lBinder, lFlags); + lJNIEnv->DeleteLocalRef(lBinder); } + lJNIEnv->DeleteLocalRef(lNativeActivity); + lJNIEnv->DeleteLocalRef(ClassNativeActivity); + lJNIEnv->DeleteLocalRef(ClassInputMethodManager); + lJNIEnv->DeleteLocalRef(lDecorView); // Finished with the JVM lJavaVM->DetachCurrentThread(); diff --git a/src/SFML/Window/Android/WindowImplAndroid.cpp b/src/SFML/Window/Android/WindowImplAndroid.cpp index 2c140b05..fb1906bb 100644 --- a/src/SFML/Window/Android/WindowImplAndroid.cpp +++ b/src/SFML/Window/Android/WindowImplAndroid.cpp @@ -33,9 +33,11 @@ #include #include -// Define missing constants -#define AMOTION_EVENT_ACTION_HOVER_MOVE 0x00000007 -#define AMOTION_EVENT_ACTION_SCROLL 0x00000008 +// Define missing constants for older API levels +#if __ANDROID_API__ < 13 + #define AMOTION_EVENT_ACTION_HOVER_MOVE 0x00000007 + #define AMOTION_EVENT_ACTION_SCROLL 0x00000008 +#endif //////////////////////////////////////////////////////////// // Private data @@ -232,7 +234,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data) if (AInputQueue_preDispatchEvent(states->inputQueue, _event)) return 1; - int32_t handled = 0; + int handled = 0; int32_t type = AInputEvent_getType(_event); @@ -244,8 +246,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data) if ((action == AKEY_EVENT_ACTION_DOWN || action == AKEY_EVENT_ACTION_UP || action == AKEY_EVENT_ACTION_MULTIPLE) && key != AKEYCODE_VOLUME_UP && key != AKEYCODE_VOLUME_DOWN) { - processKeyEvent(_event, states); - handled = 1; + handled = processKeyEvent(_event, states); } } else if (type == AINPUT_EVENT_TYPE_MOTION) @@ -256,16 +257,15 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data) { case AMOTION_EVENT_ACTION_SCROLL: { - processScrollEvent(_event, states); - handled = 1; + handled = processScrollEvent(_event, states); break; } - case AMOTION_EVENT_ACTION_HOVER_MOVE: + // todo: should hover_move indeed trigger the event? + // case AMOTION_EVENT_ACTION_HOVER_MOVE: case AMOTION_EVENT_ACTION_MOVE: { - processMotionEvent(_event, states); - handled = 1; + handled = processMotionEvent(_event, states); break; } @@ -273,8 +273,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data) case AMOTION_EVENT_ACTION_POINTER_DOWN: case AMOTION_EVENT_ACTION_DOWN: { - processPointerEvent(true, _event, states); - handled = 1; + handled = processPointerEvent(true, _event, states); break; } @@ -282,8 +281,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data) case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: { - processPointerEvent(false, _event, states); - handled = 1; + handled = processPointerEvent(false, _event, states); break; } } @@ -298,7 +296,7 @@ int WindowImplAndroid::processEvent(int fd, int events, void* data) //////////////////////////////////////////////////////////// -void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* states) +int WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* states) { // Prepare the Java virtual machine jint lResult; @@ -314,8 +312,10 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs); - if (lResult == JNI_ERR) + if (lResult == JNI_ERR) { err() << "Failed to initialize JNI, couldn't get the Unicode value" << std::endl; + return 0; + } // Retrieve everything we need to create this MotionEvent in Java jlong downTime = AMotionEvent_getDownTime(_event); @@ -340,6 +340,9 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* jmethodID MethodGetAxisValue = lJNIEnv->GetMethodID(ClassMotionEvent, "getAxisValue", "(I)F"); jfloat delta = lJNIEnv->CallFloatMethod(ObjectMotionEvent, MethodGetAxisValue, 0x00000001); + lJNIEnv->DeleteLocalRef(ClassMotionEvent); + lJNIEnv->DeleteLocalRef(ObjectMotionEvent); + // Create and send our mouse wheel event Event event; event.type = Event::MouseWheelMoved; @@ -351,11 +354,13 @@ void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* // Detach this thread from the JVM lJavaVM->DetachCurrentThread(); + + return 1; } //////////////////////////////////////////////////////////// -void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* states) +int WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* states) { int32_t device = AInputEvent_getSource(_event); int32_t action = AKeyEvent_getAction(_event); @@ -374,7 +379,7 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta case AKEY_EVENT_ACTION_DOWN: event.type = Event::KeyPressed; forwardEvent(event); - break; + return 1; case AKEY_EVENT_ACTION_UP: event.type = Event::KeyReleased; forwardEvent(event); @@ -385,7 +390,7 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta event.text.unicode = unicode; forwardEvent(event); } - break; + return 1; case AKEY_EVENT_ACTION_MULTIPLE: // Since complex inputs don't get separate key down/up events // both have to be faked at once @@ -400,27 +405,26 @@ void WindowImplAndroid::processKeyEvent(AInputEvent* _event, ActivityStates* sta { // This is a unique sequence, which is not yet exposed in the NDK // http://code.google.com/p/android/issues/detail?id=33998 + return 0; } - else + else if (int unicode = getUnicode(_event)) // This is a repeated sequence { - // This is a repeated sequence - if (int unicode = getUnicode(_event)) - { - event.type = Event::TextEntered; - event.text.unicode = unicode; + event.type = Event::TextEntered; + event.text.unicode = unicode; - int32_t repeats = AKeyEvent_getRepeatCount(_event); - for (int32_t i = 0; i < repeats; ++i) - forwardEvent(event); - } + int32_t repeats = AKeyEvent_getRepeatCount(_event); + for (int32_t i = 0; i < repeats; ++i) + forwardEvent(event); + return 1; } break; } + return 0; } //////////////////////////////////////////////////////////// -void WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates* states) +int WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates* states) { int32_t device = AInputEvent_getSource(_event); int32_t action = AMotionEvent_getAction(_event); @@ -462,11 +466,12 @@ void WindowImplAndroid::processMotionEvent(AInputEvent* _event, ActivityStates* forwardEvent(event); } + return 1; } //////////////////////////////////////////////////////////// -void WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, ActivityStates* states) +int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, ActivityStates* states) { int32_t device = AInputEvent_getSource(_event); int32_t action = AMotionEvent_getAction(_event); @@ -525,6 +530,7 @@ void WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, Ac } forwardEvent(event); + return 1; } @@ -693,6 +699,9 @@ int WindowImplAndroid::getUnicode(AInputEvent* event) jmethodID MethodGetUnicode = lJNIEnv->GetMethodID(ClassKeyEvent, "getUnicodeChar", "(I)I"); int unicode = lJNIEnv->CallIntMethod(ObjectKeyEvent, MethodGetUnicode, metaState); + lJNIEnv->DeleteLocalRef(ClassKeyEvent); + lJNIEnv->DeleteLocalRef(ObjectKeyEvent); + // Detach this thread from the JVM lJavaVM->DetachCurrentThread(); diff --git a/src/SFML/Window/Android/WindowImplAndroid.hpp b/src/SFML/Window/Android/WindowImplAndroid.hpp index cdfb5217..fb05b35b 100644 --- a/src/SFML/Window/Android/WindowImplAndroid.hpp +++ b/src/SFML/Window/Android/WindowImplAndroid.hpp @@ -194,10 +194,10 @@ private: //////////////////////////////////////////////////////////// static int processEvent(int fd, int events, void* data); - static void processScrollEvent(AInputEvent* _event, ActivityStates* states); - static void processKeyEvent(AInputEvent* _event, ActivityStates* states); - static void processMotionEvent(AInputEvent* _event, ActivityStates* states); - static void processPointerEvent(bool isDown, AInputEvent* event, ActivityStates* states); + static int processScrollEvent(AInputEvent* _event, ActivityStates* states); + static int processKeyEvent(AInputEvent* _event, ActivityStates* states); + static int processMotionEvent(AInputEvent* _event, ActivityStates* states); + static int processPointerEvent(bool isDown, AInputEvent* event, ActivityStates* states); //////////////////////////////////////////////////////////// /// \brief Convert a Android key to SFML key code