Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
import java.util.List;

import android.content.Context;
import android.hardware.lights.Light;
import android.hardware.lights.LightsRequest;
import android.hardware.lights.LightsManager;
import android.hardware.lights.LightState;
import android.graphics.Color;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;
Expand All @@ -25,7 +30,7 @@ public class SDLControllerManager
static native void nativeAddJoystick(int device_id, String name, String desc,
int vendor_id, int product_id,
int button_mask,
int naxes, int axis_mask, int nhats, boolean can_rumble);
int naxes, int axis_mask, int nhats, boolean can_rumble, boolean has_rgb_led);
static native void nativeRemoveJoystick(int device_id);
static native void nativeAddHaptic(int device_id, String name);
static native void nativeRemoveHaptic(int device_id);
Expand Down Expand Up @@ -69,6 +74,13 @@ static void pollInputDevices() {
mJoystickHandler.pollInputDevices();
}

/**
* This method is called by SDL using JNI.
*/
static void joystickSetLED(int device_id, int red, int green, int blue) {
mJoystickHandler.setLED(device_id, red, green, blue);
}

/**
* This method is called by SDL using JNI.
*/
Expand Down Expand Up @@ -139,6 +151,8 @@ static class SDLJoystick {
String desc;
ArrayList<InputDevice.MotionRange> axes;
ArrayList<InputDevice.MotionRange> hats;
ArrayList<Light> lights;
LightsManager.LightsSession lightsSession;
}
static class RangeComparator implements Comparator<InputDevice.MotionRange> {
@Override
Expand Down Expand Up @@ -211,6 +225,7 @@ void pollInputDevices() {
joystick.desc = getJoystickDescriptor(joystickDevice);
joystick.axes = new ArrayList<InputDevice.MotionRange>();
joystick.hats = new ArrayList<InputDevice.MotionRange>();
joystick.lights = new ArrayList<Light>();

List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
Collections.sort(ranges, new RangeComparator());
Expand All @@ -225,18 +240,30 @@ void pollInputDevices() {
}

boolean can_rumble = false;
boolean has_rgb_led = false;
if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
VibratorManager manager = joystickDevice.getVibratorManager();
int[] vibrators = manager.getVibratorIds();
VibratorManager vibratorManager = joystickDevice.getVibratorManager();
int[] vibrators = vibratorManager.getVibratorIds();
if (vibrators.length > 0) {
can_rumble = true;
}
LightsManager lightsManager = joystickDevice.getLightsManager();
List<Light> lights = lightsManager.getLights();
for (Light light : lights) {
if (light.hasRgbControl()) {
joystick.lights.add(light);
}
}
if (!joystick.lights.isEmpty()) {
joystick.lightsSession = lightsManager.openSession();
has_rgb_led = 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, can_rumble);
getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2, can_rumble, has_rgb_led);
}
}
}
Expand All @@ -262,6 +289,16 @@ void pollInputDevices() {
SDLControllerManager.nativeRemoveJoystick(device_id);
for (int i = 0; i < mJoysticks.size(); i++) {
if (mJoysticks.get(i).device_id == device_id) {
if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
if (mJoysticks.get(i).lightsSession != null) {
try {
mJoysticks.get(i).lightsSession.close();
} catch (Exception e) {
// Session may already be unregistered when device disconnects
}
mJoysticks.get(i).lightsSession = null;
}
}
mJoysticks.remove(i);
break;
}
Expand Down Expand Up @@ -453,6 +490,24 @@ int getButtonMask(InputDevice joystickDevice) {
}
return button_mask;
}

void setLED(int device_id, int red, int green, int blue) {
if (Build.VERSION.SDK_INT < 31 /* Android 12.0 (S) */) {
return;
}
SDLJoystick joystick = getJoystick(device_id);
if (joystick == null || joystick.lights.isEmpty()) {
return;
}
LightsRequest.Builder lightsRequest = new LightsRequest.Builder();
LightState lightState = new LightState.Builder().setColor(Color.rgb(red, green, blue)).build();
for (Light light : joystick.lights) {
if (light.hasRgbControl()) {
lightsRequest.addLight(light, lightState);
}
}
joystick.lightsSession.requestLights(lightsRequest.build());
}
}

class SDLHapticHandler_API31 extends SDLHapticHandler {
Expand Down
19 changes: 14 additions & 5 deletions src/core/android/SDL_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
JNIEnv *env, jclass jcls,
jint device_id, jstring device_name, jstring device_desc, jint vendor_id, jint product_id,
jint button_mask, jint naxes, jint axis_mask, jint nhats, jboolean can_rumble);
jint button_mask, jint naxes, jint axis_mask, jint nhats, jboolean can_rumble, jboolean has_rgb_led);

JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
JNIEnv *env, jclass jcls,
Expand All @@ -334,7 +334,7 @@ static JNINativeMethod SDLControllerManager_tab[] = {
{ "onNativePadUp", "(II)Z", SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp) },
{ "onNativeJoy", "(IIF)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy) },
{ "onNativeHat", "(IIII)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat) },
{ "nativeAddJoystick", "(ILjava/lang/String;Ljava/lang/String;IIIIIIZ)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick) },
{ "nativeAddJoystick", "(ILjava/lang/String;Ljava/lang/String;IIIIIIZZ)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick) },
{ "nativeRemoveJoystick", "(I)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick) },
{ "nativeAddHaptic", "(ILjava/lang/String;)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic) },
{ "nativeRemoveHaptic", "(I)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic) }
Expand Down Expand Up @@ -406,6 +406,7 @@ static jclass mControllerManagerClass;

// method signatures
static jmethodID midPollInputDevices;
static jmethodID midJoystickSetLED;
static jmethodID midPollHapticDevices;
static jmethodID midHapticRun;
static jmethodID midHapticRumble;
Expand Down Expand Up @@ -752,6 +753,8 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env

midPollInputDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"pollInputDevices", "()V");
midJoystickSetLED = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"joystickSetLED", "(IIII)V");
midPollHapticDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"pollHapticDevices", "()V");
midHapticRun = (*env)->GetStaticMethodID(env, mControllerManagerClass,
Expand All @@ -761,7 +764,7 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env
midHapticStop = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"hapticStop", "(I)V");

if (!midPollInputDevices || !midPollHapticDevices || !midHapticRun || !midHapticRumble || !midHapticStop) {
if (!midPollInputDevices || !midJoystickSetLED || !midPollHapticDevices || !midHapticRun || !midHapticRumble || !midHapticStop) {
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLControllerManager.java?");
}

Expand Down Expand Up @@ -1180,13 +1183,13 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
JNIEnv *env, jclass jcls,
jint device_id, jstring device_name, jstring device_desc,
jint vendor_id, jint product_id,
jint button_mask, jint naxes, jint axis_mask, jint nhats, jboolean can_rumble)
jint button_mask, jint naxes, jint axis_mask, jint nhats, jboolean can_rumble, jboolean has_rgb_led)
{
#ifdef SDL_JOYSTICK_ANDROID
const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
const char *desc = (*env)->GetStringUTFChars(env, device_desc, NULL);

Android_AddJoystick(device_id, name, desc, vendor_id, product_id, button_mask, naxes, axis_mask, nhats, can_rumble);
Android_AddJoystick(device_id, name, desc, vendor_id, product_id, button_mask, naxes, axis_mask, nhats, can_rumble, has_rgb_led);

(*env)->ReleaseStringUTFChars(env, device_name, name);
(*env)->ReleaseStringUTFChars(env, device_desc, desc);
Expand Down Expand Up @@ -2175,6 +2178,12 @@ void Android_JNI_PollInputDevices(void)
(*env)->CallStaticVoidMethod(env, mControllerManagerClass, midPollInputDevices);
}

void Android_JNI_JoystickSetLED(int device_id, int red, int green, int blue)
{
JNIEnv *env = Android_JNI_GetEnv();
(*env)->CallStaticVoidMethod(env, mControllerManagerClass, midJoystickSetLED, device_id, red, green, blue);
}

void Android_JNI_PollHapticDevices(void)
{
JNIEnv *env = Android_JNI_GetEnv();
Expand Down
1 change: 1 addition & 0 deletions src/core/android/SDL_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ int Android_JNI_GetPowerInfo(int *plugged, int *charged, int *battery, int *seco

// Joystick support
void Android_JNI_PollInputDevices(void);
void Android_JNI_JoystickSetLED(int device_id, int red, int green, int blue);

// Haptic support
void Android_JNI_PollHapticDevices(void);
Expand Down
17 changes: 15 additions & 2 deletions src/joystick/android/SDL_sysjoystick.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ bool Android_OnHat(int device_id, int hat_id, int x, int y)
return false;
}

void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble)
void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble, bool has_rgb_led)
{
SDL_joylist_item *item;
SDL_GUID guid;
Expand Down Expand Up @@ -380,6 +380,7 @@ void Android_AddJoystick(int device_id, const char *name, const char *desc, int
item->naxes = naxes;
item->nhats = nhats;
item->can_rumble = can_rumble;
item->has_rgb_led = has_rgb_led;
item->device_instance = SDL_GetNextObjectID();
if (!SDL_joylist_tail) {
SDL_joylist = SDL_joylist_tail = item;
Expand Down Expand Up @@ -581,6 +582,10 @@ static bool ANDROID_JoystickOpen(SDL_Joystick *joystick, int device_index)
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true);
}

if (item->has_rgb_led) {
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RGB_LED_BOOLEAN, true);
}

return true;
}

Expand All @@ -607,7 +612,15 @@ static bool ANDROID_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_r

static bool ANDROID_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata;
if (!item) {
return SDL_SetError("SetLED failed, device disconnected");
}
if (!item->has_rgb_led) {
return SDL_Unsupported();
}
Android_JNI_JoystickSetLED(item->device_id, red, green, blue);
return true;
}

static bool ANDROID_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
Expand Down
3 changes: 2 additions & 1 deletion src/joystick/android/SDL_sysjoystick_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ extern bool Android_OnPadDown(int device_id, int keycode);
extern bool Android_OnPadUp(int device_id, int keycode);
extern bool Android_OnJoy(int device_id, int axisnum, float value);
extern bool Android_OnHat(int device_id, int hat_id, int x, int y);
extern void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble);
extern void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble, bool has_rgb_led);
extern void Android_RemoveJoystick(int device_id);

// A linked list of available joysticks
Expand All @@ -46,6 +46,7 @@ typedef struct SDL_joylist_item
int nbuttons, naxes, nhats;
int dpad_state;
bool can_rumble;
bool has_rgb_led;

struct SDL_joylist_item *next;
} SDL_joylist_item;
Expand Down
Loading