summaryrefslogtreecommitdiff
path: root/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
diff options
context:
space:
mode:
Diffstat (limited to 'SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java')
-rw-r--r--SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java318
1 files changed, 318 insertions, 0 deletions
diff --git a/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java b/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
new file mode 100644
index 0000000..2741438
--- /dev/null
+++ b/SDL-3.2.8/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
@@ -0,0 +1,318 @@
1package org.libsdl.app;
2
3import android.hardware.usb.*;
4import android.os.Build;
5import android.util.Log;
6import java.util.Arrays;
7
8class HIDDeviceUSB implements HIDDevice {
9
10 private static final String TAG = "hidapi";
11
12 protected HIDDeviceManager mManager;
13 protected UsbDevice mDevice;
14 protected int mInterfaceIndex;
15 protected int mInterface;
16 protected int mDeviceId;
17 protected UsbDeviceConnection mConnection;
18 protected UsbEndpoint mInputEndpoint;
19 protected UsbEndpoint mOutputEndpoint;
20 protected InputThread mInputThread;
21 protected boolean mRunning;
22 protected boolean mFrozen;
23
24 public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_index) {
25 mManager = manager;
26 mDevice = usbDevice;
27 mInterfaceIndex = interface_index;
28 mInterface = mDevice.getInterface(mInterfaceIndex).getId();
29 mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
30 mRunning = false;
31 }
32
33 public String getIdentifier() {
34 return String.format("%s/%x/%x/%d", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId(), mInterfaceIndex);
35 }
36
37 @Override
38 public int getId() {
39 return mDeviceId;
40 }
41
42 @Override
43 public int getVendorId() {
44 return mDevice.getVendorId();
45 }
46
47 @Override
48 public int getProductId() {
49 return mDevice.getProductId();
50 }
51
52 @Override
53 public String getSerialNumber() {
54 String result = null;
55 if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
56 try {
57 result = mDevice.getSerialNumber();
58 }
59 catch (SecurityException exception) {
60 //Log.w(TAG, "App permissions mean we cannot get serial number for device " + getDeviceName() + " message: " + exception.getMessage());
61 }
62 }
63 if (result == null) {
64 result = "";
65 }
66 return result;
67 }
68
69 @Override
70 public int getVersion() {
71 return 0;
72 }
73
74 @Override
75 public String getManufacturerName() {
76 String result = null;
77 if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
78 result = mDevice.getManufacturerName();
79 }
80 if (result == null) {
81 result = String.format("%x", getVendorId());
82 }
83 return result;
84 }
85
86 @Override
87 public String getProductName() {
88 String result = null;
89 if (Build.VERSION.SDK_INT >= 21 /* Android 5.0 (LOLLIPOP) */) {
90 result = mDevice.getProductName();
91 }
92 if (result == null) {
93 result = String.format("%x", getProductId());
94 }
95 return result;
96 }
97
98 @Override
99 public UsbDevice getDevice() {
100 return mDevice;
101 }
102
103 public String getDeviceName() {
104 return getManufacturerName() + " " + getProductName() + "(0x" + String.format("%x", getVendorId()) + "/0x" + String.format("%x", getProductId()) + ")";
105 }
106
107 @Override
108 public boolean open() {
109 mConnection = mManager.getUSBManager().openDevice(mDevice);
110 if (mConnection == null) {
111 Log.w(TAG, "Unable to open USB device " + getDeviceName());
112 return false;
113 }
114
115 // Force claim our interface
116 UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
117 if (!mConnection.claimInterface(iface, true)) {
118 Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
119 close();
120 return false;
121 }
122
123 // Find the endpoints
124 for (int j = 0; j < iface.getEndpointCount(); j++) {
125 UsbEndpoint endpt = iface.getEndpoint(j);
126 switch (endpt.getDirection()) {
127 case UsbConstants.USB_DIR_IN:
128 if (mInputEndpoint == null) {
129 mInputEndpoint = endpt;
130 }
131 break;
132 case UsbConstants.USB_DIR_OUT:
133 if (mOutputEndpoint == null) {
134 mOutputEndpoint = endpt;
135 }
136 break;
137 }
138 }
139
140 // Make sure the required endpoints were present
141 if (mInputEndpoint == null || mOutputEndpoint == null) {
142 Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
143 close();
144 return false;
145 }
146
147 // Start listening for input
148 mRunning = true;
149 mInputThread = new InputThread();
150 mInputThread.start();
151
152 return true;
153 }
154
155 @Override
156 public int writeReport(byte[] report, boolean feature) {
157 if (mConnection == null) {
158 Log.w(TAG, "writeReport() called with no device connection");
159 return -1;
160 }
161
162 if (feature) {
163 int res = -1;
164 int offset = 0;
165 int length = report.length;
166 boolean skipped_report_id = false;
167 byte report_number = report[0];
168
169 if (report_number == 0x0) {
170 ++offset;
171 --length;
172 skipped_report_id = true;
173 }
174
175 res = mConnection.controlTransfer(
176 UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_OUT,
177 0x09/*HID set_report*/,
178 (3/*HID feature*/ << 8) | report_number,
179 mInterface,
180 report, offset, length,
181 1000/*timeout millis*/);
182
183 if (res < 0) {
184 Log.w(TAG, "writeFeatureReport() returned " + res + " on device " + getDeviceName());
185 return -1;
186 }
187
188 if (skipped_report_id) {
189 ++length;
190 }
191 return length;
192 } else {
193 int res = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
194 if (res != report.length) {
195 Log.w(TAG, "writeOutputReport() returned " + res + " on device " + getDeviceName());
196 }
197 return res;
198 }
199 }
200
201 @Override
202 public boolean readReport(byte[] report, boolean feature) {
203 int res = -1;
204 int offset = 0;
205 int length = report.length;
206 boolean skipped_report_id = false;
207 byte report_number = report[0];
208
209 if (mConnection == null) {
210 Log.w(TAG, "readReport() called with no device connection");
211 return false;
212 }
213
214 if (report_number == 0x0) {
215 /* Offset the return buffer by 1, so that the report ID
216 will remain in byte 0. */
217 ++offset;
218 --length;
219 skipped_report_id = true;
220 }
221
222 res = mConnection.controlTransfer(
223 UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_IN,
224 0x01/*HID get_report*/,
225 ((feature ? 3/*HID feature*/ : 1/*HID Input*/) << 8) | report_number,
226 mInterface,
227 report, offset, length,
228 1000/*timeout millis*/);
229
230 if (res < 0) {
231 Log.w(TAG, "getFeatureReport() returned " + res + " on device " + getDeviceName());
232 return false;
233 }
234
235 if (skipped_report_id) {
236 ++res;
237 ++length;
238 }
239
240 byte[] data;
241 if (res == length) {
242 data = report;
243 } else {
244 data = Arrays.copyOfRange(report, 0, res);
245 }
246 mManager.HIDDeviceReportResponse(mDeviceId, data);
247
248 return true;
249 }
250
251 @Override
252 public void close() {
253 mRunning = false;
254 if (mInputThread != null) {
255 while (mInputThread.isAlive()) {
256 mInputThread.interrupt();
257 try {
258 mInputThread.join();
259 } catch (InterruptedException e) {
260 // Keep trying until we're done
261 }
262 }
263 mInputThread = null;
264 }
265 if (mConnection != null) {
266 UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
267 mConnection.releaseInterface(iface);
268 mConnection.close();
269 mConnection = null;
270 }
271 }
272
273 @Override
274 public void shutdown() {
275 close();
276 mManager = null;
277 }
278
279 @Override
280 public void setFrozen(boolean frozen) {
281 mFrozen = frozen;
282 }
283
284 protected class InputThread extends Thread {
285 @Override
286 public void run() {
287 int packetSize = mInputEndpoint.getMaxPacketSize();
288 byte[] packet = new byte[packetSize];
289 while (mRunning) {
290 int r;
291 try
292 {
293 r = mConnection.bulkTransfer(mInputEndpoint, packet, packetSize, 1000);
294 }
295 catch (Exception e)
296 {
297 Log.v(TAG, "Exception in UsbDeviceConnection bulktransfer: " + e);
298 break;
299 }
300 if (r < 0) {
301 // Could be a timeout or an I/O error
302 }
303 if (r > 0) {
304 byte[] data;
305 if (r == packetSize) {
306 data = packet;
307 } else {
308 data = Arrays.copyOfRange(packet, 0, r);
309 }
310
311 if (!mFrozen) {
312 mManager.HIDDeviceInputReport(mDeviceId, data);
313 }
314 }
315 }
316 }
317 }
318}