Просмотр исходного кода

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

Sylvain Becker 14 часов назад
Родитель
Сommit
fc3a96e47a

+ 2 - 2
android-project/app/proguard-rules.pro

@@ -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);

+ 5 - 3
android-project/app/src/main/java/org/libsdl/app/SDLActivity.java

@@ -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) {

+ 63 - 47
android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java

@@ -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();
-
-        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;
+    synchronized void detectDevices() {
+       int[] deviceIds = InputDevice.getDeviceIds();
+       for (int device_id : deviceIds) {
+           if (SDLControllerManager.isDeviceSDLJoystick(device_id)) {
+               deviceAdded(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;

+ 11 - 11
src/core/android/SDL_android.c

@@ -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)

+ 2 - 2
src/core/android/SDL_android.h

@@ -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);

+ 1 - 2
src/haptic/android/SDL_syshaptic.c

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

+ 2 - 21
src/joystick/android/SDL_sysjoystick.c

@@ -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;
 }