HIDDeviceManager.java 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. package org.libsdl.app;
  2. import android.app.PendingIntent;
  3. import android.bluetooth.BluetoothAdapter;
  4. import android.bluetooth.BluetoothDevice;
  5. import android.bluetooth.BluetoothManager;
  6. import android.bluetooth.BluetoothProfile;
  7. import android.util.Log;
  8. import android.content.BroadcastReceiver;
  9. import android.content.Context;
  10. import android.content.Intent;
  11. import android.content.IntentFilter;
  12. import android.content.SharedPreferences;
  13. import android.content.pm.PackageManager;
  14. import android.hardware.usb.*;
  15. import android.os.Handler;
  16. import android.os.Looper;
  17. import java.util.HashMap;
  18. import java.util.ArrayList;
  19. import java.util.List;
  20. public class HIDDeviceManager {
  21. private static final String TAG = "hidapi";
  22. private static final String ACTION_USB_PERMISSION = "org.libsdl.app.USB_PERMISSION";
  23. protected Context mContext;
  24. private HashMap<Integer, HIDDevice> mDevicesById = new HashMap<Integer, HIDDevice>();
  25. private HashMap<UsbDevice, HIDDeviceUSB> mUSBDevices = new HashMap<UsbDevice, HIDDeviceUSB>();
  26. private HashMap<BluetoothDevice, HIDDeviceBLESteamController> mBluetoothDevices = new HashMap<BluetoothDevice, HIDDeviceBLESteamController>();
  27. private int mNextDeviceId = 0;
  28. private SharedPreferences mSharedPreferences = null;
  29. private boolean mIsChromebook = false;
  30. private UsbManager mUsbManager;
  31. private Handler mHandler;
  32. private BluetoothManager mBluetoothManager;
  33. private List<BluetoothDevice> mLastBluetoothDevices;
  34. private final BroadcastReceiver mUsbBroadcast = new BroadcastReceiver() {
  35. @Override
  36. public void onReceive(Context context, Intent intent) {
  37. String action = intent.getAction();
  38. if (action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
  39. UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
  40. handleUsbDeviceAttached(usbDevice);
  41. } else if (action.equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
  42. UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
  43. handleUsbDeviceDetached(usbDevice);
  44. } else if (action.equals(HIDDeviceManager.ACTION_USB_PERMISSION)) {
  45. UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
  46. handleUsbDevicePermission(usbDevice, intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false));
  47. }
  48. }
  49. };
  50. private final BroadcastReceiver mBluetoothBroadcast = new BroadcastReceiver() {
  51. @Override
  52. public void onReceive(Context context, Intent intent) {
  53. String action = intent.getAction();
  54. // Bluetooth device was connected. If it was a Steam Controller, handle it
  55. if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
  56. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  57. Log.d(TAG, "Bluetooth device connected: " + device);
  58. if (isSteamController(device)) {
  59. connectBluetoothDevice(device);
  60. }
  61. }
  62. // Bluetooth device was disconnected, remove from controller manager (if any)
  63. if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
  64. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  65. Log.d(TAG, "Bluetooth device disconnected: " + device);
  66. disconnectBluetoothDevice(device);
  67. }
  68. }
  69. };
  70. public HIDDeviceManager(Context context) {
  71. mContext = context;
  72. HIDDeviceRegisterCallback(this);
  73. mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE);
  74. mIsChromebook = mContext.getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
  75. // if (shouldClear) {
  76. // SharedPreferences.Editor spedit = mSharedPreferences.edit();
  77. // spedit.clear();
  78. // spedit.commit();
  79. // }
  80. // else
  81. {
  82. mNextDeviceId = mSharedPreferences.getInt("next_device_id", 0);
  83. }
  84. initializeUSB();
  85. initializeBluetooth();
  86. }
  87. public Context getContext() {
  88. return mContext;
  89. }
  90. public int getDeviceIDForIdentifier(String identifier) {
  91. SharedPreferences.Editor spedit = mSharedPreferences.edit();
  92. int result = mSharedPreferences.getInt(identifier, 0);
  93. if (result == 0) {
  94. result = mNextDeviceId++;
  95. spedit.putInt("next_device_id", mNextDeviceId);
  96. }
  97. spedit.putInt(identifier, result);
  98. spedit.commit();
  99. return result;
  100. }
  101. protected void initializeUSB() {
  102. mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
  103. /*
  104. // Logging
  105. for (UsbDevice device : mUsbManager.getDeviceList().values()) {
  106. Log.i(TAG,"Path: " + device.getDeviceName());
  107. Log.i(TAG,"Manufacturer: " + device.getManufacturerName());
  108. Log.i(TAG,"Product: " + device.getProductName());
  109. Log.i(TAG,"ID: " + device.getDeviceId());
  110. Log.i(TAG,"Class: " + device.getDeviceClass());
  111. Log.i(TAG,"Protocol: " + device.getDeviceProtocol());
  112. Log.i(TAG,"Vendor ID " + device.getVendorId());
  113. Log.i(TAG,"Product ID: " + device.getProductId());
  114. Log.i(TAG,"Interface count: " + device.getInterfaceCount());
  115. Log.i(TAG,"---------------------------------------");
  116. // Get interface details
  117. for (int index = 0; index < device.getInterfaceCount(); index++) {
  118. UsbInterface mUsbInterface = device.getInterface(index);
  119. Log.i(TAG," ***** *****");
  120. Log.i(TAG," Interface index: " + index);
  121. Log.i(TAG," Interface ID: " + mUsbInterface.getId());
  122. Log.i(TAG," Interface class: " + mUsbInterface.getInterfaceClass());
  123. Log.i(TAG," Interface subclass: " + mUsbInterface.getInterfaceSubclass());
  124. Log.i(TAG," Interface protocol: " + mUsbInterface.getInterfaceProtocol());
  125. Log.i(TAG," Endpoint count: " + mUsbInterface.getEndpointCount());
  126. // Get endpoint details
  127. for (int epi = 0; epi < mUsbInterface.getEndpointCount(); epi++)
  128. {
  129. UsbEndpoint mEndpoint = mUsbInterface.getEndpoint(epi);
  130. Log.i(TAG," ++++ ++++ ++++");
  131. Log.i(TAG," Endpoint index: " + epi);
  132. Log.i(TAG," Attributes: " + mEndpoint.getAttributes());
  133. Log.i(TAG," Direction: " + mEndpoint.getDirection());
  134. Log.i(TAG," Number: " + mEndpoint.getEndpointNumber());
  135. Log.i(TAG," Interval: " + mEndpoint.getInterval());
  136. Log.i(TAG," Packet size: " + mEndpoint.getMaxPacketSize());
  137. Log.i(TAG," Type: " + mEndpoint.getType());
  138. }
  139. }
  140. }
  141. Log.i(TAG," No more devices connected.");
  142. */
  143. // Register for USB broadcasts and permission completions
  144. IntentFilter filter = new IntentFilter();
  145. filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
  146. filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
  147. filter.addAction(HIDDeviceManager.ACTION_USB_PERMISSION);
  148. mContext.registerReceiver(mUsbBroadcast, filter);
  149. for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
  150. handleUsbDeviceAttached(usbDevice);
  151. }
  152. }
  153. UsbManager getUSBManager() {
  154. return mUsbManager;
  155. }
  156. protected void shutdownUSB() {
  157. mContext.unregisterReceiver(mUsbBroadcast);
  158. }
  159. protected boolean isHIDDeviceUSB(UsbDevice usbDevice) {
  160. for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); ++interface_number) {
  161. if (isHIDDeviceInterface(usbDevice, interface_number)) {
  162. return true;
  163. }
  164. }
  165. return false;
  166. }
  167. protected boolean isHIDDeviceInterface(UsbDevice usbDevice, int interface_number) {
  168. UsbInterface usbInterface = usbDevice.getInterface(interface_number);
  169. if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID) {
  170. return true;
  171. }
  172. if (interface_number == 0) {
  173. if (isXbox360Controller(usbDevice, usbInterface) || isXboxOneController(usbDevice, usbInterface)) {
  174. return true;
  175. }
  176. }
  177. return false;
  178. }
  179. protected boolean isXbox360Controller(UsbDevice usbDevice, UsbInterface usbInterface) {
  180. final int XB360_IFACE_SUBCLASS = 93;
  181. final int XB360_IFACE_PROTOCOL = 1; // Wired only
  182. final int[] SUPPORTED_VENDORS = {
  183. 0x0079, // GPD Win 2
  184. 0x044f, // Thrustmaster
  185. 0x045e, // Microsoft
  186. 0x046d, // Logitech
  187. 0x056e, // Elecom
  188. 0x06a3, // Saitek
  189. 0x0738, // Mad Catz
  190. 0x07ff, // Mad Catz
  191. 0x0e6f, // Unknown
  192. 0x0f0d, // Hori
  193. 0x11c9, // Nacon
  194. 0x12ab, // Unknown
  195. 0x1430, // RedOctane
  196. 0x146b, // BigBen
  197. 0x1532, // Razer Sabertooth
  198. 0x15e4, // Numark
  199. 0x162e, // Joytech
  200. 0x1689, // Razer Onza
  201. 0x1bad, // Harmonix
  202. 0x24c6, // PowerA
  203. };
  204. if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
  205. usbInterface.getInterfaceSubclass() == XB360_IFACE_SUBCLASS &&
  206. usbInterface.getInterfaceProtocol() == XB360_IFACE_PROTOCOL) {
  207. int vendor_id = usbDevice.getVendorId();
  208. for (int supportedVid : SUPPORTED_VENDORS) {
  209. if (vendor_id == supportedVid) {
  210. return true;
  211. }
  212. }
  213. }
  214. return false;
  215. }
  216. protected boolean isXboxOneController(UsbDevice usbDevice, UsbInterface usbInterface) {
  217. final int XB1_IFACE_SUBCLASS = 71;
  218. final int XB1_IFACE_PROTOCOL = 208;
  219. final int[] SUPPORTED_VENDORS = {
  220. 0x045e, // Microsoft
  221. 0x0738, // Mad Catz
  222. 0x0e6f, // Unknown
  223. 0x0f0d, // Hori
  224. 0x1532, // Razer Wildcat
  225. 0x24c6, // PowerA
  226. };
  227. if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
  228. usbInterface.getInterfaceSubclass() == XB1_IFACE_SUBCLASS &&
  229. usbInterface.getInterfaceProtocol() == XB1_IFACE_PROTOCOL) {
  230. int vendor_id = usbDevice.getVendorId();
  231. for (int supportedVid : SUPPORTED_VENDORS) {
  232. if (vendor_id == supportedVid) {
  233. return true;
  234. }
  235. }
  236. }
  237. return false;
  238. }
  239. protected void handleUsbDeviceAttached(UsbDevice usbDevice) {
  240. if (isHIDDeviceUSB(usbDevice)) {
  241. connectHIDDeviceUSB(usbDevice);
  242. }
  243. }
  244. protected void handleUsbDeviceDetached(UsbDevice usbDevice) {
  245. HIDDeviceUSB device = mUSBDevices.get(usbDevice);
  246. if (device == null)
  247. return;
  248. int id = device.getId();
  249. mUSBDevices.remove(usbDevice);
  250. mDevicesById.remove(id);
  251. device.shutdown();
  252. HIDDeviceDisconnected(id);
  253. }
  254. protected void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) {
  255. HIDDeviceUSB device = mUSBDevices.get(usbDevice);
  256. if (device == null)
  257. return;
  258. boolean opened = false;
  259. if (permission_granted) {
  260. opened = device.open();
  261. }
  262. HIDDeviceOpenResult(device.getId(), opened);
  263. }
  264. protected void connectHIDDeviceUSB(UsbDevice usbDevice) {
  265. synchronized (this) {
  266. for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); interface_number++) {
  267. if (isHIDDeviceInterface(usbDevice, interface_number)) {
  268. HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_number);
  269. int id = device.getId();
  270. mUSBDevices.put(usbDevice, device);
  271. mDevicesById.put(id, device);
  272. HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), interface_number);
  273. break;
  274. }
  275. }
  276. }
  277. }
  278. protected void initializeBluetooth() {
  279. Log.d(TAG, "Initializing Bluetooth");
  280. if (mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
  281. Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH");
  282. return;
  283. }
  284. // Find bonded bluetooth controllers and create SteamControllers for them
  285. mBluetoothManager = (BluetoothManager)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
  286. if (mBluetoothManager == null) {
  287. // This device doesn't support Bluetooth.
  288. return;
  289. }
  290. BluetoothAdapter btAdapter = mBluetoothManager.getAdapter();
  291. if (btAdapter == null) {
  292. // This device has Bluetooth support in the codebase, but has no available adapters.
  293. return;
  294. }
  295. // Get our bonded devices.
  296. for (BluetoothDevice device : btAdapter.getBondedDevices()) {
  297. Log.d(TAG, "Bluetooth device available: " + device);
  298. if (isSteamController(device)) {
  299. connectBluetoothDevice(device);
  300. }
  301. }
  302. // NOTE: These don't work on Chromebooks, to my undying dismay.
  303. IntentFilter filter = new IntentFilter();
  304. filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
  305. filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
  306. mContext.registerReceiver(mBluetoothBroadcast, filter);
  307. if (mIsChromebook) {
  308. mHandler = new Handler(Looper.getMainLooper());
  309. mLastBluetoothDevices = new ArrayList<>();
  310. // final HIDDeviceManager finalThis = this;
  311. // mHandler.postDelayed(new Runnable() {
  312. // @Override
  313. // public void run() {
  314. // finalThis.chromebookConnectionHandler();
  315. // }
  316. // }, 5000);
  317. }
  318. }
  319. protected void shutdownBluetooth() {
  320. try {
  321. mContext.unregisterReceiver(mBluetoothBroadcast);
  322. } catch (Exception e) {
  323. // We may not have registered, that's okay
  324. }
  325. }
  326. // Chromebooks do not pass along ACTION_ACL_CONNECTED / ACTION_ACL_DISCONNECTED properly.
  327. // This function provides a sort of dummy version of that, watching for changes in the
  328. // connected devices and attempting to add controllers as things change.
  329. public void chromebookConnectionHandler() {
  330. if (!mIsChromebook) {
  331. return;
  332. }
  333. ArrayList<BluetoothDevice> disconnected = new ArrayList<>();
  334. ArrayList<BluetoothDevice> connected = new ArrayList<>();
  335. List<BluetoothDevice> currentConnected = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
  336. for (BluetoothDevice bluetoothDevice : currentConnected) {
  337. if (!mLastBluetoothDevices.contains(bluetoothDevice)) {
  338. connected.add(bluetoothDevice);
  339. }
  340. }
  341. for (BluetoothDevice bluetoothDevice : mLastBluetoothDevices) {
  342. if (!currentConnected.contains(bluetoothDevice)) {
  343. disconnected.add(bluetoothDevice);
  344. }
  345. }
  346. mLastBluetoothDevices = currentConnected;
  347. for (BluetoothDevice bluetoothDevice : disconnected) {
  348. disconnectBluetoothDevice(bluetoothDevice);
  349. }
  350. for (BluetoothDevice bluetoothDevice : connected) {
  351. connectBluetoothDevice(bluetoothDevice);
  352. }
  353. final HIDDeviceManager finalThis = this;
  354. mHandler.postDelayed(new Runnable() {
  355. @Override
  356. public void run() {
  357. finalThis.chromebookConnectionHandler();
  358. }
  359. }, 10000);
  360. }
  361. public boolean connectBluetoothDevice(BluetoothDevice bluetoothDevice) {
  362. Log.v(TAG, "connectBluetoothDevice device=" + bluetoothDevice);
  363. synchronized (this) {
  364. if (mBluetoothDevices.containsKey(bluetoothDevice)) {
  365. Log.v(TAG, "Steam controller with address " + bluetoothDevice + " already exists, attempting reconnect");
  366. HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
  367. device.reconnect();
  368. return false;
  369. }
  370. HIDDeviceBLESteamController device = new HIDDeviceBLESteamController(this, bluetoothDevice);
  371. int id = device.getId();
  372. mBluetoothDevices.put(bluetoothDevice, device);
  373. mDevicesById.put(id, device);
  374. // The Steam Controller will mark itself connected once initialization is complete
  375. }
  376. return true;
  377. }
  378. public void disconnectBluetoothDevice(BluetoothDevice bluetoothDevice) {
  379. synchronized (this) {
  380. HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
  381. if (device == null)
  382. return;
  383. int id = device.getId();
  384. mBluetoothDevices.remove(bluetoothDevice);
  385. mDevicesById.remove(id);
  386. device.shutdown();
  387. HIDDeviceDisconnected(id);
  388. }
  389. }
  390. public boolean isSteamController(BluetoothDevice bluetoothDevice) {
  391. // Sanity check. If you pass in a null device, by definition it is never a Steam Controller.
  392. if (bluetoothDevice == null) {
  393. return false;
  394. }
  395. // If the device has no local name, we really don't want to try an equality check against it.
  396. if (bluetoothDevice.getName() == null) {
  397. return false;
  398. }
  399. return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0);
  400. }
  401. public void close() {
  402. shutdownUSB();
  403. shutdownBluetooth();
  404. synchronized (this) {
  405. for (HIDDevice device : mDevicesById.values()) {
  406. device.shutdown();
  407. }
  408. mDevicesById.clear();
  409. mBluetoothDevices.clear();
  410. HIDDeviceReleaseCallback();
  411. }
  412. }
  413. public void setFrozen(boolean frozen) {
  414. synchronized (this) {
  415. for (HIDDevice device : mDevicesById.values()) {
  416. device.setFrozen(frozen);
  417. }
  418. }
  419. }
  420. //////////////////////////////////////////////////////////////////////////////////////////////////////
  421. //////////////////////////////////////////////////////////////////////////////////////////////////////
  422. //////////////////////////////////////////////////////////////////////////////////////////////////////
  423. private HIDDevice getDevice(int id) {
  424. synchronized (this) {
  425. HIDDevice result = mDevicesById.get(id);
  426. if (result == null) {
  427. Log.v(TAG, "No device for id: " + id);
  428. Log.v(TAG, "Available devices: " + mDevicesById.keySet());
  429. }
  430. return result;
  431. }
  432. }
  433. //////////////////////////////////////////////////////////////////////////////////////////////////////
  434. ////////// JNI interface functions
  435. //////////////////////////////////////////////////////////////////////////////////////////////////////
  436. boolean openDevice(int deviceID) {
  437. // Look to see if this is a USB device and we have permission to access it
  438. for (HIDDeviceUSB device : mUSBDevices.values()) {
  439. if (deviceID == device.getId()) {
  440. UsbDevice usbDevice = device.getDevice();
  441. if (!mUsbManager.hasPermission(usbDevice)) {
  442. HIDDeviceOpenPending(deviceID);
  443. try {
  444. mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), 0));
  445. } catch (Exception e) {
  446. Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
  447. HIDDeviceOpenResult(deviceID, false);
  448. }
  449. return false;
  450. }
  451. break;
  452. }
  453. }
  454. try {
  455. Log.v(TAG, "openDevice deviceID=" + deviceID);
  456. HIDDevice device;
  457. device = getDevice(deviceID);
  458. if (device == null) {
  459. HIDDeviceDisconnected(deviceID);
  460. return false;
  461. }
  462. return device.open();
  463. } catch (Exception e) {
  464. Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
  465. }
  466. return false;
  467. }
  468. int sendOutputReport(int deviceID, byte[] report) {
  469. try {
  470. Log.v(TAG, "sendOutputReport deviceID=" + deviceID + " length=" + report.length);
  471. HIDDevice device;
  472. device = getDevice(deviceID);
  473. if (device == null) {
  474. HIDDeviceDisconnected(deviceID);
  475. return -1;
  476. }
  477. return device.sendOutputReport(report);
  478. } catch (Exception e) {
  479. Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
  480. }
  481. return -1;
  482. }
  483. int sendFeatureReport(int deviceID, byte[] report) {
  484. try {
  485. Log.v(TAG, "sendFeatureReport deviceID=" + deviceID + " length=" + report.length);
  486. HIDDevice device;
  487. device = getDevice(deviceID);
  488. if (device == null) {
  489. HIDDeviceDisconnected(deviceID);
  490. return -1;
  491. }
  492. return device.sendFeatureReport(report);
  493. } catch (Exception e) {
  494. Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
  495. }
  496. return -1;
  497. }
  498. boolean getFeatureReport(int deviceID, byte[] report) {
  499. try {
  500. Log.v(TAG, "getFeatureReport deviceID=" + deviceID);
  501. HIDDevice device;
  502. device = getDevice(deviceID);
  503. if (device == null) {
  504. HIDDeviceDisconnected(deviceID);
  505. return false;
  506. }
  507. return device.getFeatureReport(report);
  508. } catch (Exception e) {
  509. Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
  510. }
  511. return false;
  512. }
  513. void closeDevice(int deviceID) {
  514. try {
  515. Log.v(TAG, "closeDevice deviceID=" + deviceID);
  516. HIDDevice device;
  517. device = getDevice(deviceID);
  518. if (device == null) {
  519. HIDDeviceDisconnected(deviceID);
  520. return;
  521. }
  522. device.close();
  523. } catch (Exception e) {
  524. Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
  525. }
  526. }
  527. //////////////////////////////////////////////////////////////////////////////////////////////////////
  528. /////////////// Native methods
  529. //////////////////////////////////////////////////////////////////////////////////////////////////////
  530. private native void HIDDeviceRegisterCallback(Object callbackHandler);
  531. private native void HIDDeviceReleaseCallback();
  532. 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);
  533. native void HIDDeviceOpenPending(int deviceID);
  534. native void HIDDeviceOpenResult(int deviceID, boolean opened);
  535. native void HIDDeviceDisconnected(int deviceID);
  536. native void HIDDeviceInputReport(int deviceID, byte[] report);
  537. native void HIDDeviceFeatureReport(int deviceID, byte[] report);
  538. }