changed build system for Android from Ant to Gradle
[rocksndiamonds.git] / build-projects / android / app / src / main / java / org / libsdl / app / HIDDeviceUSB.java
diff --git a/build-projects/android/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java b/build-projects/android/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
new file mode 100644 (file)
index 0000000..33816e3
--- /dev/null
@@ -0,0 +1,304 @@
+package org.libsdl.app;
+
+import android.hardware.usb.*;
+import android.os.Build;
+import android.util.Log;
+import java.util.Arrays;
+
+class HIDDeviceUSB implements HIDDevice {
+
+    private static final String TAG = "hidapi";
+
+    protected HIDDeviceManager mManager;
+    protected UsbDevice mDevice;
+    protected int mInterfaceIndex;
+    protected int mInterface;
+    protected int mDeviceId;
+    protected UsbDeviceConnection mConnection;
+    protected UsbEndpoint mInputEndpoint;
+    protected UsbEndpoint mOutputEndpoint;
+    protected InputThread mInputThread;
+    protected boolean mRunning;
+    protected boolean mFrozen;
+
+    public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_index) {
+        mManager = manager;
+        mDevice = usbDevice;
+        mInterfaceIndex = interface_index;
+        mInterface = mDevice.getInterface(mInterfaceIndex).getId();
+        mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
+        mRunning = false;
+    }
+
+    public String getIdentifier() {
+        return String.format("%s/%x/%x/%d", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId(), mInterfaceIndex);
+    }
+
+    @Override
+    public int getId() {
+        return mDeviceId;
+    }
+
+    @Override
+    public int getVendorId() {
+        return mDevice.getVendorId();
+    }
+
+    @Override
+    public int getProductId() {
+        return mDevice.getProductId();
+    }
+
+    @Override
+    public String getSerialNumber() {
+        String result = null;
+        if (Build.VERSION.SDK_INT >= 21) {
+            result = mDevice.getSerialNumber();
+        }
+        if (result == null) {
+            result = "";
+        }
+        return result;
+    }
+
+    @Override
+    public int getVersion() {
+        return 0;
+    }
+
+    @Override
+    public String getManufacturerName() {
+        String result = null;
+        if (Build.VERSION.SDK_INT >= 21) {
+            result = mDevice.getManufacturerName();
+        }
+        if (result == null) {
+            result = String.format("%x", getVendorId());
+        }
+        return result;
+    }
+
+    @Override
+    public String getProductName() {
+        String result = null;
+        if (Build.VERSION.SDK_INT >= 21) {
+            result = mDevice.getProductName();
+        }
+        if (result == null) {
+            result = String.format("%x", getProductId());
+        }
+        return result;
+    }
+
+    @Override
+    public UsbDevice getDevice() {
+        return mDevice;
+    }
+
+    public String getDeviceName() {
+        return getManufacturerName() + " " + getProductName() + "(0x" + String.format("%x", getVendorId()) + "/0x" + String.format("%x", getProductId()) + ")";
+    }
+
+    @Override
+    public boolean open() {
+        mConnection = mManager.getUSBManager().openDevice(mDevice);
+        if (mConnection == null) {
+            Log.w(TAG, "Unable to open USB device " + getDeviceName());
+            return false;
+        }
+
+        // Force claim our interface
+        UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
+        if (!mConnection.claimInterface(iface, true)) {
+            Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
+            close();
+            return false;
+        }
+
+        // Find the endpoints
+        for (int j = 0; j < iface.getEndpointCount(); j++) {
+            UsbEndpoint endpt = iface.getEndpoint(j);
+            switch (endpt.getDirection()) {
+            case UsbConstants.USB_DIR_IN:
+                if (mInputEndpoint == null) {
+                    mInputEndpoint = endpt;
+                }
+                break;
+            case UsbConstants.USB_DIR_OUT:
+                if (mOutputEndpoint == null) {
+                    mOutputEndpoint = endpt;
+                }
+                break;
+            }
+        }
+
+        // Make sure the required endpoints were present
+        if (mInputEndpoint == null || mOutputEndpoint == null) {
+            Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
+            close();
+            return false;
+        }
+
+        // Start listening for input
+        mRunning = true;
+        mInputThread = new InputThread();
+        mInputThread.start();
+
+        return true;
+    }
+
+    @Override
+    public int sendFeatureReport(byte[] report) {
+        int res = -1;
+        int offset = 0;
+        int length = report.length;
+        boolean skipped_report_id = false;
+        byte report_number = report[0];
+
+        if (report_number == 0x0) {
+            ++offset;
+            --length;
+            skipped_report_id = true;
+        }
+
+        res = mConnection.controlTransfer(
+            UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_OUT,
+            0x09/*HID set_report*/,
+            (3/*HID feature*/ << 8) | report_number,
+            mInterface,
+            report, offset, length,
+            1000/*timeout millis*/);
+
+        if (res < 0) {
+            Log.w(TAG, "sendFeatureReport() returned " + res + " on device " + getDeviceName());
+            return -1;
+        }
+
+        if (skipped_report_id) {
+            ++length;
+        }
+        return length;
+    }
+
+    @Override
+    public int sendOutputReport(byte[] report) {
+        int r = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
+        if (r != report.length) {
+            Log.w(TAG, "sendOutputReport() returned " + r + " on device " + getDeviceName());
+        }
+        return r;
+    }
+
+    @Override
+    public boolean getFeatureReport(byte[] report) {
+        int res = -1;
+        int offset = 0;
+        int length = report.length;
+        boolean skipped_report_id = false;
+        byte report_number = report[0];
+
+        if (report_number == 0x0) {
+            /* Offset the return buffer by 1, so that the report ID
+               will remain in byte 0. */
+            ++offset;
+            --length;
+            skipped_report_id = true;
+        }
+
+        res = mConnection.controlTransfer(
+            UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_IN,
+            0x01/*HID get_report*/,
+            (3/*HID feature*/ << 8) | report_number,
+            mInterface,
+            report, offset, length,
+            1000/*timeout millis*/);
+
+        if (res < 0) {
+            Log.w(TAG, "getFeatureReport() returned " + res + " on device " + getDeviceName());
+            return false;
+        }
+
+        if (skipped_report_id) {
+            ++res;
+            ++length;
+        }
+
+        byte[] data;
+        if (res == length) {
+            data = report;
+        } else {
+            data = Arrays.copyOfRange(report, 0, res);
+        }
+        mManager.HIDDeviceFeatureReport(mDeviceId, data);
+
+        return true;
+    }
+
+    @Override
+    public void close() {
+        mRunning = false;
+        if (mInputThread != null) {
+            while (mInputThread.isAlive()) {
+                mInputThread.interrupt();
+                try {
+                    mInputThread.join();
+                } catch (InterruptedException e) {
+                    // Keep trying until we're done
+                }
+            }
+            mInputThread = null;
+        }
+        if (mConnection != null) {
+            UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
+            mConnection.releaseInterface(iface);
+            mConnection.close();
+            mConnection = null;
+        }
+    }
+
+    @Override
+    public void shutdown() {
+        close();
+        mManager = null;
+    }
+
+    @Override
+    public void setFrozen(boolean frozen) {
+        mFrozen = frozen;
+    }
+
+    protected class InputThread extends Thread {
+        @Override
+        public void run() {
+            int packetSize = mInputEndpoint.getMaxPacketSize();
+            byte[] packet = new byte[packetSize];
+            while (mRunning) {
+                int r;
+                try
+                {
+                    r = mConnection.bulkTransfer(mInputEndpoint, packet, packetSize, 1000);
+                }
+                catch (Exception e)
+                {
+                    Log.v(TAG, "Exception in UsbDeviceConnection bulktransfer: " + e);
+                    break;
+                }
+                if (r < 0) {
+                    // Could be a timeout or an I/O error
+                }
+                if (r > 0) {
+                    byte[] data;
+                    if (r == packetSize) {
+                        data = packet;
+                    } else {
+                        data = Arrays.copyOfRange(packet, 0, r);
+                    }
+
+                    if (!mFrozen) {
+                        mManager.HIDDeviceInputReport(mDeviceId, data);
+                    }
+                }
+            }
+        }
+    }
+}