66import java .util .List ;
77
88import android .content .Context ;
9+ import android .hardware .lights .Light ;
10+ import android .hardware .lights .LightsRequest ;
11+ import android .hardware .lights .LightsManager ;
12+ import android .hardware .lights .LightState ;
13+ import android .graphics .Color ;
914import android .os .Build ;
1015import android .os .VibrationEffect ;
1116import android .os .Vibrator ;
@@ -25,7 +30,7 @@ public class SDLControllerManager
2530 static native void nativeAddJoystick (int device_id , String name , String desc ,
2631 int vendor_id , int product_id ,
2732 int button_mask ,
28- int naxes , int axis_mask , int nhats , boolean can_rumble );
33+ int naxes , int axis_mask , int nhats , boolean can_rumble , boolean has_rgb_led );
2934 static native void nativeRemoveJoystick (int device_id );
3035 static native void nativeAddHaptic (int device_id , String name );
3136 static native void nativeRemoveHaptic (int device_id );
@@ -69,6 +74,13 @@ static void pollInputDevices() {
6974 mJoystickHandler .pollInputDevices ();
7075 }
7176
77+ /**
78+ * This method is called by SDL using JNI.
79+ */
80+ static void joystickSetLED (int device_id , int red , int green , int blue ) {
81+ mJoystickHandler .setLED (device_id , red , green , blue );
82+ }
83+
7284 /**
7385 * This method is called by SDL using JNI.
7486 */
@@ -139,6 +151,8 @@ static class SDLJoystick {
139151 String desc ;
140152 ArrayList <InputDevice .MotionRange > axes ;
141153 ArrayList <InputDevice .MotionRange > hats ;
154+ ArrayList <Light > lights ;
155+ LightsManager .LightsSession lightsSession ;
142156 }
143157 static class RangeComparator implements Comparator <InputDevice .MotionRange > {
144158 @ Override
@@ -197,7 +211,7 @@ public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
197211 /**
198212 * Handles adding and removing of input devices.
199213 */
200- void pollInputDevices () {
214+ synchronized void pollInputDevices () {
201215 int [] deviceIds = InputDevice .getDeviceIds ();
202216
203217 for (int device_id : deviceIds ) {
@@ -211,6 +225,7 @@ void pollInputDevices() {
211225 joystick .desc = getJoystickDescriptor (joystickDevice );
212226 joystick .axes = new ArrayList <InputDevice .MotionRange >();
213227 joystick .hats = new ArrayList <InputDevice .MotionRange >();
228+ joystick .lights = new ArrayList <Light >();
214229
215230 List <InputDevice .MotionRange > ranges = joystickDevice .getMotionRanges ();
216231 Collections .sort (ranges , new RangeComparator ());
@@ -225,18 +240,30 @@ void pollInputDevices() {
225240 }
226241
227242 boolean can_rumble = false ;
243+ boolean has_rgb_led = false ;
228244 if (Build .VERSION .SDK_INT >= 31 /* Android 12.0 (S) */ ) {
229- VibratorManager manager = joystickDevice .getVibratorManager ();
230- int [] vibrators = manager .getVibratorIds ();
245+ VibratorManager vibratorManager = joystickDevice .getVibratorManager ();
246+ int [] vibrators = vibratorManager .getVibratorIds ();
231247 if (vibrators .length > 0 ) {
232248 can_rumble = true ;
233249 }
250+ LightsManager lightsManager = joystickDevice .getLightsManager ();
251+ List <Light > lights = lightsManager .getLights ();
252+ for (Light light : lights ) {
253+ if (light .hasRgbControl ()) {
254+ joystick .lights .add (light );
255+ }
256+ }
257+ if (!joystick .lights .isEmpty ()) {
258+ joystick .lightsSession = lightsManager .openSession ();
259+ has_rgb_led = true ;
260+ }
234261 }
235262
236263 mJoysticks .add (joystick );
237264 SDLControllerManager .nativeAddJoystick (joystick .device_id , joystick .name , joystick .desc ,
238265 getVendorId (joystickDevice ), getProductId (joystickDevice ),
239- getButtonMask (joystickDevice ), joystick .axes .size (), getAxisMask (joystick .axes ), joystick .hats .size ()/2 , can_rumble );
266+ getButtonMask (joystickDevice ), joystick .axes .size (), getAxisMask (joystick .axes ), joystick .hats .size ()/2 , can_rumble , has_rgb_led );
240267 }
241268 }
242269 }
@@ -262,6 +289,16 @@ void pollInputDevices() {
262289 SDLControllerManager .nativeRemoveJoystick (device_id );
263290 for (int i = 0 ; i < mJoysticks .size (); i ++) {
264291 if (mJoysticks .get (i ).device_id == device_id ) {
292+ if (Build .VERSION .SDK_INT >= 31 /* Android 12.0 (S) */ ) {
293+ if (mJoysticks .get (i ).lightsSession != null ) {
294+ try {
295+ mJoysticks .get (i ).lightsSession .close ();
296+ } catch (Exception e ) {
297+ // Session may already be unregistered when device disconnects
298+ }
299+ mJoysticks .get (i ).lightsSession = null ;
300+ }
301+ }
265302 mJoysticks .remove (i );
266303 break ;
267304 }
@@ -270,7 +307,7 @@ void pollInputDevices() {
270307 }
271308 }
272309
273- protected SDLJoystick getJoystick (int device_id ) {
310+ synchronized protected SDLJoystick getJoystick (int device_id ) {
274311 for (SDLJoystick joystick : mJoysticks ) {
275312 if (joystick .device_id == device_id ) {
276313 return joystick ;
@@ -453,6 +490,24 @@ int getButtonMask(InputDevice joystickDevice) {
453490 }
454491 return button_mask ;
455492 }
493+
494+ void setLED (int device_id , int red , int green , int blue ) {
495+ if (Build .VERSION .SDK_INT < 31 /* Android 12.0 (S) */ ) {
496+ return ;
497+ }
498+ SDLJoystick joystick = getJoystick (device_id );
499+ if (joystick == null || joystick .lights .isEmpty ()) {
500+ return ;
501+ }
502+ LightsRequest .Builder lightsRequest = new LightsRequest .Builder ();
503+ LightState lightState = new LightState .Builder ().setColor (Color .rgb (red , green , blue )).build ();
504+ for (Light light : joystick .lights ) {
505+ if (light .hasRgbControl ()) {
506+ lightsRequest .addLight (light , lightState );
507+ }
508+ }
509+ joystick .lightsSession .requestLights (lightsRequest .build ());
510+ }
456511}
457512
458513class SDLHapticHandler_API31 extends SDLHapticHandler {
@@ -587,7 +642,7 @@ void stop(int device_id) {
587642 }
588643 }
589644
590- void pollHapticDevices () {
645+ synchronized void pollHapticDevices () {
591646
592647 final int deviceId_VIBRATOR_SERVICE = 999999 ;
593648 boolean hasVibratorService = false ;
@@ -635,7 +690,7 @@ void pollHapticDevices() {
635690 }
636691 }
637692
638- protected SDLHaptic getHaptic (int device_id ) {
693+ synchronized protected SDLHaptic getHaptic (int device_id ) {
639694 for (SDLHaptic haptic : mHaptics ) {
640695 if (haptic .device_id == device_id ) {
641696 return haptic ;
@@ -700,6 +755,9 @@ public boolean onGenericMotion(View v, MotionEvent event) {
700755
701756 // BUTTON_STYLUS_PRIMARY is 2^5, so shift by 4, and apply SDL_PEN_INPUT_DOWN/SDL_PEN_INPUT_ERASER_TIP
702757 int buttons = (event .getButtonState () >> 4 ) | (1 << (toolType == MotionEvent .TOOL_TYPE_STYLUS ? 0 : 30 ));
758+ if ((event .getButtonState () & MotionEvent .BUTTON_TERTIARY ) != 0 ) {
759+ buttons |= 0x08 ;
760+ }
703761
704762 SDLActivity .onNativePen (event .getPointerId (i ), getPenDeviceType (event .getDevice ()), buttons , action , x , y , p );
705763 consumed = true ;
0 commit comments