Added support for claiming individiual interfaces on USB devices on Android

This is needed for supporting multiple wireless Xbox 360 controllers
This commit is contained in:
Sam Lantinga 2020-01-13 15:35:52 -08:00
parent acbf25935e
commit 1d321850b6
4 changed files with 60 additions and 61 deletions

View File

@ -1,5 +1,7 @@
package org.libsdl.app; package org.libsdl.app;
import android.hardware.usb.UsbDevice;
interface HIDDevice interface HIDDevice
{ {
public int getId(); public int getId();
@ -9,6 +11,7 @@ interface HIDDevice
public int getVersion(); public int getVersion();
public String getManufacturerName(); public String getManufacturerName();
public String getProductName(); public String getProductName();
public UsbDevice getDevice();
public boolean open(); public boolean open();
public int sendFeatureReport(byte[] report); public int sendFeatureReport(byte[] report);
public int sendOutputReport(byte[] report); public int sendOutputReport(byte[] report);

View File

@ -9,6 +9,7 @@ import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothGattService;
import android.hardware.usb.UsbDevice;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Log; import android.util.Log;
@ -564,6 +565,11 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
} }
@Override @Override
public UsbDevice getDevice() {
return null;
}
@Override
public boolean open() { public boolean open() {
return true; return true;
} }

View File

@ -19,8 +19,9 @@ import android.hardware.usb.*;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import java.util.HashMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
public class HIDDeviceManager { public class HIDDeviceManager {
@ -50,7 +51,6 @@ public class HIDDeviceManager {
private Context mContext; 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<BluetoothDevice, HIDDeviceBLESteamController> mBluetoothDevices = new HashMap<BluetoothDevice, HIDDeviceBLESteamController>(); private HashMap<BluetoothDevice, HIDDeviceBLESteamController> mBluetoothDevices = new HashMap<BluetoothDevice, HIDDeviceBLESteamController>();
private int mNextDeviceId = 0; private int mNextDeviceId = 0;
private SharedPreferences mSharedPreferences = null; private SharedPreferences mSharedPreferences = null;
@ -337,28 +337,31 @@ public class HIDDeviceManager {
} }
private void handleUsbDeviceDetached(UsbDevice usbDevice) { private void handleUsbDeviceDetached(UsbDevice usbDevice) {
HIDDeviceUSB device = mUSBDevices.get(usbDevice); List<Integer> devices = new ArrayList<Integer>();
if (device == null) for (HIDDevice device : mDevicesById.values()) {
return; if (usbDevice.equals(device.getDevice())) {
devices.add(device.getId());
int id = device.getId(); }
mUSBDevices.remove(usbDevice); }
for (int id : devices) {
HIDDevice device = mDevicesById.get(id);
mDevicesById.remove(id); mDevicesById.remove(id);
device.shutdown(); device.shutdown();
HIDDeviceDisconnected(id); HIDDeviceDisconnected(id);
} }
}
private void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) { private void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) {
HIDDeviceUSB device = mUSBDevices.get(usbDevice); for (HIDDevice device : mDevicesById.values()) {
if (device == null) if (usbDevice.equals(device.getDevice())) {
return;
boolean opened = false; boolean opened = false;
if (permission_granted) { if (permission_granted) {
opened = device.open(); opened = device.open();
} }
HIDDeviceOpenResult(device.getId(), opened); HIDDeviceOpenResult(device.getId(), opened);
} }
}
}
private void connectHIDDeviceUSB(UsbDevice usbDevice) { private void connectHIDDeviceUSB(UsbDevice usbDevice) {
synchronized (this) { synchronized (this) {
@ -366,10 +369,8 @@ public class HIDDeviceManager {
if (isHIDDeviceInterface(usbDevice, interface_number)) { if (isHIDDeviceInterface(usbDevice, interface_number)) {
HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_number); HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_number);
int id = device.getId(); int id = device.getId();
mUSBDevices.put(usbDevice, device);
mDevicesById.put(id, device); mDevicesById.put(id, device);
HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), interface_number); HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), interface_number);
break;
} }
} }
} }
@ -566,11 +567,16 @@ public class HIDDeviceManager {
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
public boolean openDevice(int deviceID) { public boolean openDevice(int deviceID) {
Log.v(TAG, "openDevice deviceID=" + deviceID);
HIDDevice device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return false;
}
// Look to see if this is a USB device and we have permission to access it // Look to see if this is a USB device and we have permission to access it
for (HIDDeviceUSB device : mUSBDevices.values()) {
if (deviceID == device.getId()) {
UsbDevice usbDevice = device.getDevice(); UsbDevice usbDevice = device.getDevice();
if (!mUsbManager.hasPermission(usbDevice)) { if (usbDevice != null && !mUsbManager.hasPermission(usbDevice)) {
HIDDeviceOpenPending(deviceID); HIDDeviceOpenPending(deviceID);
try { try {
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), 0)); mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), 0));
@ -580,19 +586,8 @@ public class HIDDeviceManager {
} }
return false; return false;
} }
break;
}
}
try { try {
Log.v(TAG, "openDevice deviceID=" + deviceID);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return false;
}
return device.open(); return device.open();
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e)); Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
@ -602,7 +597,7 @@ public class HIDDeviceManager {
public int sendOutputReport(int deviceID, byte[] report) { public int sendOutputReport(int deviceID, byte[] report) {
try { try {
Log.v(TAG, "sendOutputReport deviceID=" + deviceID + " length=" + report.length); //Log.v(TAG, "sendOutputReport deviceID=" + deviceID + " length=" + report.length);
HIDDevice device; HIDDevice device;
device = getDevice(deviceID); device = getDevice(deviceID);
if (device == null) { if (device == null) {
@ -619,7 +614,7 @@ public class HIDDeviceManager {
public int sendFeatureReport(int deviceID, byte[] report) { public int sendFeatureReport(int deviceID, byte[] report) {
try { try {
Log.v(TAG, "sendFeatureReport deviceID=" + deviceID + " length=" + report.length); //Log.v(TAG, "sendFeatureReport deviceID=" + deviceID + " length=" + report.length);
HIDDevice device; HIDDevice device;
device = getDevice(deviceID); device = getDevice(deviceID);
if (device == null) { if (device == null) {
@ -636,7 +631,7 @@ public class HIDDeviceManager {
public boolean getFeatureReport(int deviceID, byte[] report) { public boolean getFeatureReport(int deviceID, byte[] report) {
try { try {
Log.v(TAG, "getFeatureReport deviceID=" + deviceID); //Log.v(TAG, "getFeatureReport deviceID=" + deviceID);
HIDDevice device; HIDDevice device;
device = getDevice(deviceID); device = getDevice(deviceID);
if (device == null) { if (device == null) {

View File

@ -29,7 +29,7 @@ class HIDDeviceUSB implements HIDDevice {
} }
public String getIdentifier() { public String getIdentifier() {
return String.format("%s/%x/%x", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId()); return String.format("%s/%x/%x/%d", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId(), mInterface);
} }
@Override @Override
@ -88,6 +88,7 @@ class HIDDeviceUSB implements HIDDevice {
return result; return result;
} }
@Override
public UsbDevice getDevice() { public UsbDevice getDevice() {
return mDevice; return mDevice;
} }
@ -104,19 +105,15 @@ class HIDDeviceUSB implements HIDDevice {
return false; return false;
} }
// Force claim all interfaces // Force claim our interface
for (int i = 0; i < mDevice.getInterfaceCount(); i++) { UsbInterface iface = mDevice.getInterface(mInterface);
UsbInterface iface = mDevice.getInterface(i);
if (!mConnection.claimInterface(iface, true)) { if (!mConnection.claimInterface(iface, true)) {
Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName()); Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
close(); close();
return false; return false;
} }
}
// Find the endpoints // Find the endpoints
UsbInterface iface = mDevice.getInterface(mInterface);
for (int j = 0; j < iface.getEndpointCount(); j++) { for (int j = 0; j < iface.getEndpointCount(); j++) {
UsbEndpoint endpt = iface.getEndpoint(j); UsbEndpoint endpt = iface.getEndpoint(j);
switch (endpt.getDirection()) { switch (endpt.getDirection()) {
@ -250,10 +247,8 @@ class HIDDeviceUSB implements HIDDevice {
mInputThread = null; mInputThread = null;
} }
if (mConnection != null) { if (mConnection != null) {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) { UsbInterface iface = mDevice.getInterface(mInterface);
UsbInterface iface = mDevice.getInterface(i);
mConnection.releaseInterface(iface); mConnection.releaseInterface(iface);
}
mConnection.close(); mConnection.close();
mConnection = null; mConnection = null;
} }