Fixed life-cycle issues with two activities sharing HIDDeviceManager
authorSam Lantinga <slouken@libsdl.org>
Mon, 08 Oct 2018 12:49:30 -0700
changeset 123084e3b4ddb8787
parent 12307 461ef7221483
child 12309 5c478c2f0422
Fixed life-cycle issues with two activities sharing HIDDeviceManager
android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java
android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
src/hidapi/android/hid.cpp
     1.1 --- a/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java	Mon Oct 08 12:49:28 2018 -0700
     1.2 +++ b/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java	Mon Oct 08 12:49:30 2018 -0700
     1.3 @@ -24,7 +24,28 @@
     1.4      private static final String TAG = "hidapi";
     1.5      private static final String ACTION_USB_PERMISSION = "org.libsdl.app.USB_PERMISSION";
     1.6  
     1.7 -    protected Context mContext;
     1.8 +    private static HIDDeviceManager sManager;
     1.9 +    private static int sManagerRefCount = 0;
    1.10 +
    1.11 +    public static HIDDeviceManager acquire(Context context) {
    1.12 +        if (sManagerRefCount == 0) {
    1.13 +            sManager = new HIDDeviceManager(context);
    1.14 +        }
    1.15 +        ++sManagerRefCount;
    1.16 +        return sManager;
    1.17 +    }
    1.18 +
    1.19 +    public static void release(HIDDeviceManager manager) {
    1.20 +        if (manager == sManager) {
    1.21 +            --sManagerRefCount;
    1.22 +            if (sManagerRefCount == 0) {
    1.23 +                sManager.close();
    1.24 +                sManager = null;
    1.25 +            }
    1.26 +        }
    1.27 +    }
    1.28 +
    1.29 +    private Context mContext;
    1.30      private HashMap<Integer, HIDDevice> mDevicesById = new HashMap<Integer, HIDDevice>();
    1.31      private HashMap<UsbDevice, HIDDeviceUSB> mUSBDevices = new HashMap<UsbDevice, HIDDeviceUSB>();
    1.32      private HashMap<BluetoothDevice, HIDDeviceBLESteamController> mBluetoothDevices = new HashMap<BluetoothDevice, HIDDeviceBLESteamController>();
    1.33 @@ -77,7 +98,7 @@
    1.34          }
    1.35      };
    1.36  
    1.37 -    public HIDDeviceManager(Context context) {
    1.38 +    private HIDDeviceManager(Context context) {
    1.39          mContext = context;
    1.40  
    1.41          // Make sure we have the HIDAPI library loaded with the native functions
    1.42 @@ -88,7 +109,7 @@
    1.43              return;
    1.44          }
    1.45  
    1.46 -        HIDDeviceRegisterCallback(this);
    1.47 +        HIDDeviceRegisterCallback();
    1.48  
    1.49          mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE);
    1.50          mIsChromebook = mContext.getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
    1.51 @@ -125,7 +146,7 @@
    1.52          return result;
    1.53      }
    1.54  
    1.55 -    protected void initializeUSB() {
    1.56 +    private void initializeUSB() {
    1.57          mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
    1.58  
    1.59          /*
    1.60 @@ -187,7 +208,7 @@
    1.61          return mUsbManager;
    1.62      }
    1.63  
    1.64 -    protected void shutdownUSB() {
    1.65 +    private void shutdownUSB() {
    1.66          try {
    1.67              mContext.unregisterReceiver(mUsbBroadcast);
    1.68          } catch (Exception e) {
    1.69 @@ -195,7 +216,7 @@
    1.70          }
    1.71      }
    1.72  
    1.73 -    protected boolean isHIDDeviceUSB(UsbDevice usbDevice) {
    1.74 +    private boolean isHIDDeviceUSB(UsbDevice usbDevice) {
    1.75          for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); ++interface_number) {
    1.76              if (isHIDDeviceInterface(usbDevice, interface_number)) {
    1.77                  return true;
    1.78 @@ -204,7 +225,7 @@
    1.79          return false;
    1.80      }
    1.81  
    1.82 -    protected boolean isHIDDeviceInterface(UsbDevice usbDevice, int interface_number) {
    1.83 +    private boolean isHIDDeviceInterface(UsbDevice usbDevice, int interface_number) {
    1.84          UsbInterface usbInterface = usbDevice.getInterface(interface_number);
    1.85          if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID) {
    1.86              return true;
    1.87 @@ -217,7 +238,7 @@
    1.88          return false;
    1.89      }
    1.90  
    1.91 -    protected boolean isXbox360Controller(UsbDevice usbDevice, UsbInterface usbInterface) {
    1.92 +    private boolean isXbox360Controller(UsbDevice usbDevice, UsbInterface usbInterface) {
    1.93          final int XB360_IFACE_SUBCLASS = 93;
    1.94          final int XB360_IFACE_PROTOCOL = 1; // Wired only
    1.95          final int[] SUPPORTED_VENDORS = {
    1.96 @@ -256,7 +277,7 @@
    1.97          return false;
    1.98      }
    1.99  
   1.100 -    protected boolean isXboxOneController(UsbDevice usbDevice, UsbInterface usbInterface) {
   1.101 +    private boolean isXboxOneController(UsbDevice usbDevice, UsbInterface usbInterface) {
   1.102          final int XB1_IFACE_SUBCLASS = 71;
   1.103          final int XB1_IFACE_PROTOCOL = 208;
   1.104          final int[] SUPPORTED_VENDORS = {
   1.105 @@ -281,13 +302,13 @@
   1.106          return false;
   1.107      }
   1.108  
   1.109 -    protected void handleUsbDeviceAttached(UsbDevice usbDevice) {
   1.110 +    private void handleUsbDeviceAttached(UsbDevice usbDevice) {
   1.111          if (isHIDDeviceUSB(usbDevice)) {
   1.112              connectHIDDeviceUSB(usbDevice);
   1.113          }
   1.114      }
   1.115  
   1.116 -    protected void handleUsbDeviceDetached(UsbDevice usbDevice) {
   1.117 +    private void handleUsbDeviceDetached(UsbDevice usbDevice) {
   1.118          HIDDeviceUSB device = mUSBDevices.get(usbDevice);
   1.119          if (device == null)
   1.120              return;
   1.121 @@ -299,7 +320,7 @@
   1.122          HIDDeviceDisconnected(id);
   1.123      }
   1.124  
   1.125 -    protected void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) {
   1.126 +    private void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) {
   1.127          HIDDeviceUSB device = mUSBDevices.get(usbDevice);
   1.128          if (device == null)
   1.129              return;
   1.130 @@ -311,7 +332,7 @@
   1.131          HIDDeviceOpenResult(device.getId(), opened);
   1.132      }
   1.133  
   1.134 -    protected void connectHIDDeviceUSB(UsbDevice usbDevice) {
   1.135 +    private void connectHIDDeviceUSB(UsbDevice usbDevice) {
   1.136          synchronized (this) {
   1.137              for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); interface_number++) {
   1.138                  if (isHIDDeviceInterface(usbDevice, interface_number)) {
   1.139 @@ -326,7 +347,7 @@
   1.140          }
   1.141      }
   1.142  
   1.143 -    protected void initializeBluetooth() {
   1.144 +    private void initializeBluetooth() {
   1.145          Log.d(TAG, "Initializing Bluetooth");
   1.146  
   1.147          if (mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
   1.148 @@ -377,7 +398,7 @@
   1.149          }
   1.150      }
   1.151  
   1.152 -    protected void shutdownBluetooth() {
   1.153 +    private void shutdownBluetooth() {
   1.154          try {
   1.155              mContext.unregisterReceiver(mBluetoothBroadcast);
   1.156          } catch (Exception e) {
   1.157 @@ -476,7 +497,7 @@
   1.158          return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0);
   1.159      }
   1.160  
   1.161 -    public void close() {
   1.162 +    private void close() {
   1.163          shutdownUSB();
   1.164          shutdownBluetooth();
   1.165          synchronized (this) {
   1.166 @@ -623,7 +644,7 @@
   1.167      /////////////// Native methods
   1.168      //////////////////////////////////////////////////////////////////////////////////////////////////////
   1.169  
   1.170 -    private native void HIDDeviceRegisterCallback(Object callbackHandler);
   1.171 +    private native void HIDDeviceRegisterCallback();
   1.172      private native void HIDDeviceReleaseCallback();
   1.173  
   1.174      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);
     2.1 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java	Mon Oct 08 12:49:28 2018 -0700
     2.2 +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java	Mon Oct 08 12:49:30 2018 -0700
     2.3 @@ -250,7 +250,7 @@
     2.4              mClipboardHandler = new SDLClipboardHandler_Old();
     2.5          }
     2.6  
     2.7 -        mHIDDeviceManager = new HIDDeviceManager(this);
     2.8 +        mHIDDeviceManager = HIDDeviceManager.acquire(this);
     2.9  
    2.10          // Set up the surface
    2.11          mSurface = new SDLSurface(getApplication());
    2.12 @@ -380,7 +380,7 @@
    2.13          Log.v(TAG, "onDestroy()");
    2.14  
    2.15          if (mHIDDeviceManager != null) {
    2.16 -            mHIDDeviceManager.close();
    2.17 +            HIDDeviceManager.release(mHIDDeviceManager);
    2.18              mHIDDeviceManager = null;
    2.19          }
    2.20  
     3.1 --- a/src/hidapi/android/hid.cpp	Mon Oct 08 12:49:28 2018 -0700
     3.2 +++ b/src/hidapi/android/hid.cpp	Mon Oct 08 12:49:30 2018 -0700
     3.3 @@ -696,7 +696,7 @@
     3.4  
     3.5  
     3.6  extern "C"
     3.7 -JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz, jobject callbackHandler);
     3.8 +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz);
     3.9  
    3.10  extern "C"
    3.11  JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz);
    3.12 @@ -721,7 +721,7 @@
    3.13  
    3.14  
    3.15  extern "C"
    3.16 -JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz, jobject callbackHandler)
    3.17 +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz )
    3.18  {
    3.19  	LOGV( "HIDDeviceRegisterCallback()");
    3.20  
    3.21 @@ -735,11 +735,19 @@
    3.22  		__android_log_print(ANDROID_LOG_ERROR, TAG, "Error initializing pthread key");
    3.23  	}
    3.24  
    3.25 -	g_HIDDeviceManagerCallbackHandler = env->NewGlobalRef( callbackHandler );
    3.26 -	jclass objClass = env->GetObjectClass( callbackHandler );
    3.27 +	if ( g_HIDDeviceManagerCallbackHandler != NULL )
    3.28 +	{
    3.29 +		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass );
    3.30 +		g_HIDDeviceManagerCallbackClass = NULL;
    3.31 +		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler );
    3.32 +		g_HIDDeviceManagerCallbackHandler = NULL;
    3.33 +	}
    3.34 +
    3.35 +	g_HIDDeviceManagerCallbackHandler = env->NewGlobalRef( thiz );
    3.36 +	jclass objClass = env->GetObjectClass( thiz );
    3.37  	if ( objClass )
    3.38  	{
    3.39 -		g_HIDDeviceManagerCallbackClass = reinterpret_cast< jclass >( env->NewGlobalRef(objClass) );
    3.40 +		g_HIDDeviceManagerCallbackClass = reinterpret_cast< jclass >( env->NewGlobalRef( objClass ) );
    3.41  		g_midHIDDeviceManagerOpen = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "openDevice", "(I)Z" );
    3.42  		if ( !g_midHIDDeviceManagerOpen )
    3.43  		{
    3.44 @@ -773,8 +781,13 @@
    3.45  JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz)
    3.46  {
    3.47  	LOGV("HIDDeviceReleaseCallback");
    3.48 -	env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass );
    3.49 -	env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler );
    3.50 +	if ( env->IsSameObject( thiz, g_HIDDeviceManagerCallbackHandler ) )
    3.51 +	{
    3.52 +		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass );
    3.53 +		g_HIDDeviceManagerCallbackClass = NULL;
    3.54 +		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler );
    3.55 +		g_HIDDeviceManagerCallbackHandler = NULL;
    3.56 +	}
    3.57  }
    3.58  
    3.59  extern "C"