From b0c48dd9dd55b460ab1f6f69604f182f6a7b33e4 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 16 Oct 2018 08:29:27 -0700 Subject: [PATCH] Support vibration magnitude on Android 8.0 (thanks Rachel!) --- .../org/libsdl/app/SDLControllerManager.java | 49 +++++++++++++++++-- src/core/android/SDL_android.c | 6 +-- src/core/android/SDL_android.h | 2 +- src/haptic/android/SDL_syshaptic.c | 7 ++- 4 files changed, 55 insertions(+), 9 deletions(-) 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 a631c3ed0a6a0..c6a33e8073146 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 static void pollHapticDevices() { /** * 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 @@ public SDLHapticHandler() { mHaptics = new ArrayList(); } - 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 37f328baeacf8..a56575e09deb7 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 006f5fdb083a6..b2ff32ea659dd 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 391b7b5d5bab7..7cb289ba581df 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; }