Commit b0c48dd9dd55b460ab1f6f69604f182f6a7b33e4

Sam Lantinga 2018-10-16T08:29:27

Support vibration magnitude on Android 8.0 (thanks Rachel!)

diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
index a631c3e..c6a33e8 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
@@ -1,5 +1,6 @@
 package org.libsdl.app;
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -77,8 +78,8 @@ public class SDLControllerManager
     /**
      * This method is called by SDL using JNI.
      */
-    public static void hapticRun(int device_id, int length) {
-        mHapticHandler.run(device_id, length);
+    public static void hapticRun(int device_id, float intensity, int length) {
+        mHapticHandler.run(device_id, intensity, length);
     }
 
     /**
@@ -423,10 +424,50 @@ class SDLHapticHandler {
         mHaptics = new ArrayList<SDLHaptic>();
     }
 
-    public void run(int device_id, int length) {
+    public void run(int device_id, float intensity, int length) {
         SDLHaptic haptic = getHaptic(device_id);
         if (haptic != null) {
-            haptic.vib.vibrate (length);
+
+            Log.d("SDL", "Rtest: Vibe with intensity " + intensity + " for " + length);
+            if (intensity == 0.0f) {
+                stop(device_id);
+                return;
+            }
+
+            if (Build.VERSION.SDK_INT >= 26) {
+                // We have to do this dynamically to avoid issues on earlier SDKs.
+                // But we want to use the VibrationEffect so we can set amplitude.
+
+                try {
+                    int vibeValue = Math.round(intensity * 255);
+
+                    if (vibeValue > 255) {
+                        vibeValue = 255;
+                    }
+                    if (vibeValue < 1) {
+                        stop(device_id);
+                        return;
+                    }
+
+                    long longLength = length;
+                    Class vibrationEffectClass = Class.forName("android.os.VibrationEffect");
+                    Method oneShotMethod = vibrationEffectClass.getMethod("createOneShot", long.class, int.class);
+                    Object effect = oneShotMethod.invoke(null, longLength, vibeValue);
+                    Method vibeEffect = android.os.Vibrator.class.getMethod("vibrate", vibrationEffectClass);
+                    vibeEffect.invoke(haptic.vib, vibrationEffectClass.cast(effect));
+                }
+                catch (Exception e) {
+                    // Fall back to the generic method, which uses DEFAULT_AMPLITUDE, but works even if
+                    // something went horribly wrong with the Android 8.0 APIs.
+                    haptic.vib.vibrate(length);
+                }
+            }
+            else {
+                // Fall back to the generic method, which uses DEFAULT_AMPLITUDE, but exists
+                // on earlier SDKs.
+
+                haptic.vib.vibrate (length);
+            }
         }
     }
 
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index 37f328b..a56575e 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -445,7 +445,7 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv* mEn
     midPollHapticDevices = (*mEnv)->GetStaticMethodID(mEnv, mControllerManagerClass,
                                 "pollHapticDevices", "()V");
     midHapticRun = (*mEnv)->GetStaticMethodID(mEnv, mControllerManagerClass,
-                                "hapticRun", "(II)V");
+                                "hapticRun", "(IFI)V");
     midHapticStop = (*mEnv)->GetStaticMethodID(mEnv, mControllerManagerClass,
                                 "hapticStop", "(I)V");
 
@@ -2005,10 +2005,10 @@ void Android_JNI_PollHapticDevices(void)
     (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midPollHapticDevices);
 }
 
-void Android_JNI_HapticRun(int device_id, int length)
+void Android_JNI_HapticRun(int device_id, float intensity, int length)
 {
     JNIEnv *env = Android_JNI_GetEnv();
-    (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midHapticRun, device_id, length);
+    (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midHapticRun, device_id, intensity, length);
 }
 
 void Android_JNI_HapticStop(int device_id)
diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h
index 006f5fd..b2ff32e 100644
--- a/src/core/android/SDL_android.h
+++ b/src/core/android/SDL_android.h
@@ -84,7 +84,7 @@ void Android_JNI_PollInputDevices(void);
 
 /* Haptic support */
 void Android_JNI_PollHapticDevices(void);
-void Android_JNI_HapticRun(int device_id, int length);
+void Android_JNI_HapticRun(int device_id, float intensity, int length);
 void Android_JNI_HapticStop(int device_id);
 
 /* Video */
diff --git a/src/haptic/android/SDL_syshaptic.c b/src/haptic/android/SDL_syshaptic.c
index 391b7b5..7cb289b 100644
--- a/src/haptic/android/SDL_syshaptic.c
+++ b/src/haptic/android/SDL_syshaptic.c
@@ -235,7 +235,12 @@ int
 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
                         Uint32 iterations)
 {
-    Android_JNI_HapticRun (((SDL_hapticlist_item *)haptic->hwdata)->device_id, effect->effect.leftright.length);
+    float large = effect->effect.leftright.large_magnitude / 32767.0f;
+    float small = effect->effect.leftright.small_magnitude / 32767.0f;
+
+    float total = (large * 0.6f) + (small * 0.4f);
+
+    Android_JNI_HapticRun (((SDL_hapticlist_item *)haptic->hwdata)->device_id, total, effect->effect.leftright.length);
     return 0;
 }