@ledgerhq/device-transport-kit-react-native-hid 0.0.0-rn-hid-20250221115747 → 0.0.0-rnhid-transport-20250411151739

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 (18) hide show
  1. package/README.md +1 -1
  2. package/android/build.gradle +3 -1
  3. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/DefaultAndroidUsbTransport.kt +16 -22
  4. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/controller/UsbPermissionReceiver.kt +1 -1
  5. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/utils/UsbDeviceMapper.kt +27 -36
  6. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/UsbConst.android.kt +1 -1
  7. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnection.kt +6 -7
  8. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionStateMachine.kt +5 -2
  9. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/device/LedgerDevice.kt +64 -49
  10. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/device/UsbInfo.kt +4 -3
  11. package/android/src/test/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionStateMachineTest.kt +713 -0
  12. package/android/src/test/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionTest.kt +218 -0
  13. package/lib/cjs/package.json +1 -1
  14. package/lib/esm/package.json +1 -1
  15. package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
  16. package/package.json +4 -4
  17. package/android/.settings/org.eclipse.buildship.core.prefs +0 -13
  18. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/DeviceAction.kt +0 -23
package/README.md CHANGED
@@ -35,7 +35,7 @@ The transport itself is only compatible with Android devices but there is no add
35
35
 
36
36
  ### Pre-requisites
37
37
 
38
- To use this transport, ensure you have the Device Magement Kit installed in your project.
38
+ To use this transport, ensure you have the Device Management Kit installed in your project.
39
39
 
40
40
  #### AndroidManifest.xml
41
41
 
@@ -93,7 +93,9 @@ dependencies {
93
93
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_stdlib_version"
94
94
  implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
95
95
  implementation "org.jetbrains.kotlinx:kotlinx-datetime:$kotlinx_datetime_version"
96
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlin_coroutines_test_version"
97
96
  implementation "com.jakewharton.timber:timber:$timber_version"
98
97
  implementation "com.ditchoom:buffer:$buffer_version"
98
+ testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
99
+ testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlin_coroutines_test_version"
100
+ testImplementation "junit:junit:4.13.2"
99
101
  }
@@ -9,13 +9,6 @@ import android.app.Application
9
9
  import android.hardware.usb.UsbDevice
10
10
  import android.hardware.usb.UsbManager
11
11
  import android.hardware.usb.UsbRequest
12
- import com.ledger.devicesdk.shared.api.discovery.DiscoveryDevice
13
- import com.ledger.devicesdk.shared.internal.connection.InternalConnectedDevice
14
- import com.ledger.devicesdk.shared.internal.connection.InternalConnectionResult
15
- import com.ledger.devicesdk.shared.internal.event.SdkEventDispatcher
16
- import com.ledger.devicesdk.shared.internal.service.logger.LoggerService
17
- import com.ledger.devicesdk.shared.internal.transport.TransportEvent
18
- import com.ledger.devicesdk.shared.internal.transport.framer.FramerService
19
12
  import com.ledger.devicesdk.shared.androidMain.transport.usb.connection.AndroidUsbApduSender
20
13
  import com.ledger.devicesdk.shared.androidMain.transport.usb.model.LedgerUsbDevice
21
14
  import com.ledger.devicesdk.shared.androidMain.transport.usb.model.UsbPermissionEvent
@@ -24,11 +17,16 @@ import com.ledger.devicesdk.shared.androidMain.transport.usb.utils.toLedgerUsbDe
24
17
  import com.ledger.devicesdk.shared.androidMain.transport.usb.utils.toScannedDevice
25
18
  import com.ledger.devicesdk.shared.androidMain.transport.usb.utils.toUsbDevices
26
19
  import com.ledger.devicesdk.shared.androidMainInternal.transport.deviceconnection.DeviceConnection
20
+ import com.ledger.devicesdk.shared.api.discovery.DiscoveryDevice
21
+ import com.ledger.devicesdk.shared.internal.connection.InternalConnectedDevice
22
+ import com.ledger.devicesdk.shared.internal.connection.InternalConnectionResult
23
+ import com.ledger.devicesdk.shared.internal.event.SdkEventDispatcher
24
+ import com.ledger.devicesdk.shared.internal.service.logger.LoggerService
27
25
  import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleDebugLogInfo
28
- import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleErrorLogInfo
29
26
  import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleInfoLogInfo
30
27
  import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleWarningLogInfo
31
- import kotlin.time.Duration
28
+ import com.ledger.devicesdk.shared.internal.transport.TransportEvent
29
+ import com.ledger.devicesdk.shared.internal.transport.framer.FramerService
32
30
  import kotlinx.coroutines.CoroutineDispatcher
33
31
  import kotlinx.coroutines.CoroutineScope
34
32
  import kotlinx.coroutines.Dispatchers
@@ -41,11 +39,10 @@ import kotlinx.coroutines.flow.MutableStateFlow
41
39
  import kotlinx.coroutines.flow.SharingStarted
42
40
  import kotlinx.coroutines.flow.first
43
41
  import kotlinx.coroutines.flow.merge
44
- import kotlinx.coroutines.flow.onStart
45
42
  import kotlinx.coroutines.flow.shareIn
46
43
  import kotlinx.coroutines.isActive
47
44
  import kotlinx.coroutines.launch
48
- import kotlin.math.log
45
+ import kotlin.time.Duration
49
46
  import kotlin.time.Duration.Companion.seconds
50
47
 
51
48
  internal class DefaultAndroidUsbTransport(
@@ -55,25 +52,23 @@ internal class DefaultAndroidUsbTransport(
55
52
  private val eventDispatcher: SdkEventDispatcher,
56
53
  private val loggerService: LoggerService,
57
54
  private val scanDelay: Duration,
58
- coroutineDispatcher: CoroutineDispatcher,
55
+ private val coroutineDispatcher: CoroutineDispatcher,
59
56
  ) : AndroidUsbTransport {
60
57
  private val scope = CoroutineScope(coroutineDispatcher + SupervisorJob())
61
58
  private val internalUsbEventFlow: MutableSharedFlow<UsbState> = MutableSharedFlow()
62
59
  private val internalUsbPermissionEventFlow: MutableSharedFlow<UsbPermissionEvent> =
63
60
  MutableSharedFlow()
64
61
 
65
- @Suppress("BackingPropertyName")
66
- private var _scanStateFlow: MutableStateFlow<List<DiscoveryDevice>> =
67
- MutableStateFlow(emptyList())
68
- private var discoveryJob: Job? = null
69
62
  private val usbConnections: MutableMap<String, DeviceConnection<AndroidUsbApduSender.Dependencies>> =
70
63
  mutableMapOf()
71
64
  private val usbConnectionsPendingReconnection: MutableSet<DeviceConnection<AndroidUsbApduSender.Dependencies>> =
72
65
  mutableSetOf()
73
66
 
67
+ private var discoveryJob: Job? = null
68
+
74
69
  override fun startScan(): Flow<List<DiscoveryDevice>> {
70
+ val scanStateFlow = MutableStateFlow<List<DiscoveryDevice>>(emptyList())
75
71
  discoveryJob?.cancel()
76
- _scanStateFlow.value = emptyList()
77
72
  discoveryJob =
78
73
  scope.launch {
79
74
  while (isActive) {
@@ -86,12 +81,12 @@ internal class DefaultAndroidUsbTransport(
86
81
  }.isEmpty()
87
82
  }.toUsbDevices()
88
83
 
89
- _scanStateFlow.value = devices.toScannedDevices()
84
+ scanStateFlow.value = devices.toScannedDevices()
90
85
 
91
86
  delay(scanDelay)
92
87
  }
93
88
  }
94
- return _scanStateFlow
89
+ return scanStateFlow
95
90
  }
96
91
 
97
92
  override fun stopScan() {
@@ -151,7 +146,7 @@ internal class DefaultAndroidUsbTransport(
151
146
  return@launch
152
147
  }
153
148
  loggerService.log(buildSimpleInfoLogInfo("AndroidUsbTransport", "Reconnecting device (sessionId=${deviceConnection.sessionId})"))
154
- deviceConnection.setApduSender(
149
+ deviceConnection.handleDeviceConnected(
155
150
  AndroidUsbApduSender(
156
151
  dependencies = AndroidUsbApduSender.Dependencies(
157
152
  usbDevice = usbDevice,
@@ -164,7 +159,6 @@ internal class DefaultAndroidUsbTransport(
164
159
  loggerService = loggerService
165
160
  )
166
161
  )
167
- deviceConnection.handleDeviceConnected()
168
162
  usbConnectionsPendingReconnection.remove(deviceConnection)
169
163
  usbConnections[deviceConnection.sessionId] = deviceConnection
170
164
  }
@@ -272,7 +266,7 @@ internal class DefaultAndroidUsbTransport(
272
266
  usbConnectionsPendingReconnection.remove(it)
273
267
  eventDispatcher.dispatch(TransportEvent.DeviceConnectionLost(sessionId))
274
268
  },
275
- coroutineScope = scope,
269
+ coroutineDispatcher = coroutineDispatcher,
276
270
  loggerService = loggerService,
277
271
  )
278
272
 
@@ -42,7 +42,7 @@ internal class UsbPermissionReceiver(
42
42
  context,
43
43
  this,
44
44
  IntentFilter(ACTION_USB_PERMISSION),
45
- ACTION_USB_PERMISSION,
45
+ null,
46
46
  null,
47
47
  ContextCompat.RECEIVER_NOT_EXPORTED,
48
48
  )
@@ -5,51 +5,42 @@
5
5
 
6
6
  package com.ledger.devicesdk.shared.androidMain.transport.usb.utils
7
7
 
8
- import com.ledger.devicesdk.shared.api.device.LedgerDevice
9
8
  import com.ledger.devicesdk.shared.androidMain.transport.usb.model.ProductId
9
+ import com.ledger.devicesdk.shared.api.device.LedgerDevice
10
10
 
11
11
  internal fun ProductId.toLedgerDevice(): LedgerDevice? =
12
- when {
13
- this.id.isLedgerDeviceProductId(LedgerDevice.NanoS)
14
- -> {
15
- LedgerDevice.NanoS
16
- }
17
-
18
- this.id.isLedgerDeviceProductId(LedgerDevice.NanoSPlus)
19
- -> {
20
- LedgerDevice.NanoSPlus
12
+ when {
13
+ this.id.isLedgerDeviceProductId(LedgerDevice.NanoS) -> {
14
+ LedgerDevice.NanoS
15
+ }
16
+ this.id.isLedgerDeviceProductId(LedgerDevice.NanoSPlus) -> {
17
+ LedgerDevice.NanoSPlus
18
+ }
19
+ this.id.isLedgerDeviceProductId(LedgerDevice.NanoX) -> {
20
+ LedgerDevice.NanoX
21
+ }
22
+ this.id.isLedgerDeviceProductId(LedgerDevice.Stax) -> {
23
+ LedgerDevice.Stax
24
+ }
25
+ this.id.isLedgerDeviceProductId(LedgerDevice.Flex) -> {
26
+ LedgerDevice.Flex
27
+ }
28
+ else -> {
29
+ null
30
+ }
21
31
  }
22
32
 
23
- this.id.isLedgerDeviceProductId(LedgerDevice.NanoX)
24
- -> {
25
- LedgerDevice.NanoX
26
- }
27
-
28
- this.id.isLedgerDeviceProductId(LedgerDevice.Stax)
29
- -> {
30
- LedgerDevice.Stax
31
- }
32
-
33
- this.id.isLedgerDeviceProductId(LedgerDevice.Flex)
34
- -> {
35
- LedgerDevice.Flex
36
- }
37
-
38
- else -> {
39
- null
40
- }
41
- }
42
-
43
33
  private fun Int.isLedgerDeviceProductId(device: LedgerDevice): Boolean {
44
34
  val productId = device.usbInfo.productIdMask.sdkHexToInt()
35
+ val bootloaderProductId = device.usbInfo.bootloaderProductId.sdkHexToInt()
45
36
  val shiftedId = this shr 8
46
- return shiftedId == productId
37
+ return shiftedId == productId || this == bootloaderProductId
47
38
  }
48
39
 
49
40
  @OptIn(ExperimentalStdlibApi::class)
50
41
  public fun String.sdkHexToInt(withPrefix: Boolean = true): Int =
51
- if (withPrefix) {
52
- this.substring(2).hexToInt()
53
- } else {
54
- this.hexToInt()
55
- }
42
+ if (withPrefix) {
43
+ this.substring(2).hexToInt()
44
+ } else {
45
+ this.hexToInt()
46
+ }
@@ -5,4 +5,4 @@
5
5
 
6
6
  package com.ledger.devicesdk.shared.androidMainInternal.transport
7
7
 
8
- internal val USB_MTU: Int = 64
8
+ internal const val USB_MTU: Int = 64
@@ -3,6 +3,7 @@ package com.ledger.devicesdk.shared.androidMainInternal.transport.deviceconnecti
3
3
  import com.ledger.devicesdk.shared.api.apdu.SendApduResult
4
4
  import com.ledger.devicesdk.shared.internal.service.logger.LoggerService
5
5
  import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleErrorLogInfo
6
+ import kotlinx.coroutines.CoroutineDispatcher
6
7
  import kotlinx.coroutines.CoroutineScope
7
8
  import kotlinx.coroutines.launch
8
9
  import kotlin.coroutines.resume
@@ -14,11 +15,12 @@ internal class DeviceConnection<Dependencies>(
14
15
  private var deviceApduSender: DeviceApduSender<Dependencies>,
15
16
  isFatalSendApduFailure: (SendApduResult.Failure) -> Boolean,
16
17
  reconnectionTimeoutDuration: Duration,
18
+ coroutineDispatcher: CoroutineDispatcher,
17
19
  private val onTerminated: (DeviceConnection<Dependencies>) -> Unit,
18
- private val coroutineScope: CoroutineScope,
19
20
  private val loggerService: LoggerService,
20
21
  ) {
21
22
  private val stateMachine: DeviceConnectionStateMachine
23
+ private val coroutineScope = CoroutineScope(coroutineDispatcher)
22
24
 
23
25
  init {
24
26
  stateMachine = DeviceConnectionStateMachine(
@@ -33,7 +35,7 @@ internal class DeviceConnection<Dependencies>(
33
35
  },
34
36
  isFatalSendApduFailure = isFatalSendApduFailure,
35
37
  reconnectionTimeoutDuration = reconnectionTimeoutDuration,
36
- coroutineScope = coroutineScope,
38
+ coroutineDispatcher = coroutineDispatcher,
37
39
  onError = {
38
40
  loggerService.log(
39
41
  buildSimpleErrorLogInfo(
@@ -51,15 +53,12 @@ internal class DeviceConnection<Dependencies>(
51
53
  stateMachine.handleApduResult(result)
52
54
  }
53
55
 
54
- public fun setApduSender(apduSender: DeviceApduSender<Dependencies>) {
55
- deviceApduSender = apduSender
56
- }
57
-
58
56
  public fun getApduSender(): DeviceApduSender<Dependencies> {
59
57
  return deviceApduSender
60
58
  }
61
59
 
62
- public fun handleDeviceConnected() {
60
+ public fun handleDeviceConnected(apduSender: DeviceApduSender<Dependencies>) {
61
+ deviceApduSender = apduSender
63
62
  stateMachine.handleDeviceConnected()
64
63
  }
65
64
 
@@ -5,6 +5,7 @@ import com.ledger.devicesdk.shared.api.apdu.SendApduResult
5
5
  import com.ledger.devicesdk.shared.internal.service.logger.LoggerService
6
6
  import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleDebugLogInfo
7
7
  import com.ledger.devicesdk.shared.internal.service.logger.buildSimpleInfoLogInfo
8
+ import kotlinx.coroutines.CoroutineDispatcher
8
9
  import kotlinx.coroutines.CoroutineScope
9
10
  import kotlinx.coroutines.Job
10
11
  import kotlinx.coroutines.launch
@@ -15,13 +16,15 @@ internal class DeviceConnectionStateMachine(
15
16
  private val onTerminated: () -> Unit,
16
17
  private val isFatalSendApduFailure: (SendApduResult.Failure) -> Boolean,
17
18
  private val reconnectionTimeoutDuration: Duration,
18
- private val coroutineScope: CoroutineScope,
19
19
  private val onError: (Throwable) -> Unit,
20
20
  private val loggerService: LoggerService,
21
+ coroutineDispatcher: CoroutineDispatcher,
21
22
  ) {
22
-
23
+ private val coroutineScope = CoroutineScope(coroutineDispatcher)
23
24
  private var state: State = State.Connected
24
25
 
26
+ fun getState() = state
27
+
25
28
  private fun pushState(newState: State) {
26
29
  when (newState) {
27
30
  is State.Connected -> {}
@@ -1,62 +1,76 @@
1
1
  package com.ledger.devicesdk.shared.api.device
2
2
 
3
3
  public sealed class LedgerDevice(
4
- public val name: String,
5
- public val usbInfo: UsbInfo,
6
- public val bleInformation: BleInformation? = null,
4
+ public val name: String,
5
+ public val usbInfo: UsbInfo,
6
+ public val bleInformation: BleInformation? = null,
7
7
  ) {
8
- public data object Flex : LedgerDevice(
9
- name = "Ledger Flex",
10
- usbInfo = UsbInfo(LEDGER_USB_VENDOR_ID, "0x70"),
11
- bleInformation =
12
- BleInformation(
13
- serviceUuid = "13d63400-2c97-3004-0000-4c6564676572",
14
- notifyCharacteristicUuid = "13d63400-2c97-3004-0001-4c6564676572",
15
- writeWithResponseCharacteristicUuid = "13d63400-2c97-3004-0002-4c6564676572",
16
- writeWithoutResponseCharacteristicUuid = "13d63400-2c97-3004-0003-4c6564676572",
17
- ),
18
- )
8
+ public data object Flex :
9
+ LedgerDevice(
10
+ name = "Ledger Flex",
11
+ usbInfo = UsbInfo(LEDGER_USB_VENDOR_ID, "0x70", "0x0007"),
12
+ bleInformation =
13
+ BleInformation(
14
+ serviceUuid = "13d63400-2c97-3004-0000-4c6564676572",
15
+ notifyCharacteristicUuid =
16
+ "13d63400-2c97-3004-0001-4c6564676572",
17
+ writeWithResponseCharacteristicUuid =
18
+ "13d63400-2c97-3004-0002-4c6564676572",
19
+ writeWithoutResponseCharacteristicUuid =
20
+ "13d63400-2c97-3004-0003-4c6564676572",
21
+ ),
22
+ )
19
23
 
20
- public data object Stax : LedgerDevice(
21
- name = "Ledger Stax",
22
- usbInfo = UsbInfo(LEDGER_USB_VENDOR_ID, "0x60"),
23
- bleInformation =
24
- BleInformation(
25
- serviceUuid = "13d63400-2c97-6004-0000-4c6564676572",
26
- notifyCharacteristicUuid = "13d63400-2c97-6004-0001-4c6564676572",
27
- writeWithResponseCharacteristicUuid = "13d63400-2c97-6004-0002-4c6564676572",
28
- writeWithoutResponseCharacteristicUuid = "13d63400-2c97-6004-0003-4c6564676572",
29
- ),
30
- )
24
+ public data object Stax :
25
+ LedgerDevice(
26
+ name = "Ledger Stax",
27
+ usbInfo = UsbInfo(LEDGER_USB_VENDOR_ID, "0x60", "0x0006"),
28
+ bleInformation =
29
+ BleInformation(
30
+ serviceUuid = "13d63400-2c97-6004-0000-4c6564676572",
31
+ notifyCharacteristicUuid =
32
+ "13d63400-2c97-6004-0001-4c6564676572",
33
+ writeWithResponseCharacteristicUuid =
34
+ "13d63400-2c97-6004-0002-4c6564676572",
35
+ writeWithoutResponseCharacteristicUuid =
36
+ "13d63400-2c97-6004-0003-4c6564676572",
37
+ ),
38
+ )
31
39
 
32
- public data object NanoX : LedgerDevice(
33
- name = "Nano X",
34
- usbInfo = UsbInfo(LEDGER_USB_VENDOR_ID, "0x40"),
35
- bleInformation =
36
- BleInformation(
37
- serviceUuid = "13d63400-2c97-0004-0000-4c6564676572",
38
- notifyCharacteristicUuid = "13d63400-2c97-0004-0001-4c6564676572",
39
- writeWithResponseCharacteristicUuid = "13d63400-2c97-0004-0002-4c6564676572",
40
- writeWithoutResponseCharacteristicUuid = "13d63400-2c97-0004-0003-4c6564676572",
41
- ),
42
- )
40
+ public data object NanoX :
41
+ LedgerDevice(
42
+ name = "Nano X",
43
+ usbInfo = UsbInfo(LEDGER_USB_VENDOR_ID, "0x40", "0x0004"),
44
+ bleInformation =
45
+ BleInformation(
46
+ serviceUuid = "13d63400-2c97-0004-0000-4c6564676572",
47
+ notifyCharacteristicUuid =
48
+ "13d63400-2c97-0004-0001-4c6564676572",
49
+ writeWithResponseCharacteristicUuid =
50
+ "13d63400-2c97-0004-0002-4c6564676572",
51
+ writeWithoutResponseCharacteristicUuid =
52
+ "13d63400-2c97-0004-0003-4c6564676572",
53
+ ),
54
+ )
43
55
 
44
- public data object NanoSPlus : LedgerDevice(
45
- name = "Nano S Plus",
46
- usbInfo = UsbInfo(LEDGER_USB_VENDOR_ID, "0x50"),
47
- bleInformation = null,
48
- )
56
+ public data object NanoSPlus :
57
+ LedgerDevice(
58
+ name = "Nano S Plus",
59
+ usbInfo = UsbInfo(LEDGER_USB_VENDOR_ID, "0x50", "0x0005"),
60
+ bleInformation = null,
61
+ )
49
62
 
50
- public data object NanoS : LedgerDevice(
51
- name = "Nano S",
52
- usbInfo = UsbInfo(LEDGER_USB_VENDOR_ID, "0x10"),
53
- bleInformation = null,
54
- )
63
+ public data object NanoS :
64
+ LedgerDevice(
65
+ name = "Nano S",
66
+ usbInfo = UsbInfo(LEDGER_USB_VENDOR_ID, "0x10", "0x0001"),
67
+ bleInformation = null,
68
+ )
55
69
 
56
70
  public companion object {
57
71
  public const val LEDGER_USB_VENDOR_ID: String = "0x2c97"
58
72
 
59
- //Cannot use reflexion here to get all subclasses as it depends of the JVM
73
+ // Cannot use reflexion here to get all subclasses as it depends of the JVM
60
74
  private val subclasses = buildList {
61
75
  add(Flex)
62
76
  add(Stax)
@@ -69,6 +83,7 @@ public sealed class LedgerDevice(
69
83
  return subclasses
70
84
  }
71
85
 
72
- public fun getAllDevicesWithBluetooth(): List<LedgerDevice> = getAllDevices().filter { it.bleInformation != null }
86
+ public fun getAllDevicesWithBluetooth(): List<LedgerDevice> =
87
+ getAllDevices().filter { it.bleInformation != null }
73
88
  }
74
- }
89
+ }
@@ -1,6 +1,7 @@
1
1
  package com.ledger.devicesdk.shared.api.device
2
2
 
3
3
  public data class UsbInfo(
4
- val vendorId: String,
5
- val productIdMask: String,
6
- )
4
+ val vendorId: String,
5
+ val productIdMask: String,
6
+ val bootloaderProductId: String,
7
+ )