Fixed bug 3191 - haptic system on android?

Patch provided by jintiao and Milan Nikolic, thanks!
This commit is contained in:
Sam Lantinga
2017-08-12 08:15:09 -07:00
parent 78c84e7029
commit 0a52db54bd
10 changed files with 521 additions and 3 deletions
+1 -1
View File
@@ -28,7 +28,7 @@ LOCAL_SRC_FILES := \
$(wildcard $(LOCAL_PATH)/src/events/*.c) \
$(wildcard $(LOCAL_PATH)/src/file/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/dummy/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/loadso/dlopen/*.c) \
+2
View File
@@ -16,6 +16,8 @@
<!-- Allow writing to external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Allow access to the vibrator -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- if you want to capture audio, uncomment this. -->
<!-- <uses-permission android:name="android.permission.RECORD_AUDIO" /> -->
@@ -61,6 +61,7 @@ public class SDLActivity extends Activity {
protected static View mTextEdit;
protected static ViewGroup mLayout;
protected static SDLJoystickHandler mJoystickHandler;
protected static SDLHapticHandler mHapticHandler;
// This is what SDL runs in. It invokes SDL_main(), eventually
protected static Thread mSDLThread;
@@ -113,6 +114,7 @@ public class SDLActivity extends Activity {
mTextEdit = null;
mLayout = null;
mJoystickHandler = null;
mHapticHandler = null;
mSDLThread = null;
mAudioTrack = null;
mAudioRecord = null;
@@ -182,6 +184,7 @@ public class SDLActivity extends Activity {
else {
mJoystickHandler = new SDLJoystickHandler();
}
mHapticHandler = new SDLHapticHandler();
mLayout = new RelativeLayout(this);
mLayout.addView(mSurface);
@@ -498,6 +501,8 @@ public class SDLActivity extends Activity {
int is_accelerometer, int nbuttons,
int naxes, int nhats, int nballs);
public static native int nativeRemoveJoystick(int device_id);
public static native int nativeAddHaptic(int device_id, String name);
public static native int nativeRemoveHaptic(int device_id);
public static native String nativeGetHint(String name);
/**
@@ -1704,6 +1709,18 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
return null;
}
public static void pollHapticDevices() {
if (SDLActivity.mSDLThread != null) {
mHapticHandler.pollHapticDevices();
}
}
public static void hapticRun(int device_id, int length) {
if (SDLActivity.mSDLThread != null) {
mHapticHandler.run(device_id, length);
}
}
@Override
public boolean handleMotionEvent(MotionEvent event) {
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
@@ -1779,3 +1796,82 @@ class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
return false;
}
}
class SDLHapticHandler {
class SDLHaptic {
public int device_id;
public String name;
public Vibrator vib;
}
private ArrayList<SDLHaptic> mHaptics;
public SDLHapticHandler() {
mHaptics = new ArrayList<SDLHaptic>();
}
public void run(int device_id, int length) {
SDLHaptic haptic = getHaptic(device_id);
if (haptic != null) {
haptic.vib.vibrate (length);
}
}
public void pollHapticDevices() {
int[] deviceIds = InputDevice.getDeviceIds();
// It helps processing the device ids in reverse order
// For example, in the case of the XBox 360 wireless dongle,
// so the first controller seen by SDL matches what the receiver
// considers to be the first controller
for(int i=deviceIds.length-1; i>-1; i--) {
SDLHaptic haptic = getHaptic(deviceIds[i]);
if (haptic == null) {
InputDevice device = InputDevice.getDevice(deviceIds[i]);
Vibrator vib = device.getVibrator ();
if(vib.hasVibrator ()) {
haptic = new SDLHaptic();
haptic.device_id = deviceIds[i];
haptic.name = device.getName();
haptic.vib = vib;
mHaptics.add(haptic);
SDLActivity.nativeAddHaptic(haptic.device_id, haptic.name);
}
}
}
/* Check removed devices */
ArrayList<Integer> removedDevices = new ArrayList<Integer>();
for(int i=0; i < mHaptics.size(); i++) {
int device_id = mHaptics.get(i).device_id;
int j;
for (j=0; j < deviceIds.length; j++) {
if (device_id == deviceIds[j]) break;
}
if (j == deviceIds.length) {
removedDevices.add(device_id);
}
}
for(int i=0; i < removedDevices.size(); i++) {
int device_id = removedDevices.get(i);
SDLActivity.nativeRemoveHaptic(device_id);
for (int j=0; j < mHaptics.size(); j++) {
if (mHaptics.get(j).device_id == device_id) {
mHaptics.remove(j);
break;
}
}
}
}
protected SDLHaptic getHaptic(int device_id) {
for(int i=0; i < mHaptics.size(); i++) {
if (mHaptics.get(i).device_id == device_id) {
return mHaptics.get(i);
}
}
return null;
}
}
+1 -1
View File
@@ -118,7 +118,7 @@
/* Enable various input drivers */
#define SDL_JOYSTICK_ANDROID 1
#define SDL_HAPTIC_DUMMY 1
#define SDL_HAPTIC_ANDROID 1
/* Enable various shared object loading systems */
#define SDL_LOADSO_DLOPEN 1
+40 -1
View File
@@ -37,6 +37,7 @@
#include "../../video/android/SDL_androidvideo.h"
#include "../../video/android/SDL_androidwindow.h"
#include "../../joystick/android/SDL_sysjoystick_c.h"
#include "../../haptic/android/SDL_syshaptic_c.h"
#include <android/log.h>
#include <pthread.h>
@@ -177,6 +178,8 @@ static jmethodID midCaptureReadShortBuffer;
static jmethodID midCaptureReadByteBuffer;
static jmethodID midCaptureClose;
static jmethodID midPollInputDevices;
static jmethodID midPollHapticDevices;
static jmethodID midHapticRun;
/* Accelerometer data storage */
static float fLastAccelerometer[3];
@@ -237,13 +240,17 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls)
"captureClose", "()V");
midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"pollInputDevices", "()V");
midPollHapticDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"pollHapticDevices", "()V");
midHapticRun = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"hapticRun", "(II)V");
bHasNewData = SDL_FALSE;
if (!midGetNativeSurface ||
!midAudioOpen || !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioClose ||
!midCaptureOpen || !midCaptureReadShortBuffer || !midCaptureReadByteBuffer || !midCaptureClose ||
!midPollInputDevices) {
!midPollInputDevices || !midPollHapticDevices || !midHapticRun) {
__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_INFO, "SDL", "SDL_Android_Init() finished!");
@@ -323,6 +330,25 @@ JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeRemoveJoystick)(
return Android_RemoveJoystick(device_id);
}
JNIEXPORT jint JNICALL Java_org_libsdl_app_SDLActivity_nativeAddHaptic(
JNIEnv* env, jclass jcls, jint device_id, jstring device_name)
{
int retval;
const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
retval = Android_AddHaptic(device_id, name);
(*env)->ReleaseStringUTFChars(env, device_name, name);
return retval;
}
JNIEXPORT jint JNICALL Java_org_libsdl_app_SDLActivity_nativeRemoveHaptic(
JNIEnv* env, jclass jcls, jint device_id)
{
return Android_RemoveHaptic(device_id);
}
/* Surface Created */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(JNIEnv* env, jclass jcls)
@@ -1570,6 +1596,19 @@ void Android_JNI_PollInputDevices(void)
(*env)->CallStaticVoidMethod(env, mActivityClass, midPollInputDevices);
}
void Android_JNI_PollHapticDevices(void)
{
JNIEnv *env = Android_JNI_GetEnv();
(*env)->CallStaticVoidMethod(env, mActivityClass, midPollHapticDevices);
}
void Android_JNI_HapticRun(int device_id, int length)
{
JNIEnv *env = Android_JNI_GetEnv();
(*env)->CallStaticVoidMethod(env, mActivityClass, midHapticRun, device_id, length);
}
/* See SDLActivity.java for constants. */
#define COMMAND_SET_KEEP_SCREEN_ON 5
+4
View File
@@ -67,6 +67,10 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco
/* Joystick support */
void Android_JNI_PollInputDevices(void);
/* Haptic support */
void Android_JNI_PollHapticDevices(void);
void Android_JNI_HapticRun(int device_id, int length);
/* Video */
void Android_JNI_SuspendScreenSaver(SDL_bool suspend);
+1
View File
@@ -313,6 +313,7 @@ SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
SDL_memset(haptic, 0, sizeof(SDL_Haptic));
haptic->rumble_id = -1;
if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
SDL_SetError("Haptic: SDL_SYS_HapticOpenFromJoystick failed.");
SDL_free(haptic);
return NULL;
}
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
#include "SDL_config.h"
#ifdef SDL_HAPTIC_ANDROID
extern int Android_AddHaptic(int device_id, const char *name);
extern int Android_RemoveHaptic(int device_id);
#endif /* SDL_HAPTIC_ANDROID */
/* vi: set ts=4 sw=4 expandtab: */
+6
View File
@@ -22,6 +22,10 @@
#include "../../SDL_internal.h"
#ifdef SDL_JOYSTICK_ANDROID
#ifndef _SDL_sysjoystick_c_h
#define _SDL_sysjoystick_c_h
#include "../SDL_sysjoystick.h"
extern int Android_OnPadDown(int device_id, int keycode);
@@ -47,6 +51,8 @@ typedef struct SDL_joylist_item
typedef SDL_joylist_item joystick_hwdata;
#endif /* _SDL_sysjoystick_c_h */
#endif /* SDL_JOYSTICK_ANDROID */
/* vi: set ts=4 sw=4 expandtab: */