Explorar o código

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.
Philipp Wiesemann %!s(int64=12) %!d(string=hai) anos
pai
achega
0db36f51aa

+ 20 - 0
android-project/src/org/libsdl/app/SDLActivity.java

@@ -1,5 +1,7 @@
 package org.libsdl.app;
 package org.libsdl.app;
 
 
+import java.util.Arrays;
+
 import android.app.*;
 import android.app.*;
 import android.content.*;
 import android.content.*;
 import android.view.*;
 import android.view.*;
@@ -386,6 +388,24 @@ public class SDLActivity extends Activity {
             mAudioTrack = null;
             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);
+    }
 }
 }
 
 
 /**
 /**

+ 26 - 0
src/core/android/SDL_android.c

@@ -1186,6 +1186,32 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco
     return 0;
     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 */
 /* sends message to be handled on the UI event dispatch thread */
 int Android_JNI_SendMessage(int command, int param)
 int Android_JNI_SendMessage(int command, int param)
 {
 {

+ 3 - 0
src/core/android/SDL_android.h

@@ -65,6 +65,9 @@ SDL_bool Android_JNI_HasClipboardText();
 /* Power support */
 /* Power support */
 int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent);
 int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent);
 
 
+/* Touch support */
+int Android_JNI_GetTouchDeviceIds(int **ids);
+
 /* Threads */
 /* Threads */
 #include <jni.h>
 #include <jni.h>
 JNIEnv *Android_JNI_GetEnv(void);
 JNIEnv *Android_JNI_GetEnv(void);

+ 14 - 0
src/video/android/SDL_androidtouch.c

@@ -31,6 +31,7 @@
 
 
 #include "SDL_androidtouch.h"
 #include "SDL_androidtouch.h"
 
 
+#include "../../core/android/SDL_android.h"
 
 
 #define ACTION_DOWN 0
 #define ACTION_DOWN 0
 #define ACTION_UP 1
 #define ACTION_UP 1
@@ -53,6 +54,19 @@ static void Android_GetWindowCoordinates(float x, float y,
     *window_y = (int)(y * window_h);
     *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)
 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;
     SDL_TouchID touchDeviceId = 0;

+ 1 - 0
src/video/android/SDL_androidtouch.h

@@ -22,6 +22,7 @@
 
 
 #include "SDL_androidvideo.h"
 #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);
 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: */
 /* vi: set ts=4 sw=4 expandtab: */

+ 3 - 0
src/video/android/SDL_androidvideo.c

@@ -36,6 +36,7 @@
 #include "SDL_androidclipboard.h"
 #include "SDL_androidclipboard.h"
 #include "SDL_androidevents.h"
 #include "SDL_androidevents.h"
 #include "SDL_androidkeyboard.h"
 #include "SDL_androidkeyboard.h"
+#include "SDL_androidtouch.h"
 #include "SDL_androidwindow.h"
 #include "SDL_androidwindow.h"
 
 
 #define ANDROID_VID_DRIVER_NAME "Android"
 #define ANDROID_VID_DRIVER_NAME "Android"
@@ -165,6 +166,8 @@ Android_VideoInit(_THIS)
 
 
     Android_InitKeyboard();
     Android_InitKeyboard();
 
 
+    Android_InitTouch();
+
     /* We're done! */
     /* We're done! */
     return 0;
     return 0;
 }
 }