From 337cea44110d1223b12a7509613f03caa56d3045 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 8 Oct 2018 12:49:30 -0700 Subject: [PATCH] Fixed life-cycle issues with two activities sharing HIDDeviceManager --- .../java/org/libsdl/app/HIDDeviceManager.java | 55 +++++++++++++------ .../main/java/org/libsdl/app/SDLActivity.java | 4 +- src/hidapi/android/hid.cpp | 27 ++++++--- 3 files changed, 60 insertions(+), 26 deletions(-) diff --git a/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java b/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java index ba30d0a01121f..761ecca0d39b9 100644 --- a/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java +++ b/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java @@ -24,7 +24,28 @@ public class HIDDeviceManager { private static final String TAG = "hidapi"; private static final String ACTION_USB_PERMISSION = "org.libsdl.app.USB_PERMISSION"; - protected Context mContext; + private static HIDDeviceManager sManager; + private static int sManagerRefCount = 0; + + public static HIDDeviceManager acquire(Context context) { + if (sManagerRefCount == 0) { + sManager = new HIDDeviceManager(context); + } + ++sManagerRefCount; + return sManager; + } + + public static void release(HIDDeviceManager manager) { + if (manager == sManager) { + --sManagerRefCount; + if (sManagerRefCount == 0) { + sManager.close(); + sManager = null; + } + } + } + + private Context mContext; private HashMap mDevicesById = new HashMap(); private HashMap mUSBDevices = new HashMap(); private HashMap mBluetoothDevices = new HashMap(); @@ -77,7 +98,7 @@ public void onReceive(Context context, Intent intent) { } }; - public HIDDeviceManager(Context context) { + private HIDDeviceManager(Context context) { mContext = context; // Make sure we have the HIDAPI library loaded with the native functions @@ -88,7 +109,7 @@ public HIDDeviceManager(Context context) { return; } - HIDDeviceRegisterCallback(this); + HIDDeviceRegisterCallback(); mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE); mIsChromebook = mContext.getPackageManager().hasSystemFeature("org.chromium.arc.device_management"); @@ -125,7 +146,7 @@ public int getDeviceIDForIdentifier(String identifier) { return result; } - protected void initializeUSB() { + private void initializeUSB() { mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE); /* @@ -187,7 +208,7 @@ UsbManager getUSBManager() { return mUsbManager; } - protected void shutdownUSB() { + private void shutdownUSB() { try { mContext.unregisterReceiver(mUsbBroadcast); } catch (Exception e) { @@ -195,7 +216,7 @@ protected void shutdownUSB() { } } - protected boolean isHIDDeviceUSB(UsbDevice usbDevice) { + private boolean isHIDDeviceUSB(UsbDevice usbDevice) { for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); ++interface_number) { if (isHIDDeviceInterface(usbDevice, interface_number)) { return true; @@ -204,7 +225,7 @@ protected boolean isHIDDeviceUSB(UsbDevice usbDevice) { return false; } - protected boolean isHIDDeviceInterface(UsbDevice usbDevice, int interface_number) { + private boolean isHIDDeviceInterface(UsbDevice usbDevice, int interface_number) { UsbInterface usbInterface = usbDevice.getInterface(interface_number); if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID) { return true; @@ -217,7 +238,7 @@ protected boolean isHIDDeviceInterface(UsbDevice usbDevice, int interface_number return false; } - protected boolean isXbox360Controller(UsbDevice usbDevice, UsbInterface usbInterface) { + private boolean isXbox360Controller(UsbDevice usbDevice, UsbInterface usbInterface) { final int XB360_IFACE_SUBCLASS = 93; final int XB360_IFACE_PROTOCOL = 1; // Wired only final int[] SUPPORTED_VENDORS = { @@ -256,7 +277,7 @@ protected boolean isXbox360Controller(UsbDevice usbDevice, UsbInterface usbInter return false; } - protected boolean isXboxOneController(UsbDevice usbDevice, UsbInterface usbInterface) { + private boolean isXboxOneController(UsbDevice usbDevice, UsbInterface usbInterface) { final int XB1_IFACE_SUBCLASS = 71; final int XB1_IFACE_PROTOCOL = 208; final int[] SUPPORTED_VENDORS = { @@ -281,13 +302,13 @@ protected boolean isXboxOneController(UsbDevice usbDevice, UsbInterface usbInter return false; } - protected void handleUsbDeviceAttached(UsbDevice usbDevice) { + private void handleUsbDeviceAttached(UsbDevice usbDevice) { if (isHIDDeviceUSB(usbDevice)) { connectHIDDeviceUSB(usbDevice); } } - protected void handleUsbDeviceDetached(UsbDevice usbDevice) { + private void handleUsbDeviceDetached(UsbDevice usbDevice) { HIDDeviceUSB device = mUSBDevices.get(usbDevice); if (device == null) return; @@ -299,7 +320,7 @@ protected void handleUsbDeviceDetached(UsbDevice usbDevice) { HIDDeviceDisconnected(id); } - protected void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) { + private void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) { HIDDeviceUSB device = mUSBDevices.get(usbDevice); if (device == null) return; @@ -311,7 +332,7 @@ protected void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission HIDDeviceOpenResult(device.getId(), opened); } - protected void connectHIDDeviceUSB(UsbDevice usbDevice) { + private void connectHIDDeviceUSB(UsbDevice usbDevice) { synchronized (this) { for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); interface_number++) { if (isHIDDeviceInterface(usbDevice, interface_number)) { @@ -326,7 +347,7 @@ protected void connectHIDDeviceUSB(UsbDevice usbDevice) { } } - protected void initializeBluetooth() { + private void initializeBluetooth() { Log.d(TAG, "Initializing Bluetooth"); if (mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) { @@ -377,7 +398,7 @@ protected void initializeBluetooth() { } } - protected void shutdownBluetooth() { + private void shutdownBluetooth() { try { mContext.unregisterReceiver(mBluetoothBroadcast); } catch (Exception e) { @@ -476,7 +497,7 @@ public boolean isSteamController(BluetoothDevice bluetoothDevice) { return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0); } - public void close() { + private void close() { shutdownUSB(); shutdownBluetooth(); synchronized (this) { @@ -623,7 +644,7 @@ public void closeDevice(int deviceID) { /////////////// Native methods ////////////////////////////////////////////////////////////////////////////////////////////////////// - private native void HIDDeviceRegisterCallback(Object callbackHandler); + private native void HIDDeviceRegisterCallback(); private native void HIDDeviceReleaseCallback(); native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number); diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 67cb3a3871682..c5901abea2ba1 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -250,7 +250,7 @@ public void onClick(DialogInterface dialog,int id) { mClipboardHandler = new SDLClipboardHandler_Old(); } - mHIDDeviceManager = new HIDDeviceManager(this); + mHIDDeviceManager = HIDDeviceManager.acquire(this); // Set up the surface mSurface = new SDLSurface(getApplication()); @@ -380,7 +380,7 @@ protected void onDestroy() { Log.v(TAG, "onDestroy()"); if (mHIDDeviceManager != null) { - mHIDDeviceManager.close(); + HIDDeviceManager.release(mHIDDeviceManager); mHIDDeviceManager = null; } diff --git a/src/hidapi/android/hid.cpp b/src/hidapi/android/hid.cpp index b9d95e9de078f..403a77d7281e3 100644 --- a/src/hidapi/android/hid.cpp +++ b/src/hidapi/android/hid.cpp @@ -696,7 +696,7 @@ static void ThreadDestroyed(void* value) extern "C" -JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz, jobject callbackHandler); +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz); extern "C" JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz); @@ -721,7 +721,7 @@ JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport) extern "C" -JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz, jobject callbackHandler) +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz ) { LOGV( "HIDDeviceRegisterCallback()"); @@ -735,11 +735,19 @@ JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallba __android_log_print(ANDROID_LOG_ERROR, TAG, "Error initializing pthread key"); } - g_HIDDeviceManagerCallbackHandler = env->NewGlobalRef( callbackHandler ); - jclass objClass = env->GetObjectClass( callbackHandler ); + if ( g_HIDDeviceManagerCallbackHandler != NULL ) + { + env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass ); + g_HIDDeviceManagerCallbackClass = NULL; + env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler ); + g_HIDDeviceManagerCallbackHandler = NULL; + } + + g_HIDDeviceManagerCallbackHandler = env->NewGlobalRef( thiz ); + jclass objClass = env->GetObjectClass( thiz ); if ( objClass ) { - g_HIDDeviceManagerCallbackClass = reinterpret_cast< jclass >( env->NewGlobalRef(objClass) ); + g_HIDDeviceManagerCallbackClass = reinterpret_cast< jclass >( env->NewGlobalRef( objClass ) ); g_midHIDDeviceManagerOpen = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "openDevice", "(I)Z" ); if ( !g_midHIDDeviceManagerOpen ) { @@ -773,8 +781,13 @@ extern "C" JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz) { LOGV("HIDDeviceReleaseCallback"); - env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass ); - env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler ); + if ( env->IsSameObject( thiz, g_HIDDeviceManagerCallbackHandler ) ) + { + env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass ); + g_HIDDeviceManagerCallbackClass = NULL; + env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler ); + g_HIDDeviceManagerCallbackHandler = NULL; + } } extern "C"