@ledgerhq/device-transport-kit-react-native-hid 0.0.0-rn-hid-fixed-device-id-20250521093943 → 0.0.0-rn-hid-improvements-20250522101701

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -123,9 +123,10 @@ internal class DefaultAndroidUsbTransport(
123
123
  "Device disconnected (sessionId=${deviceConnection.sessionId})"
124
124
  )
125
125
  )
126
- deviceConnection.handleDeviceDisconnected()
127
126
  usbConnections.remove(key)
128
127
  usbConnectionsPendingReconnection.add(deviceConnection)
128
+ deviceConnection.handleDeviceDisconnected()
129
+ (deviceConnection.getApduSender() as AndroidUsbApduSender).release()
129
130
  }
130
131
  }
131
132
  }
@@ -325,9 +326,10 @@ internal class DefaultAndroidUsbTransport(
325
326
  val deviceConnection = DeviceConnection(
326
327
  sessionId = sessionId,
327
328
  deviceApduSender = apduSender,
328
- isFatalSendApduFailure = { false }, // TODO: refine this
329
+ isFatalSendApduFailure = { false },
329
330
  reconnectionTimeoutDuration = 5.seconds,
330
331
  onTerminated = {
332
+ (it.getApduSender() as AndroidUsbApduSender).release()
331
333
  usbConnections.remove(sessionId)
332
334
  usbConnectionsPendingReconnection.remove(it)
333
335
  eventDispatcher.dispatch(TransportEvent.DeviceConnectionLost(sessionId))
@@ -22,7 +22,6 @@ import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleErrorLogIn
22
22
  import com.ledger.devicesdk.shared.internal.transport.framer.FramerService
23
23
  import com.ledger.devicesdk.shared.internal.transport.framer.to2BytesArray
24
24
  import kotlinx.coroutines.CoroutineDispatcher
25
- import kotlinx.coroutines.cancel
26
25
  import kotlinx.coroutines.delay
27
26
  import kotlinx.coroutines.launch
28
27
  import kotlinx.coroutines.withContext
@@ -36,7 +35,7 @@ private const val DEFAULT_USB_INTERFACE = 0
36
35
 
37
36
  internal class AndroidUsbApduSender(
38
37
  override val dependencies: Dependencies,
39
- private val usbManager: UsbManager,
38
+ usbManager: UsbManager,
40
39
  private val framerService: FramerService,
41
40
  private val request: UsbRequest,
42
41
  private val ioDispatcher: CoroutineDispatcher,
@@ -47,49 +46,48 @@ internal class AndroidUsbApduSender(
47
46
  val ledgerUsbDevice: LedgerUsbDevice,
48
47
  )
49
48
 
49
+ private val usbDevice = dependencies.usbDevice
50
+ private val usbInterface = usbDevice.getInterface(DEFAULT_USB_INTERFACE)
51
+ private val androidToUsbEndpoint =
52
+ usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_OUT }
53
+ private val usbToAndroidEndpoint =
54
+ usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_IN }
55
+ private val usbConnection = usbManager.openDevice(usbDevice)
56
+ .apply { claimInterface(usbInterface, true) }
57
+
58
+
59
+ fun release() {
60
+ usbConnection.releaseInterface(usbInterface)
61
+ usbConnection.close()
62
+ }
63
+
50
64
  override suspend fun send(apdu: ByteArray, abortTimeoutDuration: Duration): SendApduResult =
51
65
  try {
52
- val usbDevice = dependencies.usbDevice
53
66
  withContext(context = ioDispatcher) {
54
- val usbInterface = usbDevice.getInterface(DEFAULT_USB_INTERFACE)
55
- val androidToUsbEndpoint =
56
- usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_OUT }
57
- val usbToAndroidEndpoint =
58
- usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_IN }
59
- val usbConnection = usbManager.openDevice(usbDevice)
60
- .apply { claimInterface(usbInterface, true) }
61
67
 
62
68
  val timeoutJob = launch {
63
69
  delay(abortTimeoutDuration)
64
- usbConnection.releaseInterface(usbInterface)
65
- usbConnection.close()
66
70
  throw SendApduTimeoutException
67
71
  }
68
72
 
69
- try {
73
+ transmitApdu(
74
+ usbConnection = usbConnection,
75
+ androidToUsbEndpoint = androidToUsbEndpoint,
76
+ rawApdu = apdu,
77
+ )
70
78
 
71
- transmitApdu(
79
+ val apduResponse =
80
+ receiveApdu(
72
81
  usbConnection = usbConnection,
73
- androidToUsbEndpoint = androidToUsbEndpoint,
74
- rawApdu = apdu,
82
+ usbToAndroidEndpoint = usbToAndroidEndpoint,
75
83
  )
84
+ timeoutJob.cancel()
76
85
 
77
- val apduResponse =
78
- receiveApdu(
79
- usbConnection = usbConnection,
80
- usbToAndroidEndpoint = usbToAndroidEndpoint,
81
- )
82
- timeoutJob.cancel()
83
-
84
- if (apduResponse.isEmpty()) {
85
- return@withContext SendApduResult.Failure(reason = SendApduFailureReason.EmptyResponse)
86
- }
87
-
88
- return@withContext SendApduResult.Success(apdu = apduResponse)
89
- } finally {
90
- usbConnection.releaseInterface(usbInterface)
91
- usbConnection.close()
86
+ if (apduResponse.isEmpty()) {
87
+ return@withContext SendApduResult.Failure(reason = SendApduFailureReason.EmptyResponse)
92
88
  }
89
+
90
+ return@withContext SendApduResult.Success(apdu = apduResponse)
93
91
  }
94
92
  } catch (e: SendApduTimeoutException) {
95
93
  loggerService.log(
@@ -132,8 +130,8 @@ internal class AndroidUsbApduSender(
132
130
  private fun receiveApdu(
133
131
  usbConnection: UsbDeviceConnection,
134
132
  usbToAndroidEndpoint: UsbEndpoint,
135
- ): ByteArray =
136
- if (!request.initialize(usbConnection, usbToAndroidEndpoint)) {
133
+ ): ByteArray {
134
+ return if (!request.initialize(usbConnection, usbToAndroidEndpoint)) {
137
135
  request.close()
138
136
  byteArrayOf()
139
137
  } else {
@@ -154,6 +152,7 @@ internal class AndroidUsbApduSender(
154
152
  }
155
153
  framerService.deserialize(mtu = USB_MTU, frames)
156
154
  }
155
+ }
157
156
 
158
157
  private fun UsbInterface.firstEndpointOrThrow(predicate: (Int) -> Boolean): UsbEndpoint {
159
158
  for (endp in 0..this.endpointCount) {
@@ -169,7 +168,7 @@ internal class AndroidUsbApduSender(
169
168
  private fun generateChannelId(): ByteArray =
170
169
  Random.nextInt(0, until = Int.MAX_VALUE).to2BytesArray()
171
170
 
172
- private data object SendApduTimeoutException: Exception() {
171
+ private data object SendApduTimeoutException : Exception() {
173
172
  private fun readResolve(): Any = SendApduTimeoutException
174
173
  }
175
174
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/device-transport-kit-react-native-hid",
3
- "version": "0.0.0-rn-hid-fixed-device-id-20250521093943",
3
+ "version": "0.0.0-rn-hid-improvements-20250522101701",
4
4
  "license": "Apache-2.0",
5
5
  "private": false,
6
6
  "react-native": "src/index.ts",
@@ -35,17 +35,17 @@
35
35
  "@types/uuid": "^10.0.0",
36
36
  "react-native": "0.76.6",
37
37
  "rxjs": "^7.8.2",
38
- "@ledgerhq/device-management-kit": "0.0.0-rn-hid-fixed-device-id-20250521093943",
38
+ "@ledgerhq/device-management-kit": "0.0.0-rn-hid-improvements-20250522101701",
39
39
  "@ledgerhq/eslint-config-dsdk": "0.0.2",
40
40
  "@ledgerhq/ldmk-tool": "0.0.1",
41
- "@ledgerhq/vitest-config-dmk": "0.0.0",
42
41
  "@ledgerhq/prettier-config-dsdk": "0.0.2",
42
+ "@ledgerhq/vitest-config-dmk": "0.0.0",
43
43
  "@ledgerhq/tsconfig-dsdk": "1.0.1"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "react-native": ">0.74.1",
47
47
  "rxjs": "^7.8.2",
48
- "@ledgerhq/device-management-kit": "0.0.0-rn-hid-fixed-device-id-20250521093943"
48
+ "@ledgerhq/device-management-kit": "0.0.0-rn-hid-improvements-20250522101701"
49
49
  },
50
50
  "scripts": {
51
51
  "prebuild": "rimraf lib",