Android: remove pollInputDevice() in favor of InputDeviceListener (#15659)

This commit is contained in:
Sylvain Becker 2026-06-04 05:38:04 +02:00 committed by GitHub
parent 42fc082b5e
commit fc3a96e47a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 85 additions and 87 deletions

View file

@ -69,9 +69,9 @@
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLControllerManager {
void joystickSetSensorsEnabled(int, boolean);
void pollInputDevices();
void detectDevices();
void joystickSetLED(int, int, int, int);
void pollHapticDevices();
void detectHapticDevices();
void hapticRun(int, float, int);
void hapticRumble(int, float, float, int);
void hapticStop(int);

View file

@ -465,6 +465,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
mSingleton = this;
SDL.setContext(this);
SDLControllerManager.initializeDeviceListener();
mClipboardHandler = new SDLClipboardHandler();
mHIDDeviceManager = HIDDeviceManager.acquire(this);
@ -545,7 +547,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
if (mHIDDeviceManager != null) {
mHIDDeviceManager.setFrozen(true);
}
}
if (!mHasMultiWindow) {
pauseNativeThread();
@ -559,7 +561,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
if (mHIDDeviceManager != null) {
mHIDDeviceManager.setFrozen(false);
}
}
if (!mHasMultiWindow) {
resumeNativeThread();
@ -638,7 +640,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
if (hasFocus || !SDLActivity.nativeGetHintBoolean("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", false)) {
if (mHIDDeviceManager != null) {
mHIDDeviceManager.setFrozen(!hasFocus);
}
}
}
if (SDLActivity.mBrokenLibraries) {

View file

@ -6,6 +6,8 @@ import java.util.Comparator;
import java.util.List;
import android.content.Context;
import android.hardware.input.InputManager;
import android.hardware.input.InputManager.InputDeviceListener;
import android.hardware.lights.Light;
import android.hardware.lights.LightsRequest;
import android.hardware.lights.LightsManager;
@ -68,6 +70,12 @@ public class SDLControllerManager
}
}
static void initializeDeviceListener() {
InputManager im = (InputManager) SDL.getContext().getSystemService(Context.INPUT_SERVICE);
im.registerInputDeviceListener(new SDLDeviceListener(), null);
}
// Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
static public boolean handleJoystickMotionEvent(MotionEvent event) {
return mJoystickHandler.handleMotionEvent(event);
@ -76,8 +84,8 @@ public class SDLControllerManager
/**
* This method is called by SDL using JNI.
*/
static void pollInputDevices() {
mJoystickHandler.pollInputDevices();
static void detectDevices() {
mJoystickHandler.detectDevices();
}
/**
@ -97,8 +105,8 @@ public class SDLControllerManager
/**
* This method is called by SDL using JNI.
*/
static void pollHapticDevices() {
mHapticHandler.pollHapticDevices();
static void detectHapticDevices() {
mHapticHandler.detectHapticDevices();
}
/**
@ -151,7 +159,27 @@ public class SDLControllerManager
((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
);
}
}
class SDLDeviceListener implements InputDeviceListener
{
@Override
public void onInputDeviceAdded(int deviceId) {
if (SDLControllerManager.isDeviceSDLJoystick(deviceId)) {
SDLControllerManager.mJoystickHandler.deviceAdded(deviceId);
}
}
@Override
public void onInputDeviceChanged(int deviceId) {
}
@Override
public void onInputDeviceRemoved(int deviceId) {
// InputDevice.getDevice(deviceId) returns NULL. so we cannot check device type
SDLControllerManager.mJoystickHandler.deviceRemoved(deviceId);
}
}
@ -228,16 +256,21 @@ class SDLJoystickHandler {
/**
* Handles adding and removing of input devices.
*/
synchronized void pollInputDevices() {
int[] deviceIds = InputDevice.getDeviceIds();
synchronized void detectDevices() {
int[] deviceIds = InputDevice.getDeviceIds();
for (int device_id : deviceIds) {
if (SDLControllerManager.isDeviceSDLJoystick(device_id)) {
deviceAdded(device_id);
}
}
}
for (int device_id : deviceIds) {
if (SDLControllerManager.isDeviceSDLJoystick(device_id)) {
SDLJoystick joystick = getJoystick(device_id);
if (joystick == null) {
InputDevice joystickDevice = InputDevice.getDevice(device_id);
joystick = new SDLJoystick();
joystick.device_id = device_id;
void deviceAdded(int device_id) {
SDLJoystick joystick = getJoystick(device_id);
if (joystick == null) {
InputDevice joystickDevice = InputDevice.getDevice(device_id);
joystick = new SDLJoystick();
joystick.device_id = device_id;
joystick.name = joystickDevice.getName();
joystick.desc = getJoystickDescriptor(joystickDevice);
joystick.axes = new ArrayList<InputDevice.MotionRange>();
@ -299,44 +332,27 @@ class SDLJoystickHandler {
getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2, can_rumble, has_rgb_led,
has_accelerometer, has_gyroscope);
}
}
}
/* Check removed devices */
ArrayList<Integer> removedDevices = null;
for (SDLJoystick joystick : mJoysticks) {
int device_id = joystick.device_id;
int i;
for (i = 0; i < deviceIds.length; i++) {
if (device_id == deviceIds[i]) break;
}
if (i == deviceIds.length) {
if (removedDevices == null) {
removedDevices = new ArrayList<Integer>();
}
removedDevices.add(device_id);
}
}
}
void deviceRemoved(int device_id) {
for (int i = 0; i < mJoysticks.size(); i++) {
if (mJoysticks.get(i).device_id == device_id) {
if (removedDevices != null) {
for (int device_id : removedDevices) {
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;
}
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.remove(i);
break;
mJoysticks.get(i).lightsSession = null;
}
}
mJoysticks.remove(i);
break;
}
}
}
@ -701,7 +717,7 @@ class SDLHapticHandler {
}
}
synchronized void pollHapticDevices() {
synchronized void detectHapticDevices() {
final int deviceId_VIBRATOR_SERVICE = 999999;
boolean hasVibratorService = false;

View file

@ -407,10 +407,10 @@ static jmethodID midAudioSetThreadPriority;
static jclass mControllerManagerClass;
// method signatures
static jmethodID midPollInputDevices;
static jmethodID midDetectDevices;
static jmethodID midJoystickSetLED;
static jmethodID midJoystickSetSensorsEnabled;
static jmethodID midPollHapticDevices;
static jmethodID midDetectHapticDevices;
static jmethodID midHapticRun;
static jmethodID midHapticRumble;
static jmethodID midHapticStop;
@ -752,14 +752,14 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env
mControllerManagerClass = (jclass)((*env)->NewGlobalRef(env, cls));
midPollInputDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"pollInputDevices", "()V");
midDetectDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"detectDevices", "()V");
midJoystickSetLED = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"joystickSetLED", "(IIII)V");
midJoystickSetSensorsEnabled = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"joystickSetSensorsEnabled", "(IZ)V");
midPollHapticDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"pollHapticDevices", "()V");
midDetectHapticDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"detectHapticDevices", "()V");
midHapticRun = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"hapticRun", "(IFI)V");
midHapticRumble = (*env)->GetStaticMethodID(env, mControllerManagerClass,
@ -767,7 +767,7 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env
midHapticStop = (*env)->GetStaticMethodID(env, mControllerManagerClass,
"hapticStop", "(I)V");
if (!midPollInputDevices || !midJoystickSetLED || !midJoystickSetSensorsEnabled || !midPollHapticDevices || !midHapticRun || !midHapticRumble || !midHapticStop) {
if (!midDetectDevices || !midJoystickSetLED || !midJoystickSetSensorsEnabled || !midDetectHapticDevices || !midHapticRun || !midHapticRumble || !midHapticStop) {
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLControllerManager.java?");
}
@ -2639,10 +2639,10 @@ void Android_JNI_InitTouch(void)
(*env)->CallStaticVoidMethod(env, mActivityClass, midInitTouch);
}
void Android_JNI_PollInputDevices(void)
void Android_JNI_DetectDevices(void)
{
JNIEnv *env = Android_JNI_GetEnv();
(*env)->CallStaticVoidMethod(env, mControllerManagerClass, midPollInputDevices);
(*env)->CallStaticVoidMethod(env, mControllerManagerClass, midDetectDevices);
}
void Android_JNI_JoystickSetLED(int device_id, int red, int green, int blue)
@ -2657,10 +2657,10 @@ void Android_JNI_JoystickSetSensorsEnabled(int device_id, bool enabled)
(*env)->CallStaticVoidMethod(env, mControllerManagerClass, midJoystickSetSensorsEnabled, device_id, (enabled == 1));
}
void Android_JNI_PollHapticDevices(void)
void Android_JNI_DetectHapticDevices(void)
{
JNIEnv *env = Android_JNI_GetEnv();
(*env)->CallStaticVoidMethod(env, mControllerManagerClass, midPollHapticDevices);
(*env)->CallStaticVoidMethod(env, mControllerManagerClass, midDetectHapticDevices);
}
void Android_JNI_HapticRun(int device_id, float intensity, int length)

View file

@ -102,12 +102,12 @@ bool Android_JNI_HasClipboardText(void);
int Android_JNI_GetPowerInfo(int *plugged, int *charged, int *battery, int *seconds, int *percent);
// Joystick support
void Android_JNI_PollInputDevices(void);
void Android_JNI_DetectDevices(void);
void Android_JNI_JoystickSetLED(int device_id, int red, int green, int blue);
void Android_JNI_JoystickSetSensorsEnabled(int device_id, bool enabled);
// Haptic support
void Android_JNI_PollHapticDevices(void);
void Android_JNI_DetectHapticDevices(void);
void Android_JNI_HapticRun(int device_id, float intensity, int length);
void Android_JNI_HapticRumble(int device_id, float low_frequency_intensity, float high_frequency_intensity, int length);
void Android_JNI_HapticStop(int device_id);

View file

@ -41,8 +41,7 @@ static int numhaptics = 0;
bool SDL_SYS_HapticInit(void)
{
Android_JNI_PollHapticDevices();
Android_JNI_DetectHapticDevices();
return true;
}

View file

@ -535,11 +535,9 @@ done:
SDL_UnlockJoysticks();
}
static void ANDROID_JoystickDetect(void);
static bool ANDROID_JoystickInit(void)
{
ANDROID_JoystickDetect();
Android_JNI_DetectDevices();
return true;
}
@ -550,16 +548,9 @@ static int ANDROID_JoystickGetCount(void)
static void ANDROID_JoystickDetect(void)
{
/* Support for device connect/disconnect is API >= 16 only,
* so we poll every three seconds
/* Support for device connect/disconnect is implemented using InputDeviceListener
* Ref: http://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
*/
static Uint64 timeout = 0;
Uint64 now = SDL_GetTicks();
if (!timeout || now >= timeout) {
timeout = now + 3000;
Android_JNI_PollInputDevices();
}
}
static bool ANDROID_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
@ -596,16 +587,6 @@ static SDL_joylist_item *JoystickByDeviceId(int device_id)
item = item->next;
}
// Joystick not found, try adding it
ANDROID_JoystickDetect();
while (item) {
if (item->device_id == device_id) {
return item;
}
item = item->next;
}
return NULL;
}