Fixed life-cycle issues with two activities sharing HIDDeviceManager

This commit is contained in:
Sam Lantinga 2018-10-08 12:49:30 -07:00
parent 1e728f5075
commit 337cea4411
3 changed files with 60 additions and 26 deletions

View File

@ -24,7 +24,28 @@ public class HIDDeviceManager {
private static final String TAG = "hidapi"; private static final String TAG = "hidapi";
private static final String ACTION_USB_PERMISSION = "org.libsdl.app.USB_PERMISSION"; 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<Integer, HIDDevice> mDevicesById = new HashMap<Integer, HIDDevice>(); private HashMap<Integer, HIDDevice> mDevicesById = new HashMap<Integer, HIDDevice>();
private HashMap<UsbDevice, HIDDeviceUSB> mUSBDevices = new HashMap<UsbDevice, HIDDeviceUSB>(); private HashMap<UsbDevice, HIDDeviceUSB> mUSBDevices = new HashMap<UsbDevice, HIDDeviceUSB>();
private HashMap<BluetoothDevice, HIDDeviceBLESteamController> mBluetoothDevices = new HashMap<BluetoothDevice, HIDDeviceBLESteamController>(); private HashMap<BluetoothDevice, HIDDeviceBLESteamController> mBluetoothDevices = new HashMap<BluetoothDevice, HIDDeviceBLESteamController>();
@ -77,7 +98,7 @@ public class HIDDeviceManager {
} }
}; };
public HIDDeviceManager(Context context) { private HIDDeviceManager(Context context) {
mContext = context; mContext = context;
// Make sure we have the HIDAPI library loaded with the native functions // Make sure we have the HIDAPI library loaded with the native functions
@ -88,7 +109,7 @@ public class HIDDeviceManager {
return; return;
} }
HIDDeviceRegisterCallback(this); HIDDeviceRegisterCallback();
mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE); mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE);
mIsChromebook = mContext.getPackageManager().hasSystemFeature("org.chromium.arc.device_management"); mIsChromebook = mContext.getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
@ -125,7 +146,7 @@ public class HIDDeviceManager {
return result; return result;
} }
protected void initializeUSB() { private void initializeUSB() {
mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE); mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
/* /*
@ -187,7 +208,7 @@ public class HIDDeviceManager {
return mUsbManager; return mUsbManager;
} }
protected void shutdownUSB() { private void shutdownUSB() {
try { try {
mContext.unregisterReceiver(mUsbBroadcast); mContext.unregisterReceiver(mUsbBroadcast);
} catch (Exception e) { } catch (Exception e) {
@ -195,7 +216,7 @@ public class HIDDeviceManager {
} }
} }
protected boolean isHIDDeviceUSB(UsbDevice usbDevice) { private boolean isHIDDeviceUSB(UsbDevice usbDevice) {
for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); ++interface_number) { for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); ++interface_number) {
if (isHIDDeviceInterface(usbDevice, interface_number)) { if (isHIDDeviceInterface(usbDevice, interface_number)) {
return true; return true;
@ -204,7 +225,7 @@ public class HIDDeviceManager {
return false; return false;
} }
protected boolean isHIDDeviceInterface(UsbDevice usbDevice, int interface_number) { private boolean isHIDDeviceInterface(UsbDevice usbDevice, int interface_number) {
UsbInterface usbInterface = usbDevice.getInterface(interface_number); UsbInterface usbInterface = usbDevice.getInterface(interface_number);
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID) { if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID) {
return true; return true;
@ -217,7 +238,7 @@ public class HIDDeviceManager {
return false; 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_SUBCLASS = 93;
final int XB360_IFACE_PROTOCOL = 1; // Wired only final int XB360_IFACE_PROTOCOL = 1; // Wired only
final int[] SUPPORTED_VENDORS = { final int[] SUPPORTED_VENDORS = {
@ -256,7 +277,7 @@ public class HIDDeviceManager {
return false; 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_SUBCLASS = 71;
final int XB1_IFACE_PROTOCOL = 208; final int XB1_IFACE_PROTOCOL = 208;
final int[] SUPPORTED_VENDORS = { final int[] SUPPORTED_VENDORS = {
@ -281,13 +302,13 @@ public class HIDDeviceManager {
return false; return false;
} }
protected void handleUsbDeviceAttached(UsbDevice usbDevice) { private void handleUsbDeviceAttached(UsbDevice usbDevice) {
if (isHIDDeviceUSB(usbDevice)) { if (isHIDDeviceUSB(usbDevice)) {
connectHIDDeviceUSB(usbDevice); connectHIDDeviceUSB(usbDevice);
} }
} }
protected void handleUsbDeviceDetached(UsbDevice usbDevice) { private void handleUsbDeviceDetached(UsbDevice usbDevice) {
HIDDeviceUSB device = mUSBDevices.get(usbDevice); HIDDeviceUSB device = mUSBDevices.get(usbDevice);
if (device == null) if (device == null)
return; return;
@ -299,7 +320,7 @@ public class HIDDeviceManager {
HIDDeviceDisconnected(id); HIDDeviceDisconnected(id);
} }
protected void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) { private void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) {
HIDDeviceUSB device = mUSBDevices.get(usbDevice); HIDDeviceUSB device = mUSBDevices.get(usbDevice);
if (device == null) if (device == null)
return; return;
@ -311,7 +332,7 @@ public class HIDDeviceManager {
HIDDeviceOpenResult(device.getId(), opened); HIDDeviceOpenResult(device.getId(), opened);
} }
protected void connectHIDDeviceUSB(UsbDevice usbDevice) { private void connectHIDDeviceUSB(UsbDevice usbDevice) {
synchronized (this) { synchronized (this) {
for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); interface_number++) { for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); interface_number++) {
if (isHIDDeviceInterface(usbDevice, interface_number)) { if (isHIDDeviceInterface(usbDevice, interface_number)) {
@ -326,7 +347,7 @@ public class HIDDeviceManager {
} }
} }
protected void initializeBluetooth() { private void initializeBluetooth() {
Log.d(TAG, "Initializing Bluetooth"); Log.d(TAG, "Initializing Bluetooth");
if (mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) { if (mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
@ -377,7 +398,7 @@ public class HIDDeviceManager {
} }
} }
protected void shutdownBluetooth() { private void shutdownBluetooth() {
try { try {
mContext.unregisterReceiver(mBluetoothBroadcast); mContext.unregisterReceiver(mBluetoothBroadcast);
} catch (Exception e) { } catch (Exception e) {
@ -476,7 +497,7 @@ public class HIDDeviceManager {
return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0); return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0);
} }
public void close() { private void close() {
shutdownUSB(); shutdownUSB();
shutdownBluetooth(); shutdownBluetooth();
synchronized (this) { synchronized (this) {
@ -623,7 +644,7 @@ public class HIDDeviceManager {
/////////////// Native methods /////////////// Native methods
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
private native void HIDDeviceRegisterCallback(Object callbackHandler); private native void HIDDeviceRegisterCallback();
private native void HIDDeviceReleaseCallback(); 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); 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);

View File

@ -250,7 +250,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
mClipboardHandler = new SDLClipboardHandler_Old(); mClipboardHandler = new SDLClipboardHandler_Old();
} }
mHIDDeviceManager = new HIDDeviceManager(this); mHIDDeviceManager = HIDDeviceManager.acquire(this);
// Set up the surface // Set up the surface
mSurface = new SDLSurface(getApplication()); mSurface = new SDLSurface(getApplication());
@ -380,7 +380,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
Log.v(TAG, "onDestroy()"); Log.v(TAG, "onDestroy()");
if (mHIDDeviceManager != null) { if (mHIDDeviceManager != null) {
mHIDDeviceManager.close(); HIDDeviceManager.release(mHIDDeviceManager);
mHIDDeviceManager = null; mHIDDeviceManager = null;
} }

View File

@ -696,7 +696,7 @@ static void ThreadDestroyed(void* value)
extern "C" 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" extern "C"
JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz); 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" 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()"); 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"); __android_log_print(ANDROID_LOG_ERROR, TAG, "Error initializing pthread key");
} }
g_HIDDeviceManagerCallbackHandler = env->NewGlobalRef( callbackHandler ); if ( g_HIDDeviceManagerCallbackHandler != NULL )
jclass objClass = env->GetObjectClass( callbackHandler ); {
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 ) 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" ); g_midHIDDeviceManagerOpen = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "openDevice", "(I)Z" );
if ( !g_midHIDDeviceManagerOpen ) if ( !g_midHIDDeviceManagerOpen )
{ {
@ -773,8 +781,13 @@ extern "C"
JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz) JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz)
{ {
LOGV("HIDDeviceReleaseCallback"); LOGV("HIDDeviceReleaseCallback");
if ( env->IsSameObject( thiz, g_HIDDeviceManagerCallbackHandler ) )
{
env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass ); env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass );
g_HIDDeviceManagerCallbackClass = NULL;
env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler ); env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler );
g_HIDDeviceManagerCallbackHandler = NULL;
}
} }
extern "C" extern "C"