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