Fixed bug 3191 - haptic system on android?
authorSam Lantinga <slouken@libsdl.org>
Sat, 12 Aug 2017 08:15:09 -0700
changeset 11238c728c661cec7
parent 11237 11c69137bfd5
child 11239 856e5e3c1e86
Fixed bug 3191 - haptic system on android?

Patch provided by jintiao and Milan Nikolic, thanks!
Android.mk
android-project/AndroidManifest.xml
android-project/src/org/libsdl/app/SDLActivity.java
include/SDL_config_android.h
src/core/android/SDL_android.c
src/core/android/SDL_android.h
src/haptic/SDL_haptic.c
src/haptic/android/SDL_syshaptic.c
src/haptic/android/SDL_syshaptic_c.h
src/joystick/android/SDL_sysjoystick_c.h
     1.1 --- a/Android.mk	Sat Aug 12 08:06:16 2017 -0700
     1.2 +++ b/Android.mk	Sat Aug 12 08:15:09 2017 -0700
     1.3 @@ -28,7 +28,7 @@
     1.4  	$(wildcard $(LOCAL_PATH)/src/events/*.c) \
     1.5  	$(wildcard $(LOCAL_PATH)/src/file/*.c) \
     1.6  	$(wildcard $(LOCAL_PATH)/src/haptic/*.c) \
     1.7 -	$(wildcard $(LOCAL_PATH)/src/haptic/dummy/*.c) \
     1.8 +	$(wildcard $(LOCAL_PATH)/src/haptic/android/*.c) \
     1.9  	$(wildcard $(LOCAL_PATH)/src/joystick/*.c) \
    1.10  	$(wildcard $(LOCAL_PATH)/src/joystick/android/*.c) \
    1.11  	$(wildcard $(LOCAL_PATH)/src/loadso/dlopen/*.c) \
     2.1 --- a/android-project/AndroidManifest.xml	Sat Aug 12 08:06:16 2017 -0700
     2.2 +++ b/android-project/AndroidManifest.xml	Sat Aug 12 08:15:09 2017 -0700
     2.3 @@ -16,6 +16,8 @@
     2.4  
     2.5      <!-- Allow writing to external storage -->
     2.6      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     2.7 +    <!-- Allow access to the vibrator -->
     2.8 +    <uses-permission android:name="android.permission.VIBRATE" />
     2.9  
    2.10      <!-- if you want to capture audio, uncomment this. -->
    2.11      <!-- <uses-permission android:name="android.permission.RECORD_AUDIO" /> -->
     3.1 --- a/android-project/src/org/libsdl/app/SDLActivity.java	Sat Aug 12 08:06:16 2017 -0700
     3.2 +++ b/android-project/src/org/libsdl/app/SDLActivity.java	Sat Aug 12 08:15:09 2017 -0700
     3.3 @@ -61,6 +61,7 @@
     3.4      protected static View mTextEdit;
     3.5      protected static ViewGroup mLayout;
     3.6      protected static SDLJoystickHandler mJoystickHandler;
     3.7 +    protected static SDLHapticHandler mHapticHandler;
     3.8  
     3.9      // This is what SDL runs in. It invokes SDL_main(), eventually
    3.10      protected static Thread mSDLThread;
    3.11 @@ -113,6 +114,7 @@
    3.12          mTextEdit = null;
    3.13          mLayout = null;
    3.14          mJoystickHandler = null;
    3.15 +        mHapticHandler = null;
    3.16          mSDLThread = null;
    3.17          mAudioTrack = null;
    3.18          mAudioRecord = null;
    3.19 @@ -182,6 +184,7 @@
    3.20          else {
    3.21              mJoystickHandler = new SDLJoystickHandler();
    3.22          }
    3.23 +        mHapticHandler = new SDLHapticHandler();
    3.24  
    3.25          mLayout = new RelativeLayout(this);
    3.26          mLayout.addView(mSurface);
    3.27 @@ -498,6 +501,8 @@
    3.28                                                 int is_accelerometer, int nbuttons,
    3.29                                                 int naxes, int nhats, int nballs);
    3.30      public static native int nativeRemoveJoystick(int device_id);
    3.31 +    public static native int nativeAddHaptic(int device_id, String name);
    3.32 +    public static native int nativeRemoveHaptic(int device_id);
    3.33      public static native String nativeGetHint(String name);
    3.34  
    3.35      /**
    3.36 @@ -1704,6 +1709,18 @@
    3.37          return null;
    3.38      }
    3.39  
    3.40 +    public static void pollHapticDevices() {
    3.41 +        if (SDLActivity.mSDLThread != null) {
    3.42 +            mHapticHandler.pollHapticDevices();
    3.43 +        }
    3.44 +    }
    3.45 +
    3.46 +    public static void hapticRun(int device_id, int length) {
    3.47 +        if (SDLActivity.mSDLThread != null) {
    3.48 +            mHapticHandler.run(device_id, length);
    3.49 +        }
    3.50 +    }
    3.51 +
    3.52      @Override
    3.53      public boolean handleMotionEvent(MotionEvent event) {
    3.54          if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
    3.55 @@ -1779,3 +1796,82 @@
    3.56          return false;
    3.57      }
    3.58  }
    3.59 +
    3.60 +class SDLHapticHandler {
    3.61 +
    3.62 +    class SDLHaptic {
    3.63 +        public int device_id;
    3.64 +        public String name;
    3.65 +        public Vibrator vib;
    3.66 +    }
    3.67 +
    3.68 +    private ArrayList<SDLHaptic> mHaptics;
    3.69 +    
    3.70 +    public SDLHapticHandler() {
    3.71 +        mHaptics = new ArrayList<SDLHaptic>();
    3.72 +    }
    3.73 +
    3.74 +    public void run(int device_id, int length) {
    3.75 +        SDLHaptic haptic = getHaptic(device_id);
    3.76 +        if (haptic != null) {
    3.77 +            haptic.vib.vibrate (length);
    3.78 +        }
    3.79 +    }
    3.80 +
    3.81 +    public void pollHapticDevices() {
    3.82 +        int[] deviceIds = InputDevice.getDeviceIds();
    3.83 +        // It helps processing the device ids in reverse order
    3.84 +        // For example, in the case of the XBox 360 wireless dongle,
    3.85 +        // so the first controller seen by SDL matches what the receiver
    3.86 +        // considers to be the first controller
    3.87 +
    3.88 +        for(int i=deviceIds.length-1; i>-1; i--) {
    3.89 +            SDLHaptic haptic = getHaptic(deviceIds[i]);
    3.90 +            if (haptic == null) {
    3.91 +                InputDevice device = InputDevice.getDevice(deviceIds[i]);
    3.92 +                Vibrator vib = device.getVibrator ();
    3.93 +                if(vib.hasVibrator ()) {
    3.94 +                    haptic = new SDLHaptic();
    3.95 +                    haptic.device_id = deviceIds[i];
    3.96 +                    haptic.name = device.getName();
    3.97 +                    haptic.vib = vib;
    3.98 +                    mHaptics.add(haptic);
    3.99 +                    SDLActivity.nativeAddHaptic(haptic.device_id, haptic.name);
   3.100 +                }
   3.101 +            }
   3.102 +        }
   3.103 +
   3.104 +        /* Check removed devices */
   3.105 +        ArrayList<Integer> removedDevices = new ArrayList<Integer>();
   3.106 +        for(int i=0; i < mHaptics.size(); i++) {
   3.107 +            int device_id = mHaptics.get(i).device_id;
   3.108 +            int j;
   3.109 +            for (j=0; j < deviceIds.length; j++) {
   3.110 +                if (device_id == deviceIds[j]) break;
   3.111 +            }
   3.112 +            if (j == deviceIds.length) {
   3.113 +                removedDevices.add(device_id);
   3.114 +            }
   3.115 +        }
   3.116 +
   3.117 +        for(int i=0; i < removedDevices.size(); i++) {
   3.118 +            int device_id = removedDevices.get(i);
   3.119 +            SDLActivity.nativeRemoveHaptic(device_id);
   3.120 +            for (int j=0; j < mHaptics.size(); j++) {
   3.121 +                if (mHaptics.get(j).device_id == device_id) {
   3.122 +                    mHaptics.remove(j);
   3.123 +                    break;
   3.124 +                }
   3.125 +            }
   3.126 +        }
   3.127 +    }
   3.128 +
   3.129 +    protected SDLHaptic getHaptic(int device_id) {
   3.130 +        for(int i=0; i < mHaptics.size(); i++) {
   3.131 +            if (mHaptics.get(i).device_id == device_id) {
   3.132 +                return mHaptics.get(i);
   3.133 +            }
   3.134 +        }
   3.135 +        return null;
   3.136 +    }   
   3.137 +}
     4.1 --- a/include/SDL_config_android.h	Sat Aug 12 08:06:16 2017 -0700
     4.2 +++ b/include/SDL_config_android.h	Sat Aug 12 08:15:09 2017 -0700
     4.3 @@ -118,7 +118,7 @@
     4.4  
     4.5  /* Enable various input drivers */
     4.6  #define SDL_JOYSTICK_ANDROID    1
     4.7 -#define SDL_HAPTIC_DUMMY    1
     4.8 +#define SDL_HAPTIC_ANDROID    1
     4.9  
    4.10  /* Enable various shared object loading systems */
    4.11  #define SDL_LOADSO_DLOPEN   1
     5.1 --- a/src/core/android/SDL_android.c	Sat Aug 12 08:06:16 2017 -0700
     5.2 +++ b/src/core/android/SDL_android.c	Sat Aug 12 08:15:09 2017 -0700
     5.3 @@ -37,6 +37,7 @@
     5.4  #include "../../video/android/SDL_androidvideo.h"
     5.5  #include "../../video/android/SDL_androidwindow.h"
     5.6  #include "../../joystick/android/SDL_sysjoystick_c.h"
     5.7 +#include "../../haptic/android/SDL_syshaptic_c.h"
     5.8  
     5.9  #include <android/log.h>
    5.10  #include <pthread.h>
    5.11 @@ -177,6 +178,8 @@
    5.12  static jmethodID midCaptureReadByteBuffer;
    5.13  static jmethodID midCaptureClose;
    5.14  static jmethodID midPollInputDevices;
    5.15 +static jmethodID midPollHapticDevices;
    5.16 +static jmethodID midHapticRun;
    5.17  
    5.18  /* Accelerometer data storage */
    5.19  static float fLastAccelerometer[3];
    5.20 @@ -237,13 +240,17 @@
    5.21                                  "captureClose", "()V");
    5.22      midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
    5.23                                  "pollInputDevices", "()V");
    5.24 +    midPollHapticDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
    5.25 +                                "pollHapticDevices", "()V");
    5.26 +    midHapticRun = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
    5.27 +                                "hapticRun", "(II)V");
    5.28  
    5.29      bHasNewData = SDL_FALSE;
    5.30  
    5.31      if (!midGetNativeSurface ||
    5.32         !midAudioOpen || !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioClose ||
    5.33         !midCaptureOpen || !midCaptureReadShortBuffer || !midCaptureReadByteBuffer || !midCaptureClose ||
    5.34 -       !midPollInputDevices) {
    5.35 +       !midPollInputDevices || !midPollHapticDevices || !midHapticRun) {
    5.36          __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
    5.37      }
    5.38      __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init() finished!");
    5.39 @@ -323,6 +330,25 @@
    5.40      return Android_RemoveJoystick(device_id);
    5.41  }
    5.42  
    5.43 +JNIEXPORT jint JNICALL Java_org_libsdl_app_SDLActivity_nativeAddHaptic(
    5.44 +    JNIEnv* env, jclass jcls, jint device_id, jstring device_name)
    5.45 +{
    5.46 +    int retval;
    5.47 +    const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
    5.48 +
    5.49 +    retval = Android_AddHaptic(device_id, name);
    5.50 +
    5.51 +    (*env)->ReleaseStringUTFChars(env, device_name, name);
    5.52 +
    5.53 +    return retval;
    5.54 +}
    5.55 +
    5.56 +JNIEXPORT jint JNICALL Java_org_libsdl_app_SDLActivity_nativeRemoveHaptic(
    5.57 +    JNIEnv* env, jclass jcls, jint device_id)
    5.58 +{
    5.59 +    return Android_RemoveHaptic(device_id);
    5.60 +}
    5.61 +
    5.62  
    5.63  /* Surface Created */
    5.64  JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(JNIEnv* env, jclass jcls)
    5.65 @@ -1570,6 +1596,19 @@
    5.66      (*env)->CallStaticVoidMethod(env, mActivityClass, midPollInputDevices);    
    5.67  }
    5.68  
    5.69 +void Android_JNI_PollHapticDevices(void)
    5.70 +{
    5.71 +    JNIEnv *env = Android_JNI_GetEnv();
    5.72 +    (*env)->CallStaticVoidMethod(env, mActivityClass, midPollHapticDevices);
    5.73 +}
    5.74 +    
    5.75 +void Android_JNI_HapticRun(int device_id, int length)
    5.76 +{
    5.77 +    JNIEnv *env = Android_JNI_GetEnv();
    5.78 +    (*env)->CallStaticVoidMethod(env, mActivityClass, midHapticRun, device_id, length);
    5.79 +}
    5.80 +
    5.81 +
    5.82  /* See SDLActivity.java for constants. */
    5.83  #define COMMAND_SET_KEEP_SCREEN_ON    5
    5.84  
     6.1 --- a/src/core/android/SDL_android.h	Sat Aug 12 08:06:16 2017 -0700
     6.2 +++ b/src/core/android/SDL_android.h	Sat Aug 12 08:15:09 2017 -0700
     6.3 @@ -67,6 +67,10 @@
     6.4  /* Joystick support */
     6.5  void Android_JNI_PollInputDevices(void);
     6.6  
     6.7 +/* Haptic support */
     6.8 +void Android_JNI_PollHapticDevices(void);
     6.9 +void Android_JNI_HapticRun(int device_id, int length);
    6.10 +
    6.11  /* Video */
    6.12  void Android_JNI_SuspendScreenSaver(SDL_bool suspend);
    6.13  
     7.1 --- a/src/haptic/SDL_haptic.c	Sat Aug 12 08:06:16 2017 -0700
     7.2 +++ b/src/haptic/SDL_haptic.c	Sat Aug 12 08:15:09 2017 -0700
     7.3 @@ -313,6 +313,7 @@
     7.4      SDL_memset(haptic, 0, sizeof(SDL_Haptic));
     7.5      haptic->rumble_id = -1;
     7.6      if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
     7.7 +        SDL_SetError("Haptic: SDL_SYS_HapticOpenFromJoystick failed.");
     7.8          SDL_free(haptic);
     7.9          return NULL;
    7.10      }
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/haptic/android/SDL_syshaptic.c	Sat Aug 12 08:15:09 2017 -0700
     8.3 @@ -0,0 +1,358 @@
     8.4 +/*
     8.5 +  Simple DirectMedia Layer
     8.6 +  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     8.7 +
     8.8 +  This software is provided 'as-is', without any express or implied
     8.9 +  warranty.  In no event will the authors be held liable for any damages
    8.10 +  arising from the use of this software.
    8.11 +
    8.12 +  Permission is granted to anyone to use this software for any purpose,
    8.13 +  including commercial applications, and to alter it and redistribute it
    8.14 +  freely, subject to the following restrictions:
    8.15 +
    8.16 +  1. The origin of this software must not be misrepresented; you must not
    8.17 +     claim that you wrote the original software. If you use this software
    8.18 +     in a product, an acknowledgment in the product documentation would be
    8.19 +     appreciated but is not required.
    8.20 +  2. Altered source versions must be plainly marked as such, and must not be
    8.21 +     misrepresented as being the original software.
    8.22 +  3. This notice may not be removed or altered from any source distribution.
    8.23 +*/
    8.24 +#include "../../SDL_internal.h"
    8.25 +
    8.26 +#ifdef SDL_HAPTIC_ANDROID
    8.27 +
    8.28 +#include "SDL_assert.h"
    8.29 +#include "SDL_timer.h"
    8.30 +#include "SDL_syshaptic_c.h"
    8.31 +#include "../SDL_syshaptic.h"
    8.32 +#include "SDL_haptic.h"
    8.33 +#include "../../core/android/SDL_android.h"
    8.34 +#include "SDL_joystick.h"
    8.35 +#include "../../joystick/SDL_sysjoystick.h"     /* For the real SDL_Joystick */
    8.36 +#include "../../joystick/android/SDL_sysjoystick_c.h"     /* For joystick hwdata */
    8.37 +
    8.38 +
    8.39 +typedef struct SDL_hapticlist_item
    8.40 +{
    8.41 +    int device_id;
    8.42 +    char *name;
    8.43 +    SDL_Haptic *haptic;
    8.44 +    struct SDL_hapticlist_item *next;
    8.45 +} SDL_hapticlist_item;
    8.46 +
    8.47 +static SDL_hapticlist_item *SDL_hapticlist = NULL;
    8.48 +static SDL_hapticlist_item *SDL_hapticlist_tail = NULL;
    8.49 +static int numhaptics = 0;
    8.50 +
    8.51 +
    8.52 +int
    8.53 +SDL_SYS_HapticInit(void)
    8.54 +{
    8.55 +    /* Support for device connect/disconnect is API >= 16 only,
    8.56 +     * so we poll every three seconds
    8.57 +     * Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
    8.58 +     */
    8.59 +    static Uint32 timeout = 0;
    8.60 +    if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
    8.61 +        timeout = SDL_GetTicks() + 3000;
    8.62 +        Android_JNI_PollHapticDevices();
    8.63 +    }
    8.64 +    return (numhaptics);
    8.65 +}
    8.66 +
    8.67 +int
    8.68 +SDL_SYS_NumHaptics(void)
    8.69 +{
    8.70 +    return (numhaptics);
    8.71 +}
    8.72 +
    8.73 +static SDL_hapticlist_item *
    8.74 +HapticByOrder(int index)
    8.75 +{
    8.76 +    SDL_hapticlist_item *item = SDL_hapticlist;
    8.77 +    if ((index < 0) || (index >= numhaptics)) {
    8.78 +        return NULL;
    8.79 +    }
    8.80 +    while (index > 0) {
    8.81 +        SDL_assert(item != NULL);
    8.82 +        --index;
    8.83 +        item = item->next;
    8.84 +    }
    8.85 +    return item;
    8.86 +}
    8.87 +
    8.88 +static SDL_hapticlist_item *
    8.89 +HapticByDevId (int device_id)
    8.90 +{
    8.91 +    SDL_hapticlist_item *item;
    8.92 +    for (item = SDL_hapticlist; item != NULL; item = item->next) {
    8.93 +        if (device_id == item->device_id) {
    8.94 +            SDL_Log("=+=+=+=+=+= HapticByDevId id [%d]", device_id);
    8.95 +            return item;
    8.96 +        }
    8.97 +    }
    8.98 +    return NULL;
    8.99 +}
   8.100 +
   8.101 +const char *
   8.102 +SDL_SYS_HapticName(int index)
   8.103 +{
   8.104 +    SDL_hapticlist_item *item = HapticByOrder(index);
   8.105 +    if (item == NULL ) {
   8.106 +        SDL_SetError("No such device");
   8.107 +        return NULL;
   8.108 +    }
   8.109 +    return item->name;
   8.110 +}
   8.111 +
   8.112 +
   8.113 +static SDL_hapticlist_item *
   8.114 +OpenHaptic(SDL_Haptic *haptic, SDL_hapticlist_item *item)
   8.115 +{
   8.116 +    if (item == NULL ) {
   8.117 +        SDL_SetError("No such device");
   8.118 +        return NULL;
   8.119 +    }
   8.120 +    if (item->haptic != NULL) {
   8.121 +        SDL_SetError("Haptic already opened");
   8.122 +        return NULL;
   8.123 +    }
   8.124 +
   8.125 +    haptic->hwdata = (struct haptic_hwdata *)item;
   8.126 +    item->haptic = haptic;
   8.127 +
   8.128 +    haptic->supported = SDL_HAPTIC_LEFTRIGHT;
   8.129 +    haptic->neffects = 1;
   8.130 +    haptic->nplaying = haptic->neffects;
   8.131 +    haptic->effects = (struct haptic_effect *)SDL_malloc (sizeof (struct haptic_effect) * haptic->neffects);
   8.132 +    if (haptic->effects == NULL) {
   8.133 +        SDL_OutOfMemory();
   8.134 +        return NULL;
   8.135 +    }
   8.136 +    SDL_memset(haptic->effects, 0, sizeof (struct haptic_effect) * haptic->neffects);
   8.137 +    return item;
   8.138 +}
   8.139 +
   8.140 +static SDL_hapticlist_item *
   8.141 +OpenHapticByOrder(SDL_Haptic *haptic, int index)
   8.142 +{
   8.143 +    return OpenHaptic (haptic, HapticByOrder(index));
   8.144 +}
   8.145 +
   8.146 +static SDL_hapticlist_item *
   8.147 +OpenHapticByDevId(SDL_Haptic *haptic, int device_id)
   8.148 +{
   8.149 +    return OpenHaptic (haptic, HapticByDevId(device_id));
   8.150 +}
   8.151 +
   8.152 +int
   8.153 +SDL_SYS_HapticOpen(SDL_Haptic *haptic)
   8.154 +{
   8.155 +    return (OpenHapticByOrder(haptic, haptic->index) == NULL ? -1 : 0);
   8.156 +}
   8.157 +
   8.158 +
   8.159 +int
   8.160 +SDL_SYS_HapticMouse(void)
   8.161 +{
   8.162 +    return 0;
   8.163 +}
   8.164 +
   8.165 +
   8.166 +int
   8.167 +SDL_SYS_JoystickIsHaptic(SDL_Joystick *joystick)
   8.168 +{
   8.169 +    SDL_hapticlist_item *item;
   8.170 +    item = HapticByDevId(((joystick_hwdata *)joystick->hwdata)->device_id);
   8.171 +    int ret = (item != NULL ? 1 : 0);
   8.172 +    return ret;
   8.173 +}
   8.174 +
   8.175 +
   8.176 +int
   8.177 +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic *haptic, SDL_Joystick *joystick)
   8.178 +{
   8.179 +    return (OpenHapticByDevId(haptic, ((joystick_hwdata *)joystick->hwdata)->device_id) == NULL ? -1 : 0);
   8.180 +}
   8.181 +
   8.182 +
   8.183 +int
   8.184 +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
   8.185 +{
   8.186 +    return (((SDL_hapticlist_item *)haptic->hwdata)->device_id == ((joystick_hwdata *)joystick->hwdata)->device_id ? 1 : 0);
   8.187 +}
   8.188 +
   8.189 +
   8.190 +void
   8.191 +SDL_SYS_HapticClose(SDL_Haptic * haptic)
   8.192 +{
   8.193 +    ((SDL_hapticlist_item *)haptic->hwdata)->haptic = NULL;
   8.194 +    haptic->hwdata = NULL;
   8.195 +    return;
   8.196 +}
   8.197 +
   8.198 +
   8.199 +void
   8.200 +SDL_SYS_HapticQuit(void)
   8.201 +{
   8.202 +    SDL_hapticlist_item *item = NULL;
   8.203 +    SDL_hapticlist_item *next = NULL;
   8.204 +
   8.205 +    for (item = SDL_hapticlist; item; item = next) {
   8.206 +        next = item->next;
   8.207 +        SDL_free(item);
   8.208 +    }
   8.209 +
   8.210 +    SDL_hapticlist = SDL_hapticlist_tail = NULL;
   8.211 +    numhaptics = 0;
   8.212 +    return;
   8.213 +}
   8.214 +
   8.215 +
   8.216 +int
   8.217 +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic,
   8.218 +                        struct haptic_effect *effect, SDL_HapticEffect * base)
   8.219 +{
   8.220 +    return 0;
   8.221 +}
   8.222 +
   8.223 +
   8.224 +int
   8.225 +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
   8.226 +                           struct haptic_effect *effect,
   8.227 +                           SDL_HapticEffect * data)
   8.228 +{
   8.229 +    return 0;
   8.230 +}
   8.231 +
   8.232 +
   8.233 +int
   8.234 +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
   8.235 +                        Uint32 iterations)
   8.236 +{
   8.237 +    Android_JNI_HapticRun (((SDL_hapticlist_item *)haptic->hwdata)->device_id, effect->effect.leftright.length);
   8.238 +    return 0;
   8.239 +}
   8.240 +
   8.241 +
   8.242 +int
   8.243 +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
   8.244 +{
   8.245 +    return 0;
   8.246 +}
   8.247 +
   8.248 +
   8.249 +void
   8.250 +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
   8.251 +{
   8.252 +    return;
   8.253 +}
   8.254 +
   8.255 +
   8.256 +int
   8.257 +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
   8.258 +                              struct haptic_effect *effect)
   8.259 +{
   8.260 +    return 0;
   8.261 +}
   8.262 +
   8.263 +
   8.264 +int
   8.265 +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
   8.266 +{
   8.267 +    return 0;
   8.268 +}
   8.269 +
   8.270 +
   8.271 +int
   8.272 +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
   8.273 +{
   8.274 +    return 0;
   8.275 +}
   8.276 +
   8.277 +int
   8.278 +SDL_SYS_HapticPause(SDL_Haptic * haptic)
   8.279 +{
   8.280 +    return 0;
   8.281 +}
   8.282 +
   8.283 +int
   8.284 +SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
   8.285 +{
   8.286 +    return 0;
   8.287 +}
   8.288 +
   8.289 +int
   8.290 +SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
   8.291 +{
   8.292 +    return 0;
   8.293 +}
   8.294 +
   8.295 +
   8.296 +
   8.297 +int
   8.298 +Android_AddHaptic(int device_id, const char *name)
   8.299 +{
   8.300 +    SDL_hapticlist_item *item;
   8.301 +    item = (SDL_hapticlist_item *) SDL_calloc(1, sizeof (SDL_hapticlist_item));
   8.302 +    if (item == NULL) {
   8.303 +        return -1;
   8.304 +    }
   8.305 +
   8.306 +    item->device_id = device_id;
   8.307 +    item->name = SDL_strdup (name);
   8.308 +    if (item->name == NULL) {
   8.309 +        SDL_free (item);
   8.310 +        return -1;
   8.311 +    }
   8.312 +
   8.313 +    if (SDL_hapticlist_tail == NULL) {
   8.314 +        SDL_hapticlist = SDL_hapticlist_tail = item;
   8.315 +    } else {
   8.316 +        SDL_hapticlist_tail->next = item;
   8.317 +        SDL_hapticlist_tail = item;
   8.318 +    }
   8.319 +
   8.320 +    ++numhaptics;
   8.321 +    return numhaptics;
   8.322 +}
   8.323 +
   8.324 +int 
   8.325 +Android_RemoveHaptic(int device_id)
   8.326 +{
   8.327 +    SDL_hapticlist_item *item;
   8.328 +    SDL_hapticlist_item *prev = NULL;
   8.329 +
   8.330 +    for (item = SDL_hapticlist; item != NULL; item = item->next) {
   8.331 +        /* found it, remove it. */
   8.332 +        if (device_id == item->device_id) {
   8.333 +            const int retval = item->haptic ? item->haptic->index : -1;
   8.334 +
   8.335 +            if (prev != NULL) {
   8.336 +                prev->next = item->next;
   8.337 +            } else {
   8.338 +                SDL_assert(SDL_hapticlist == item);
   8.339 +                SDL_hapticlist = item->next;
   8.340 +            }
   8.341 +            if (item == SDL_hapticlist_tail) {
   8.342 +                SDL_hapticlist_tail = prev;
   8.343 +            }
   8.344 +
   8.345 +            /* Need to decrement the haptic count */
   8.346 +            --numhaptics;
   8.347 +            /* !!! TODO: Send a haptic remove event? */
   8.348 +
   8.349 +            SDL_free(item->name);
   8.350 +            SDL_free(item);
   8.351 +            return retval;
   8.352 +        }
   8.353 +        prev = item;
   8.354 +    }
   8.355 +    return -1;
   8.356 +}
   8.357 +
   8.358 +
   8.359 +#endif /* SDL_HAPTIC_ANDROID */
   8.360 +
   8.361 +/* vi: set ts=4 sw=4 expandtab: */
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/haptic/android/SDL_syshaptic_c.h	Sat Aug 12 08:15:09 2017 -0700
     9.3 @@ -0,0 +1,12 @@
     9.4 +#include "SDL_config.h"
     9.5 +
     9.6 +#ifdef SDL_HAPTIC_ANDROID
     9.7 +
     9.8 +
     9.9 +extern int Android_AddHaptic(int device_id, const char *name);
    9.10 +extern int Android_RemoveHaptic(int device_id);
    9.11 +
    9.12 +
    9.13 +#endif /* SDL_HAPTIC_ANDROID */
    9.14 +
    9.15 +/* vi: set ts=4 sw=4 expandtab: */
    10.1 --- a/src/joystick/android/SDL_sysjoystick_c.h	Sat Aug 12 08:06:16 2017 -0700
    10.2 +++ b/src/joystick/android/SDL_sysjoystick_c.h	Sat Aug 12 08:15:09 2017 -0700
    10.3 @@ -22,6 +22,10 @@
    10.4  #include "../../SDL_internal.h"
    10.5  
    10.6  #ifdef SDL_JOYSTICK_ANDROID
    10.7 +
    10.8 +#ifndef _SDL_sysjoystick_c_h
    10.9 +#define _SDL_sysjoystick_c_h
   10.10 +
   10.11  #include "../SDL_sysjoystick.h"
   10.12  
   10.13  extern int Android_OnPadDown(int device_id, int keycode);
   10.14 @@ -47,6 +51,8 @@
   10.15  
   10.16  typedef SDL_joylist_item joystick_hwdata;
   10.17  
   10.18 +#endif /* _SDL_sysjoystick_c_h */
   10.19 +
   10.20  #endif /* SDL_JOYSTICK_ANDROID */
   10.21  
   10.22  /* vi: set ts=4 sw=4 expandtab: */