|
@@ -9,6 +9,7 @@ import android.content.Context;
|
|
|
import android.os.Build;
|
|
|
import android.os.VibrationEffect;
|
|
|
import android.os.Vibrator;
|
|
|
+import android.os.VibratorManager;
|
|
|
import android.util.Log;
|
|
|
import android.view.InputDevice;
|
|
|
import android.view.KeyEvent;
|
|
@@ -24,7 +25,7 @@ public class SDLControllerManager
|
|
|
public static native int nativeAddJoystick(int device_id, String name, String desc,
|
|
|
int vendor_id, int product_id,
|
|
|
int button_mask,
|
|
|
- int naxes, int axis_mask, int nhats);
|
|
|
+ int naxes, int axis_mask, int nhats, boolean can_rumble);
|
|
|
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);
|
|
@@ -50,7 +51,9 @@ public class SDLControllerManager
|
|
|
}
|
|
|
|
|
|
if (mHapticHandler == null) {
|
|
|
- if (Build.VERSION.SDK_INT >= 26 /* Android 8.0 (O) */) {
|
|
|
+ if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
|
|
|
+ mHapticHandler = new SDLHapticHandler_API31();
|
|
|
+ } else if (Build.VERSION.SDK_INT >= 26 /* Android 8.0 (O) */) {
|
|
|
mHapticHandler = new SDLHapticHandler_API26();
|
|
|
} else {
|
|
|
mHapticHandler = new SDLHapticHandler();
|
|
@@ -84,6 +87,13 @@ public class SDLControllerManager
|
|
|
mHapticHandler.run(device_id, intensity, length);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * This method is called by SDL using JNI.
|
|
|
+ */
|
|
|
+ public static void hapticRumble(int device_id, float low_frequency_intensity, float high_frequency_intensity, int length) {
|
|
|
+ mHapticHandler.rumble(device_id, low_frequency_intensity, high_frequency_intensity, length);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* This method is called by SDL using JNI.
|
|
|
*/
|
|
@@ -233,10 +243,19 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ boolean can_rumble = false;
|
|
|
+ if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
|
|
|
+ VibratorManager manager = joystickDevice.getVibratorManager();
|
|
|
+ int[] vibrators = manager.getVibratorIds();
|
|
|
+ if (vibrators.length > 0) {
|
|
|
+ can_rumble = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
mJoysticks.add(joystick);
|
|
|
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc,
|
|
|
getVendorId(joystickDevice), getProductId(joystickDevice),
|
|
|
- getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2);
|
|
|
+ getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2, can_rumble);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -470,12 +489,63 @@ class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+class SDLHapticHandler_API31 extends SDLHapticHandler {
|
|
|
+ @Override
|
|
|
+ public void run(int device_id, float intensity, int length) {
|
|
|
+ SDLHaptic haptic = getHaptic(device_id);
|
|
|
+ if (haptic != null) {
|
|
|
+ vibrate(haptic.vib, intensity, length);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void rumble(int device_id, float low_frequency_intensity, float high_frequency_intensity, int length) {
|
|
|
+ InputDevice device = InputDevice.getDevice(device_id);
|
|
|
+ if (device == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ VibratorManager manager = device.getVibratorManager();
|
|
|
+ int[] vibrators = manager.getVibratorIds();
|
|
|
+ if (vibrators.length >= 2) {
|
|
|
+ vibrate(manager.getVibrator(vibrators[0]), low_frequency_intensity, length);
|
|
|
+ vibrate(manager.getVibrator(vibrators[1]), high_frequency_intensity, length);
|
|
|
+ } else if (vibrators.length == 1) {
|
|
|
+ float intensity = (low_frequency_intensity * 0.6f) + (high_frequency_intensity * 0.4f);
|
|
|
+ vibrate(manager.getVibrator(vibrators[0]), intensity, length);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void vibrate(Vibrator vibrator, float intensity, int length) {
|
|
|
+ if (intensity == 0.0f) {
|
|
|
+ vibrator.cancel();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ int value = Math.round(intensity * 255);
|
|
|
+ if (value > 255) {
|
|
|
+ value = 255;
|
|
|
+ }
|
|
|
+ if (value < 1) {
|
|
|
+ vibrator.cancel();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ vibrator.vibrate(VibrationEffect.createOneShot(length, value));
|
|
|
+ }
|
|
|
+ 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.
|
|
|
+ vibrator.vibrate(length);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
class SDLHapticHandler_API26 extends SDLHapticHandler {
|
|
|
@Override
|
|
|
public void run(int device_id, float intensity, int length) {
|
|
|
SDLHaptic haptic = getHaptic(device_id);
|
|
|
if (haptic != null) {
|
|
|
- Log.d("SDL", "Rtest: Vibe with intensity " + intensity + " for " + length);
|
|
|
if (intensity == 0.0f) {
|
|
|
stop(device_id);
|
|
|
return;
|
|
@@ -523,6 +593,10 @@ class SDLHapticHandler {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public void rumble(int device_id, float low_frequency_intensity, float high_frequency_intensity, int length) {
|
|
|
+ // Not supported in older APIs
|
|
|
+ }
|
|
|
+
|
|
|
public void stop(int device_id) {
|
|
|
SDLHaptic haptic = getHaptic(device_id);
|
|
|
if (haptic != null) {
|
|
@@ -535,30 +609,6 @@ class SDLHapticHandler {
|
|
|
final int deviceId_VIBRATOR_SERVICE = 999999;
|
|
|
boolean hasVibratorService = false;
|
|
|
|
|
|
- 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 != null) {
|
|
|
- if (vib.hasVibrator()) {
|
|
|
- haptic = new SDLHaptic();
|
|
|
- haptic.device_id = deviceIds[i];
|
|
|
- haptic.name = device.getName();
|
|
|
- haptic.vib = vib;
|
|
|
- mHaptics.add(haptic);
|
|
|
- SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/* Check VIBRATOR_SERVICE */
|
|
|
Vibrator vib = (Vibrator) SDL.getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
|
|
if (vib != null) {
|
|
@@ -581,18 +631,11 @@ class SDLHapticHandler {
|
|
|
ArrayList<Integer> removedDevices = null;
|
|
|
for (SDLHaptic haptic : mHaptics) {
|
|
|
int device_id = haptic.device_id;
|
|
|
- int i;
|
|
|
- for (i = 0; i < deviceIds.length; i++) {
|
|
|
- if (device_id == deviceIds[i]) break;
|
|
|
- }
|
|
|
-
|
|
|
if (device_id != deviceId_VIBRATOR_SERVICE || !hasVibratorService) {
|
|
|
- if (i == deviceIds.length) {
|
|
|
- if (removedDevices == null) {
|
|
|
- removedDevices = new ArrayList<Integer>();
|
|
|
- }
|
|
|
- removedDevices.add(device_id);
|
|
|
+ if (removedDevices == null) {
|
|
|
+ removedDevices = new ArrayList<Integer>();
|
|
|
}
|
|
|
+ removedDevices.add(device_id);
|
|
|
} // else: don't remove the vibrator if it is still present
|
|
|
}
|
|
|
|