From 0db36f51aa7a867f36e875f89a2caf89181e8463 Mon Sep 17 00:00:00 2001 From: Philipp Wiesemann Date: Sat, 5 Oct 2013 17:08:19 +0200 Subject: [PATCH] Added detection of touch devices before first touch events happen on Android. On Android available touch devices are now added with video initialization (like the keyboard). This fixes SDL_GetNumTouchDevices() returning 0 before any touch events happened although there is a touch screen available. The adding of touch devices after a touch event was received is still active to allow connecting devices later (if this is possible) and to provide a fallback if the new init did not work somehow. For the implementation JNI was used and API level 9 is required. There seems to be nothing in the Android NDK's input header (input.h) to implement everything on C side without communication with Java side. --- .../src/org/libsdl/app/SDLActivity.java | 20 ++++++++++++++ src/core/android/SDL_android.c | 26 +++++++++++++++++++ src/core/android/SDL_android.h | 3 +++ src/video/android/SDL_androidtouch.c | 14 ++++++++++ src/video/android/SDL_androidtouch.h | 1 + src/video/android/SDL_androidvideo.c | 3 +++ 6 files changed, 67 insertions(+) diff --git a/android-project/src/org/libsdl/app/SDLActivity.java b/android-project/src/org/libsdl/app/SDLActivity.java index 52e48e23673b0..1e194fa3d9771 100644 --- a/android-project/src/org/libsdl/app/SDLActivity.java +++ b/android-project/src/org/libsdl/app/SDLActivity.java @@ -1,5 +1,7 @@ package org.libsdl.app; +import java.util.Arrays; + import android.app.*; import android.content.*; import android.view.*; @@ -386,6 +388,24 @@ public static void audioQuit() { mAudioTrack = null; } } + + // Input + + /** + * @return an array which may be empty but is never null. + */ + public static int[] inputGetInputDeviceIds(int sources) { + int[] ids = InputDevice.getDeviceIds(); + int[] filtered = new int[ids.length]; + int used = 0; + for (int i = 0; i < ids.length; ++i) { + InputDevice device = InputDevice.getDevice(ids[i]); + if ((device != null) && ((device.getSources() & sources) != 0)) { + filtered[used++] = device.getId(); + } + } + return Arrays.copyOf(filtered, used); + } } /** diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 00592e87afe39..688055bbf177e 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -1186,6 +1186,32 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco return 0; } +/* returns number of found touch devices as return value and ids in parameter ids */ +int Android_JNI_GetTouchDeviceIds(int **ids) { + JNIEnv *env = Android_JNI_GetEnv(); + jint sources = 4098; /* == InputDevice.SOURCE_TOUCHSCREEN */ + jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "inputGetInputDeviceIds", "(I)[I"); + jintArray array = (jintArray) (*env)->CallStaticObjectMethod(env, mActivityClass, mid, sources); + int number = 0; + *ids = NULL; + if (array) { + number = (int) (*env)->GetArrayLength(env, array); + if (0 < number) { + jint* elements = (*env)->GetIntArrayElements(env, array, NULL); + if (elements) { + int i; + *ids = SDL_malloc(number * sizeof (*ids[0])); + for (i = 0; i < number; ++i) { /* not assuming sizeof (jint) == sizeof (int) */ + *ids[i] = elements[i]; + } + (*env)->ReleaseIntArrayElements(env, array, elements, JNI_ABORT); + } + } + (*env)->DeleteLocalRef(env, array); + } + return number; +} + /* sends message to be handled on the UI event dispatch thread */ int Android_JNI_SendMessage(int command, int param) { diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h index feb7a60237df8..6181a15db89ed 100644 --- a/src/core/android/SDL_android.h +++ b/src/core/android/SDL_android.h @@ -65,6 +65,9 @@ SDL_bool Android_JNI_HasClipboardText(); /* Power support */ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent); +/* Touch support */ +int Android_JNI_GetTouchDeviceIds(int **ids); + /* Threads */ #include JNIEnv *Android_JNI_GetEnv(void); diff --git a/src/video/android/SDL_androidtouch.c b/src/video/android/SDL_androidtouch.c index 3265b54eb096b..6ad26e2c9651f 100644 --- a/src/video/android/SDL_androidtouch.c +++ b/src/video/android/SDL_androidtouch.c @@ -31,6 +31,7 @@ #include "SDL_androidtouch.h" +#include "../../core/android/SDL_android.h" #define ACTION_DOWN 0 #define ACTION_UP 1 @@ -53,6 +54,19 @@ static void Android_GetWindowCoordinates(float x, float y, *window_y = (int)(y * window_h); } +void Android_InitTouch(void) +{ + int i; + int* ids; + int number = Android_JNI_GetTouchDeviceIds(&ids); + if (0 < number) { + for (i = 0; i < number; ++i) { + SDL_AddTouch((SDL_TouchID) ids[i], ""); /* no error handling */ + } + SDL_free(ids); + } +} + void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p) { SDL_TouchID touchDeviceId = 0; diff --git a/src/video/android/SDL_androidtouch.h b/src/video/android/SDL_androidtouch.h index 50a3ebdc8a4f1..346d73a664970 100644 --- a/src/video/android/SDL_androidtouch.h +++ b/src/video/android/SDL_androidtouch.h @@ -22,6 +22,7 @@ #include "SDL_androidvideo.h" +extern void Android_InitTouch(void); extern void Android_OnTouch( int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p); /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index 0bf3a2ce96a2a..fc766ece7f643 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -36,6 +36,7 @@ #include "SDL_androidclipboard.h" #include "SDL_androidevents.h" #include "SDL_androidkeyboard.h" +#include "SDL_androidtouch.h" #include "SDL_androidwindow.h" #define ANDROID_VID_DRIVER_NAME "Android" @@ -165,6 +166,8 @@ Android_VideoInit(_THIS) Android_InitKeyboard(); + Android_InitTouch(); + /* We're done! */ return 0; }