99import android .os .Build ;
1010import android .os .VibrationEffect ;
1111import android .os .Vibrator ;
12+ import android .os .VibratorManager ;
1213import android .util .Log ;
1314import android .view .InputDevice ;
1415import android .view .KeyEvent ;
@@ -24,7 +25,7 @@ public class SDLControllerManager
2425 public static native int nativeAddJoystick (int device_id , String name , String desc ,
2526 int vendor_id , int product_id ,
2627 int button_mask ,
27- int naxes , int axis_mask , int nhats );
28+ int naxes , int axis_mask , int nhats , boolean can_rumble );
2829 public static native int nativeRemoveJoystick (int device_id );
2930 public static native int nativeAddHaptic (int device_id , String name );
3031 public static native int nativeRemoveHaptic (int device_id );
@@ -50,7 +51,9 @@ public static void initialize() {
5051 }
5152
5253 if (mHapticHandler == null ) {
53- if (Build .VERSION .SDK_INT >= 26 /* Android 8.0 (O) */ ) {
54+ if (Build .VERSION .SDK_INT >= 31 /* Android 12.0 (S) */ ) {
55+ mHapticHandler = new SDLHapticHandler_API31 ();
56+ } else if (Build .VERSION .SDK_INT >= 26 /* Android 8.0 (O) */ ) {
5457 mHapticHandler = new SDLHapticHandler_API26 ();
5558 } else {
5659 mHapticHandler = new SDLHapticHandler ();
@@ -84,6 +87,13 @@ public static void hapticRun(int device_id, float intensity, int length) {
8487 mHapticHandler .run (device_id , intensity , length );
8588 }
8689
90+ /**
91+ * This method is called by SDL using JNI.
92+ */
93+ public static void hapticRumble (int device_id , float low_frequency_intensity , float high_frequency_intensity , int length ) {
94+ mHapticHandler .rumble (device_id , low_frequency_intensity , high_frequency_intensity , length );
95+ }
96+
8797 /**
8898 * This method is called by SDL using JNI.
8999 */
@@ -233,10 +243,19 @@ public void pollInputDevices() {
233243 }
234244 }
235245
246+ boolean can_rumble = false ;
247+ if (Build .VERSION .SDK_INT >= 31 /* Android 12.0 (S) */ ) {
248+ VibratorManager manager = joystickDevice .getVibratorManager ();
249+ int [] vibrators = manager .getVibratorIds ();
250+ if (vibrators .length > 0 ) {
251+ can_rumble = true ;
252+ }
253+ }
254+
236255 mJoysticks .add (joystick );
237256 SDLControllerManager .nativeAddJoystick (joystick .device_id , joystick .name , joystick .desc ,
238257 getVendorId (joystickDevice ), getProductId (joystickDevice ),
239- getButtonMask (joystickDevice ), joystick .axes .size (), getAxisMask (joystick .axes ), joystick .hats .size ()/2 );
258+ getButtonMask (joystickDevice ), joystick .axes .size (), getAxisMask (joystick .axes ), joystick .hats .size ()/2 , can_rumble );
240259 }
241260 }
242261 }
@@ -470,12 +489,63 @@ public int getButtonMask(InputDevice joystickDevice) {
470489 }
471490}
472491
492+ class SDLHapticHandler_API31 extends SDLHapticHandler {
493+ @ Override
494+ public void run (int device_id , float intensity , int length ) {
495+ SDLHaptic haptic = getHaptic (device_id );
496+ if (haptic != null ) {
497+ vibrate (haptic .vib , intensity , length );
498+ }
499+ }
500+
501+ @ Override
502+ public void rumble (int device_id , float low_frequency_intensity , float high_frequency_intensity , int length ) {
503+ InputDevice device = InputDevice .getDevice (device_id );
504+ if (device == null ) {
505+ return ;
506+ }
507+
508+ VibratorManager manager = device .getVibratorManager ();
509+ int [] vibrators = manager .getVibratorIds ();
510+ if (vibrators .length >= 2 ) {
511+ vibrate (manager .getVibrator (vibrators [0 ]), low_frequency_intensity , length );
512+ vibrate (manager .getVibrator (vibrators [1 ]), high_frequency_intensity , length );
513+ } else if (vibrators .length == 1 ) {
514+ float intensity = (low_frequency_intensity * 0.6f ) + (high_frequency_intensity * 0.4f );
515+ vibrate (manager .getVibrator (vibrators [0 ]), intensity , length );
516+ }
517+ }
518+
519+ private void vibrate (Vibrator vibrator , float intensity , int length ) {
520+ if (intensity == 0.0f ) {
521+ vibrator .cancel ();
522+ return ;
523+ }
524+
525+ int value = Math .round (intensity * 255 );
526+ if (value > 255 ) {
527+ value = 255 ;
528+ }
529+ if (value < 1 ) {
530+ vibrator .cancel ();
531+ return ;
532+ }
533+ try {
534+ vibrator .vibrate (VibrationEffect .createOneShot (length , value ));
535+ }
536+ catch (Exception e ) {
537+ // Fall back to the generic method, which uses DEFAULT_AMPLITUDE, but works even if
538+ // something went horribly wrong with the Android 8.0 APIs.
539+ vibrator .vibrate (length );
540+ }
541+ }
542+ }
543+
473544class SDLHapticHandler_API26 extends SDLHapticHandler {
474545 @ Override
475546 public void run (int device_id , float intensity , int length ) {
476547 SDLHaptic haptic = getHaptic (device_id );
477548 if (haptic != null ) {
478- Log .d ("SDL" , "Rtest: Vibe with intensity " + intensity + " for " + length );
479549 if (intensity == 0.0f ) {
480550 stop (device_id );
481551 return ;
@@ -523,6 +593,10 @@ public void run(int device_id, float intensity, int length) {
523593 }
524594 }
525595
596+ public void rumble (int device_id , float low_frequency_intensity , float high_frequency_intensity , int length ) {
597+ // Not supported in older APIs
598+ }
599+
526600 public void stop (int device_id ) {
527601 SDLHaptic haptic = getHaptic (device_id );
528602 if (haptic != null ) {
@@ -535,30 +609,6 @@ public void pollHapticDevices() {
535609 final int deviceId_VIBRATOR_SERVICE = 999999 ;
536610 boolean hasVibratorService = false ;
537611
538- int [] deviceIds = InputDevice .getDeviceIds ();
539- // It helps processing the device ids in reverse order
540- // For example, in the case of the XBox 360 wireless dongle,
541- // so the first controller seen by SDL matches what the receiver
542- // considers to be the first controller
543-
544- for (int i = deviceIds .length - 1 ; i > -1 ; i --) {
545- SDLHaptic haptic = getHaptic (deviceIds [i ]);
546- if (haptic == null ) {
547- InputDevice device = InputDevice .getDevice (deviceIds [i ]);
548- Vibrator vib = device .getVibrator ();
549- if (vib != null ) {
550- if (vib .hasVibrator ()) {
551- haptic = new SDLHaptic ();
552- haptic .device_id = deviceIds [i ];
553- haptic .name = device .getName ();
554- haptic .vib = vib ;
555- mHaptics .add (haptic );
556- SDLControllerManager .nativeAddHaptic (haptic .device_id , haptic .name );
557- }
558- }
559- }
560- }
561-
562612 /* Check VIBRATOR_SERVICE */
563613 Vibrator vib = (Vibrator ) SDL .getContext ().getSystemService (Context .VIBRATOR_SERVICE );
564614 if (vib != null ) {
@@ -581,18 +631,11 @@ public void pollHapticDevices() {
581631 ArrayList <Integer > removedDevices = null ;
582632 for (SDLHaptic haptic : mHaptics ) {
583633 int device_id = haptic .device_id ;
584- int i ;
585- for (i = 0 ; i < deviceIds .length ; i ++) {
586- if (device_id == deviceIds [i ]) break ;
587- }
588-
589634 if (device_id != deviceId_VIBRATOR_SERVICE || !hasVibratorService ) {
590- if (i == deviceIds .length ) {
591- if (removedDevices == null ) {
592- removedDevices = new ArrayList <Integer >();
593- }
594- removedDevices .add (device_id );
635+ if (removedDevices == null ) {
636+ removedDevices = new ArrayList <Integer >();
595637 }
638+ removedDevices .add (device_id );
596639 } // else: don't remove the vibrator if it is still present
597640 }
598641
0 commit comments