From 47c8dcc968b29db7164e3ee5b5a8d8874ef7d26b Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 20 May 2026 14:57:36 -0700 Subject: [PATCH] android: handle sensor registration synchronized in one place --- .../org/libsdl/app/SDLControllerManager.java | 16 +++------- .../java/org/libsdl/app/SDLSensorManager.java | 32 +++++++++++++++++++ .../main/java/org/libsdl/app/SDLSurface.java | 6 ++-- 3 files changed, 40 insertions(+), 14 deletions(-) create mode 100644 android-project/app/src/main/java/org/libsdl/app/SDLSensorManager.java diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java index bce15e9de2..a41467c61d 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java @@ -91,13 +91,7 @@ public class SDLControllerManager * This method is called by SDL using JNI. */ static void joystickSetSensorsEnabled(int device_id, boolean enabled) { - // Run this on the UI thread so we don't race with enableSensor() in SDLSurface.java - SDL.getContext().runOnUiThread(new Runnable() { - @Override - public void run() { - mJoystickHandler.setSensorsEnabled(device_id, enabled); - } - }); + mJoystickHandler.setSensorsEnabled(device_id, enabled); } /** @@ -558,17 +552,17 @@ class SDLJoystickHandler { } if (enabled) { if (joystick.accelerometerSensor != null) { - joystick.sensorManager.registerListener(joystick.sensorListener, joystick.accelerometerSensor, SensorManager.SENSOR_DELAY_GAME, null); + SDLSensorManager.registerListener(joystick.sensorManager, joystick.sensorListener, joystick.accelerometerSensor, SensorManager.SENSOR_DELAY_GAME); } if (joystick.gyroscopeSensor != null) { - joystick.sensorManager.registerListener(joystick.sensorListener, joystick.gyroscopeSensor, SensorManager.SENSOR_DELAY_GAME, null); + SDLSensorManager.registerListener(joystick.sensorManager, joystick.sensorListener, joystick.gyroscopeSensor, SensorManager.SENSOR_DELAY_GAME); } } else { if (joystick.accelerometerSensor != null) { - joystick.sensorManager.unregisterListener(joystick.sensorListener, joystick.accelerometerSensor); + SDLSensorManager.unregisterListener(joystick.sensorManager, joystick.sensorListener, joystick.accelerometerSensor); } if (joystick.gyroscopeSensor != null) { - joystick.sensorManager.unregisterListener(joystick.sensorListener, joystick.gyroscopeSensor); + SDLSensorManager.unregisterListener(joystick.sensorManager, joystick.sensorListener, joystick.gyroscopeSensor); } } } diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLSensorManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLSensorManager.java new file mode 100644 index 0000000000..586e3fab6e --- /dev/null +++ b/android-project/app/src/main/java/org/libsdl/app/SDLSensorManager.java @@ -0,0 +1,32 @@ +package org.libsdl.app; + +import android.hardware.Sensor; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; + +// This class coordinates synchronized access to sensor manager registration +// +// This prevents a java.util.ConcurrentModificationException exception on +// Android 16, specifically on the Samsung Tab S9 Ultra. + +class SDLSensorManager +{ + static private SDLSensorManager mManager = new SDLSensorManager(); + + public static void registerListener(SensorManager manager, SensorEventListener listener, Sensor sensor, int samplingPeriodUs) { + mManager.RegisterListener(manager, listener, sensor, samplingPeriodUs); + } + + public static void unregisterListener(SensorManager manager, SensorEventListener listener, Sensor sensor) { + mManager.UnregisterListener(manager, listener, sensor); + } + + private synchronized void RegisterListener(SensorManager manager, SensorEventListener listener, Sensor sensor, int samplingPeriodUs) { + manager.registerListener(listener, sensor, samplingPeriodUs, null); + } + + private synchronized void UnregisterListener(SensorManager manager, SensorEventListener listener, Sensor sensor) { + manager.unregisterListener(listener, sensor); + } +} + diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java b/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java index dedc00b78a..196cf04ec2 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java @@ -328,11 +328,11 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, protected void enableSensor(int sensortype, boolean enabled) { // TODO: This uses getDefaultSensor - what if we have >1 accels? if (enabled) { - mSensorManager.registerListener(this, + SDLSensorManager.registerListener(mSensorManager, this, mSensorManager.getDefaultSensor(sensortype), - SensorManager.SENSOR_DELAY_GAME, null); + SensorManager.SENSOR_DELAY_GAME); } else { - mSensorManager.unregisterListener(this, + SDLSensorManager.unregisterListener(mSensorManager, this, mSensorManager.getDefaultSensor(sensortype)); } }