@ledgerhq/device-transport-kit-react-native-hid 0.0.0-rn-hid-improvements-20250523090318 → 0.0.0-rn-ble-pairing-removed-while-reconnecting-20250731133348

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 (53) hide show
  1. package/android/src/main/kotlin/com/ledger/androidtransporthid/TransportHidModule.kt +3 -32
  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 +14 -84
  4. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/connection/AndroidUsbApduSender.kt +31 -85
  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 +3 -4
  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/api/discovery/DiscoveryDevice.kt +1 -1
  10. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/connection/InternalConnectedDevice.kt +1 -1
  11. package/android/src/test/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionStateMachineTest.kt +31 -47
  12. package/android/src/test/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionTest.kt +5 -9
  13. package/lib/cjs/api/bridge/DefaultNativeModuleWrapper.js +1 -1
  14. package/lib/cjs/api/bridge/DefaultNativeModuleWrapper.js.map +3 -3
  15. package/lib/cjs/api/bridge/mapper.js +1 -1
  16. package/lib/cjs/api/bridge/mapper.js.map +2 -2
  17. package/lib/cjs/api/bridge/mapper.test.js +1 -1
  18. package/lib/cjs/api/bridge/mapper.test.js.map +2 -2
  19. package/lib/cjs/api/bridge/types.js +1 -1
  20. package/lib/cjs/api/bridge/types.js.map +1 -1
  21. package/lib/cjs/api/transport/Errors.js +1 -1
  22. package/lib/cjs/api/transport/Errors.js.map +3 -3
  23. package/lib/cjs/api/transport/NativeModuleWrapper.js +1 -1
  24. package/lib/cjs/api/transport/NativeModuleWrapper.js.map +1 -1
  25. package/lib/cjs/api/transport/RNHidTransport.js +1 -1
  26. package/lib/cjs/api/transport/RNHidTransport.js.map +3 -3
  27. package/lib/cjs/api/transport/RNHidTransport.test.js +1 -1
  28. package/lib/cjs/api/transport/RNHidTransport.test.js.map +2 -2
  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/types/api/bridge/DefaultNativeModuleWrapper.d.ts +1 -1
  43. package/lib/types/api/bridge/DefaultNativeModuleWrapper.d.ts.map +1 -1
  44. package/lib/types/api/bridge/mapper.d.ts.map +1 -1
  45. package/lib/types/api/bridge/types.d.ts +2 -2
  46. package/lib/types/api/bridge/types.d.ts.map +1 -1
  47. package/lib/types/api/transport/Errors.d.ts +1 -1
  48. package/lib/types/api/transport/Errors.d.ts.map +1 -1
  49. package/lib/types/api/transport/NativeModuleWrapper.d.ts +1 -1
  50. package/lib/types/api/transport/NativeModuleWrapper.d.ts.map +1 -1
  51. package/lib/types/api/transport/RNHidTransport.d.ts.map +1 -1
  52. package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
  53. package/package.json +5 -5
@@ -22,7 +22,6 @@ import com.ledger.devicesdk.shared.internal.connection.InternalConnectedDevice
22
22
  import com.ledger.devicesdk.shared.internal.connection.InternalConnectionResult
23
23
  import com.ledger.devicesdk.shared.internal.event.SdkEventDispatcher
24
24
  import com.ledger.devicesdk.shared.internal.service.logger.LoggerService
25
- import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleDebugLogInfo
26
25
  import com.ledger.devicesdk.shared.internal.transport.TransportEvent
27
26
  import kotlinx.coroutines.CoroutineScope
28
27
  import kotlinx.coroutines.Dispatchers
@@ -32,7 +31,6 @@ import kotlinx.coroutines.flow.onEach
32
31
  import kotlinx.coroutines.launch
33
32
  import timber.log.Timber
34
33
  import kotlin.random.Random
35
- import kotlin.time.Duration
36
34
  import kotlin.time.Duration.Companion.milliseconds
37
35
 
38
36
  class TransportHidModule(
@@ -50,7 +48,7 @@ class TransportHidModule(
50
48
  private val loggerService: LoggerService =
51
49
  LoggerService { info ->
52
50
  Timber.tag("LDMKTransportHIDModule " + info.tag).d(info.message)
53
- // sendEvent(reactContext, BridgeEvents.TransportLog(info))
51
+ sendEvent(reactContext, BridgeEvents.TransportLog(info))
54
52
  }
55
53
 
56
54
  private val transport: AndroidUsbTransport? by lazy {
@@ -208,29 +206,7 @@ class TransportHidModule(
208
206
  }
209
207
 
210
208
  @ReactMethod
211
- fun sendApdu(
212
- sessionId: String,
213
- apduBase64: String,
214
- triggersDisconnection: Boolean,
215
- abortTimeout: Int,
216
- promise: Promise
217
- ) {
218
- // Log PERF: "Timestamp of the start of the function"
219
- loggerService.log(
220
- buildSimpleDebugLogInfo(
221
- "AndroidUsbTransport",
222
- "PERF: [@ReactMethod sendApdu] called at ${System.currentTimeMillis()}",
223
- )
224
- )
225
- fun logEnd() = run {
226
- loggerService.log(
227
- buildSimpleDebugLogInfo(
228
- "AndroidUsbTransport",
229
- "PERF: [@ReactMethod sendApdu] finished at ${System.currentTimeMillis()}",
230
- )
231
- )
232
- }
233
-
209
+ fun sendApdu(sessionId: String, apduBase64: String, promise: Promise) {
234
210
  try {
235
211
  val device = connectedDevices.firstOrNull() { it.id == sessionId }
236
212
  if (device == null) {
@@ -240,20 +216,15 @@ class TransportHidModule(
240
216
  coroutineScope.launch {
241
217
  try {
242
218
  val apdu: ByteArray = Base64.decode(apduBase64, Base64.DEFAULT)
243
- val abortTimeoutDuration = if (abortTimeout <= 0) Duration.INFINITE else abortTimeout.milliseconds
244
- val res =
245
- device.sendApduFn(apdu, triggersDisconnection, abortTimeoutDuration)
246
- logEnd()
219
+ val res = device.sendApduFn(apdu)
247
220
  promise.resolve(res.toWritableMap())
248
221
  } catch (e: Exception) {
249
222
  Timber.i("$e, ${e.cause}")
250
- logEnd()
251
223
  promise.reject(e)
252
224
  }
253
225
  }
254
226
  } catch (e: Exception) {
255
227
  Timber.i("$e, ${e.cause}")
256
- logEnd()
257
228
  promise.reject(e)
258
229
  }
259
230
  }
@@ -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,29 +138,14 @@ 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})"
188
- )
189
- )
148
+ loggerService.log(buildSimpleInfoLogInfo("AndroidUsbTransport", "Reconnecting device (sessionId=${deviceConnection.sessionId})"))
190
149
  deviceConnection.handleDeviceConnected(
191
150
  AndroidUsbApduSender(
192
151
  dependencies = AndroidUsbApduSender.Dependencies(
@@ -236,12 +195,7 @@ internal class DefaultAndroidUsbTransport(
236
195
  device = usbDevice,
237
196
  )
238
197
 
239
- loggerService.log(
240
- buildSimpleDebugLogInfo(
241
- "AndroidUsbTransport",
242
- "Waiting for permission result"
243
- )
244
- )
198
+ loggerService.log(buildSimpleDebugLogInfo("AndroidUsbTransport", "Waiting for permission result"))
245
199
 
246
200
  val result = eventsFlow.first {
247
201
  it is UsbPermissionEvent.PermissionGranted ||
@@ -275,33 +229,12 @@ internal class DefaultAndroidUsbTransport(
275
229
  }
276
230
 
277
231
  override suspend fun connect(discoveryDevice: DiscoveryDevice): InternalConnectionResult {
278
-
279
- loggerService.log(
280
- buildSimpleDebugLogInfo(
281
- "AndroidUsbTransport",
282
- "[connect] discoveryDevice=$discoveryDevice"
283
- )
284
- )
285
-
286
- val usbDevices = usbManager.deviceList.values
287
-
288
- var usbDevice: UsbDevice? =
289
- usbDevices.firstOrNull { it.deviceId == discoveryDevice.uid.toInt() }
290
-
291
- if (usbDevice == null) {
292
- // This is useful for LL during the OS update
293
- loggerService.log(buildSimpleDebugLogInfo("AndroidUsbTransport", "[connect] No device found with matching id, looking for device with matching model"))
294
- usbDevice =
295
- usbDevices.firstOrNull { it.toLedgerUsbDevice()?.ledgerDevice == discoveryDevice.ledgerDevice }
296
- } else {
297
- loggerService.log(buildSimpleDebugLogInfo("AndroidUsbTransport", "[connect] Found device with matching id"))
298
- }
232
+ val usbDevice: UsbDevice? =
233
+ usbManager.deviceList.values.firstOrNull { it.deviceId == discoveryDevice.uid.toInt() }
299
234
 
300
235
  val ledgerUsbDevice = usbDevice?.toLedgerUsbDevice()
301
236
 
302
237
  return if (usbDevice == null || ledgerUsbDevice == null) {
303
- loggerService.log(
304
- buildSimpleDebugLogInfo("AndroidUsbTransport", "[connect] No device found"))
305
238
  InternalConnectionResult.ConnectionError(error = InternalConnectionResult.Failure.DeviceNotFound)
306
239
  } else {
307
240
  val permissionResult = checkOrRequestPermission(usbDevice)
@@ -326,10 +259,9 @@ internal class DefaultAndroidUsbTransport(
326
259
  val deviceConnection = DeviceConnection(
327
260
  sessionId = sessionId,
328
261
  deviceApduSender = apduSender,
329
- isFatalSendApduFailure = { false },
262
+ isFatalSendApduFailure = { false }, // TODO: refine this
330
263
  reconnectionTimeoutDuration = 5.seconds,
331
264
  onTerminated = {
332
- (it.getApduSender() as AndroidUsbApduSender).release()
333
265
  usbConnections.remove(sessionId)
334
266
  usbConnectionsPendingReconnection.remove(it)
335
267
  eventDispatcher.dispatch(TransportEvent.DeviceConnectionLost(sessionId))
@@ -344,9 +276,7 @@ internal class DefaultAndroidUsbTransport(
344
276
  discoveryDevice.name,
345
277
  discoveryDevice.ledgerDevice,
346
278
  discoveryDevice.connectivityType,
347
- sendApduFn = { apdu: ByteArray, triggersDisconnection: Boolean, abortTimeoutDuration: Duration ->
348
- deviceConnection.requestSendApdu(apdu, triggersDisconnection, abortTimeoutDuration)
349
- }
279
+ sendApduFn = { apdu -> deviceConnection.requestSendApdu(apdu) },
350
280
  )
351
281
 
352
282
  usbConnections[sessionId] = deviceConnection
@@ -13,22 +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
- import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleDebugLogInfo
22
22
  import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleErrorLogInfo
23
+ import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleInfoLogInfo
23
24
  import com.ledger.devicesdk.shared.internal.transport.framer.FramerService
24
25
  import com.ledger.devicesdk.shared.internal.transport.framer.to2BytesArray
25
- import kotlinx.coroutines.CoroutineDispatcher
26
- import kotlinx.coroutines.delay
27
- import kotlinx.coroutines.launch
28
- import kotlinx.coroutines.withContext
29
26
  import java.nio.ByteBuffer
30
27
  import kotlin.random.Random
31
- import kotlin.time.Duration
28
+ import kotlinx.coroutines.CoroutineDispatcher
29
+ import kotlinx.coroutines.withContext
30
+ import timber.log.Timber
32
31
 
33
32
  private const val USB_TIMEOUT = 500
34
33
 
@@ -36,116 +35,71 @@ private const val DEFAULT_USB_INTERFACE = 0
36
35
 
37
36
  internal class AndroidUsbApduSender(
38
37
  override val dependencies: Dependencies,
39
- usbManager: UsbManager,
38
+ private val usbManager: UsbManager,
40
39
  private val framerService: FramerService,
41
40
  private val request: UsbRequest,
42
41
  private val ioDispatcher: CoroutineDispatcher,
43
42
  private val loggerService: LoggerService,
44
43
  ) : DeviceApduSender<AndroidUsbApduSender.Dependencies> {
44
+
45
45
  data class Dependencies(
46
46
  val usbDevice: UsbDevice,
47
47
  val ledgerUsbDevice: LedgerUsbDevice,
48
48
  )
49
49
 
50
- private val usbDevice = dependencies.usbDevice
51
- private val usbInterface = usbDevice.getInterface(DEFAULT_USB_INTERFACE)
52
- private val androidToUsbEndpoint =
53
- usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_OUT }
54
- private val usbToAndroidEndpoint =
55
- usbInterface.firstEndpointOrThrow { it == UsbConstants.USB_DIR_IN }
56
- private val usbConnection = usbManager.openDevice(usbDevice)
57
- .apply { claimInterface(usbInterface, true) }
58
-
59
-
60
- fun release() {
61
- usbConnection.releaseInterface(usbInterface)
62
- usbConnection.close()
63
- }
64
-
65
- override suspend fun send(apdu: ByteArray, abortTimeoutDuration: Duration): SendApduResult {
66
- val t1 = System.currentTimeMillis()
67
- return try {
50
+ override suspend fun send(apdu: ByteArray): SendApduResult =
51
+ try {
52
+ val usbDevice = dependencies.usbDevice
68
53
  withContext(context = ioDispatcher) {
69
-
70
- val timeoutJob = launch {
71
- delay(abortTimeoutDuration)
72
- throw SendApduTimeoutException
73
- }
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) }
74
58
 
75
59
  transmitApdu(
76
60
  usbConnection = usbConnection,
77
61
  androidToUsbEndpoint = androidToUsbEndpoint,
78
62
  rawApdu = apdu,
79
63
  )
80
-
81
64
  val apduResponse =
82
65
  receiveApdu(
83
66
  usbConnection = usbConnection,
84
67
  usbToAndroidEndpoint = usbToAndroidEndpoint,
85
68
  )
86
- timeoutJob.cancel()
87
69
 
88
- if (apduResponse.isEmpty()) {
89
- return@withContext SendApduResult.Failure(reason = SendApduFailureReason.EmptyResponse)
90
- }
70
+ usbConnection.releaseInterface(usbInterface)
71
+ usbConnection.close()
91
72
 
92
- return@withContext SendApduResult.Success(apdu = apduResponse)
73
+ SendApduResult.Success(apdu = apduResponse)
93
74
  }
94
- } catch (e: SendApduTimeoutException) {
95
- loggerService.log(
96
- buildSimpleErrorLogInfo(
97
- "AndroidUsbApduSender",
98
- "timeout in send: $e"
99
- )
100
- )
101
- SendApduResult.Failure(reason = SendApduFailureReason.AbortTimeout)
102
75
  } catch (e: NoSuchElementException) {
103
- loggerService.log(
104
- buildSimpleErrorLogInfo(
105
- "AndroidUsbApduSender",
106
- "no endpoint found: $e"
107
- )
108
- )
109
76
  SendApduResult.Failure(reason = SendApduFailureReason.NoUsbEndpointFound)
110
77
  } catch (e: Exception) {
111
78
  loggerService.log(buildSimpleErrorLogInfo("AndroidUsbApduSender", "error in send: $e"))
112
79
  SendApduResult.Failure(reason = SendApduFailureReason.Unknown)
113
- } finally {
114
- val t2 = System.currentTimeMillis()
115
- loggerService.log(buildSimpleDebugLogInfo("AndroidUsbApduSender", "PERF: [native sendApdu total]: ${t2 - t1}"))
116
80
  }
117
- }
118
81
 
119
82
  private fun transmitApdu(
120
83
  usbConnection: UsbDeviceConnection,
121
84
  androidToUsbEndpoint: UsbEndpoint,
122
85
  rawApdu: ByteArray,
123
86
  ) {
124
- val t1 = System.currentTimeMillis()
125
- framerService.serialize(mtu = USB_MTU, channelId = generateChannelId(), rawApdu = rawApdu)
126
- .forEach { apduFrame ->
127
- val buffer = apduFrame.toByteArray()
128
- usbConnection.bulkTransfer(
129
- androidToUsbEndpoint,
130
- buffer,
131
- apduFrame.size(),
132
- USB_TIMEOUT
133
- )
134
- }
135
- val t2 = System.currentTimeMillis()
136
- loggerService.log(buildSimpleDebugLogInfo("AndroidUsbApduSender", "PERF: [transmitApdu]: ${t2 - t1}"))
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
+ }
137
92
  }
138
93
 
139
94
  private fun receiveApdu(
140
95
  usbConnection: UsbDeviceConnection,
141
96
  usbToAndroidEndpoint: UsbEndpoint,
142
- ): ByteArray {
143
- return if (!request.initialize(usbConnection, usbToAndroidEndpoint)) {
97
+ ): ByteArray =
98
+ if (!request.initialize(usbConnection, usbToAndroidEndpoint)) {
144
99
  request.close()
145
100
  byteArrayOf()
146
101
  } else {
147
- val t1 = System.currentTimeMillis()
148
- val frames = framerService.createApduFrames(mtu = USB_MTU, isUsbTransport = true) {
102
+ val frames = framerService.createApduFrames(mtu = USB_MTU, isUsbTransport = true){
149
103
  val buffer = ByteArray(USB_MTU)
150
104
  val responseBuffer = ByteBuffer.allocate(USB_MTU)
151
105
 
@@ -153,19 +107,16 @@ internal class AndroidUsbApduSender(
153
107
  if (!queuingResult) {
154
108
  request.close()
155
109
  byteArrayOf()
156
- } else {
110
+ }
111
+ else{
157
112
  usbConnection.requestWait()
158
113
  responseBuffer.rewind()
159
114
  responseBuffer.get(buffer, 0, responseBuffer.remaining())
160
115
  buffer
161
116
  }
162
117
  }
163
- val result = framerService.deserialize(mtu = USB_MTU, frames)
164
- val t2 = System.currentTimeMillis()
165
- loggerService.log(buildSimpleDebugLogInfo("AndroidUsbApduSender", "PERF: [receiveApdu]: ${t2 - t1}"))
166
- result
118
+ framerService.deserialize(mtu = USB_MTU, frames)
167
119
  }
168
- }
169
120
 
170
121
  private fun UsbInterface.firstEndpointOrThrow(predicate: (Int) -> Boolean): UsbEndpoint {
171
122
  for (endp in 0..this.endpointCount) {
@@ -178,10 +129,5 @@ internal class AndroidUsbApduSender(
178
129
  throw NoSuchElementException("No endpoint matching the predicate")
179
130
  }
180
131
 
181
- private fun generateChannelId(): ByteArray =
182
- Random.nextInt(0, until = Int.MAX_VALUE).to2BytesArray()
183
-
184
- private data object SendApduTimeoutException : Exception() {
185
- private fun readResolve(): Any = SendApduTimeoutException
186
- }
132
+ private fun generateChannelId(): ByteArray = Random.nextInt(0, until = Int.MAX_VALUE).to2BytesArray()
187
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
  )
@@ -12,7 +12,7 @@ import kotlinx.coroutines.launch
12
12
  import kotlin.time.Duration
13
13
 
14
14
  internal class DeviceConnectionStateMachine(
15
- private val sendApduFn: (apdu: ByteArray, abortTimeoutDuration: Duration) -> Unit,
15
+ private val sendApduFn: (apdu: ByteArray) -> Unit,
16
16
  private val onTerminated: () -> Unit,
17
17
  private val isFatalSendApduFailure: (SendApduResult.Failure) -> Boolean,
18
18
  private val reconnectionTimeoutDuration: Duration,
@@ -29,7 +29,7 @@ internal class DeviceConnectionStateMachine(
29
29
  when (newState) {
30
30
  is State.Connected -> {}
31
31
  is State.SendingApdu -> {
32
- sendApduFn(newState.requestContent.apdu, newState.requestContent.abortTimeoutDuration)
32
+ sendApduFn(newState.requestContent.apdu)
33
33
  }
34
34
 
35
35
  is State.WaitingForReconnection -> {
@@ -240,7 +240,7 @@ internal class DeviceConnectionStateMachine(
240
240
  -> Event: $event
241
241
  -> New state: $state
242
242
  """.trimIndent()
243
- // loggerService.log(buildSimpleDebugLogInfo("DeviceConnectionStateMachine", logMessage))
243
+ loggerService.log(buildSimpleDebugLogInfo("DeviceConnectionStateMachine", logMessage))
244
244
  }
245
245
 
246
246
  private var timeoutJob: Job? = null
@@ -280,7 +280,6 @@ internal class DeviceConnectionStateMachine(
280
280
  data class SendApduRequestContent(
281
281
  val apdu: ByteArray,
282
282
  val triggersDisconnection: Boolean,
283
- val abortTimeoutDuration: Duration,
284
283
  val resultCallback: (SendApduResult) -> Unit
285
284
  )
286
285
 
@@ -44,8 +44,4 @@ public sealed class SendApduFailureReason {
44
44
  public data object DeviceDisconnected : SendApduFailureReason()
45
45
 
46
46
  public data object Unknown : SendApduFailureReason()
47
-
48
- public data object AbortTimeout : SendApduFailureReason()
49
-
50
- public data object EmptyResponse : SendApduFailureReason()
51
47
  }
@@ -8,7 +8,7 @@ package com.ledger.devicesdk.shared.api.discovery
8
8
  import com.ledger.devicesdk.shared.api.device.LedgerDevice
9
9
  import kotlinx.datetime.Clock
10
10
 
11
- public data class DiscoveryDevice(
11
+ public class DiscoveryDevice(
12
12
  public val uid: String,
13
13
  public val name: String,
14
14
  public val ledgerDevice: LedgerDevice,
@@ -9,5 +9,5 @@ internal data class InternalConnectedDevice(
9
9
  val name: String,
10
10
  val ledgerDevice: LedgerDevice,
11
11
  val connectivity: ConnectivityType,
12
- val sendApduFn: suspend (apdu: ByteArray, triggersDisconnection: Boolean, abortTimeoutDuration: kotlin.time.Duration) -> SendApduResult,
12
+ val sendApduFn: suspend (ByteArray) -> SendApduResult,
13
13
  )