Skip to content

Commit

Permalink
Added support for claiming individiual interfaces on USB devices on A…
Browse files Browse the repository at this point in the history
…ndroid

This is needed for supporting multiple wireless Xbox 360 controllers
  • Loading branch information
slouken committed Jan 13, 2020
1 parent acbf259 commit 1d32185
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 61 deletions.
@@ -1,5 +1,7 @@
package org.libsdl.app;

import android.hardware.usb.UsbDevice;

interface HIDDevice
{
public int getId();
Expand All @@ -9,6 +11,7 @@ interface HIDDevice
public int getVersion();
public String getManufacturerName();
public String getProductName();
public UsbDevice getDevice();
public boolean open();
public int sendFeatureReport(byte[] report);
public int sendOutputReport(byte[] report);
Expand Down
Expand Up @@ -9,6 +9,7 @@
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothGattService;
import android.hardware.usb.UsbDevice;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
Expand Down Expand Up @@ -563,6 +564,11 @@ public String getProductName() {
return "Steam Controller";
}

@Override
public UsbDevice getDevice() {
return null;
}

@Override
public boolean open() {
return true;
Expand Down
Expand Up @@ -19,8 +19,9 @@
import android.os.Handler;
import android.os.Looper;

import java.util.HashMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

public class HIDDeviceManager {
Expand Down Expand Up @@ -50,7 +51,6 @@ public static void release(HIDDeviceManager manager) {

private Context mContext;
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 int mNextDeviceId = 0;
private SharedPreferences mSharedPreferences = null;
Expand Down Expand Up @@ -337,27 +337,30 @@ private void handleUsbDeviceAttached(UsbDevice usbDevice) {
}

private void handleUsbDeviceDetached(UsbDevice usbDevice) {
HIDDeviceUSB device = mUSBDevices.get(usbDevice);
if (device == null)
return;

int id = device.getId();
mUSBDevices.remove(usbDevice);
mDevicesById.remove(id);
device.shutdown();
HIDDeviceDisconnected(id);
List<Integer> devices = new ArrayList<Integer>();
for (HIDDevice device : mDevicesById.values()) {
if (usbDevice.equals(device.getDevice())) {
devices.add(device.getId());
}
}
for (int id : devices) {
HIDDevice device = mDevicesById.get(id);
mDevicesById.remove(id);
device.shutdown();
HIDDeviceDisconnected(id);
}
}

private void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) {
HIDDeviceUSB device = mUSBDevices.get(usbDevice);
if (device == null)
return;

boolean opened = false;
if (permission_granted) {
opened = device.open();
for (HIDDevice device : mDevicesById.values()) {
if (usbDevice.equals(device.getDevice())) {
boolean opened = false;
if (permission_granted) {
opened = device.open();
}
HIDDeviceOpenResult(device.getId(), opened);
}
}
HIDDeviceOpenResult(device.getId(), opened);
}

private void connectHIDDeviceUSB(UsbDevice usbDevice) {
Expand All @@ -366,10 +369,8 @@ private void connectHIDDeviceUSB(UsbDevice usbDevice) {
if (isHIDDeviceInterface(usbDevice, interface_number)) {
HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_number);
int id = device.getId();
mUSBDevices.put(usbDevice, device);
mDevicesById.put(id, device);
HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), interface_number);
break;
}
}
}
Expand Down Expand Up @@ -566,33 +567,27 @@ private HIDDevice getDevice(int id) {
//////////////////////////////////////////////////////////////////////////////////////////////////////

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
for (HIDDeviceUSB device : mUSBDevices.values()) {
if (deviceID == device.getId()) {
UsbDevice usbDevice = device.getDevice();
if (!mUsbManager.hasPermission(usbDevice)) {
HIDDeviceOpenPending(deviceID);
try {
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), 0));
} catch (Exception e) {
Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
HIDDeviceOpenResult(deviceID, false);
}
return false;
}
break;
UsbDevice usbDevice = device.getDevice();
if (usbDevice != null && !mUsbManager.hasPermission(usbDevice)) {
HIDDeviceOpenPending(deviceID);
try {
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), 0));
} catch (Exception e) {
Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
HIDDeviceOpenResult(deviceID, false);
}
return false;
}

try {
Log.v(TAG, "openDevice deviceID=" + deviceID);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return false;
}

return device.open();
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
Expand All @@ -602,7 +597,7 @@ public boolean openDevice(int deviceID) {

public int sendOutputReport(int deviceID, byte[] report) {
try {
Log.v(TAG, "sendOutputReport deviceID=" + deviceID + " length=" + report.length);
//Log.v(TAG, "sendOutputReport deviceID=" + deviceID + " length=" + report.length);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
Expand All @@ -619,7 +614,7 @@ public int sendOutputReport(int deviceID, byte[] report) {

public int sendFeatureReport(int deviceID, byte[] report) {
try {
Log.v(TAG, "sendFeatureReport deviceID=" + deviceID + " length=" + report.length);
//Log.v(TAG, "sendFeatureReport deviceID=" + deviceID + " length=" + report.length);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
Expand All @@ -636,7 +631,7 @@ public int sendFeatureReport(int deviceID, byte[] report) {

public boolean getFeatureReport(int deviceID, byte[] report) {
try {
Log.v(TAG, "getFeatureReport deviceID=" + deviceID);
//Log.v(TAG, "getFeatureReport deviceID=" + deviceID);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
Expand Down
25 changes: 10 additions & 15 deletions android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
Expand Up @@ -29,7 +29,7 @@ public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface
}

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
Expand Down Expand Up @@ -88,6 +88,7 @@ public String getProductName() {
return result;
}

@Override
public UsbDevice getDevice() {
return mDevice;
}
Expand All @@ -104,19 +105,15 @@ public boolean open() {
return false;
}

// Force claim all interfaces
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
UsbInterface iface = mDevice.getInterface(i);

if (!mConnection.claimInterface(iface, true)) {
Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
close();
return false;
}
// Force claim our interface
UsbInterface iface = mDevice.getInterface(mInterface);
if (!mConnection.claimInterface(iface, true)) {
Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
close();
return false;
}

// Find the endpoints
UsbInterface iface = mDevice.getInterface(mInterface);
for (int j = 0; j < iface.getEndpointCount(); j++) {
UsbEndpoint endpt = iface.getEndpoint(j);
switch (endpt.getDirection()) {
Expand Down Expand Up @@ -250,10 +247,8 @@ public void close() {
mInputThread = null;
}
if (mConnection != null) {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
UsbInterface iface = mDevice.getInterface(i);
mConnection.releaseInterface(iface);
}
UsbInterface iface = mDevice.getInterface(mInterface);
mConnection.releaseInterface(iface);
mConnection.close();
mConnection = null;
}
Expand Down

0 comments on commit 1d32185

Please sign in to comment.