@ledgerhq/device-transport-kit-react-native-hid 0.0.0-develop-20250415001140

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 (181) hide show
  1. package/LICENSE.MD +202 -0
  2. package/README.md +84 -0
  3. package/android/build.gradle +101 -0
  4. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  5. package/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  6. package/android/gradle.properties +1 -0
  7. package/android/gradlew +252 -0
  8. package/android/gradlew.bat +94 -0
  9. package/android/src/main/AndroidManifest.xml +3 -0
  10. package/android/src/main/kotlin/com/ledger/androidtransporthid/BridgeEvents.kt +42 -0
  11. package/android/src/main/kotlin/com/ledger/androidtransporthid/TransportHidModule.kt +241 -0
  12. package/android/src/main/kotlin/com/ledger/androidtransporthid/TransportHidPackage.kt +25 -0
  13. package/android/src/main/kotlin/com/ledger/androidtransporthid/bridge/serialization.kt +124 -0
  14. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/AndroidUsbTransport.kt +16 -0
  15. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/DefaultAndroidUsbTransport.kt +298 -0
  16. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/UsbPermissionRequester.kt +18 -0
  17. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/connection/AndroidUsbApduSender.kt +133 -0
  18. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/controller/UsbAttachedReceiverController.kt +59 -0
  19. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/controller/UsbDetachedReceiverController.kt +58 -0
  20. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/controller/UsbPermissionReceiver.kt +92 -0
  21. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/model/LedgerUsbDevice.kt +16 -0
  22. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/model/ProductId.kt +11 -0
  23. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/model/UsbPermissionEvent.kt +14 -0
  24. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/model/UsbState.kt +16 -0
  25. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/model/VendorId.kt +11 -0
  26. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/utils/UsbDeviceMapper.kt +46 -0
  27. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMain/transport/usb/utils/UsbMapper.kt +56 -0
  28. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/UsbConst.android.kt +8 -0
  29. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceApduSender.kt +13 -0
  30. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnection.kt +95 -0
  31. package/android/src/main/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionStateMachine.kt +314 -0
  32. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/apdu/Apdu.kt +44 -0
  33. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/apdu/ApduBuilder.kt +88 -0
  34. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/apdu/ApduParser.kt +37 -0
  35. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/apdu/ApduUtils.kt +37 -0
  36. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/apdu/SendApduResult.kt +47 -0
  37. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/connection/ConnectedDevice.kt +25 -0
  38. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/connection/ConnectionResult.kt +45 -0
  39. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/device/BleInformation.kt +8 -0
  40. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/device/LedgerDevice.kt +89 -0
  41. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/device/UsbInfo.kt +7 -0
  42. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/disconnection/DisconnectionResult.kt +10 -0
  43. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/discovery/ConnectivityType.kt +10 -0
  44. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/discovery/DiscoveryDevice.kt +18 -0
  45. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/discovery/DiscoveryResult.kt +28 -0
  46. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/utils/ByteArrayExtension.kt +116 -0
  47. package/android/src/main/kotlin/com/ledger/devicesdk/shared/api/utils/StringExtension.kt +21 -0
  48. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/connection/InternalConnectedDevice.kt +13 -0
  49. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/connection/InternalConnectionResult.kt +41 -0
  50. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/coroutine/SDKScope.kt +25 -0
  51. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/coroutine/SDKScopeHandler.kt +18 -0
  52. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/event/SdkEventDispatcher.kt +19 -0
  53. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/service/logger/DisableLoggerService.kt +12 -0
  54. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/service/logger/LogInfo.kt +52 -0
  55. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/service/logger/LogLevel.kt +13 -0
  56. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/service/logger/LoggerService.kt +10 -0
  57. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/transport/Transport.kt +21 -0
  58. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/transport/TransportEvent.kt +18 -0
  59. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/transport/framer/FramerService.kt +210 -0
  60. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/transport/framer/FramerUtils.kt +35 -0
  61. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/transport/framer/model/ApduConst.kt +9 -0
  62. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/transport/framer/model/ApduFrame.kt +66 -0
  63. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/transport/framer/model/ApduFramerHeader.kt +74 -0
  64. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/transport/framer/model/FramerConst.kt +14 -0
  65. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/transport/utils/ByteExtension.kt +21 -0
  66. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/transport/utils/InternalByteArrayExtension.kt +18 -0
  67. package/android/src/main/kotlin/com/ledger/devicesdk/shared/internal/utils/Controller.kt +12 -0
  68. package/android/src/test/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionStateMachineTest.kt +713 -0
  69. package/android/src/test/kotlin/com/ledger/devicesdk/shared/androidMainInternal/transport/deviceconnection/DeviceConnectionTest.kt +218 -0
  70. package/lib/cjs/api/RNHidTransportFactory.js +2 -0
  71. package/lib/cjs/api/RNHidTransportFactory.js.map +7 -0
  72. package/lib/cjs/api/bridge/DefaultNativeModuleWrapper.js +2 -0
  73. package/lib/cjs/api/bridge/DefaultNativeModuleWrapper.js.map +7 -0
  74. package/lib/cjs/api/bridge/NativeTransportModule.js +2 -0
  75. package/lib/cjs/api/bridge/NativeTransportModule.js.map +7 -0
  76. package/lib/cjs/api/bridge/StubNativeModuleWrapper.js +2 -0
  77. package/lib/cjs/api/bridge/StubNativeModuleWrapper.js.map +7 -0
  78. package/lib/cjs/api/bridge/mapper.js +2 -0
  79. package/lib/cjs/api/bridge/mapper.js.map +7 -0
  80. package/lib/cjs/api/bridge/mapper.test.js +2 -0
  81. package/lib/cjs/api/bridge/mapper.test.js.map +7 -0
  82. package/lib/cjs/api/bridge/types.js +2 -0
  83. package/lib/cjs/api/bridge/types.js.map +7 -0
  84. package/lib/cjs/api/helpers/base64Utils.js +2 -0
  85. package/lib/cjs/api/helpers/base64Utils.js.map +7 -0
  86. package/lib/cjs/api/helpers/base64Utils.test.js +2 -0
  87. package/lib/cjs/api/helpers/base64Utils.test.js.map +7 -0
  88. package/lib/cjs/api/helpers/getObservableOfArraysNewItems.js +2 -0
  89. package/lib/cjs/api/helpers/getObservableOfArraysNewItems.js.map +7 -0
  90. package/lib/cjs/api/helpers/getObservableOfArraysNewItems.test.js +2 -0
  91. package/lib/cjs/api/helpers/getObservableOfArraysNewItems.test.js.map +7 -0
  92. package/lib/cjs/api/transport/Errors.js +2 -0
  93. package/lib/cjs/api/transport/Errors.js.map +7 -0
  94. package/lib/cjs/api/transport/NativeModuleWrapper.js +2 -0
  95. package/lib/cjs/api/transport/NativeModuleWrapper.js.map +7 -0
  96. package/lib/cjs/api/transport/RNHidTransport.js +2 -0
  97. package/lib/cjs/api/transport/RNHidTransport.js.map +7 -0
  98. package/lib/cjs/api/transport/RNHidTransport.test.js +2 -0
  99. package/lib/cjs/api/transport/RNHidTransport.test.js.map +7 -0
  100. package/lib/cjs/api/transport/rnHidTransportIdentifier.js +2 -0
  101. package/lib/cjs/api/transport/rnHidTransportIdentifier.js.map +7 -0
  102. package/lib/cjs/api/transport/types.js +2 -0
  103. package/lib/cjs/api/transport/types.js.map +7 -0
  104. package/lib/cjs/index.js +2 -0
  105. package/lib/cjs/index.js.map +7 -0
  106. package/lib/cjs/package.json +61 -0
  107. package/lib/esm/api/RNHidTransportFactory.js +2 -0
  108. package/lib/esm/api/RNHidTransportFactory.js.map +7 -0
  109. package/lib/esm/api/bridge/DefaultNativeModuleWrapper.js +2 -0
  110. package/lib/esm/api/bridge/DefaultNativeModuleWrapper.js.map +7 -0
  111. package/lib/esm/api/bridge/NativeTransportModule.js +2 -0
  112. package/lib/esm/api/bridge/NativeTransportModule.js.map +7 -0
  113. package/lib/esm/api/bridge/StubNativeModuleWrapper.js +2 -0
  114. package/lib/esm/api/bridge/StubNativeModuleWrapper.js.map +7 -0
  115. package/lib/esm/api/bridge/mapper.js +2 -0
  116. package/lib/esm/api/bridge/mapper.js.map +7 -0
  117. package/lib/esm/api/bridge/mapper.test.js +2 -0
  118. package/lib/esm/api/bridge/mapper.test.js.map +7 -0
  119. package/lib/esm/api/bridge/types.js +2 -0
  120. package/lib/esm/api/bridge/types.js.map +7 -0
  121. package/lib/esm/api/helpers/base64Utils.js +2 -0
  122. package/lib/esm/api/helpers/base64Utils.js.map +7 -0
  123. package/lib/esm/api/helpers/base64Utils.test.js +2 -0
  124. package/lib/esm/api/helpers/base64Utils.test.js.map +7 -0
  125. package/lib/esm/api/helpers/getObservableOfArraysNewItems.js +2 -0
  126. package/lib/esm/api/helpers/getObservableOfArraysNewItems.js.map +7 -0
  127. package/lib/esm/api/helpers/getObservableOfArraysNewItems.test.js +2 -0
  128. package/lib/esm/api/helpers/getObservableOfArraysNewItems.test.js.map +7 -0
  129. package/lib/esm/api/transport/Errors.js +2 -0
  130. package/lib/esm/api/transport/Errors.js.map +7 -0
  131. package/lib/esm/api/transport/NativeModuleWrapper.js +1 -0
  132. package/lib/esm/api/transport/NativeModuleWrapper.js.map +7 -0
  133. package/lib/esm/api/transport/RNHidTransport.js +2 -0
  134. package/lib/esm/api/transport/RNHidTransport.js.map +7 -0
  135. package/lib/esm/api/transport/RNHidTransport.test.js +2 -0
  136. package/lib/esm/api/transport/RNHidTransport.test.js.map +7 -0
  137. package/lib/esm/api/transport/rnHidTransportIdentifier.js +2 -0
  138. package/lib/esm/api/transport/rnHidTransportIdentifier.js.map +7 -0
  139. package/lib/esm/api/transport/types.js +1 -0
  140. package/lib/esm/api/transport/types.js.map +7 -0
  141. package/lib/esm/index.js +2 -0
  142. package/lib/esm/index.js.map +7 -0
  143. package/lib/esm/package.json +61 -0
  144. package/lib/types/api/RNHidTransportFactory.d.ts +3 -0
  145. package/lib/types/api/RNHidTransportFactory.d.ts.map +1 -0
  146. package/lib/types/api/bridge/DefaultNativeModuleWrapper.d.ts +22 -0
  147. package/lib/types/api/bridge/DefaultNativeModuleWrapper.d.ts.map +1 -0
  148. package/lib/types/api/bridge/NativeTransportModule.d.ts +3 -0
  149. package/lib/types/api/bridge/NativeTransportModule.d.ts.map +1 -0
  150. package/lib/types/api/bridge/StubNativeModuleWrapper.d.ts +15 -0
  151. package/lib/types/api/bridge/StubNativeModuleWrapper.d.ts.map +1 -0
  152. package/lib/types/api/bridge/mapper.d.ts +10 -0
  153. package/lib/types/api/bridge/mapper.d.ts.map +1 -0
  154. package/lib/types/api/bridge/mapper.test.d.ts +2 -0
  155. package/lib/types/api/bridge/mapper.test.d.ts.map +1 -0
  156. package/lib/types/api/bridge/types.d.ts +61 -0
  157. package/lib/types/api/bridge/types.d.ts.map +1 -0
  158. package/lib/types/api/helpers/base64Utils.d.ts +13 -0
  159. package/lib/types/api/helpers/base64Utils.d.ts.map +1 -0
  160. package/lib/types/api/helpers/base64Utils.test.d.ts +2 -0
  161. package/lib/types/api/helpers/base64Utils.test.d.ts.map +1 -0
  162. package/lib/types/api/helpers/getObservableOfArraysNewItems.d.ts +15 -0
  163. package/lib/types/api/helpers/getObservableOfArraysNewItems.d.ts.map +1 -0
  164. package/lib/types/api/helpers/getObservableOfArraysNewItems.test.d.ts +2 -0
  165. package/lib/types/api/helpers/getObservableOfArraysNewItems.test.d.ts.map +1 -0
  166. package/lib/types/api/transport/Errors.d.ts +7 -0
  167. package/lib/types/api/transport/Errors.d.ts.map +1 -0
  168. package/lib/types/api/transport/NativeModuleWrapper.d.ts +23 -0
  169. package/lib/types/api/transport/NativeModuleWrapper.d.ts.map +1 -0
  170. package/lib/types/api/transport/RNHidTransport.d.ts +23 -0
  171. package/lib/types/api/transport/RNHidTransport.d.ts.map +1 -0
  172. package/lib/types/api/transport/RNHidTransport.test.d.ts +2 -0
  173. package/lib/types/api/transport/RNHidTransport.test.d.ts.map +1 -0
  174. package/lib/types/api/transport/rnHidTransportIdentifier.d.ts +2 -0
  175. package/lib/types/api/transport/rnHidTransportIdentifier.d.ts.map +1 -0
  176. package/lib/types/api/transport/types.d.ts +12 -0
  177. package/lib/types/api/transport/types.d.ts.map +1 -0
  178. package/lib/types/index.d.ts +3 -0
  179. package/lib/types/index.d.ts.map +1 -0
  180. package/lib/types/tsconfig.prod.tsbuildinfo +1 -0
  181. package/package.json +60 -0
@@ -0,0 +1,94 @@
1
+ @rem
2
+ @rem Copyright 2015 the original author or authors.
3
+ @rem
4
+ @rem Licensed under the Apache License, Version 2.0 (the "License");
5
+ @rem you may not use this file except in compliance with the License.
6
+ @rem You may obtain a copy of the License at
7
+ @rem
8
+ @rem https://www.apache.org/licenses/LICENSE-2.0
9
+ @rem
10
+ @rem Unless required by applicable law or agreed to in writing, software
11
+ @rem distributed under the License is distributed on an "AS IS" BASIS,
12
+ @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ @rem See the License for the specific language governing permissions and
14
+ @rem limitations under the License.
15
+ @rem
16
+ @rem SPDX-License-Identifier: Apache-2.0
17
+ @rem
18
+
19
+ @if "%DEBUG%"=="" @echo off
20
+ @rem ##########################################################################
21
+ @rem
22
+ @rem Gradle startup script for Windows
23
+ @rem
24
+ @rem ##########################################################################
25
+
26
+ @rem Set local scope for the variables with windows NT shell
27
+ if "%OS%"=="Windows_NT" setlocal
28
+
29
+ set DIRNAME=%~dp0
30
+ if "%DIRNAME%"=="" set DIRNAME=.
31
+ @rem This is normally unused
32
+ set APP_BASE_NAME=%~n0
33
+ set APP_HOME=%DIRNAME%
34
+
35
+ @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36
+ for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37
+
38
+ @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39
+ set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40
+
41
+ @rem Find java.exe
42
+ if defined JAVA_HOME goto findJavaFromJavaHome
43
+
44
+ set JAVA_EXE=java.exe
45
+ %JAVA_EXE% -version >NUL 2>&1
46
+ if %ERRORLEVEL% equ 0 goto execute
47
+
48
+ echo. 1>&2
49
+ echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50
+ echo. 1>&2
51
+ echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52
+ echo location of your Java installation. 1>&2
53
+
54
+ goto fail
55
+
56
+ :findJavaFromJavaHome
57
+ set JAVA_HOME=%JAVA_HOME:"=%
58
+ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59
+
60
+ if exist "%JAVA_EXE%" goto execute
61
+
62
+ echo. 1>&2
63
+ echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64
+ echo. 1>&2
65
+ echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66
+ echo location of your Java installation. 1>&2
67
+
68
+ goto fail
69
+
70
+ :execute
71
+ @rem Setup the command line
72
+
73
+ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74
+
75
+
76
+ @rem Execute Gradle
77
+ "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78
+
79
+ :end
80
+ @rem End local scope for the variables with windows NT shell
81
+ if %ERRORLEVEL% equ 0 goto mainEnd
82
+
83
+ :fail
84
+ rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85
+ rem the _cmd.exe /c_ return code!
86
+ set EXIT_CODE=%ERRORLEVEL%
87
+ if %EXIT_CODE% equ 0 set EXIT_CODE=1
88
+ if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89
+ exit /b %EXIT_CODE%
90
+
91
+ :mainEnd
92
+ if "%OS%"=="Windows_NT" endlocal
93
+
94
+ :omega
@@ -0,0 +1,3 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <uses-feature android:name="android.hardware.usb.host" android:required="false"/>
3
+ </manifest>
@@ -0,0 +1,42 @@
1
+ package com.ledger.androidtransporthid
2
+
3
+ import com.facebook.react.bridge.ReactContext
4
+ import com.facebook.react.bridge.WritableArray
5
+ import com.facebook.react.bridge.WritableMap
6
+ import com.facebook.react.modules.core.DeviceEventManagerModule
7
+ import com.ledger.androidtransporthid.bridge.toWritableArray
8
+ import com.ledger.androidtransporthid.bridge.toWritableMap
9
+ import com.ledger.devicesdk.shared.api.discovery.DiscoveryDevice
10
+ import com.ledger.devicesdk.shared.internal.service.logger.LogInfo
11
+ import com.ledger.devicesdk.shared.internal.transport.TransportEvent
12
+
13
+ internal sealed class EventParams {
14
+ data class WMap(val map: WritableMap): EventParams()
15
+ data class WArray(val arr: WritableArray): EventParams()
16
+ data object Empty: EventParams()
17
+ }
18
+
19
+ internal sealed class BridgeEvents(val eventName: String, val params: EventParams) {
20
+ data class DiscoveredDevices(
21
+ val devices: List<DiscoveryDevice>,
22
+ ): BridgeEvents("DiscoveredDevices", EventParams.WArray(devices.toWritableArray()))
23
+ data class TransportLog(
24
+ val logInfo: LogInfo,
25
+ ): BridgeEvents("TransportLog", EventParams.WMap(logInfo.toWritableMap()));
26
+ data class DeviceDisconnected(
27
+ val deviceConnectionLost: TransportEvent.DeviceConnectionLost,
28
+ ): BridgeEvents("DeviceDisconnected", EventParams.WMap(deviceConnectionLost.toWritableMap()))
29
+ }
30
+
31
+ internal fun sendEvent(reactContext: ReactContext, bridgeEvent: BridgeEvents) {
32
+ reactContext
33
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
34
+ .emit(
35
+ bridgeEvent.eventName,
36
+ when (bridgeEvent.params) {
37
+ is EventParams.WMap -> bridgeEvent.params.map
38
+ is EventParams.WArray -> bridgeEvent.params.arr
39
+ is EventParams.Empty -> null
40
+ }
41
+ )
42
+ }
@@ -0,0 +1,241 @@
1
+ package com.ledger.androidtransporthid
2
+
3
+ import android.app.PendingIntent
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.hardware.usb.UsbManager
7
+ import android.util.Base64
8
+ import com.facebook.react.bridge.LifecycleEventListener
9
+ import com.facebook.react.bridge.Promise
10
+ import com.facebook.react.bridge.ReactApplicationContext
11
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
12
+ import com.facebook.react.bridge.ReactMethod
13
+ import com.ledger.androidtransporthid.bridge.toWritableMap
14
+ import com.ledger.devicesdk.shared.androidMain.transport.usb.AndroidUsbTransport
15
+ import com.ledger.devicesdk.shared.androidMain.transport.usb.DefaultAndroidUsbTransport
16
+ import com.ledger.devicesdk.shared.androidMain.transport.usb.controller.ACTION_USB_PERMISSION
17
+ import com.ledger.devicesdk.shared.androidMain.transport.usb.controller.UsbAttachedReceiverController
18
+ import com.ledger.devicesdk.shared.androidMain.transport.usb.controller.UsbDetachedReceiverController
19
+ import com.ledger.devicesdk.shared.androidMain.transport.usb.controller.UsbPermissionReceiver
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
25
+ import com.ledger.devicesdk.shared.internal.transport.TransportEvent
26
+ import kotlinx.coroutines.CoroutineScope
27
+ import kotlinx.coroutines.Dispatchers
28
+ import kotlinx.coroutines.Job
29
+ import kotlinx.coroutines.flow.launchIn
30
+ import kotlinx.coroutines.flow.onEach
31
+ import kotlinx.coroutines.launch
32
+ import timber.log.Timber
33
+ import kotlin.random.Random
34
+ import kotlin.time.Duration.Companion.milliseconds
35
+
36
+ class TransportHidModule(
37
+ private val reactContext: ReactApplicationContext,
38
+ private val coroutineScope: CoroutineScope
39
+ ) :
40
+ ReactContextBaseJavaModule(reactContext), LifecycleEventListener {
41
+ override fun getName(): String = "RCTTransportHIDModule"
42
+
43
+ private var usbPermissionReceiver: UsbPermissionReceiver? = null
44
+ private var usbAttachedReceiverController: UsbAttachedReceiverController? = null
45
+ private var usbDetachedReceiverController: UsbDetachedReceiverController? = null
46
+ private var sdkEventDispatcher: SdkEventDispatcher = SdkEventDispatcher()
47
+ private var eventDispatcherListeningJob: Job
48
+ private val loggerService: LoggerService =
49
+ LoggerService { info ->
50
+ Timber.tag("RNHIDModule " + info.tag).d(info.message)
51
+ sendEvent(reactContext, BridgeEvents.TransportLog(info))
52
+ }
53
+
54
+ private val transport: AndroidUsbTransport? by lazy {
55
+ val currentActivity = reactContext.currentActivity
56
+ val currentApplication = currentActivity?.application
57
+
58
+ var transport: AndroidUsbTransport? = null
59
+ if (currentApplication != null) {
60
+ val usbManager = reactContext.getSystemService(Context.USB_SERVICE) as UsbManager
61
+ transport = DefaultAndroidUsbTransport(
62
+ application = currentApplication,
63
+ usbManager = usbManager,
64
+ permissionRequester = { context, manager, device ->
65
+ manager.requestPermission(
66
+ device,
67
+ PendingIntent.getBroadcast(
68
+ context,
69
+ Random.nextInt(),
70
+ Intent(ACTION_USB_PERMISSION).apply {
71
+ setPackage(context.packageName)
72
+ },
73
+ PendingIntent.FLAG_IMMUTABLE,
74
+ ),
75
+ )
76
+ },
77
+ eventDispatcher = sdkEventDispatcher,
78
+ coroutineDispatcher = Dispatchers.IO,
79
+ loggerService = loggerService,
80
+ scanDelay = 500.milliseconds,
81
+ )
82
+ usbPermissionReceiver = UsbPermissionReceiver(
83
+ context = reactContext,
84
+ androidUsbTransport = transport,
85
+ usbManager = usbManager,
86
+ loggerService = loggerService
87
+ )
88
+ usbDetachedReceiverController = UsbDetachedReceiverController(
89
+ context = reactContext,
90
+ androidUsbTransport = transport,
91
+ )
92
+ usbAttachedReceiverController = UsbAttachedReceiverController(
93
+ context = reactContext,
94
+ androidUsbTransport = transport,
95
+ )
96
+ usbPermissionReceiver!!.start()
97
+ usbAttachedReceiverController!!.start()
98
+ usbDetachedReceiverController!!.start()
99
+ }
100
+ transport
101
+ }
102
+
103
+ private val discoveryDevices: MutableList<DiscoveryDevice> = mutableListOf()
104
+ private val connectedDevices: MutableList<InternalConnectedDevice> = mutableListOf()
105
+
106
+ init {
107
+ reactContext.addLifecycleEventListener(this)
108
+ Timber.plant(Timber.DebugTree())
109
+ eventDispatcherListeningJob = sdkEventDispatcher.listen().onEach {
110
+ when (it) {
111
+ is TransportEvent.DeviceConnectionLost -> {
112
+ Timber.tag("RNHIDModule")
113
+ Timber.i("TransportEvent.DeviceConnectionLost ${it.id}")
114
+ connectedDevices.removeIf { device -> device.id == it.id }
115
+ sendEvent(reactContext, BridgeEvents.DeviceDisconnected(it))
116
+ }
117
+
118
+ else -> {}
119
+ }
120
+ }.launchIn(scope = coroutineScope)
121
+ }
122
+
123
+ override fun onHostResume() {}
124
+
125
+ override fun onHostPause() {}
126
+
127
+ override fun onHostDestroy() {
128
+ usbPermissionReceiver?.stop()
129
+ usbAttachedReceiverController?.stop()
130
+ usbDetachedReceiverController?.stop()
131
+ eventDispatcherListeningJob.cancel()
132
+ transport?.stopScan()
133
+ }
134
+
135
+ private var discoveryCount = 0
136
+
137
+ @ReactMethod
138
+ fun startScan(promise: Promise) {
139
+ discoveryCount += 1
140
+ if (discoveryCount > 1) {
141
+ promise.resolve(null)
142
+ return
143
+ }
144
+ try {
145
+ transport!!.startScan().onEach {
146
+ discoveryDevices.clear()
147
+ discoveryDevices += it
148
+ sendEvent(reactContext, BridgeEvents.DiscoveredDevices(it))
149
+ }.launchIn(scope = coroutineScope)
150
+ promise.resolve(null)
151
+ } catch (e: Exception) {
152
+ promise.reject(e);
153
+ }
154
+ }
155
+
156
+ @ReactMethod
157
+ fun stopScan(promise: Promise) {
158
+ discoveryCount -= 1
159
+ if (discoveryCount > 0) {
160
+ promise.resolve(null)
161
+ return
162
+ }
163
+ try {
164
+ transport!!.stopScan()
165
+ promise.resolve(null)
166
+ } catch (e: Exception) {
167
+ promise.reject(e);
168
+ }
169
+ }
170
+
171
+ @ReactMethod()
172
+ fun connectDevice(uid: String, promise: Promise) {
173
+ val device = discoveryDevices.firstOrNull { it.uid == uid }
174
+ if (device == null) {
175
+ promise.reject(Exception("[TransportHidModule][connectDevice] Device not found"))
176
+ return
177
+ }
178
+
179
+ coroutineScope.launch {
180
+ try {
181
+ val connectionResult = transport!!.connect(device)
182
+ when (connectionResult) {
183
+ is InternalConnectionResult.Connected -> {
184
+ connectedDevices.add(connectionResult.device)
185
+ }
186
+
187
+ else -> {}
188
+ }
189
+ promise.resolve(connectionResult.toWritableMap())
190
+ } catch (e: Exception) {
191
+ promise.reject(e)
192
+ }
193
+ }
194
+ }
195
+
196
+ @ReactMethod
197
+ fun disconnectDevice(sessionId: String, promise: Promise) {
198
+ coroutineScope.launch {
199
+ try {
200
+ transport!!.disconnect(sessionId)
201
+ promise.resolve(null);
202
+ } catch (e: Exception) {
203
+ promise.reject(e)
204
+ }
205
+ }
206
+ }
207
+
208
+ @ReactMethod
209
+ fun sendApdu(sessionId: String, apduBase64: String, promise: Promise) {
210
+ try {
211
+ val device = connectedDevices.firstOrNull() { it.id == sessionId }
212
+ if (device == null) {
213
+ promise.reject(Exception("[TransportHidModule][sendApdu] Device not found"))
214
+ return
215
+ }
216
+ coroutineScope.launch {
217
+ try {
218
+ val apdu: ByteArray = Base64.decode(apduBase64, Base64.DEFAULT)
219
+ val res = device.sendApduFn(apdu)
220
+ promise.resolve(res.toWritableMap())
221
+ } catch (e: Exception) {
222
+ Timber.i("$e, ${e.cause}")
223
+ promise.reject(e)
224
+ }
225
+ }
226
+ } catch (e: Exception) {
227
+ Timber.i("$e, ${e.cause}")
228
+ promise.reject(e)
229
+ }
230
+ }
231
+
232
+ @ReactMethod
233
+ fun addListener(eventName: String) {
234
+ // Nothing to do in our case, but React Native will issue a warning if this isn't implemented
235
+ }
236
+
237
+ @ReactMethod
238
+ fun removeListeners(count: Int) {
239
+ // Nothing to do in our case, but React Native will issue a warning if this isn't implemented
240
+ }
241
+ }
@@ -0,0 +1,25 @@
1
+ package com.ledger.androidtransporthid
2
+
3
+ import android.view.View
4
+ import com.facebook.react.ReactPackage
5
+ import com.facebook.react.bridge.NativeModule
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.uimanager.ReactShadowNode
8
+ import com.facebook.react.uimanager.ViewManager
9
+ import kotlinx.coroutines.CoroutineScope
10
+ import kotlinx.coroutines.Dispatchers
11
+
12
+ class TransportHidPackage() : ReactPackage {
13
+ override fun createNativeModules(reactContext: ReactApplicationContext): MutableList<NativeModule> {
14
+ return mutableListOf(
15
+ TransportHidModule(
16
+ reactContext = reactContext,
17
+ coroutineScope = CoroutineScope(Dispatchers.Default)
18
+ )
19
+ )
20
+ }
21
+
22
+ override fun createViewManagers(p0: ReactApplicationContext): MutableList<ViewManager<View, ReactShadowNode<*>>> {
23
+ return mutableListOf()
24
+ }
25
+ }
@@ -0,0 +1,124 @@
1
+ package com.ledger.androidtransporthid.bridge
2
+
3
+ import android.util.Base64
4
+ import com.facebook.react.bridge.Arguments
5
+ import com.facebook.react.bridge.WritableArray
6
+ import com.facebook.react.bridge.WritableMap
7
+ import com.ledger.devicesdk.shared.api.apdu.SendApduFailureReason
8
+ import com.ledger.devicesdk.shared.api.apdu.SendApduResult
9
+ import com.ledger.devicesdk.shared.api.device.LedgerDevice
10
+ import com.ledger.devicesdk.shared.api.discovery.ConnectivityType
11
+ import com.ledger.devicesdk.shared.api.discovery.DiscoveryDevice
12
+ import com.ledger.devicesdk.shared.internal.connection.InternalConnectionResult
13
+ import com.ledger.devicesdk.shared.internal.service.logger.LogInfo
14
+ import com.ledger.devicesdk.shared.internal.service.logger.LogLevel
15
+ import com.ledger.devicesdk.shared.internal.transport.TransportEvent
16
+ import kotlinx.datetime.Clock
17
+
18
+ fun LedgerDevice.toWritableMap(): WritableMap =
19
+ Arguments.createMap().apply {
20
+ putString("name", name)
21
+ putString("usbProductIdMask", usbInfo.productIdMask)
22
+ }
23
+
24
+ fun DiscoveryDevice.toWritableMap(): WritableMap =
25
+ Arguments.createMap().apply {
26
+ putString("uid", uid)
27
+ putString("name", name)
28
+ putMap("ledgerDevice", ledgerDevice.toWritableMap())
29
+ }
30
+
31
+
32
+ internal fun LogLevel.toSerializedString(): String =
33
+ when (this) {
34
+ LogLevel.DEBUG -> "debug"
35
+ LogLevel.INFO -> "info"
36
+ LogLevel.WARNING -> "warning"
37
+ LogLevel.ERROR -> "error"
38
+ }
39
+
40
+
41
+ internal fun LogInfo.toWritableMap(): WritableMap =
42
+ Arguments.createMap().apply {
43
+ putString("level", level.toSerializedString())
44
+ putString("tag", "[TransportHidModule][${tag}]")
45
+ putString("message", message)
46
+ putMap("jsonPayLoad", Arguments.makeNativeMap(jsonPayLoad))
47
+ putString("timestamp", Clock.System.now().toEpochMilliseconds().toString())
48
+ }
49
+
50
+ internal fun InternalConnectionResult.toWritableMap(): WritableMap =
51
+ when (this) {
52
+ is InternalConnectionResult.Connected -> {
53
+ Arguments.createMap().apply {
54
+ putBoolean("success", true)
55
+ putString("sessionId", sessionId)
56
+ putMap("ledgerDevice", device.ledgerDevice.toWritableMap())
57
+ putString("deviceName", device.name)
58
+ }
59
+ }
60
+ is InternalConnectionResult.ConnectionError -> {
61
+ Arguments.createMap().apply {
62
+ putString("error", when (error) {
63
+ /**
64
+ * Most of these errors are for the BLE lib so it does not really make sense
65
+ * to have them here but for the sake of being explicit and not using an "else"
66
+ * where a new error type could be added, we list everything.
67
+ */
68
+ InternalConnectionResult.Failure.BleNotSupported -> "BleNotSupported"
69
+ InternalConnectionResult.Failure.ConnectionTimeout -> "ConnectionTimeout"
70
+ InternalConnectionResult.Failure.DeviceConnectivityBluetoothDisabled -> "DeviceConnectivityBluetoothDisabled"
71
+ InternalConnectionResult.Failure.DeviceConnectivityLocationDisabled -> "DeviceConnectivityLocationDisabled"
72
+ InternalConnectionResult.Failure.DeviceNotFound -> "DeviceNotFound"
73
+ InternalConnectionResult.Failure.InitializingFailed -> "InitializingFailed"
74
+ InternalConnectionResult.Failure.InternalState -> "InternalState"
75
+ InternalConnectionResult.Failure.NoDeviceAddress -> "NoDeviceAddress"
76
+ InternalConnectionResult.Failure.PairingFailed -> "PairingFailed"
77
+ InternalConnectionResult.Failure.PermissionNotGranted -> "PermissionNotGranted"
78
+ InternalConnectionResult.Failure.ServiceNotFound -> "ServiceNotFound"
79
+ is InternalConnectionResult.Failure.Unknown -> "UnknownError: ${error.msg}"
80
+ })
81
+ putBoolean("success", false)
82
+ }
83
+ }
84
+ }
85
+
86
+ internal fun SendApduResult.toWritableMap(): WritableMap {
87
+ when(this) {
88
+ is SendApduResult.Success -> {
89
+ return Arguments.createMap().apply {
90
+ putBoolean("success", true)
91
+ putString("apdu", Base64.encodeToString(apdu, Base64.DEFAULT))
92
+ }
93
+ }
94
+ is SendApduResult.Failure -> {
95
+ return Arguments.createMap().apply {
96
+ putBoolean("success", false)
97
+ putString("error", when (reason) {
98
+ SendApduFailureReason.ApduNotWellFormatted -> "ApduNotWellFormatted"
99
+ SendApduFailureReason.DeviceBusy -> "DeviceBusy"
100
+ SendApduFailureReason.DeviceLocked -> "DeviceLocked"
101
+ SendApduFailureReason.DeviceNotFound -> "DeviceNotFound"
102
+ SendApduFailureReason.NoResponse -> "NoResponse"
103
+ SendApduFailureReason.NoUsbEndpointFound -> "NoUsbEndpointFound"
104
+ SendApduFailureReason.DeviceDisconnected -> "DeviceDisconnected"
105
+ SendApduFailureReason.Unknown -> "Unknown"
106
+ })
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ internal fun TransportEvent.DeviceConnectionLost.toWritableMap(): WritableMap =
113
+ Arguments.createMap().apply {
114
+ putString("id", id)
115
+ }
116
+
117
+ /* lists */
118
+
119
+ fun List<DiscoveryDevice>.toWritableArray(): WritableArray =
120
+ Arguments.createArray().apply {
121
+ forEach {
122
+ pushMap(it.toWritableMap())
123
+ }
124
+ }
@@ -0,0 +1,16 @@
1
+ /*
2
+ * SPDX-FileCopyrightText: 2023 Ledger SAS
3
+ * SPDX-License-Identifier: LicenseRef-LEDGER
4
+ */
5
+
6
+ package com.ledger.devicesdk.shared.androidMain.transport.usb
7
+
8
+ import com.ledger.devicesdk.shared.internal.transport.Transport
9
+ import com.ledger.devicesdk.shared.androidMain.transport.usb.model.UsbPermissionEvent
10
+ import com.ledger.devicesdk.shared.androidMain.transport.usb.model.UsbState
11
+
12
+ internal interface AndroidUsbTransport: Transport {
13
+ fun updateUsbState(state: UsbState)
14
+
15
+ fun updateUsbEvent(event: UsbPermissionEvent)
16
+ }