Skip to content

Commit 54aa256

Browse files
committed
feat(suite-native): implement reset method for native USB device
1 parent 5248994 commit 54aa256

File tree

4 files changed

+36
-12
lines changed

4 files changed

+36
-12
lines changed

packages/react-native-usb/android/src/main/java/io/trezor/rnusb/ReactNativeUsbModule.kt

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import expo.modules.kotlin.Promise
2020
import expo.modules.kotlin.exception.CodedException
2121
import expo.modules.core.errors.ModuleDestroyedException
2222
import java.nio.ByteBuffer
23+
import java.util.concurrent.ConcurrentHashMap
2324

2425
// Convert Android USBDevice to JS compatible WebUSBDevice
2526
typealias WebUSBDevice = Map<String, Any?>
@@ -71,6 +72,10 @@ class ReactNativeUsbModule : Module() {
7172
return@AsyncFunction openDevice(deviceName)
7273
}
7374

75+
AsyncFunction("reset") { deviceName: String ->
76+
return@AsyncFunction resetDevice(deviceName)
77+
}
78+
7479
AsyncFunction("close") { deviceName: String ->
7580
return@AsyncFunction closeDevice(deviceName)
7681
}
@@ -156,7 +161,7 @@ class ReactNativeUsbModule : Module() {
156161
for (device in devicesList) {
157162
if (usbManager.hasPermission(device)) {
158163
Log.d(LOG_TAG, "Has permission, send event onDeviceConnected: $device")
159-
164+
160165
val webUsbDevice = if (hasOpenedConnection(device.deviceName)) {
161166
Log.d(LOG_TAG, "Device already opened: $device")
162167
getWebUSBDevice(device)
@@ -220,7 +225,8 @@ class ReactNativeUsbModule : Module() {
220225
get() = context.getSystemService(Context.USB_SERVICE) as UsbManager
221226

222227

223-
private val openedConnections = mutableMapOf<String, UsbDeviceConnection>()
228+
private val openedConnections = ConcurrentHashMap<String, UsbDeviceConnection>()
229+
private val pendingRequests = ConcurrentHashMap<String, UsbRequest>()
224230

225231
// We need to store device metadata because we can't access them in detached event
226232
private val devicesHistory = mutableMapOf<String, WebUSBDevice>()
@@ -248,6 +254,12 @@ class ReactNativeUsbModule : Module() {
248254
return getWebUSBDevice(device)
249255
}
250256

257+
private fun resetDevice(deviceName: String) {
258+
Log.d(LOG_TAG, "Resetting device $deviceName")
259+
val usbRequest = pendingRequests.remove(deviceName)
260+
usbRequest?.cancel()
261+
}
262+
251263
private fun closeDevice(deviceName: String) {
252264
Log.d(LOG_TAG, "Closing device $deviceName")
253265
getOpenedConnection(deviceName).close()
@@ -256,12 +268,10 @@ class ReactNativeUsbModule : Module() {
256268

257269
private fun closeAllOpenedDevices() {
258270
Log.d(LOG_TAG, "Closing all devices")
259-
with(openedConnections.iterator()) {
260-
forEach {
261-
it.value.close()
262-
remove()
263-
}
264-
}
271+
pendingRequests.values.forEach { it.cancel() }
272+
pendingRequests.clear()
273+
openedConnections.values.forEach { it.close() }
274+
openedConnections.clear()
265275
}
266276

267277
private fun selectConfiguration(deviceName: String, configurationIndex: Int) {
@@ -352,7 +362,19 @@ class ReactNativeUsbModule : Module() {
352362
req.initialize(usbConnection, usbEndpoint)
353363
req.queue(buffer)
354364

355-
val result = usbConnection.requestWait()
365+
if (pendingRequests.putIfAbsent(device.deviceName, req) != null) {
366+
req.cancel()
367+
req.close()
368+
Log.e(LOG_TAG, "Transfer already in progress for device ${device.deviceName}")
369+
throw Exception("Transfer already in progress for device ${device.deviceName}")
370+
}
371+
372+
val result = try {
373+
usbConnection.requestWait()
374+
} finally {
375+
pendingRequests.remove(device.deviceName)
376+
req.close()
377+
}
356378

357379
if (result == null) {
358380
Log.e(LOG_TAG, "Failed to transfer data from device ${device.deviceName}")
@@ -378,7 +400,6 @@ class ReactNativeUsbModule : Module() {
378400
return isConnectionOpened
379401
}
380402

381-
382403
private fun getDeviceByName(deviceName: String): UsbDevice {
383404
Log.d(LOG_TAG, "getDeviceByName: $deviceName")
384405
val devices = usbManager.deviceList.values.toList()

packages/react-native-usb/src/ReactNativeUsb.types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export interface WebUSBDevice {
5151
readonly configurations: USBConfiguration[];
5252
readonly opened: boolean;
5353
open(): Promise<void>;
54+
reset(): Promise<void>;
5455
close(): Promise<void>;
5556
forget(): Promise<void>;
5657
selectConfiguration(configurationValue: number): Promise<void>;
@@ -77,7 +78,6 @@ export interface WebUSBDevice {
7778
data: BufferSource,
7879
packetLengths: number[],
7980
): Promise<USBIsochronousOutTransferResult>;
80-
reset(): Promise<void>;
8181
}
8282

8383
export interface OnConnectEvent extends Event {

packages/react-native-usb/src/ReactNativeUsbModule.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type DeviceEvents = {
1010

1111
declare class ReactNativeUsbModuleDeclaration extends NativeModule<DeviceEvents> {
1212
open: (deviceName: string) => Promise<void>;
13+
reset: (deviceName: string) => Promise<void>;
1314
close: (deviceName: string) => Promise<void>;
1415
claimInterface: (deviceName: string, interfaceNumber: number) => Promise<void>;
1516
releaseInterface: (deviceName: string, interfaceNumber: number) => Promise<void>;

packages/react-native-usb/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export const setPriorityMode = (isInPriorityMode: boolean) =>
1717

1818
const open = (deviceName: string) => ReactNativeUsbModule.open(deviceName);
1919

20+
const reset = (deviceName: string) => ReactNativeUsbModule.reset(deviceName);
21+
2022
const close = (deviceName: string) => ReactNativeUsbModule.close(deviceName);
2123

2224
const claimInterface = (deviceName: string, interfaceNumber: number) =>
@@ -73,6 +75,7 @@ const createNoop = (methodName: string) => async () => {
7375
const createWebUSBDevice = (device: NativeDevice): WebUSBDevice => ({
7476
...device,
7577
open: () => open(device.deviceName),
78+
reset: () => reset(device.deviceName),
7679
close: () => close(device.deviceName),
7780
forget: createNoop('forget'),
7881
selectConfiguration: (configurationValue: number) =>
@@ -90,7 +93,6 @@ const createWebUSBDevice = (device: NativeDevice): WebUSBDevice => ({
9093
transferOut(device.deviceName, endpointNumber, data),
9194
isochronousTransferIn: createNoop('isochronousTransferIn'),
9295
isochronousTransferOut: createNoop('isochronousTransferOut'),
93-
reset: createNoop('reset'),
9496

9597
// TODO: Implement these properties, very low priority we are not using them anywhere
9698
usbVersionMajor: 2,

0 commit comments

Comments
 (0)