@ledgerhq/device-transport-kit-react-native-hid 0.0.0-develop-20250904001204 → 0.0.0-e2e-speculos-20250904125723

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.
Files changed (54) hide show
  1. package/android/src/main/kotlin/com/ledger/androidtransporthid/TransportHidModule.kt +3 -12
  2. package/android/src/main/kotlin/com/ledger/androidtransporthid/bridge/serialization.kt +0 -2
  3. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/DefaultAndroidUsbTransport.kt +23 -85
  4. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/connection/AndroidUsbApduSender.kt +29 -70
  5. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceApduSender.kt +1 -2
  6. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnection.kt +4 -5
  7. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionStateMachine.kt +33 -103
  8. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/apdu/SendApduResult.kt +0 -4
  9. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/connection/InternalConnectedDevice.kt +1 -1
  10. package/android/src/test/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionStateMachineTest.kt +46 -189
  11. package/android/src/test/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionTest.kt +5 -9
  12. package/lib/cjs/api/bridge/DefaultNativeModuleWrapper.js +1 -1
  13. package/lib/cjs/api/bridge/DefaultNativeModuleWrapper.js.map +3 -3
  14. package/lib/cjs/api/bridge/mapper.js +1 -1
  15. package/lib/cjs/api/bridge/mapper.js.map +2 -2
  16. package/lib/cjs/api/bridge/mapper.test.js +1 -1
  17. package/lib/cjs/api/bridge/mapper.test.js.map +2 -2
  18. package/lib/cjs/api/bridge/types.js +1 -1
  19. package/lib/cjs/api/bridge/types.js.map +1 -1
  20. package/lib/cjs/api/transport/Errors.js +1 -1
  21. package/lib/cjs/api/transport/Errors.js.map +3 -3
  22. package/lib/cjs/api/transport/NativeModuleWrapper.js +1 -1
  23. package/lib/cjs/api/transport/NativeModuleWrapper.js.map +1 -1
  24. package/lib/cjs/api/transport/RNHidTransport.js +1 -1
  25. package/lib/cjs/api/transport/RNHidTransport.js.map +3 -3
  26. package/lib/cjs/api/transport/RNHidTransport.test.js +1 -1
  27. package/lib/cjs/api/transport/RNHidTransport.test.js.map +2 -2
  28. package/lib/cjs/package.json +1 -1
  29. package/lib/esm/api/bridge/DefaultNativeModuleWrapper.js +1 -1
  30. package/lib/esm/api/bridge/DefaultNativeModuleWrapper.js.map +3 -3
  31. package/lib/esm/api/bridge/mapper.js +1 -1
  32. package/lib/esm/api/bridge/mapper.js.map +3 -3
  33. package/lib/esm/api/bridge/mapper.test.js +1 -1
  34. package/lib/esm/api/bridge/mapper.test.js.map +3 -3
  35. package/lib/esm/api/bridge/types.js.map +1 -1
  36. package/lib/esm/api/transport/Errors.js +1 -1
  37. package/lib/esm/api/transport/Errors.js.map +3 -3
  38. package/lib/esm/api/transport/RNHidTransport.js +1 -1
  39. package/lib/esm/api/transport/RNHidTransport.js.map +3 -3
  40. package/lib/esm/api/transport/RNHidTransport.test.js +1 -1
  41. package/lib/esm/api/transport/RNHidTransport.test.js.map +3 -3
  42. package/lib/esm/package.json +1 -1
  43. package/lib/types/api/bridge/DefaultNativeModuleWrapper.d.ts +1 -1
  44. package/lib/types/api/bridge/DefaultNativeModuleWrapper.d.ts.map +1 -1
  45. package/lib/types/api/bridge/mapper.d.ts.map +1 -1
  46. package/lib/types/api/bridge/types.d.ts +2 -2
  47. package/lib/types/api/bridge/types.d.ts.map +1 -1
  48. package/lib/types/api/transport/Errors.d.ts +1 -1
  49. package/lib/types/api/transport/Errors.d.ts.map +1 -1
  50. package/lib/types/api/transport/NativeModuleWrapper.d.ts +1 -1
  51. package/lib/types/api/transport/NativeModuleWrapper.d.ts.map +1 -1
  52. package/lib/types/api/transport/RNHidTransport.d.ts.map +1 -1
  53. package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
  54. package/package.json +9 -9
@@ -31,7 +31,6 @@ import kotlinx.coroutines.flow.onEach
31
31
  import kotlinx.coroutines.launch
32
32
  import timber.log.Timber
33
33
  import kotlin.random.Random
34
- import kotlin.time.Duration
35
34
  import kotlin.time.Duration.Companion.milliseconds
36
35
 
37
36
  class TransportHidModule(
@@ -49,7 +48,7 @@ class TransportHidModule(
49
48
  private val loggerService: LoggerService =
50
49
  LoggerService { info ->
51
50
  Timber.tag("LDMKTransportHIDModule " + info.tag).d(info.message)
52
- // sendEvent(reactContext, BridgeEvents.TransportLog(info))
51
+ sendEvent(reactContext, BridgeEvents.TransportLog(info))
53
52
  }
54
53
 
55
54
  private val transport: AndroidUsbTransport? by lazy {
@@ -207,13 +206,7 @@ class TransportHidModule(
207
206
  }
208
207
 
209
208
  @ReactMethod
210
- fun sendApdu(
211
- sessionId: String,
212
- apduBase64: String,
213
- triggersDisconnection: Boolean,
214
- abortTimeout: Int,
215
- promise: Promise
216
- ) {
209
+ fun sendApdu(sessionId: String, apduBase64: String, promise: Promise) {
217
210
  try {
218
211
  val device = connectedDevices.firstOrNull() { it.id == sessionId }
219
212
  if (device == null) {
@@ -223,9 +216,7 @@ class TransportHidModule(
223
216
  coroutineScope.launch {
224
217
  try {
225
218
  val apdu: ByteArray = Base64.decode(apduBase64, Base64.DEFAULT)
226
- val abortTimeoutDuration = if (abortTimeout <= 0) Duration.INFINITE else abortTimeout.milliseconds
227
- val res =
228
- device.sendApduFn(apdu, triggersDisconnection, abortTimeoutDuration)
219
+ val res = device.sendApduFn(apdu)
229
220
  promise.resolve(res.toWritableMap())
230
221
  } catch (e: Exception) {
231
222
  Timber.i("$e, ${e.cause}")
@@ -103,8 +103,6 @@ internal fun SendApduResult.toWritableMap(): WritableMap {
103
103
  SendApduFailureReason.NoUsbEndpointFound -> "NoUsbEndpointFound"
104
104
  SendApduFailureReason.DeviceDisconnected -> "DeviceDisconnected"
105
105
  SendApduFailureReason.Unknown -> "Unknown"
106
- SendApduFailureReason.AbortTimeout -> "SendApduTimeout"
107
- SendApduFailureReason.EmptyResponse -> "EmptyResponse"
108
106
  })
109
107
  }
110
108
  }
@@ -97,57 +97,31 @@ internal class DefaultAndroidUsbTransport(
97
97
  override fun updateUsbState(state: UsbState) {
98
98
  when (state) {
99
99
  is UsbState.Detached -> {
100
- loggerService.log(
101
- buildSimpleDebugLogInfo(
102
- "AndroidUsbTransport",
103
- "Detached deviceId=${state.ledgerUsbDevice.uid}"
104
- )
105
- )
100
+ loggerService.log(buildSimpleDebugLogInfo("AndroidUsbTransport", "Detached deviceId=${state.ledgerUsbDevice.uid}"))
106
101
  usbConnections.entries.find {
107
102
  it.value.getApduSender().dependencies.ledgerUsbDevice.uid == state.ledgerUsbDevice.uid
108
103
  }.let { item ->
109
104
  scope.launch {
110
105
  if (item == null) {
111
- loggerService.log(
112
- buildSimpleWarningLogInfo(
113
- "AndroidUsbTransport",
114
- "No connection found"
115
- )
116
- )
106
+ loggerService.log(buildSimpleWarningLogInfo("AndroidUsbTransport", "No connection found"))
117
107
  return@launch
118
108
  }
119
109
  val (key, deviceConnection) = item
120
- loggerService.log(
121
- buildSimpleInfoLogInfo(
122
- "AndroidUsbTransport",
123
- "Device disconnected (sessionId=${deviceConnection.sessionId})"
124
- )
125
- )
110
+ loggerService.log(buildSimpleInfoLogInfo("AndroidUsbTransport", "Device disconnected (sessionId=${deviceConnection.sessionId})"))
111
+ deviceConnection.handleDeviceDisconnected()
126
112
  usbConnections.remove(key)
127
113
  usbConnectionsPendingReconnection.add(deviceConnection)
128
- deviceConnection.handleDeviceDisconnected()
129
- (deviceConnection.getApduSender() as AndroidUsbApduSender).release()
130
114
  }
131
115
  }
132
116
  }
133
117
 
134
118
  is UsbState.Attached -> {
135
- loggerService.log(
136
- buildSimpleDebugLogInfo(
137
- "AndroidUsbTransport",
138
- "Attached deviceId=${state.ledgerUsbDevice.uid}, pendingReconnections=${usbConnectionsPendingReconnection}"
139
- )
140
- )
119
+ loggerService.log(buildSimpleDebugLogInfo("AndroidUsbTransport", "Attached deviceId=${state.ledgerUsbDevice.uid}, pendingReconnections=${usbConnectionsPendingReconnection}"))
141
120
  val usbDevice = usbManager.deviceList.values.firstOrNull {
142
121
  it.toLedgerUsbDevice()?.uid == state.ledgerUsbDevice.uid
143
122
  }
144
123
  if (usbDevice == null) {
145
- loggerService.log(
146
- buildSimpleWarningLogInfo(
147
- "AndroidUsbTransport",
148
- "No UsbDevice found"
149
- )
150
- )
124
+ loggerService.log(buildSimpleWarningLogInfo("AndroidUsbTransport", "No UsbDevice found"))
151
125
  return
152
126
  }
153
127
  usbConnectionsPendingReconnection.firstOrNull {
@@ -164,53 +138,27 @@ internal class DefaultAndroidUsbTransport(
164
138
  )
165
139
  return@launch
166
140
  }
167
- loggerService.log(
168
- buildSimpleDebugLogInfo(
169
- "AndroidUsbTransport",
170
- "Found matching device connection $deviceConnection"
171
- )
172
- )
141
+ loggerService.log(buildSimpleDebugLogInfo("AndroidUsbTransport", "Found matching device connection $deviceConnection"))
173
142
 
174
143
  val permissionResult = checkOrRequestPermission(usbDevice)
175
144
  if (permissionResult is PermissionResult.Denied) {
176
- loggerService.log(
177
- buildSimpleDebugLogInfo(
178
- "AndroidUsbTransport",
179
- "Permission denied"
180
- )
181
- )
145
+ loggerService.log(buildSimpleDebugLogInfo("AndroidUsbTransport", "Permission denied"))
182
146
  return@launch
183
147
  }
184
- loggerService.log(
185
- buildSimpleInfoLogInfo(
186
- "AndroidUsbTransport",
187
- "Reconnecting device (sessionId=${deviceConnection.sessionId})"
148
+ loggerService.log(buildSimpleInfoLogInfo("AndroidUsbTransport", "Reconnecting device (sessionId=${deviceConnection.sessionId})"))
149
+ deviceConnection.handleDeviceConnected(
150
+ AndroidUsbApduSender(
151
+ dependencies = AndroidUsbApduSender.Dependencies(
152
+ usbDevice = usbDevice,
153
+ ledgerUsbDevice = state.ledgerUsbDevice,
154
+ ),
155
+ usbManager = usbManager,
156
+ ioDispatcher = Dispatchers.IO,
157
+ framerService = FramerService(loggerService),
158
+ request = UsbRequest(),
159
+ loggerService = loggerService
188
160
  )
189
161
  )
190
-
191
- val apduSender = AndroidUsbApduSender(
192
- dependencies = AndroidUsbApduSender.Dependencies(
193
- usbDevice = usbDevice,
194
- ledgerUsbDevice = state.ledgerUsbDevice,
195
- ),
196
- usbManager = usbManager,
197
- ioDispatcher = Dispatchers.IO,
198
- framerService = FramerService(loggerService),
199
- request = UsbRequest(),
200
- loggerService = loggerService
201
- )
202
-
203
- if (!usbConnectionsPendingReconnection.contains(deviceConnection)) {
204
- /**
205
- * We check this because maybe by the time we get here,
206
- * the reconnection has timed out and the session has been terminated.
207
- * Easy to reproduce for instance if the permission request requires
208
- * a user interaction.
209
- */
210
- apduSender.release()
211
- return@launch
212
- }
213
- deviceConnection.handleDeviceConnected(apduSender)
214
162
  usbConnectionsPendingReconnection.remove(deviceConnection)
215
163
  usbConnections[deviceConnection.sessionId] = deviceConnection
216
164
  }
@@ -247,12 +195,7 @@ internal class DefaultAndroidUsbTransport(
247
195
  device = usbDevice,
248
196
  )
249
197
 
250
- loggerService.log(
251
- buildSimpleDebugLogInfo(
252
- "AndroidUsbTransport",
253
- "Waiting for permission result"
254
- )
255
- )
198
+ loggerService.log(buildSimpleDebugLogInfo("AndroidUsbTransport", "Waiting for permission result"))
256
199
 
257
200
  val result = eventsFlow.first {
258
201
  it is UsbPermissionEvent.PermissionGranted ||
@@ -316,10 +259,9 @@ internal class DefaultAndroidUsbTransport(
316
259
  val deviceConnection = DeviceConnection(
317
260
  sessionId = sessionId,
318
261
  deviceApduSender = apduSender,
319
- isFatalSendApduFailure = { false },
262
+ isFatalSendApduFailure = { false }, // TODO: refine this
320
263
  reconnectionTimeoutDuration = 5.seconds,
321
264
  onTerminated = {
322
- (it.getApduSender() as AndroidUsbApduSender).release()
323
265
  usbConnections.remove(sessionId)
324
266
  usbConnectionsPendingReconnection.remove(it)
325
267
  eventDispatcher.dispatch(TransportEvent.DeviceConnectionLost(sessionId))
@@ -334,9 +276,7 @@ internal class DefaultAndroidUsbTransport(
334
276
  discoveryDevice.name,
335
277
  discoveryDevice.ledgerDevice,
336
278
  discoveryDevice.connectivityType,
337
- sendApduFn = { apdu: ByteArray, triggersDisconnection: Boolean, abortTimeoutDuration: Duration ->
338
- deviceConnection.requestSendApdu(apdu, triggersDisconnection, abortTimeoutDuration)
339
- }
279
+ sendApduFn = { apdu -> deviceConnection.requestSendApdu(apdu) },
340
280
  )
341
281
 
342
282
  usbConnections[sessionId] = deviceConnection
@@ -346,9 +286,7 @@ internal class DefaultAndroidUsbTransport(
346
286
  }
347
287
 
348
288
  override suspend fun disconnect(deviceId: String) {
349
- // The DeviceConnection is either in usbConnections or usbConnectionsPendingReconnection
350
289
  usbConnections[deviceId]?.requestCloseConnection()
351
- usbConnectionsPendingReconnection.find { it.sessionId == deviceId }?.requestCloseConnection()
352
290
  }
353
291
 
354
292
  private fun generateSessionId(usbDevice: UsbDevice): String = "usb_${usbDevice.deviceId}"
@@ -13,21 +13,21 @@ import android.hardware.usb.UsbInterface
13
13
  import android.hardware.usb.UsbManager
14
14
  import android.hardware.usb.UsbRequest
15
15
  import com.ledger.devicesdk.shared.androidMain.transport.usb.model.LedgerUsbDevice
16
- import com.ledger.devicesdk.shared.androidMainInternal.transport.USB_MTU
17
- import com.ledger.devicesdk.shared.androidMainInternal.transport.deviceconnection.DeviceApduSender
18
16
  import com.ledger.devicesdk.shared.api.apdu.SendApduFailureReason
19
17
  import com.ledger.devicesdk.shared.api.apdu.SendApduResult
18
+ import com.ledger.devicesdk.shared.androidMainInternal.transport.deviceconnection.DeviceApduSender
19
+ import com.ledger.devicesdk.shared.api.utils.toHexadecimalString
20
+ import com.ledger.devicesdk.shared.androidMainInternal.transport.USB_MTU
20
21
  import com.ledger.devicesdk.shared.internal.service.logger.LoggerService
21
22
  import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleErrorLogInfo
23
+ import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleInfoLogInfo
22
24
  import com.ledger.devicesdk.shared.internal.transport.framer.FramerService
23
25
  import com.ledger.devicesdk.shared.internal.transport.framer.to2BytesArray
24
- import kotlinx.coroutines.CoroutineDispatcher
25
- import kotlinx.coroutines.delay
26
- import kotlinx.coroutines.launch
27
- import kotlinx.coroutines.withContext
28
26
  import java.nio.ByteBuffer
29
27
  import kotlin.random.Random
30
- import kotlin.time.Duration
28
+ import kotlinx.coroutines.CoroutineDispatcher
29
+ import kotlinx.coroutines.withContext
30
+ import timber.log.Timber
31
31
 
32
32
  private const val USB_TIMEOUT = 500
33
33
 
@@ -35,75 +35,44 @@ private const val DEFAULT_USB_INTERFACE = 0
35
35
 
36
36
  internal class AndroidUsbApduSender(
37
37
  override val dependencies: Dependencies,
38
- usbManager: UsbManager,
38
+ private val usbManager: UsbManager,
39
39
  private val framerService: FramerService,
40
40
  private val request: UsbRequest,
41
41
  private val ioDispatcher: CoroutineDispatcher,
42
42
  private val loggerService: LoggerService,
43
43
  ) : DeviceApduSender<AndroidUsbApduSender.Dependencies> {
44
+
44
45
  data class Dependencies(
45
46
  val usbDevice: UsbDevice,
46
47
  val ledgerUsbDevice: LedgerUsbDevice,
47
48
  )
48
49
 
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
-
64
- override suspend fun send(apdu: ByteArray, abortTimeoutDuration: Duration): SendApduResult =
50
+ override suspend fun send(apdu: ByteArray): SendApduResult =
65
51
  try {
52
+ val usbDevice = dependencies.usbDevice
66
53
  withContext(context = ioDispatcher) {
67
-
68
- val timeoutJob = launch {
69
- delay(abortTimeoutDuration)
70
- throw SendApduTimeoutException
71
- }
54
+ val usbInterface = usbDevice.getInterface(DEFAULT_USB_INTERFACE)
55
+ val androidToUsbEndpoint = usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_OUT }
56
+ val usbToAndroidEndpoint = usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_IN }
57
+ val usbConnection = usbManager.openDevice(usbDevice).apply { claimInterface(usbInterface, true) }
72
58
 
73
59
  transmitApdu(
74
60
  usbConnection = usbConnection,
75
61
  androidToUsbEndpoint = androidToUsbEndpoint,
76
62
  rawApdu = apdu,
77
63
  )
78
-
79
64
  val apduResponse =
80
65
  receiveApdu(
81
66
  usbConnection = usbConnection,
82
67
  usbToAndroidEndpoint = usbToAndroidEndpoint,
83
68
  )
84
- timeoutJob.cancel()
85
69
 
86
- if (apduResponse.isEmpty()) {
87
- return@withContext SendApduResult.Failure(reason = SendApduFailureReason.EmptyResponse)
88
- }
70
+ usbConnection.releaseInterface(usbInterface)
71
+ usbConnection.close()
89
72
 
90
- return@withContext SendApduResult.Success(apdu = apduResponse)
73
+ SendApduResult.Success(apdu = apduResponse)
91
74
  }
92
- } catch (e: SendApduTimeoutException) {
93
- loggerService.log(
94
- buildSimpleErrorLogInfo(
95
- "AndroidUsbApduSender",
96
- "timeout in send: $e"
97
- )
98
- )
99
- SendApduResult.Failure(reason = SendApduFailureReason.AbortTimeout)
100
75
  } catch (e: NoSuchElementException) {
101
- loggerService.log(
102
- buildSimpleErrorLogInfo(
103
- "AndroidUsbApduSender",
104
- "no endpoint found: $e"
105
- )
106
- )
107
76
  SendApduResult.Failure(reason = SendApduFailureReason.NoUsbEndpointFound)
108
77
  } catch (e: Exception) {
109
78
  loggerService.log(buildSimpleErrorLogInfo("AndroidUsbApduSender", "error in send: $e"))
@@ -115,27 +84,22 @@ internal class AndroidUsbApduSender(
115
84
  androidToUsbEndpoint: UsbEndpoint,
116
85
  rawApdu: ByteArray,
117
86
  ) {
118
- framerService.serialize(mtu = USB_MTU, channelId = generateChannelId(), rawApdu = rawApdu)
119
- .forEach { apduFrame ->
120
- val buffer = apduFrame.toByteArray()
121
- usbConnection.bulkTransfer(
122
- androidToUsbEndpoint,
123
- buffer,
124
- apduFrame.size(),
125
- USB_TIMEOUT
126
- )
127
- }
87
+ framerService.serialize(mtu = USB_MTU, channelId = generateChannelId(), rawApdu = rawApdu).forEach { apduFrame ->
88
+ val buffer = apduFrame.toByteArray()
89
+ Timber.i("APDU sent = ${buffer.toHexadecimalString()}")
90
+ usbConnection.bulkTransfer(androidToUsbEndpoint, buffer, apduFrame.size(), USB_TIMEOUT)
91
+ }
128
92
  }
129
93
 
130
94
  private fun receiveApdu(
131
95
  usbConnection: UsbDeviceConnection,
132
96
  usbToAndroidEndpoint: UsbEndpoint,
133
- ): ByteArray {
134
- return if (!request.initialize(usbConnection, usbToAndroidEndpoint)) {
97
+ ): ByteArray =
98
+ if (!request.initialize(usbConnection, usbToAndroidEndpoint)) {
135
99
  request.close()
136
100
  byteArrayOf()
137
101
  } else {
138
- val frames = framerService.createApduFrames(mtu = USB_MTU, isUsbTransport = true) {
102
+ val frames = framerService.createApduFrames(mtu = USB_MTU, isUsbTransport = true){
139
103
  val buffer = ByteArray(USB_MTU)
140
104
  val responseBuffer = ByteBuffer.allocate(USB_MTU)
141
105
 
@@ -143,7 +107,8 @@ internal class AndroidUsbApduSender(
143
107
  if (!queuingResult) {
144
108
  request.close()
145
109
  byteArrayOf()
146
- } else {
110
+ }
111
+ else{
147
112
  usbConnection.requestWait()
148
113
  responseBuffer.rewind()
149
114
  responseBuffer.get(buffer, 0, responseBuffer.remaining())
@@ -152,7 +117,6 @@ internal class AndroidUsbApduSender(
152
117
  }
153
118
  framerService.deserialize(mtu = USB_MTU, frames)
154
119
  }
155
- }
156
120
 
157
121
  private fun UsbInterface.firstEndpointOrThrow(predicate: (Int) -> Boolean): UsbEndpoint {
158
122
  for (endp in 0..this.endpointCount) {
@@ -165,10 +129,5 @@ internal class AndroidUsbApduSender(
165
129
  throw NoSuchElementException("No endpoint matching the predicate")
166
130
  }
167
131
 
168
- private fun generateChannelId(): ByteArray =
169
- Random.nextInt(0, until = Int.MAX_VALUE).to2BytesArray()
170
-
171
- private data object SendApduTimeoutException : Exception() {
172
- private fun readResolve(): Any = SendApduTimeoutException
173
- }
132
+ private fun generateChannelId(): ByteArray = Random.nextInt(0, until = Int.MAX_VALUE).to2BytesArray()
174
133
  }
@@ -6,9 +6,8 @@
6
6
  package com.ledger.devicesdk.shared.androidMainInternal.transport.deviceconnection
7
7
 
8
8
  import com.ledger.devicesdk.shared.api.apdu.SendApduResult
9
- import kotlin.time.Duration
10
9
 
11
10
  internal interface DeviceApduSender<Dependencies> {
12
- suspend fun send(apdu: ByteArray, abortTimeoutDuration: Duration): SendApduResult
11
+ suspend fun send(apdu: ByteArray): SendApduResult
13
12
  val dependencies: Dependencies
14
13
  }
@@ -24,9 +24,9 @@ internal class DeviceConnection<Dependencies>(
24
24
 
25
25
  init {
26
26
  stateMachine = DeviceConnectionStateMachine(
27
- sendApduFn = { apdu, abortTimeoutDuration ->
27
+ sendApduFn = {
28
28
  coroutineScope.launch {
29
- val res = deviceApduSender.send(apdu, abortTimeoutDuration)
29
+ val res = deviceApduSender.send(it)
30
30
  handleApduResult(res)
31
31
  }
32
32
  },
@@ -66,13 +66,12 @@ internal class DeviceConnection<Dependencies>(
66
66
  stateMachine.handleDeviceDisconnected()
67
67
  }
68
68
 
69
- public suspend fun requestSendApdu(apdu: ByteArray, triggersDisconnection: Boolean, abortTimeoutDuration: Duration): SendApduResult =
69
+ public suspend fun requestSendApdu(apdu: ByteArray): SendApduResult =
70
70
  suspendCoroutine { cont ->
71
71
  stateMachine.requestSendApdu(
72
72
  DeviceConnectionStateMachine.SendApduRequestContent(
73
73
  apdu = apdu,
74
- triggersDisconnection = apduTriggersDisconnection(apdu) || triggersDisconnection,
75
- abortTimeoutDuration = abortTimeoutDuration,
74
+ triggersDisconnection = apduTriggersDisconnection(apdu),
76
75
  resultCallback = cont::resume
77
76
  )
78
77
  )